Skip to content

Commit 681a613

Browse files
committed
Sema: Correct handling of Self-derived types in default witness matching
We want to use the context archetypes of the requirement in this case. NFC until the next patch lands.
1 parent 768f6da commit 681a613

File tree

1 file changed

+49
-29
lines changed

1 file changed

+49
-29
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 49 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -934,11 +934,18 @@ matchWitness(TypeChecker &tc,
934934
// the required type and the witness type.
935935
cs.emplace(tc, dc, ConstraintSystemOptions());
936936

937-
Type model;
938-
if (conformance)
939-
model = conformance->getType();
940-
else
941-
model = dc->getDeclaredTypeInContext();
937+
Type selfIfaceTy = proto->getProtocolSelf()->getDeclaredType();
938+
Type selfTy;
939+
940+
// For a concrete conformance, use the conforming type as the
941+
// base type of the requirement and witness lookup.
942+
if (conformance) {
943+
selfTy = conformance->getType();
944+
945+
// For a default witness, use the requirement's context archetype.
946+
} else {
947+
selfTy = ArchetypeBuilder::mapTypeIntoContext(dc, selfIfaceTy);
948+
}
942949

943950
// Open up the witness type.
944951
witnessType = witness->getInterfaceType();
@@ -950,7 +957,7 @@ matchWitness(TypeChecker &tc,
950957
LocatorPathElt(ConstraintLocator::Witness, witness));
951958
if (witness->getDeclContext()->isTypeContext()) {
952959
std::tie(openedFullWitnessType, openWitnessType)
953-
= cs->getTypeOfMemberReference(model, witness,
960+
= cs->getTypeOfMemberReference(selfTy, witness,
954961
/*isTypeReference=*/false,
955962
/*isDynamicResult=*/false,
956963
witnessLocator,
@@ -972,7 +979,7 @@ matchWitness(TypeChecker &tc,
972979
DeclContext *reqDC = req->getInnermostDeclContext();
973980
llvm::DenseMap<CanType, TypeVariableType *> replacements;
974981
std::tie(openedFullReqType, reqType)
975-
= cs->getTypeOfMemberReference(model, req,
982+
= cs->getTypeOfMemberReference(selfTy, req,
976983
/*isTypeReference=*/false,
977984
/*isDynamicResult=*/false,
978985
locator,
@@ -981,31 +988,45 @@ matchWitness(TypeChecker &tc,
981988

982989
// Bind the associated types.
983990
for (const auto &replacement : replacements) {
984-
if (auto gpType = replacement.first->getAs<GenericTypeParamType>()) {
985-
// Record the type variable for 'Self'.
986-
if (gpType->getDepth() == 0 && gpType->getIndex() == 0) {
987-
cs->SelfTypeVar = replacement.second;
988-
continue;
989-
}
990-
991-
// Replace any other type variable with the archetype within
992-
// the requirement's context.
993-
cs->addConstraint(ConstraintKind::Bind,
994-
replacement.second,
995-
ArchetypeBuilder::mapTypeIntoContext(reqDC, gpType),
996-
locator);
997-
998-
// Associated type of 'Self'.
999-
} else if (auto assocType = getReferencedAssocTypeOfProtocol(
991+
992+
// If we have a concrete conformance, handle Self-derived type parameters
993+
// differently.
994+
if (conformance) {
995+
if (replacement.first->is<GenericTypeParamType>()) {
996+
// For a concrete conformance, we record the type variable for 'Self'
997+
// without doing anything else. See the comment for SelfTypeVar in
998+
// ConstraintSystem.h.
999+
if (selfIfaceTy->isEqual(replacement.first)) {
1000+
cs->SelfTypeVar = replacement.second;
1001+
continue;
1002+
}
1003+
1004+
// Inner generic parameter of the requirement -- fall through below.
1005+
1006+
} else if (auto assocType = getReferencedAssocTypeOfProtocol(
10001007
replacement.first, proto)) {
1001-
if (conformance) {
1008+
1009+
// Look up the associated type witness.
10021010
cs->addConstraint(ConstraintKind::Bind,
10031011
replacement.second,
10041012
conformance->getTypeWitness(assocType, nullptr)
10051013
.getReplacement(),
10061014
locator);
1015+
continue;
1016+
} else {
1017+
continue;
10071018
}
10081019
}
1020+
1021+
// Replace any other type variable with the archetype within the
1022+
// requirement's context.
1023+
auto contextTy = ArchetypeBuilder::mapTypeIntoContext(
1024+
reqDC, replacement.first);
1025+
1026+
cs->addConstraint(ConstraintKind::Bind,
1027+
replacement.second,
1028+
contextTy,
1029+
locator);
10091030
}
10101031
reqType = reqType->getRValueType();
10111032

@@ -1042,7 +1063,7 @@ matchWitness(TypeChecker &tc,
10421063
if (openedFullWitnessType->hasTypeVariable()) {
10431064
// Figure out the context we're substituting into.
10441065
auto witnessDC = witness->getInnermostDeclContext();
1045-
1066+
10461067
// Compute the set of substitutions we'll need for the witness.
10471068
solution->computeSubstitutions(witness->getInterfaceType(),
10481069
witnessDC, openedFullWitnessType,
@@ -2311,7 +2332,8 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
23112332

23122333
// If the requirement is optional, it's okay. We'll satisfy this via
23132334
// our handling of default definitions.
2314-
// FIXME: also check for a default definition here.
2335+
//
2336+
// FIXME: revisit this once we get default definitions in protocol bodies.
23152337
//
23162338
// Treat 'unavailable' implicitly as if it were 'optional'.
23172339
// The compiler will reject actual uses.
@@ -2400,7 +2422,7 @@ ResolveWitnessResult ConformanceChecker::resolveWitnessViaDerivation(
24002422
return ResolveWitnessResult::ExplicitFailed;
24012423
}
24022424

2403-
// FIXME: use default definitions??
2425+
// FIXME: revisit this once we get default implementations in protocol bodies.
24042426
ResolveWitnessResult ConformanceChecker::resolveWitnessViaDefault(
24052427
ValueDecl *requirement) {
24062428
assert(!isa<AssociatedTypeDecl>(requirement) && "Use resolveTypeWitnessVia*");
@@ -2413,8 +2435,6 @@ ResolveWitnessResult ConformanceChecker::resolveWitnessViaDefault(
24132435
return ResolveWitnessResult::Success;
24142436
}
24152437

2416-
// FIXME: Default definition.
2417-
24182438
diagnoseOrDefer(requirement, true,
24192439
[requirement](TypeChecker &tc, NormalProtocolConformance *conformance) {
24202440
auto dc = conformance->getDeclContext();

0 commit comments

Comments
 (0)