Skip to content

Commit 588603f

Browse files
committed
Sema: Pass the correct substitutions to 'checkGenericArguments' instead of mapping into context in place
1 parent 48c5d14 commit 588603f

File tree

7 files changed

+93
-46
lines changed

7 files changed

+93
-46
lines changed

lib/Sema/TypeCheckGeneric.cpp

+2-10
Original file line numberDiff line numberDiff line change
@@ -800,7 +800,7 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator,
800800
///
801801

802802
RequirementCheckResult TypeChecker::checkGenericArguments(
803-
DeclContext *dc, SourceLoc loc, SourceLoc noteLoc, Type owner,
803+
ModuleDecl *module, SourceLoc loc, SourceLoc noteLoc, Type owner,
804804
TypeArrayView<GenericTypeParamType> genericParams,
805805
ArrayRef<Requirement> requirements,
806806
TypeSubstitutionFn substitutions,
@@ -815,7 +815,6 @@ RequirementCheckResult TypeChecker::checkGenericArguments(
815815
SmallVector<RequirementSet, 8> pendingReqs;
816816
pendingReqs.push_back({requirements, {}});
817817

818-
auto *module = dc->getParentModule();
819818
ASTContext &ctx = module->getASTContext();
820819
while (!pendingReqs.empty()) {
821820
auto current = pendingReqs.pop_back_val();
@@ -824,14 +823,7 @@ RequirementCheckResult TypeChecker::checkGenericArguments(
824823
auto req = rawReq;
825824
if (current.Parents.empty()) {
826825
auto substed = rawReq.subst(
827-
[&](SubstitutableType *type) -> Type {
828-
auto substType = substitutions(type);
829-
if (substType->hasTypeParameter())
830-
return dc->mapTypeIntoContext(substType);
831-
return substType;
832-
},
833-
LookUpConformanceInModule(module),
834-
options);
826+
substitutions, LookUpConformanceInModule(module), options);
835827
if (!substed) {
836828
// Another requirement will fail later; just continue.
837829
valid = false;

lib/Sema/TypeCheckProtocol.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -4705,8 +4705,9 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup(
47054705
// If the type comes from a constrained extension or has a 'where'
47064706
// clause, check those requirements now.
47074707
if (!skipRequirementCheck &&
4708-
!TypeChecker::checkContextualRequirements(genericDecl, Adoptee,
4709-
SourceLoc(), DC)) {
4708+
!TypeChecker::checkContextualRequirements(
4709+
genericDecl, Adoptee, SourceLoc(), DC->getParentModule(),
4710+
DC->getGenericSignatureOfContext())) {
47104711
continue;
47114712
}
47124713

@@ -4798,7 +4799,7 @@ void ConformanceChecker::ensureRequirementsAreSatisfied() {
47984799
proto, substitutingType, ProtocolConformanceRef(Conformance));
47994800

48004801
auto result = TypeChecker::checkGenericArguments(
4801-
DC, Loc, Loc,
4802+
DC->getParentModule(), Loc, Loc,
48024803
// FIXME: maybe this should be the conformance's type
48034804
proto->getDeclaredInterfaceType(),
48044805
{ proto->getSelfInterfaceType() },

lib/Sema/TypeCheckProtocolInference.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -1086,8 +1086,8 @@ bool AssociatedTypeInference::checkCurrentTypeWitnesses(
10861086
sanitizeProtocolRequirements(proto, proto->getRequirementSignature(),
10871087
sanitizedRequirements);
10881088
auto result =
1089-
TypeChecker::checkGenericArguments(dc, SourceLoc(), SourceLoc(),
1090-
typeInContext,
1089+
TypeChecker::checkGenericArguments(dc->getParentModule(), SourceLoc(),
1090+
SourceLoc(), typeInContext,
10911091
{ proto->getSelfInterfaceType() },
10921092
sanitizedRequirements,
10931093
QuerySubstitutionMap{substitutions},
@@ -1134,7 +1134,7 @@ bool AssociatedTypeInference::checkConstrainedExtension(ExtensionDecl *ext) {
11341134

11351135
SubstOptions options = getSubstOptionsWithCurrentTypeWitnesses();
11361136
switch (TypeChecker::checkGenericArguments(
1137-
dc, SourceLoc(), SourceLoc(), adoptee,
1137+
dc->getParentModule(), SourceLoc(), SourceLoc(), adoptee,
11381138
ext->getGenericSignature().getGenericParams(),
11391139
ext->getGenericSignature().getRequirements(),
11401140
QueryTypeSubstitutionMap{subs},

lib/Sema/TypeCheckType.cpp

+33-18
Original file line numberDiff line numberDiff line change
@@ -569,17 +569,12 @@ static bool isPointerToVoid(ASTContext &Ctx, Type Ty, bool &IsMutable) {
569569
return BGT->getGenericArgs().front()->isVoid();
570570
}
571571

572-
/// Even if the type is not generic, it might be inside of a generic
573-
/// context or have a free-standing 'where' clause, so we need to
574-
/// those check requirements too.
575-
///
576-
/// Return true on success.
577572
bool TypeChecker::checkContextualRequirements(GenericTypeDecl *decl,
578-
Type parentTy,
579-
SourceLoc loc,
580-
DeclContext *dc) {
581-
if (!parentTy || parentTy->hasUnboundGenericType() ||
582-
parentTy->hasTypeVariable()) {
573+
Type parentTy, SourceLoc loc,
574+
ModuleDecl *module,
575+
GenericSignature contextSig) {
576+
assert(parentTy && "expected a parent type");
577+
if (parentTy->hasUnboundGenericType() || parentTy->hasTypeVariable()) {
583578
return true;
584579
}
585580

@@ -599,12 +594,16 @@ bool TypeChecker::checkContextualRequirements(GenericTypeDecl *decl,
599594
noteLoc = loc;
600595
}
601596

597+
if (contextSig) {
598+
parentTy = contextSig.getGenericEnvironment()->mapTypeIntoContext(parentTy);
599+
}
600+
602601
const auto subMap = parentTy->getContextSubstitutions(decl->getDeclContext());
603602
const auto genericSig = decl->getGenericSignature();
604603

605604
const auto result =
606605
TypeChecker::checkGenericArguments(
607-
dc, loc, noteLoc,
606+
module, loc, noteLoc,
608607
decl->getDeclaredInterfaceType(),
609608
genericSig.getGenericParams(),
610609
genericSig.getRequirements(),
@@ -679,7 +678,13 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
679678
return type;
680679
}
681680

682-
if (TypeChecker::checkContextualRequirements(decl, parentTy, loc, dc))
681+
if (!parentTy) {
682+
return type;
683+
}
684+
685+
if (TypeChecker::checkContextualRequirements(
686+
decl, parentTy, loc, dc->getParentModule(),
687+
resolution.getGenericSignature()))
683688
return type;
684689

685690
return ErrorType::get(resolution.getASTContext());
@@ -872,10 +877,6 @@ Type TypeResolution::applyUnboundGenericArguments(
872877
}
873878
}
874879

875-
SourceLoc noteLoc = decl->getLoc();
876-
if (noteLoc.isInvalid())
877-
noteLoc = loc;
878-
879880
// Realize the types of the generic arguments and add them to the
880881
// substitution map.
881882
for (unsigned i = 0, e = genericArgs.size(); i < e; ++i) {
@@ -895,11 +896,25 @@ Type TypeResolution::applyUnboundGenericArguments(
895896
auto *module = getDeclContext()->getParentModule();
896897

897898
if (!skipRequirementsCheck && getStage() > TypeResolutionStage::Structural) {
899+
TypeSubstitutionMap contextualSubs = subs;
900+
if (getStage() == TypeResolutionStage::Interface) {
901+
if (const auto contextSig = getGenericSignature()) {
902+
auto *genericEnv = contextSig.getGenericEnvironment();
903+
for (auto &pair : contextualSubs) {
904+
pair.second = genericEnv->mapTypeIntoContext(pair.second);
905+
}
906+
}
907+
}
908+
909+
SourceLoc noteLoc = decl->getLoc();
910+
if (noteLoc.isInvalid())
911+
noteLoc = loc;
912+
898913
auto result = TypeChecker::checkGenericArguments(
899-
getDeclContext(), loc, noteLoc,
914+
module, loc, noteLoc,
900915
UnboundGenericType::get(decl, parentTy, getASTContext()),
901916
genericSig.getGenericParams(), genericSig.getRequirements(),
902-
QueryTypeSubstitutionMap{subs});
917+
QueryTypeSubstitutionMap{contextualSubs});
903918

904919
switch (result) {
905920
case RequirementCheckResult::Failure:

lib/Sema/TypeCheckType.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -312,10 +312,6 @@ class TypeResolution {
312312
placeholderHandler(placeholderHandler),
313313
genericEnv(nullptr) {}
314314

315-
/// Retrieves the generic signature for the context, or NULL if there is
316-
/// no generic signature to resolve types.
317-
GenericSignature getGenericSignature() const;
318-
319315
public:
320316
/// Form a type resolution for the structure of a type, which does not
321317
/// attempt to resolve member types of type parameters to a particular
@@ -373,6 +369,10 @@ class TypeResolution {
373369
return placeholderHandler;
374370
}
375371

372+
/// Retrieves the generic signature for the context, or NULL if there is
373+
/// no generic signature to resolve types.
374+
GenericSignature getGenericSignature() const;
375+
376376
/// Resolves a TypeRepr to a type.
377377
///
378378
/// Performs name lookup, checking of generic arguments, and so on in order

lib/Sema/TypeChecker.h

+45-6
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ std::string gatherGenericParamBindingsText(
445445
/// Check the given set of generic arguments against the requirements in a
446446
/// generic signature.
447447
///
448-
/// \param dc The context in which the generic arguments should be checked.
448+
/// \param module The module to use for conformace lookup.
449449
/// \param loc The location at which any diagnostics should be emitted.
450450
/// \param noteLoc The location at which any notes will be printed.
451451
/// \param owner The type that owns the generic signature.
@@ -454,7 +454,7 @@ std::string gatherGenericParamBindingsText(
454454
/// should be checked.
455455
/// \param substitutions Substitutions from interface types of the signature.
456456
RequirementCheckResult checkGenericArguments(
457-
DeclContext *dc, SourceLoc loc, SourceLoc noteLoc, Type owner,
457+
ModuleDecl *module, SourceLoc loc, SourceLoc noteLoc, Type owner,
458458
TypeArrayView<GenericTypeParamType> genericParams,
459459
ArrayRef<Requirement> requirements, TypeSubstitutionFn substitutions,
460460
SubstOptions options = None);
@@ -465,10 +465,49 @@ RequirementCheckResult checkGenericArguments(
465465
ArrayRef<Requirement> requirements,
466466
TypeSubstitutionFn substitutions);
467467

468-
bool checkContextualRequirements(GenericTypeDecl *decl,
469-
Type parentTy,
470-
SourceLoc loc,
471-
DeclContext *dc);
468+
/// Checks whether the generic requirements imposed on the nested type
469+
/// declaration \p decl (if present) are in agreement with the substitutions
470+
/// that are needed to spell it as a member of the given parent type
471+
/// \p parentTy.
472+
///
473+
/// For example, given
474+
/// \code
475+
/// struct S<X> {}
476+
/// extension S where X == Bool {
477+
/// struct Inner {}
478+
/// }
479+
/// \endcode
480+
/// \c Inner cannot be referenced on \c S<Int>, because its contextual
481+
/// requirement \c X \c == \c Bool is not satisfied by the substitution
482+
/// \c [X \c = \c Int].
483+
///
484+
/// Similarly, \c typealias \c Y below is a viable type witness in the
485+
/// conformance of \c S to \c P, because its contextual requirement
486+
/// \c Self.X \c == \c Bool is satisfied by the substitution
487+
/// \c [Self \c = \c S].
488+
/// \code
489+
/// protocol P {
490+
/// associatedtype X
491+
/// associatedtype Y
492+
/// }
493+
/// extension P where X == Bool {
494+
/// typealias Y = Bool
495+
/// }
496+
///
497+
/// struct S: P {
498+
/// typealias X = Bool
499+
/// }
500+
/// \endcode
501+
///
502+
/// \param module The module to use for conformace lookup.
503+
/// \param contextSig The generic signature that should be used to map
504+
/// \p parentTy into context. We pass a generic signature to secure on-demand
505+
/// computation of the associated generic enviroment.
506+
///
507+
/// \returns \c true on success.
508+
bool checkContextualRequirements(GenericTypeDecl *decl, Type parentTy,
509+
SourceLoc loc, ModuleDecl *module,
510+
GenericSignature contextSig);
472511

473512
/// Add any implicitly-defined constructors required for the given
474513
/// struct, class or actor.

validation-test/compiler_crashers_2_fixed/0161-sr6569.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ protocol P {
66

77
struct Type<Param> {}
88
extension Type: P where Param: P, Param.A == Type<Param> {
9-
// expected-error@-1 5{{extension of generic struct 'Type' has self-referential generic requirements}}
10-
// expected-note@-2 5{{through reference here}}
9+
// expected-error@-1 6{{extension of generic struct 'Type' has self-referential generic requirements}}
10+
// expected-note@-2 6{{through reference here}}
1111
// expected-error@-3 {{type 'Type<Param>' does not conform to protocol 'P'}}
1212
typealias A = Param
1313
// expected-note@-1 2{{through reference here}}

0 commit comments

Comments
 (0)