Skip to content

Commit 004f145

Browse files
committed
Sema: Fix some problems with generic typealiases
The underlying type can now refer to generic parameters from an outer context, and we allow qualified and unqualified access to such typealiases. One problem remains, with specializations of generic typealiases in expression parsing context, marked with FIXME in the test.
1 parent c06fd1a commit 004f145

File tree

5 files changed

+216
-84
lines changed

5 files changed

+216
-84
lines changed

lib/Sema/ConstraintSystem.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -593,8 +593,8 @@ namespace {
593593
// pointing at a generic TypeAliasDecl here. If we find a way to
594594
// handle generic TypeAliases elsewhere, this can just become a
595595
// call to BoundGenericType::get().
596-
return cs.TC.applyUnboundGenericArguments(unbound, SourceLoc(), cs.DC,
597-
arguments,
596+
return cs.TC.applyUnboundGenericArguments(unbound, unboundDecl,
597+
SourceLoc(), cs.DC, arguments,
598598
/*isGenericSignature*/false,
599599
/*resolver*/nullptr);
600600
}

lib/Sema/TypeCheckType.cpp

Lines changed: 90 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ Type TypeChecker::resolveTypeInContext(
209209
// If we have a callback to report dependencies, do so.
210210
if (unsatisfiedDependency &&
211211
(*unsatisfiedDependency)(requestResolveTypeDecl(typeDecl)))
212-
return nullptr;
212+
return Type();
213213

214214
// If we found a generic parameter, map to the archetype if there is one.
215215
if (auto genericParam = dyn_cast<GenericTypeParamDecl>(typeDecl)) {
@@ -233,7 +233,7 @@ Type TypeChecker::resolveTypeInContext(
233233
// We might have an invalid extension that didn't resolve.
234234
if (ownerNominal == nullptr && ownerDC->isExtensionContext()) {
235235
assert(cast<ExtensionDecl>(ownerDC)->isInvalid());
236-
return ErrorType::get(ownerDC->getASTContext());
236+
return ErrorType::get(Context);
237237
}
238238

239239
auto assocType = dyn_cast<AssociatedTypeDecl>(typeDecl);
@@ -372,7 +372,7 @@ Type TypeChecker::resolveTypeInContext(
372372

373373
auto protoSelf = parentDC->getProtocolSelf();
374374
if (protoSelf == nullptr)
375-
return ErrorType::get(parentDC->getASTContext());
375+
return ErrorType::get(Context);
376376

377377
auto selfType = protoSelf
378378
->getDeclaredType()
@@ -402,61 +402,85 @@ Type TypeChecker::resolveTypeInContext(
402402
}
403403

404404
assert(incomplete && "Should have found type by now");
405-
return ErrorType::get(ownerDC->getASTContext());
405+
return ErrorType::get(Context);
406406
}
407407

408-
Type TypeChecker::applyGenericArguments(Type type, SourceLoc loc,
409-
DeclContext *dc,
408+
Type TypeChecker::applyGenericArguments(Type type, TypeDecl *decl,
409+
SourceLoc loc, DeclContext *dc,
410410
GenericIdentTypeRepr *generic,
411411
bool isGenericSignature,
412412
GenericTypeResolver *resolver) {
413413

414-
auto unbound = type->getAs<UnboundGenericType>();
415-
if (!unbound) {
416-
if (!type->is<ErrorType>()) {
417-
auto diag = diagnose(loc, diag::not_a_generic_type, type);
414+
if (type->is<ErrorType>()) {
415+
generic->setInvalid();
416+
return type;
417+
}
418+
419+
// We must either have an unbound generic type, or a generic type alias.
420+
if (!type->is<UnboundGenericType>() &&
421+
!(isa<TypeAliasDecl>(decl) &&
422+
cast<TypeAliasDecl>(decl)->getGenericParams())) {
423+
424+
auto diag = diagnose(loc, diag::not_a_generic_type, type);
425+
426+
// Don't add fixit on module type; that isn't the right type regardless
427+
// of whether it had generic arguments.
428+
if (!type->is<ModuleType>())
429+
diag.fixItRemove(generic->getAngleBrackets());
418430

419-
// Don't add fixit on module type; that isn't the right type regardless
420-
// of whether it had generic arguments.
421-
if (!type->is<ModuleType>())
422-
diag.fixItRemove(generic->getAngleBrackets());
423-
}
424431
generic->setInvalid();
425432
return type;
426433
}
427434

435+
// If we have a non-generic type alias, we have an unbound generic type.
436+
// Grab the decl from the unbound generic type.
437+
//
438+
// The idea is if you write:
439+
//
440+
// typealias Foo = Bar.Baz
441+
//
442+
// Then 'Foo<Int>' applies arguments to Bar.Baz, whereas if you write:
443+
//
444+
// typealias Foo<T> = Bar.Baz<T>
445+
//
446+
// Then 'Foo<Int>' applies arguments to Foo itself.
447+
//
448+
if (isa<TypeAliasDecl>(decl) &&
449+
!cast<TypeAliasDecl>(decl)->getGenericParams()) {
450+
decl = type->castTo<UnboundGenericType>()->getDecl();
451+
}
452+
428453
// Make sure we have the right number of generic arguments.
429454
// FIXME: If we have fewer arguments than we need, that might be okay, if
430455
// we're allowed to deduce the remaining arguments from context.
431-
auto unboundDecl = unbound->getDecl();
456+
auto genericDecl = cast<GenericTypeDecl>(decl);
432457
auto genericArgs = generic->getGenericArgs();
433-
auto genericParams = unboundDecl->getGenericParams();
458+
auto genericParams = genericDecl->getGenericParams();
434459
if (genericParams->size() != genericArgs.size()) {
435-
diagnose(loc, diag::type_parameter_count_mismatch, unboundDecl->getName(),
460+
diagnose(loc, diag::type_parameter_count_mismatch, decl->getName(),
436461
genericParams->size(), genericArgs.size(),
437462
genericArgs.size() < genericParams->size())
438463
.highlight(generic->getAngleBrackets());
439-
diagnose(unboundDecl, diag::generic_type_declared_here,
440-
unboundDecl->getName());
464+
diagnose(decl, diag::generic_type_declared_here,
465+
decl->getName());
441466
return nullptr;
442467
}
443468

444469
SmallVector<TypeLoc, 8> args;
445470
for (auto tyR : genericArgs)
446471
args.push_back(tyR);
447472

448-
return applyUnboundGenericArguments(unbound, loc, dc, args,
473+
return applyUnboundGenericArguments(type, genericDecl, loc, dc, args,
449474
isGenericSignature, resolver);
450475
}
451476

452477
/// Apply generic arguments to the given type.
453478
Type TypeChecker::applyUnboundGenericArguments(
454-
UnboundGenericType *unbound, SourceLoc loc, DeclContext *dc,
479+
Type type, GenericTypeDecl *decl, SourceLoc loc, DeclContext *dc,
455480
MutableArrayRef<TypeLoc> genericArgs, bool isGenericSignature,
456481
GenericTypeResolver *resolver) {
457482

458-
assert(unbound &&
459-
genericArgs.size() == unbound->getDecl()->getGenericParams()->size() &&
483+
assert(genericArgs.size() == decl->getGenericParams()->size() &&
460484
"invalid arguments, use applyGenericArguments for diagnostic emitting");
461485

462486
// Make sure we always have a resolver to use.
@@ -477,50 +501,48 @@ Type TypeChecker::applyUnboundGenericArguments(
477501

478502
genericArgTypes.push_back(genericArg.getType());
479503
}
480-
504+
481505
// If we're completing a generic TypeAlias, then we map the types provided
482506
// onto the underlying type.
483-
if (auto *TAD = dyn_cast<TypeAliasDecl>(unbound->getDecl())) {
507+
if (auto *TAD = dyn_cast<TypeAliasDecl>(decl)) {
484508
auto signature = TAD->getGenericSignature();
485-
assert(TAD->getGenericParams()->getAllArchetypes().size()
486-
== genericArgs.size() &&
487-
signature->getInnermostGenericParams().size() == genericArgs.size()&&
488-
"argument arity mismatch");
489509

490-
SmallVector<Substitution, 4> subs;
491-
subs.reserve(genericArgs.size());
492-
493-
// If we have any nested archetypes from an outer type, include them
494-
// verbatim.
495-
auto outerParams = signature->getGenericParams();
496-
outerParams = outerParams.drop_back(genericArgs.size());
497-
for (auto param : outerParams) {
498-
Type type = resolver->resolveGenericTypeParamType(param);
510+
TypeSubstitutionMap subs;
511+
for (unsigned i = 0, e = genericArgs.size(); i < e; i++) {
512+
auto t = signature->getInnermostGenericParams()[i];
513+
subs[t->getCanonicalType().getPointer()] = genericArgs[i].getType();
514+
}
499515

500-
subs.push_back(Substitution(type, {}));
516+
if (auto outerSig = TAD->getDeclContext()->getGenericSignatureOfContext()) {
517+
for (auto outerParam : outerSig->getGenericParams()) {
518+
subs[outerParam->getCanonicalType().getPointer()] =
519+
ArchetypeBuilder::mapTypeIntoContext(TAD->getDeclContext(),
520+
outerParam);
521+
}
501522
}
502-
503-
for (auto t : genericArgs)
504-
subs.push_back(Substitution(t.getType(), {}));
505-
506-
auto subst = TAD->getGenericParams()->getSubstitutionMap(subs);
523+
524+
// FIXME: Change callers to pass the right type in for generic typealiases
525+
if (type->is<UnboundGenericType>() || isa<NameAliasType>(type.getPointer())) {
526+
type = ArchetypeBuilder::mapTypeOutOfContext(TAD, TAD->getUnderlyingType());
527+
}
528+
529+
type = type.subst(dc->getParentModule(), subs, None);
507530

508531
// FIXME: return a SubstitutedType to preserve the fact that
509532
// we resolved a generic TypeAlias, for availability diagnostics.
510533
// A better fix might be to introduce a BoundGenericAliasType
511534
// which desugars as appropriate.
512-
return SubstitutedType::get(
513-
TAD->getDeclaredType(),
514-
TAD->getUnderlyingType().subst(TAD->getParentModule(), subst, None),
515-
Context);
535+
return SubstitutedType::get(TAD->getDeclaredType(), type, Context);
516536
}
517537

518538
// Form the bound generic type.
519-
auto *BGT = BoundGenericType::get(cast<NominalTypeDecl>(unbound->getDecl()),
520-
unbound->getParent(), genericArgTypes);
539+
auto *UGT = type->castTo<UnboundGenericType>();
540+
auto *BGT = BoundGenericType::get(cast<NominalTypeDecl>(decl),
541+
UGT->getParent(), genericArgTypes);
542+
521543
// Check protocol conformance.
522544
if (!BGT->hasTypeParameter() && !BGT->hasTypeVariable()) {
523-
SourceLoc noteLoc = unbound->getDecl()->getLoc();
545+
SourceLoc noteLoc = decl->getLoc();
524546
if (noteLoc.isInvalid())
525547
noteLoc = loc;
526548

@@ -532,14 +554,13 @@ Type TypeChecker::applyUnboundGenericArguments(
532554
ArrayRef<Type> allGenericArgs = BGT->getAllGenericArgs(scratch);
533555

534556
// Check the generic arguments against the generic signature.
535-
auto genericSig = unbound->getDecl()->getGenericSignature();
536-
if (!unbound->getDecl()->hasType() ||
537-
unbound->getDecl()->isValidatingGenericSignature()) {
557+
auto genericSig = decl->getGenericSignature();
558+
if (!decl->hasType() || decl->isValidatingGenericSignature()) {
538559
diagnose(loc, diag::recursive_requirement_reference);
539560
return nullptr;
540561
}
541562
assert(genericSig != nullptr);
542-
if (checkGenericArguments(dc, loc, noteLoc, unbound, genericSig,
563+
if (checkGenericArguments(dc, loc, noteLoc, UGT, genericSig,
543564
allGenericArgs))
544565
return nullptr;
545566

@@ -549,14 +570,16 @@ Type TypeChecker::applyUnboundGenericArguments(
549570
return BGT;
550571
}
551572

552-
static Type applyGenericTypeReprArgs(TypeChecker &TC, Type type, SourceLoc loc,
573+
static Type applyGenericTypeReprArgs(TypeChecker &TC, Type type,
574+
TypeDecl *decl,
575+
SourceLoc loc,
553576
DeclContext *dc,
554577
GenericIdentTypeRepr *generic,
555578
bool isGenericSignature,
556579
GenericTypeResolver *resolver) {
557580

558-
Type ty = TC.applyGenericArguments(type, loc, dc, generic, isGenericSignature,
559-
resolver);
581+
Type ty = TC.applyGenericArguments(type, decl, loc, dc, generic,
582+
isGenericSignature, resolver);
560583
if (!ty)
561584
return ErrorType::get(TC.Context);
562585
return ty;
@@ -660,7 +683,7 @@ static Type resolveTypeDecl(TypeChecker &TC, TypeDecl *typeDecl, SourceLoc loc,
660683

661684
if (generic && !options.contains(TR_ResolveStructure)) {
662685
// Apply the generic arguments to the type.
663-
type = applyGenericTypeReprArgs(TC, type, loc, dc, generic,
686+
type = applyGenericTypeReprArgs(TC, type, typeDecl, loc, dc, generic,
664687
options.contains(TR_GenericSignature),
665688
resolver);
666689
}
@@ -1035,7 +1058,7 @@ static Type resolveNestedIdentTypeComponent(
10351058
// If there are generic arguments, apply them now.
10361059
if (auto genComp = dyn_cast<GenericIdentTypeRepr>(comp)) {
10371060
memberType = applyGenericTypeReprArgs(
1038-
TC, memberType, comp->getIdLoc(), DC, genComp,
1061+
TC, memberType, typeDecl, comp->getIdLoc(), DC, genComp,
10391062
options.contains(TR_GenericSignature), resolver);
10401063

10411064
// Propagate failure.
@@ -1154,7 +1177,7 @@ static Type resolveNestedIdentTypeComponent(
11541177
// If there are generic arguments, apply them now.
11551178
if (auto genComp = dyn_cast<GenericIdentTypeRepr>(comp))
11561179
memberType = applyGenericTypeReprArgs(
1157-
TC, memberType, comp->getIdLoc(), DC, genComp,
1180+
TC, memberType, member, comp->getIdLoc(), DC, genComp,
11581181
options.contains(TR_GenericSignature), resolver);
11591182

11601183
// If we found a reference to an associated type or other member type that
@@ -2235,16 +2258,17 @@ Type TypeResolver::resolveDictionaryType(DictionaryTypeRepr *repr,
22352258

22362259
Type valueTy = resolveType(repr->getValue(), withoutContext(options));
22372260
if (!valueTy || valueTy->is<ErrorType>()) return valueTy;
2238-
2261+
2262+
auto dictDecl = TC.Context.getDictionaryDecl();
2263+
22392264
if (auto dictTy = TC.getDictionaryType(repr->getBrackets().Start, keyTy,
22402265
valueTy)) {
22412266
// Check the requirements on the generic arguments.
2242-
auto unboundTy = UnboundGenericType::get(TC.Context.getDictionaryDecl(),
2243-
nullptr, TC.Context);
2267+
auto unboundTy = dictDecl->getDeclaredType();
22442268
TypeLoc args[2] = { TypeLoc(repr->getKey()), TypeLoc(repr->getValue()) };
22452269

22462270
if (!TC.applyUnboundGenericArguments(
2247-
unboundTy, repr->getStartLoc(), DC, args,
2271+
unboundTy, dictDecl, repr->getStartLoc(), DC, args,
22482272
options.contains(TR_GenericSignature), Resolver)) {
22492273
return ErrorType::get(TC.Context);
22502274
}

lib/Sema/TypeChecker.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,7 @@ class TypeChecker final : public LazyResolver {
774774
/// to be in a correct and valid form.
775775
///
776776
/// \param type The generic type to which to apply arguments.
777+
/// \param decl The declaration of the type.
777778
/// \param loc The source location for diagnostic reporting.
778779
/// \param dc The context where the arguments are applied.
779780
/// \param generic The arguments to apply with the angle bracket range for
@@ -786,8 +787,8 @@ class TypeChecker final : public LazyResolver {
786787
/// error.
787788
///
788789
/// \see applyUnboundGenericArguments
789-
Type applyGenericArguments(Type type, SourceLoc loc, DeclContext *dc,
790-
GenericIdentTypeRepr *generic,
790+
Type applyGenericArguments(Type type, TypeDecl *decl, SourceLoc loc,
791+
DeclContext *dc, GenericIdentTypeRepr *generic,
791792
bool isGenericSignature,
792793
GenericTypeResolver *resolver);
793794

@@ -797,7 +798,8 @@ class TypeChecker final : public LazyResolver {
797798
/// number of generic arguments given, whereas applyGenericArguments emits
798799
/// diagnostics in those cases.
799800
///
800-
/// \param unbound The unbound generic type to which to apply arguments.
801+
/// \param type The unbound generic type to which to apply arguments.
802+
/// \param decl The declaration of the type.
801803
/// \param loc The source location for diagnostic reporting.
802804
/// \param dc The context where the arguments are applied.
803805
/// \param genericArgs The list of generic arguments to apply to the type.
@@ -809,8 +811,8 @@ class TypeChecker final : public LazyResolver {
809811
/// error.
810812
///
811813
/// \see applyGenericArguments
812-
Type applyUnboundGenericArguments(UnboundGenericType *unbound, SourceLoc loc,
813-
DeclContext *dc,
814+
Type applyUnboundGenericArguments(Type type, GenericTypeDecl *decl,
815+
SourceLoc loc, DeclContext *dc,
814816
MutableArrayRef<TypeLoc> genericArgs,
815817
bool isGenericSignature,
816818
GenericTypeResolver *resolver);

0 commit comments

Comments
 (0)