[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
This commit is contained in:
Pavel Yaskevich
2018-01-23 19:21:59 -08:00
parent 98fc073e2e
commit a11263b156
2 changed files with 75 additions and 1 deletions

View File

@@ -954,6 +954,29 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value,
return { valueType, valueType };
}
static NominalTypeDecl *getInnermostConformingDC(TypeChecker &TC,
DeclContext *DC,
ProtocolDecl *protocol) {
do {
if (DC->isTypeContext()) {
auto *NTD = DC->getAsNominalTypeOrNominalTypeExtensionContext();
auto type = NTD->getDeclaredType();
ConformanceCheckOptions options;
options |= ConformanceCheckFlags::InExpression;
options |= ConformanceCheckFlags::SuppressDependencyTracking;
options |= ConformanceCheckFlags::SkipConditionalRequirements;
auto result =
TC.conformsToProtocol(type, protocol, NTD->getDeclContext(), options);
if (result)
return NTD;
}
} while ((DC = DC->getParent()));
return nullptr;
}
/// Bind type variables for archetypes that are determined from
/// context.
///
@@ -1015,8 +1038,18 @@ static void bindArchetypesFromContext(
// parameters, or because this generic parameter was constrained
// away into a concrete type.
if (found != replacements.end()) {
Type contextTy;
if (genericEnv) {
contextTy = genericEnv->mapTypeIntoContext(paramTy);
} else {
auto *protocol = parentDC->getAsProtocolOrProtocolExtensionContext();
auto conformingDC = getInnermostConformingDC(cs.TC, cs.DC, protocol);
assert(conformingDC);
contextTy = conformingDC->getDeclaredTypeInContext();
}
auto typeVar = found->second;
auto contextTy = genericEnv->mapTypeIntoContext(paramTy);
cs.addConstraint(ConstraintKind::Bind, typeVar, contextTy,
locatorPtr);
}

View File

@@ -0,0 +1,41 @@
// RUN: not %target-swift-frontend %s -typecheck
protocol A {
var question: String { get }
struct B {
var answer: Int = 42
func foo(a: A) {
_ = a.question
}
}
}
class C : A {
var question: String = "ultimate question"
func foo() -> B {}
func bar() -> A.B {}
func baz(b: B) {
_ = b.answer
}
}
class D : A {
var question: String = ""
struct E {
func baz(b: B) {
_ = b.answer
}
}
}
class F<T> : A {
var question: String = ""
func foo(b: B) {
_ = b.answer
}
}