Skip to content

Commit e127690

Browse files
authored
Merge pull request swiftlang#41286 from jckarter/opaque-type-repeat-application-with-different-substitutions
Don't terminate ReplaceOpaqueTypesWithUnderlyingTypes if same opaque type is substituted with different substitution arguments.
2 parents c54dccb + ed7bd9b commit e127690

File tree

3 files changed

+41
-13
lines changed

3 files changed

+41
-13
lines changed

include/swift/AST/Types.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5673,9 +5673,12 @@ enum class OpaqueSubstitutionKind {
56735673
/// archetypes with underlying types visible at a given resilience expansion
56745674
/// to their underlying types.
56755675
class ReplaceOpaqueTypesWithUnderlyingTypes {
5676+
public:
5677+
using SeenDecl = std::pair<OpaqueTypeDecl *, SubstitutionMap>;
5678+
private:
56765679
ResilienceExpansion contextExpansion;
56775680
llvm::PointerIntPair<const DeclContext *, 1, bool> inContextAndIsWholeModule;
5678-
llvm::SmallPtrSetImpl<OpaqueTypeDecl *> *seenDecls;
5681+
llvm::DenseSet<SeenDecl> *seenDecls;
56795682

56805683
public:
56815684
ReplaceOpaqueTypesWithUnderlyingTypes(const DeclContext *inContext,
@@ -5687,7 +5690,7 @@ class ReplaceOpaqueTypesWithUnderlyingTypes {
56875690

56885691
ReplaceOpaqueTypesWithUnderlyingTypes(
56895692
const DeclContext *inContext, ResilienceExpansion contextExpansion,
5690-
bool isWholeModuleContext, llvm::SmallPtrSetImpl<OpaqueTypeDecl *> &seen);
5693+
bool isWholeModuleContext, llvm::DenseSet<SeenDecl> &seen);
56915694

56925695
/// TypeSubstitutionFn
56935696
Type operator()(SubstitutableType *maybeOpaqueType) const;

lib/AST/Type.cpp

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3502,7 +3502,8 @@ ReplaceOpaqueTypesWithUnderlyingTypes::shouldPerformSubstitution(
35023502

35033503
static Type substOpaqueTypesWithUnderlyingTypesRec(
35043504
Type ty, const DeclContext *inContext, ResilienceExpansion contextExpansion,
3505-
bool isWholeModuleContext, SmallPtrSetImpl<OpaqueTypeDecl *> &decls) {
3505+
bool isWholeModuleContext,
3506+
llvm::DenseSet<ReplaceOpaqueTypesWithUnderlyingTypes::SeenDecl> &decls) {
35063507
ReplaceOpaqueTypesWithUnderlyingTypes replacer(inContext, contextExpansion,
35073508
isWholeModuleContext, decls);
35083509
return ty.subst(replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes);
@@ -3566,7 +3567,7 @@ static bool canSubstituteTypeInto(Type ty, const DeclContext *dc,
35663567

35673568
ReplaceOpaqueTypesWithUnderlyingTypes::ReplaceOpaqueTypesWithUnderlyingTypes(
35683569
const DeclContext *inContext, ResilienceExpansion contextExpansion,
3569-
bool isWholeModuleContext, llvm::SmallPtrSetImpl<OpaqueTypeDecl *> &seen)
3570+
bool isWholeModuleContext, llvm::DenseSet<SeenDecl> &seen)
35703571
: contextExpansion(contextExpansion),
35713572
inContextAndIsWholeModule(inContext, isWholeModuleContext),
35723573
seenDecls(&seen) {}
@@ -3618,24 +3619,25 @@ operator()(SubstitutableType *maybeOpaqueType) const {
36183619

36193620
// If the type changed, but still contains opaque types, recur.
36203621
if (!substTy->isEqual(maybeOpaqueType) && substTy->hasOpaqueArchetype()) {
3622+
SeenDecl seenKey(opaqueRoot->getDecl(), opaqueRoot->getSubstitutions());
36213623
if (auto *alreadySeen = this->seenDecls) {
36223624
// Detect substitution loops. If we find one, just bounce the original
36233625
// type back to the caller. This substitution will fail at runtime
36243626
// instead.
3625-
if (!alreadySeen->insert(opaqueRoot->getDecl()).second) {
3627+
if (!alreadySeen->insert(seenKey).second) {
36263628
return maybeOpaqueType;
36273629
}
36283630

36293631
auto res = ::substOpaqueTypesWithUnderlyingTypesRec(
36303632
substTy, inContext, contextExpansion, isContextWholeModule,
36313633
*alreadySeen);
3632-
alreadySeen->erase(opaqueRoot->getDecl());
3634+
alreadySeen->erase(seenKey);
36333635
return res;
36343636
} else {
36353637
// We're the top of the stack for the recursion check. Allocate a set of
36363638
// opaque result type decls we've already seen for the rest of the check.
3637-
SmallPtrSet<OpaqueTypeDecl *, 8> seenDecls;
3638-
seenDecls.insert(opaqueRoot->getDecl());
3639+
llvm::DenseSet<SeenDecl> seenDecls;
3640+
seenDecls.insert(seenKey);
36393641
return ::substOpaqueTypesWithUnderlyingTypesRec(
36403642
substTy, inContext, contextExpansion, isContextWholeModule,
36413643
seenDecls);
@@ -3648,7 +3650,7 @@ operator()(SubstitutableType *maybeOpaqueType) const {
36483650
static ProtocolConformanceRef substOpaqueTypesWithUnderlyingTypesRec(
36493651
ProtocolConformanceRef ref, Type origType, const DeclContext *inContext,
36503652
ResilienceExpansion contextExpansion, bool isWholeModuleContext,
3651-
SmallPtrSetImpl<OpaqueTypeDecl *> &decls) {
3653+
llvm::DenseSet<ReplaceOpaqueTypesWithUnderlyingTypes::SeenDecl> &decls) {
36523654
ReplaceOpaqueTypesWithUnderlyingTypes replacer(inContext, contextExpansion,
36533655
isWholeModuleContext, decls);
36543656
return ref.subst(origType, replacer, replacer,
@@ -3732,24 +3734,26 @@ operator()(CanType maybeOpaqueType, Type replacementType,
37323734

37333735
// If the type still contains opaque types, recur.
37343736
if (substTy->hasOpaqueArchetype()) {
3737+
SeenDecl seenKey(opaqueRoot->getDecl(), opaqueRoot->getSubstitutions());
3738+
37353739
if (auto *alreadySeen = this->seenDecls) {
37363740
// Detect substitution loops. If we find one, just bounce the original
37373741
// type back to the caller. This substitution will fail at runtime
37383742
// instead.
3739-
if (!alreadySeen->insert(opaqueRoot->getDecl()).second) {
3743+
if (!alreadySeen->insert(seenKey).second) {
37403744
return abstractRef;
37413745
}
37423746

37433747
auto res = ::substOpaqueTypesWithUnderlyingTypesRec(
37443748
substRef, substTy, inContext, contextExpansion, isContextWholeModule,
37453749
*alreadySeen);
3746-
alreadySeen->erase(opaqueRoot->getDecl());
3750+
alreadySeen->erase(seenKey);
37473751
return res;
37483752
} else {
37493753
// We're the top of the stack for the recursion check. Allocate a set of
37503754
// opaque result type decls we've already seen for the rest of the check.
3751-
SmallPtrSet<OpaqueTypeDecl *, 8> seenDecls;
3752-
seenDecls.insert(opaqueRoot->getDecl());
3755+
llvm::DenseSet<SeenDecl> seenDecls;
3756+
seenDecls.insert(seenKey);
37533757
return ::substOpaqueTypesWithUnderlyingTypesRec(
37543758
substRef, substTy, inContext, contextExpansion, isContextWholeModule,
37553759
seenDecls);
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %target-swift-emit-sil -disable-availability-checking -verify %s
2+
3+
// rdar://88120984
4+
5+
protocol P {}
6+
7+
private struct Wrapped<T: P>: P { var x: T }
8+
9+
extension P {
10+
func wrapped() -> some P {
11+
return Wrapped(x: self)
12+
}
13+
}
14+
15+
class CWrap<T: P> { init(x: T) {} }
16+
17+
func foo<T: P>(x: T) {
18+
let y = x.wrapped().wrapped().wrapped().wrapped()
19+
20+
_ = CWrap(x: y)
21+
}

0 commit comments

Comments
 (0)