Skip to content

Commit da3468a

Browse files
authored
Merge pull request #23652 from xedin/rdar-49371608
[ConstraintSystem] Delay adding contextual requirements until parent …
2 parents b0dff8a + 8e42049 commit da3468a

File tree

2 files changed

+61
-33
lines changed

2 files changed

+61
-33
lines changed

lib/Sema/ConstraintSystem.cpp

Lines changed: 50 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -490,47 +490,64 @@ static void checkNestedTypeConstraints(ConstraintSystem &cs, Type type,
490490
// info than that, unlike a typealias
491491
}
492492

493+
if (!parentTy)
494+
return;
495+
493496
// If this decl is generic, the constraints are handled when the generic
494497
// parameters are applied, so we don't have to handle them here (which makes
495498
// getting the right substitution maps easier).
496-
if (decl && !decl->isGeneric()) {
497-
auto extension = dyn_cast<ExtensionDecl>(decl->getDeclContext());
498-
if (parentTy && extension && extension->isConstrainedExtension()) {
499-
auto contextSubMap = parentTy->getContextSubstitutionMap(
500-
extension->getParentModule(),
501-
extension->getSelfNominalTypeDecl());
502-
if (!subMap) {
503-
// The substitution map wasn't set above, meaning we should grab the map
504-
// for the extension itself.
505-
subMap = parentTy->getContextSubstitutionMap(
506-
extension->getParentModule(), extension);
507-
}
499+
if (!decl || decl->isGeneric())
500+
return;
508501

509-
if (auto *signature = decl->getGenericSignature()) {
510-
cs.openGenericRequirements(
511-
extension, signature, /*skipProtocolSelfConstraint*/ true, locator,
512-
[&](Type type) {
513-
// Why do we look in two substitution maps? We have to use the
514-
// context substitution map to find types, because we need to
515-
// avoid thinking about them when handling the constraints, or all
516-
// the requirements in the signature become tautologies (if the
517-
// extension has 'T == Int', subMap will map T -> Int, so the
518-
// requirement becomes Int == Int no matter what the actual types
519-
// are here). However, we need the conformances for the extension
520-
// because the requirements might look like `T: P, T.U: Q`, where
521-
// U is an associated type of protocol P.
522-
return type.subst(QuerySubstitutionMap{contextSubMap},
523-
LookUpConformanceInSubstitutionMap(subMap),
524-
SubstFlags::UseErrorType);
525-
});
526-
}
502+
// struct A<T> {
503+
// let foo: [T]
504+
// }
505+
//
506+
// extension A : Codable where T: Codable {
507+
// enum CodingKeys: String, CodingKey {
508+
// case foo = "foo"
509+
// }
510+
// }
511+
//
512+
// Reference to `A.CodingKeys.foo` would point to `A` as an
513+
// unbound generic type. Conditional requirements would be
514+
// added when `A` is "opened". Les delay this check until then.
515+
if (parentTy->hasUnboundGenericType())
516+
return;
517+
518+
auto extension = dyn_cast<ExtensionDecl>(decl->getDeclContext());
519+
if (extension && extension->isConstrainedExtension()) {
520+
auto contextSubMap = parentTy->getContextSubstitutionMap(
521+
extension->getParentModule(), extension->getSelfNominalTypeDecl());
522+
if (!subMap) {
523+
// The substitution map wasn't set above, meaning we should grab the map
524+
// for the extension itself.
525+
subMap = parentTy->getContextSubstitutionMap(extension->getParentModule(),
526+
extension);
527527
}
528528

529-
// And now make sure sure the parent is okay, for things like X<T>.Y.Z.
530-
if (parentTy) {
531-
checkNestedTypeConstraints(cs, parentTy, locator);
529+
if (auto *signature = decl->getGenericSignature()) {
530+
cs.openGenericRequirements(
531+
extension, signature, /*skipProtocolSelfConstraint*/ true, locator,
532+
[&](Type type) {
533+
// Why do we look in two substitution maps? We have to use the
534+
// context substitution map to find types, because we need to
535+
// avoid thinking about them when handling the constraints, or all
536+
// the requirements in the signature become tautologies (if the
537+
// extension has 'T == Int', subMap will map T -> Int, so the
538+
// requirement becomes Int == Int no matter what the actual types
539+
// are here). However, we need the conformances for the extension
540+
// because the requirements might look like `T: P, T.U: Q`, where
541+
// U is an associated type of protocol P.
542+
return type.subst(QuerySubstitutionMap{contextSubMap},
543+
LookUpConformanceInSubstitutionMap(subMap),
544+
SubstFlags::UseErrorType);
545+
});
532546
}
533547
}
548+
549+
// And now make sure sure the parent is okay, for things like X<T>.Y.Z.
550+
checkNestedTypeConstraints(cs, parentTy, locator);
534551
}
535552

536553
Type ConstraintSystem::openUnboundGenericType(
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
struct A<T> {
4+
let foo: [T]
5+
}
6+
7+
extension A : Codable where T: Codable {
8+
enum CodingKeys: String, CodingKey {
9+
case foo = "foo"
10+
}
11+
}

0 commit comments

Comments
 (0)