Skip to content

Commit 971e5e3

Browse files
authored
Merge pull request #60833 from slavapestov/fix-rdar98404650
AST: Work around shortcoming in abstract conformance representation when computing override substitutions
2 parents 1f38c4b + 259b2e2 commit 971e5e3

File tree

5 files changed

+54
-10
lines changed

5 files changed

+54
-10
lines changed

include/swift/AST/ASTContext.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1255,7 +1255,7 @@ class ASTContext final {
12551255
/// \param type The type for which we are retrieving the conformance.
12561256
///
12571257
/// \param inherited The inherited conformance.
1258-
InheritedProtocolConformance *
1258+
ProtocolConformance *
12591259
getInheritedConformance(Type type, ProtocolConformance *inherited);
12601260

12611261
/// Get the lazy data for the given declaration.

lib/AST/ASTContext.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2448,30 +2448,39 @@ ASTContext::getSpecializedConformance(Type type,
24482448
return result;
24492449
}
24502450

2451-
InheritedProtocolConformance *
2451+
ProtocolConformance *
24522452
ASTContext::getInheritedConformance(Type type, ProtocolConformance *inherited) {
24532453
// Collapse multiple levels of inherited conformance.
2454-
while (auto *otherInherited = dyn_cast<InheritedProtocolConformance>(inherited))
2454+
if (auto *otherInherited = dyn_cast<InheritedProtocolConformance>(inherited))
24552455
inherited = otherInherited->getInheritedConformance();
24562456

24572457
assert(isa<SpecializedProtocolConformance>(inherited) ||
24582458
isa<NormalProtocolConformance>(inherited) ||
24592459
isa<BuiltinProtocolConformance>(inherited));
24602460

2461+
// Collapse useless inherited conformances. Conformance lookup with aa
2462+
// archetype T that has a superclass bound C will return a concrete
2463+
// conformance if C conforms to the protocol P. This is wrapped in an
2464+
// inherited conformance with the archetype type T. If you then substitute
2465+
// T := C, you don't want to form an inherited conformance with a type of
2466+
// C, because the underlying conformance already has a type of C.
2467+
if (inherited->getType()->isEqual(type))
2468+
return inherited;
2469+
24612470
llvm::FoldingSetNodeID id;
24622471
InheritedProtocolConformance::Profile(id, type, inherited);
24632472

24642473
// Figure out which arena this conformance should go into.
24652474
AllocationArena arena = getArena(type->getRecursiveProperties());
24662475

2467-
// Did we already record the normal protocol conformance?
2476+
// Did we already record the inherited protocol conformance?
24682477
void *insertPos;
24692478
auto &inheritedConformances = getImpl().getArena(arena).InheritedConformances;
24702479
if (auto result
24712480
= inheritedConformances.FindNodeOrInsertPos(id, insertPos))
24722481
return result;
24732482

2474-
// Build a new normal protocol conformance.
2483+
// Build a new inherited protocol conformance.
24752484
auto result = new (*this, arena) InheritedProtocolConformance(type, inherited);
24762485
inheritedConformances.InsertNode(result, insertPos);
24772486
return result;

lib/AST/SubstitutionMap.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -534,10 +534,25 @@ OverrideSubsInfo::OverrideSubsInfo(const NominalTypeDecl *baseNominal,
534534
if (auto baseNominalSig = baseNominal->getGenericSignature()) {
535535
BaseDepth = baseNominalSig.getGenericParams().back()->getDepth() + 1;
536536

537+
auto *genericEnv = derivedNominal->getGenericEnvironment();
537538
auto derivedNominalTy = derivedNominal->getDeclaredInterfaceType();
539+
540+
// FIXME: Map in and out of context to get more accurate
541+
// conformance information. If the base generic signature
542+
// is <T: P> and the derived generic signature is <T: C>
543+
// where C is a class that conforms to P, then we want the
544+
// substitution map to store the concrete conformance C: P
545+
// and not the abstract conformance T: P.
546+
if (genericEnv) {
547+
derivedNominalTy = genericEnv->mapTypeIntoContext(
548+
derivedNominalTy);
549+
}
550+
538551
BaseSubMap = derivedNominalTy->getContextSubstitutionMap(
539-
baseNominal->getParentModule(), baseNominal);
540-
assert(!BaseSubMap.hasArchetypes());
552+
baseNominal->getParentModule(), baseNominal,
553+
genericEnv);
554+
555+
BaseSubMap = BaseSubMap.mapReplacementTypesOutOfContext();
541556
}
542557

543558
if (auto derivedNominalSig = derivedNominal->getGenericSignature())

lib/AST/Type.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4886,11 +4886,15 @@ TypeBase::getContextSubstitutions(const DeclContext *dc,
48864886
break;
48874887
}
48884888

4889+
// Add any outer generic parameters from the local context.
48894890
while (n > 0) {
48904891
auto *gp = params[--n];
4891-
auto substTy = (genericEnv
4892-
? genericEnv->mapTypeIntoContext(gp)
4893-
: gp);
4892+
Type substTy = gp;
4893+
if (baseTy && baseTy->is<ErrorType>())
4894+
substTy = ErrorType::get(baseTy->getASTContext());
4895+
else if (genericEnv)
4896+
substTy = genericEnv->mapTypeIntoContext(gp);
4897+
48944898
auto result = substitutions.insert(
48954899
{gp->getCanonicalType()->castTo<GenericTypeParamType>(),
48964900
substTy});
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %target-swift-emit-silgen %s | %FileCheck %s
2+
3+
class Base<T: P> {
4+
init(x: Int = 0) {}
5+
}
6+
7+
class Derived<T: C> : Base<T> {}
8+
9+
protocol P {}
10+
class C: P {}
11+
12+
_ = Derived<C>()
13+
14+
// CHECK-LABEL: sil [ossa] @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
15+
// CHECK: [[FN:%.*]] = function_ref @$s35default_arguments_inherited_generic4BaseC1xACyxGSi_tcfcfA_ : $@convention(thin) <τ_0_0 where τ_0_0 : P> () -> Int
16+
// CHECK: apply [[FN]]<C>() : $@convention(thin) <τ_0_0 where τ_0_0 : P> () -> Int

0 commit comments

Comments
 (0)