Skip to content

Commit 9f82032

Browse files
authored
Merge pull request #23717 from xedin/rdar-49371608-5.0
[5.0][ConstraintSystem] Delay adding contextual requirements until parent …
2 parents 39c525e + 64ff24c commit 9f82032

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
@@ -489,47 +489,64 @@ static void checkNestedTypeConstraints(ConstraintSystem &cs, Type type,
489489
// info than that, unlike a typealias
490490
}
491491

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

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

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

535552
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)