mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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:
@@ -954,6 +954,29 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value,
|
|||||||
return { valueType, valueType };
|
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
|
/// Bind type variables for archetypes that are determined from
|
||||||
/// context.
|
/// context.
|
||||||
///
|
///
|
||||||
@@ -1015,8 +1038,18 @@ static void bindArchetypesFromContext(
|
|||||||
// parameters, or because this generic parameter was constrained
|
// parameters, or because this generic parameter was constrained
|
||||||
// away into a concrete type.
|
// away into a concrete type.
|
||||||
if (found != replacements.end()) {
|
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 typeVar = found->second;
|
||||||
auto contextTy = genericEnv->mapTypeIntoContext(paramTy);
|
|
||||||
cs.addConstraint(ConstraintKind::Bind, typeVar, contextTy,
|
cs.addConstraint(ConstraintKind::Bind, typeVar, contextTy,
|
||||||
locatorPtr);
|
locatorPtr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user