Skip to content

Commit 9826aaa

Browse files
authored
Merge pull request #28275 from slavapestov/check-where-clause-non-generic-type
Check generic requirements of parent context when realizing non-generic types
2 parents 0b6ef0d + 0e06792 commit 9826aaa

File tree

9 files changed

+224
-161
lines changed

9 files changed

+224
-161
lines changed

lib/Sema/ConstraintSystem.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -677,8 +677,6 @@ Type ConstraintSystem::openUnboundGenericType(
677677
Type type, ConstraintLocatorBuilder locator) {
678678
assert(!type->getCanonicalType()->hasTypeParameter());
679679

680-
checkNestedTypeConstraints(*this, type, locator);
681-
682680
if (!type->hasUnboundGenericType())
683681
return type;
684682

@@ -1036,6 +1034,8 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value,
10361034
TypeResolverContext::InExpression,
10371035
/*isSpecialized=*/false);
10381036

1037+
checkNestedTypeConstraints(*this, type, locator);
1038+
10391039
// Open the type.
10401040
type = openUnboundGenericType(type, locator);
10411041

@@ -1289,6 +1289,9 @@ ConstraintSystem::getTypeOfMemberReference(
12891289

12901290
auto memberTy = TypeChecker::substMemberTypeWithBase(DC->getParentModule(),
12911291
typeDecl, baseObjTy);
1292+
1293+
checkNestedTypeConstraints(*this, memberTy, locator);
1294+
12921295
// Open the type if it was a reference to a generic type.
12931296
memberTy = openUnboundGenericType(memberTy, locator);
12941297

lib/Sema/TypeCheckType.cpp

Lines changed: 113 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -626,17 +626,107 @@ static bool isPointerToVoid(ASTContext &Ctx, Type Ty, bool &IsMutable) {
626626
return BGT->getGenericArgs().front()->isVoid();
627627
}
628628

629-
Type TypeChecker::applyGenericArguments(Type type,
630-
SourceLoc loc,
631-
TypeResolution resolution,
632-
GenericIdentTypeRepr *generic,
633-
TypeResolutionOptions options) {
629+
static Type checkConstrainedExtensionRequirements(Type type,
630+
SourceLoc loc,
631+
DeclContext *dc) {
632+
// Even if the type is not generic, it might be inside of a generic
633+
// context, so we need to check requirements.
634+
GenericTypeDecl *decl;
635+
Type parentTy;
636+
if (auto *aliasTy = dyn_cast<TypeAliasType>(type.getPointer())) {
637+
decl = aliasTy->getDecl();
638+
parentTy = aliasTy->getParent();
639+
} else if (auto *nominalTy = type->getAs<NominalType>()) {
640+
decl = nominalTy->getDecl();
641+
parentTy = nominalTy->getParent();
642+
} else {
643+
return type;
644+
}
645+
646+
// FIXME: Some day the type might also have its own 'where' clause, even
647+
// if its not generic.
648+
649+
auto *ext = dyn_cast<ExtensionDecl>(decl->getDeclContext());
650+
if (!ext || !ext->isConstrainedExtension())
651+
return type;
652+
653+
if (parentTy->hasUnboundGenericType() ||
654+
parentTy->hasTypeVariable()) {
655+
return type;
656+
}
657+
658+
auto subMap = parentTy->getContextSubstitutions(ext);
659+
660+
SourceLoc noteLoc = ext->getLoc();
661+
if (noteLoc.isInvalid())
662+
noteLoc = loc;
663+
664+
auto genericSig = ext->getGenericSignature();
665+
auto result =
666+
TypeChecker::checkGenericArguments(
667+
dc, loc, noteLoc, type,
668+
genericSig->getGenericParams(),
669+
genericSig->getRequirements(),
670+
QueryTypeSubstitutionMap{subMap},
671+
TypeChecker::LookUpConformance(dc),
672+
None);
673+
674+
switch (result) {
675+
case RequirementCheckResult::Failure:
676+
case RequirementCheckResult::SubstitutionFailure:
677+
return ErrorType::get(dc->getASTContext());
678+
case RequirementCheckResult::Success:
679+
return type;
680+
}
681+
}
682+
683+
static void diagnoseUnboundGenericType(Type ty, SourceLoc loc);
684+
685+
/// Apply generic arguments to the given type.
686+
///
687+
/// If the type is itself not generic, this does nothing.
688+
///
689+
/// This function emits diagnostics about an invalid type or the wrong number
690+
/// of generic arguments, whereas applyUnboundGenericArguments requires this
691+
/// to be in a correct and valid form.
692+
///
693+
/// \param type The generic type to which to apply arguments.
694+
/// \param resolution The type resolution to perform.
695+
/// \param comp The arguments to apply with the angle bracket range for
696+
/// diagnostics.
697+
/// \param options The type resolution context.
698+
///
699+
/// \returns A BoundGenericType bound to the given arguments, or null on
700+
/// error.
701+
///
702+
/// \see applyUnboundGenericArguments
703+
static Type applyGenericArguments(Type type,
704+
TypeResolution resolution,
705+
ComponentIdentTypeRepr *comp,
706+
TypeResolutionOptions options) {
707+
auto dc = resolution.getDeclContext();
708+
auto loc = comp->getIdLoc();
709+
710+
auto *generic = dyn_cast<GenericIdentTypeRepr>(comp);
711+
if (!generic) {
712+
if (type->is<UnboundGenericType>() &&
713+
!options.is(TypeResolverContext::TypeAliasDecl) &&
714+
!options.contains(TypeResolutionFlags::AllowUnboundGenerics)) {
715+
diagnoseUnboundGenericType(type, loc);
716+
return ErrorType::get(type->getASTContext());
717+
}
718+
719+
if (resolution.getStage() == TypeResolutionStage::Structural)
720+
return type;
721+
722+
return checkConstrainedExtensionRequirements(type, loc, dc);
723+
}
724+
634725
if (type->hasError()) {
635726
generic->setInvalid();
636727
return type;
637728
}
638729

639-
auto dc = resolution.getDeclContext();
640730
auto &ctx = dc->getASTContext();
641731
auto &diags = ctx.Diags;
642732

@@ -716,15 +806,14 @@ Type TypeChecker::applyGenericArguments(Type type,
716806
args.push_back(substTy);
717807
}
718808

719-
auto result = applyUnboundGenericArguments(unboundType, genericDecl, loc,
720-
resolution, args);
721-
if (!result)
722-
return result;
809+
auto result = TypeChecker::applyUnboundGenericArguments(
810+
unboundType, genericDecl, loc,
811+
resolution, args);
723812

724813
if (!options.contains(TypeResolutionFlags::AllowUnavailable)) {
725814
if (options.isAnyExpr() || dc->getParent()->isLocalContext())
726815
if (dc->getResilienceExpansion() == ResilienceExpansion::Minimal)
727-
diagnoseGenericTypeExportability(loc, result, dc);
816+
TypeChecker::diagnoseGenericTypeExportability(loc, result, dc);
728817
}
729818

730819
// Migration hack.
@@ -908,41 +997,25 @@ static void maybeDiagnoseBadConformanceRef(DeclContext *dc,
908997
}
909998

910999
/// Returns a valid type or ErrorType in case of an error.
911-
static Type resolveTypeDecl(TypeDecl *typeDecl, SourceLoc loc,
1000+
static Type resolveTypeDecl(TypeDecl *typeDecl,
9121001
DeclContext *foundDC, TypeResolution resolution,
913-
GenericIdentTypeRepr *generic,
1002+
ComponentIdentTypeRepr *comp,
9141003
TypeResolutionOptions options) {
915-
9161004
// Resolve the type declaration to a specific type. How this occurs
9171005
// depends on the current context and where the type was found.
918-
Type type = TypeChecker::resolveTypeInContext(typeDecl, foundDC, resolution,
919-
options, generic);
920-
921-
if (type->is<UnboundGenericType>() && !generic &&
922-
!options.is(TypeResolverContext::TypeAliasDecl) &&
923-
!options.contains(TypeResolutionFlags::AllowUnboundGenerics)) {
924-
diagnoseUnboundGenericType(type, loc);
925-
return ErrorType::get(typeDecl->getASTContext());
926-
}
1006+
Type type = TypeChecker::resolveTypeInContext(
1007+
typeDecl, foundDC, resolution, options,
1008+
isa<GenericIdentTypeRepr>(comp));
9271009

9281010
if (type->hasError() && foundDC &&
9291011
(isa<AssociatedTypeDecl>(typeDecl) || isa<TypeAliasDecl>(typeDecl))) {
9301012
auto fromDC = resolution.getDeclContext();
9311013
assert(fromDC && "No declaration context for type resolution?");
9321014
maybeDiagnoseBadConformanceRef(fromDC, foundDC->getDeclaredInterfaceType(),
933-
loc, typeDecl);
934-
}
935-
936-
if (generic) {
937-
// Apply the generic arguments to the type.
938-
type = TypeChecker::applyGenericArguments(type, loc, resolution, generic,
939-
options);
940-
if (!type)
941-
return nullptr;
1015+
comp->getIdLoc(), typeDecl);
9421016
}
9431017

944-
assert(type);
945-
return type;
1018+
return applyGenericArguments(type, resolution, comp, options);
9461019
}
9471020

9481021
static std::string getDeclNameFromContext(DeclContext *dc,
@@ -1217,9 +1290,8 @@ resolveTopLevelIdentTypeComponent(TypeResolution resolution,
12171290
// that now.
12181291
if (auto *typeDecl = comp->getBoundDecl()) {
12191292
// Resolve the type declaration within this context.
1220-
return resolveTypeDecl(typeDecl, comp->getIdLoc(),
1221-
comp->getDeclContext(), resolution,
1222-
dyn_cast<GenericIdentTypeRepr>(comp), options);
1293+
return resolveTypeDecl(typeDecl, comp->getDeclContext(), resolution,
1294+
comp, options);
12231295
}
12241296

12251297
// Resolve the first component, which is the only one that requires
@@ -1265,13 +1337,8 @@ resolveTopLevelIdentTypeComponent(TypeResolution resolution,
12651337
auto *foundDC = entry.getDeclContext();
12661338
auto *typeDecl = cast<TypeDecl>(entry.getValueDecl());
12671339

1268-
Type type = resolveTypeDecl(typeDecl, comp->getIdLoc(),
1269-
foundDC, resolution,
1270-
dyn_cast<GenericIdentTypeRepr>(comp), options);
1271-
1272-
if (!type)
1273-
return type;
1274-
1340+
Type type = resolveTypeDecl(typeDecl, foundDC, resolution,
1341+
comp, options);
12751342
if (type->is<ErrorType>())
12761343
return type;
12771344

@@ -1355,23 +1422,6 @@ static Type resolveNestedIdentTypeComponent(
13551422
auto &ctx = DC->getASTContext();
13561423
auto &diags = ctx.Diags;
13571424

1358-
auto maybeApplyGenericArgs = [&](Type memberType) {
1359-
// If there are generic arguments, apply them now.
1360-
if (auto genComp = dyn_cast<GenericIdentTypeRepr>(comp)) {
1361-
return TypeChecker::applyGenericArguments(memberType, comp->getIdLoc(),
1362-
resolution, genComp, options);
1363-
}
1364-
1365-
if (memberType->is<UnboundGenericType>() &&
1366-
!options.is(TypeResolverContext::TypeAliasDecl) &&
1367-
!options.contains(TypeResolutionFlags::AllowUnboundGenerics)) {
1368-
diagnoseUnboundGenericType(memberType, comp->getLoc());
1369-
return ErrorType::get(ctx);
1370-
}
1371-
1372-
return memberType;
1373-
};
1374-
13751425
auto maybeDiagnoseBadMemberType = [&](TypeDecl *member, Type memberType,
13761426
AssociatedTypeDecl *inferredAssocType) {
13771427
// Diagnose invalid cases.
@@ -1416,7 +1466,7 @@ static Type resolveNestedIdentTypeComponent(
14161466
return memberType;
14171467

14181468
// If there are generic arguments, apply them now.
1419-
return maybeApplyGenericArgs(memberType);
1469+
return applyGenericArguments(memberType, resolution, comp, options);
14201470
};
14211471

14221472
// Short-circuiting.
@@ -1433,7 +1483,7 @@ static Type resolveNestedIdentTypeComponent(
14331483
// type later on.
14341484
if (!memberType->is<DependentMemberType>() ||
14351485
memberType->castTo<DependentMemberType>()->getAssocType()) {
1436-
return maybeApplyGenericArgs(memberType);
1486+
return applyGenericArguments(memberType, resolution, comp, options);
14371487
}
14381488

14391489
return memberType;

lib/Sema/TypeChecker.h

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -630,28 +630,6 @@ class TypeChecker final {
630630
TypeResolutionOptions options,
631631
bool isSpecialized);
632632

633-
/// Apply generic arguments to the given type.
634-
///
635-
/// This function emits diagnostics about an invalid type or the wrong number
636-
/// of generic arguments, whereas applyUnboundGenericArguments requires this
637-
/// to be in a correct and valid form.
638-
///
639-
/// \param type The generic type to which to apply arguments.
640-
/// \param loc The source location for diagnostic reporting.
641-
/// \param resolution The type resolution to perform.
642-
/// \param generic The arguments to apply with the angle bracket range for
643-
/// diagnostics.
644-
/// \param options The type resolution context.
645-
///
646-
/// \returns A BoundGenericType bound to the given arguments, or null on
647-
/// error.
648-
///
649-
/// \see applyUnboundGenericArguments
650-
static Type applyGenericArguments(Type type, SourceLoc loc,
651-
TypeResolution resolution,
652-
GenericIdentTypeRepr *generic,
653-
TypeResolutionOptions options);
654-
655633
/// Apply generic arguments to the given type.
656634
///
657635
/// This function requires a valid unbound generic type with the correct

0 commit comments

Comments
 (0)