Skip to content

Commit 455ba6e

Browse files
committed
[Constraint System] Fix covariant erasure for constrained existentials
Constrained existentials should be type erased to a dependent upper bound if the dependent member has a reduced type.
1 parent 9f809fa commit 455ba6e

File tree

4 files changed

+96
-8
lines changed

4 files changed

+96
-8
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5534,6 +5534,10 @@ Type typeEraseOpenedExistentialReference(Type type, Type existentialBaseType,
55345534
TypeVariableType *openedTypeVar,
55355535
TypePosition outermostPosition);
55365536

5537+
Type transformFn(Type type, Type existentialBaseType,
5538+
TypePosition initialPos);
5539+
5540+
55375541
/// Returns true if a reference to a member on a given base type will apply
55385542
/// its curried self parameter, assuming it has one.
55395543
///

lib/AST/GenericSignature.cpp

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -635,19 +635,91 @@ Type GenericSignatureImpl::getNonDependentUpperBounds(Type type) const {
635635
// If the class contains a type parameter, try looking for a non-dependent
636636
// superclass.
637637
while (superclass && superclass->hasTypeParameter()) {
638+
// auto primaryAssocTypes = proto->getPrimaryAssociatedTypes();
639+
// if (!primaryAssocTypes.empty()) {
640+
// SmallVector<Type, 2> argTypes;
641+
//
642+
// // Attempt to recover same-type requirements on primary associated types.
643+
// for (auto *assocType : primaryAssocTypes) {
644+
// // For each primary associated type A of P, compute the reduced type
645+
// // of T.[P]A.
646+
// auto *memberType = DependentMemberType::get(type, assocType);
647+
// auto reducedType = getReducedType(memberType);
648+
//
649+
// }
650+
// }
651+
638652
superclass = superclass->getSuperclass();
639653
}
640-
641654
if (superclass) {
642655
types.push_back(superclass);
643656
hasExplicitAnyObject = false;
644657
}
645658
}
659+
660+
// Protocol Inheritence
661+
// Change here too! if there is a reduced type, erase to it othererwise keep goign until we hit something that has unresolved components
646662
for (auto *proto : getRequiredProtocols(type)) {
647663
if (proto->requiresClass())
648664
hasExplicitAnyObject = false;
665+
666+
auto *baseType = proto->getDeclaredInterfaceType()->castTo<ProtocolType>();
667+
668+
auto primaryAssocTypes = proto->getPrimaryAssociatedTypes();
669+
if (!primaryAssocTypes.empty()) {
670+
SmallVector<Type, 2> argTypes;
671+
672+
// Attempt to recover same-type requirements on primary associated types.
673+
for (auto *assocType : primaryAssocTypes) {
674+
// For each primary associated type A of P, compute the reduced type
675+
// of T.[P]A.
676+
auto *memberType = DependentMemberType::get(type, assocType);
677+
auto reducedType = getReducedType(memberType);
678+
679+
// If the reduced type is at a lower depth than the root generic
680+
// parameter of T, then it's constrained.
681+
bool hasOuterGenericParam = false;
682+
bool hasInnerGenericParam = false;
683+
reducedType.visit([&](Type t) {
684+
if (auto *paramTy = t->getAs<GenericTypeParamType>()) {
685+
unsigned rootDepth = type->getRootGenericParam()->getDepth();
686+
if (paramTy->getDepth() == rootDepth)
687+
hasInnerGenericParam = true;
688+
else {
689+
assert(paramTy->getDepth() < rootDepth);
690+
hasOuterGenericParam = true;
691+
}
692+
}
693+
});
649694

650-
types.push_back(proto->getDeclaredInterfaceType());
695+
if (hasInnerGenericParam && hasOuterGenericParam) {
696+
llvm::errs() << "Weird same-type requirements?\n";
697+
llvm::errs() << "Interface type: " << type << "\n";
698+
llvm::errs() << "Member type: " << memberType << "\n";
699+
llvm::errs() << "Reduced member type: " << reducedType << "\n";
700+
llvm::errs() << GenericSignature(this) << "\n";
701+
abort();
702+
}
703+
704+
if (!hasInnerGenericParam)
705+
argTypes.push_back(reducedType);
706+
}
707+
// We should have either constrained all primary associated types,
708+
// or none of them.
709+
if (!argTypes.empty()) {
710+
if (argTypes.size() != primaryAssocTypes.size()) {
711+
llvm::errs() << "Not all primary associated types constrained?\n";
712+
llvm::errs() << "Interface type: " << type << "\n";
713+
llvm::errs() << GenericSignature(this) << "\n";
714+
abort();
715+
}
716+
717+
types.push_back(ParameterizedProtocolType::get(getASTContext(), baseType, argTypes));
718+
continue;
719+
}
720+
}
721+
722+
types.push_back(baseType);
651723
}
652724

653725
auto constraint = ProtocolCompositionType::get(

lib/Sema/ConstraintSystem.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2103,7 +2103,7 @@ typeEraseExistentialSelfReferences(
21032103
if (t->is<GenericTypeParamType>()) {
21042104
erasedTy = baseTy;
21052105
} else {
2106-
erasedTy = existentialSig->getDependentUpperBounds(t);
2106+
erasedTy = existentialSig->getNonDependentUpperBounds(t);
21072107
}
21082108

21092109
if (metatypeDepth) {
@@ -2114,8 +2114,7 @@ typeEraseExistentialSelfReferences(
21142114
return erasedTy;
21152115
});
21162116
};
2117-
2118-
return transformFn(refTy, outermostPosition);
2117+
return transformFn(refTy, outermostPosition);
21192118
}
21202119

21212120
Type constraints::typeEraseOpenedExistentialReference(

test/Constraints/opened_existentials.swift

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -311,15 +311,28 @@ class C1 {}
311311
class C2<T>: C1 {}
312312

313313
// Protocols With Associated Types
314-
protocol T {
314+
protocol P1 {
315315
associatedtype A
316316
associatedtype B: C2<A>
317317

318318
func returnAssocTypeB() -> B
319319
}
320320

321-
func testAssocReturn(p: any T) {
322-
let _ = p.returnAssocTypeB() // expected-error {{inferred result type 'C2<(any T).A>' requires explicit coercion due to loss of generic requirements}} {{29-29=as C2<(any T).A>}}
321+
func testAssocReturn(p: any P1) { // should return C1
322+
let _ = p.returnAssocTypeB() // expected-error {{inferred result type 'C2<(any T).A>' requires explicit coercion due to loss of generic requirements}} {{29-29=as C2<(any P1).A>}}
323+
}
324+
325+
326+
// Protocols With Associated Types
327+
protocol P2<A> {
328+
associatedtype A
329+
associatedtype B: C2<A>
330+
331+
func returnAssocTypeB() -> B
332+
}
333+
334+
func testAssocReturn(p: any P2<Int>) { // should return C2<A>
335+
let _ = p.returnAssocTypeB() // expected-error {{inferred result type 'C2<(any P2).A>' requires explicit coercion due to loss of generic requirements}} {{29-29=as C2<(any P2).A>}}
323336
}
324337

325338
// Protocols With Primary Associated Types

0 commit comments

Comments
 (0)