Skip to content

Commit 84f9fcd

Browse files
committed
[ConstraintSystem] Bind Self to correct contextual type for nested types in protocol
If something that we are trying to contextually bind is a nested type inside protocol or protocol extension, let's try to find the innermost conforming type from the current declaration context and map Self parameter of the protocol to that nominal type. Since nested types in protocols aren't yet implemented this is going to result in failure, but that's better than crashing. Resolves: rdar://problem/36449760 (cherry picked from commit a11263b)
1 parent 5ffecf6 commit 84f9fcd

File tree

2 files changed

+75
-1
lines changed

2 files changed

+75
-1
lines changed

lib/Sema/ConstraintSystem.cpp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,29 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value,
954954
return { valueType, valueType };
955955
}
956956

957+
static NominalTypeDecl *getInnermostConformingDC(TypeChecker &TC,
958+
DeclContext *DC,
959+
ProtocolDecl *protocol) {
960+
do {
961+
if (DC->isTypeContext()) {
962+
auto *NTD = DC->getAsNominalTypeOrNominalTypeExtensionContext();
963+
auto type = NTD->getDeclaredType();
964+
965+
ConformanceCheckOptions options;
966+
options |= ConformanceCheckFlags::InExpression;
967+
options |= ConformanceCheckFlags::SuppressDependencyTracking;
968+
options |= ConformanceCheckFlags::SkipConditionalRequirements;
969+
970+
auto result =
971+
TC.conformsToProtocol(type, protocol, NTD->getDeclContext(), options);
972+
973+
if (result)
974+
return NTD;
975+
}
976+
} while ((DC = DC->getParent()));
977+
978+
return nullptr;
979+
}
957980
/// Bind type variables for archetypes that are determined from
958981
/// context.
959982
///
@@ -1015,8 +1038,18 @@ static void bindArchetypesFromContext(
10151038
// parameters, or because this generic parameter was constrained
10161039
// away into a concrete type.
10171040
if (found != replacements.end()) {
1041+
Type contextTy;
1042+
1043+
if (genericEnv) {
1044+
contextTy = genericEnv->mapTypeIntoContext(paramTy);
1045+
} else {
1046+
auto *protocol = parentDC->getAsProtocolOrProtocolExtensionContext();
1047+
auto conformingDC = getInnermostConformingDC(cs.TC, cs.DC, protocol);
1048+
assert(conformingDC);
1049+
contextTy = conformingDC->getDeclaredTypeInContext();
1050+
}
1051+
10181052
auto typeVar = found->second;
1019-
auto contextTy = genericEnv->mapTypeIntoContext(paramTy);
10201053
cs.addConstraint(ConstraintKind::Bind, typeVar, contextTy,
10211054
locatorPtr);
10221055
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: not %target-swift-frontend %s -typecheck
2+
3+
protocol A {
4+
var question: String { get }
5+
6+
struct B {
7+
var answer: Int = 42
8+
9+
func foo(a: A) {
10+
_ = a.question
11+
}
12+
}
13+
}
14+
15+
class C : A {
16+
var question: String = "ultimate question"
17+
18+
func foo() -> B {}
19+
func bar() -> A.B {}
20+
func baz(b: B) {
21+
_ = b.answer
22+
}
23+
}
24+
25+
class D : A {
26+
var question: String = ""
27+
28+
struct E {
29+
func baz(b: B) {
30+
_ = b.answer
31+
}
32+
}
33+
}
34+
35+
class F<T> : A {
36+
var question: String = ""
37+
38+
func foo(b: B) {
39+
_ = b.answer
40+
}
41+
}

0 commit comments

Comments
 (0)