Sema: Use weighted reduction order for opaque return types

If the opaque generic signature has a same-type requirement between
an outer type parameter and an opaque type parameter, the former
should always precede the latter in the type parameter order, even
if it is longer. Achieve this by giving the innermost generic
parameters a non-zero weight in the opaque generic signature.

Now, when we map a type parameter into an opaque generic environment,
we correctly decide if it is represented by a type parameter of the
outer generic signature, in which case we apply the outer substitution
map instead of instantiating an archetype.

The included test case demonstrates the issue; we declare an opaque
return type `some P<T.A.A>`, so the opaque generic signature has a
requirement `T.A.A == <<some P>>.A`. Previously, the reduced type of
`<<some P>>.A` was `<<some P>>.A`, so it remained opaque; now we
apply outer substitutions to `T.A.A`.

- Fixes https://github.com/swiftlang/swift/issues/81036.
- Fixes rdar://problem/149871931.
This commit is contained in:
Slava Pestov
2025-04-29 13:54:56 -04:00
parent 651e0af4d1
commit 8ab5ca2a7a
2 changed files with 31 additions and 4 deletions

View File

@@ -142,7 +142,7 @@ OpaqueResultTypeRequest::evaluate(Evaluator &evaluator,
for (unsigned i = 0; i < opaqueReprs.size(); ++i) {
auto *currentRepr = opaqueReprs[i];
if( auto opaqueReturn = dyn_cast<OpaqueReturnTypeRepr>(currentRepr) ) {
if (auto opaqueReturn = dyn_cast<OpaqueReturnTypeRepr>(currentRepr)) {
// Usually, we resolve the opaque constraint and bail if it isn't a class
// or existential type (see below). However, in this case we know we will
// fail, so we can bail early and provide a better diagnostic.
@@ -163,13 +163,13 @@ OpaqueResultTypeRequest::evaluate(Evaluator &evaluator,
}
}
auto *paramType = GenericTypeParamType::getType(opaqueSignatureDepth, i,
ctx);
auto *paramType = GenericTypeParamType::getOpaqueResultType(
opaqueSignatureDepth, i, ctx);
genericParamTypes.push_back(paramType);
TypeRepr *constraint = currentRepr;
if (auto opaqueReturn = dyn_cast<OpaqueReturnTypeRepr>(currentRepr)){
if (auto opaqueReturn = dyn_cast<OpaqueReturnTypeRepr>(currentRepr)) {
constraint = opaqueReturn->getConstraint();
}
// Try to resolve the constraint repr in the parent decl context. It

View File

@@ -0,0 +1,27 @@
// RUN: %target-swift-emit-silgen %s
protocol N {
associatedtype A: N
}
struct G<T>: N {
typealias A = G<G<T>>
}
protocol P<A> {
associatedtype A
}
struct GG<T>: P {
typealias A = T
}
func f<T: N>(_: T) -> some P<T.A.A> {
return GG<T.A.A>()
}
func g<T: P>(_: T) -> T.A { fatalError() }
func h(_: G<G<G<Int>>>) {}
h(g(f(G<Int>())))