diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 3e29c740aa6c1..0f48d8def7543 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -3043,12 +3043,21 @@ ProtocolConformanceRef ReplaceOpaqueTypesWithUnderlyingTypes:: operator()(CanType maybeOpaqueType, Type replacementType, ProtocolDecl *protocol) const { auto abstractRef = ProtocolConformanceRef(protocol); - + auto archetypeAndRoot = getArchetypeAndRootOpaqueArchetype(maybeOpaqueType); if (!archetypeAndRoot) { - assert(maybeOpaqueType->isTypeParameter() || - maybeOpaqueType->is()); - return abstractRef; + if (maybeOpaqueType->isTypeParameter() || + maybeOpaqueType->is()) + return abstractRef; + + // SIL type lowering may have already substituted away the opaque type, in + // which case we'll end up "substituting" the same type. + if (maybeOpaqueType->isEqual(replacementType)) { + return inContext->getParentModule() + ->lookupConformance(replacementType, protocol); + } + + llvm_unreachable("origType should have been an opaque type or type parameter"); } auto archetype = archetypeAndRoot->first; diff --git a/test/SILGen/opaque_type_lowering_in_substitution.swift b/test/SILGen/opaque_type_lowering_in_substitution.swift new file mode 100644 index 0000000000000..903de21148a03 --- /dev/null +++ b/test/SILGen/opaque_type_lowering_in_substitution.swift @@ -0,0 +1,16 @@ +// RUN: %target-swift-emit-silgen -disable-availability-checking -verify %s +protocol P {} +extension Int: P {} + +func foo() -> some P { return 0 } +func bar(_ x: T) -> some P { return x } + +struct Bas { init(_: T) {} } + +func abstraction_level(x: T) -> (T) -> () { + return { _ in () } +} + +func test() { + abstraction_level(x: Bas(bar(foo())))(Bas(bar(foo()))) +}