Skip to content

Commit a2777f4

Browse files
committed
[test] Test covariant erasure for constrained existentials
And update expectederror for member access test
1 parent 38a6726 commit a2777f4

File tree

7 files changed

+157
-15
lines changed

7 files changed

+157
-15
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/CSFix.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2506,6 +2506,14 @@ bool AddExplicitExistentialCoercion::isRequired(
25062506
RequiresCoercion = true;
25072507
return Action::Stop;
25082508
}
2509+
2510+
if (auto *const nominal = erasedMemberTy->getAs<NominalOrBoundGenericNominalType>()) {
2511+
// Bound Generic Nominals
2512+
if (!hasConstrainedAssociatedTypes(member, *existentialType)) {
2513+
RequiresCoercion = true;
2514+
return Action::Stop;
2515+
}
2516+
}
25092517

25102518
return Action::SkipChildren;
25112519
}
@@ -2554,6 +2562,7 @@ bool AddExplicitExistentialCoercion::isRequired(
25542562
case RequirementKind::Layout: {
25552563
if (isAnchoredOn(req.getFirstType(), member->getAssocType()))
25562564
return true;
2565+
25572566
break;
25582567
}
25592568

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: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,3 +305,55 @@ func testExplicitCoercionRequirement(v: any B, otherV: any B & D) {
305305
getP((getC(v) as any P)) // Ok - parens avoid opening suppression
306306
getP((v.getC() as any P)) // Ok - parens avoid opening suppression
307307
}
308+
309+
// Generic Class Types
310+
class C1 {}
311+
class C2<T>: C1 {}
312+
313+
// Protocols With Associated Types
314+
protocol P1 {
315+
associatedtype A
316+
associatedtype B: C2<A>
317+
318+
func returnAssocTypeB() -> B
319+
}
320+
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>}}
336+
}
337+
338+
// Protocols With Primary Associated Types
339+
protocol U<A> {
340+
associatedtype A
341+
associatedtype B: C2<A>
342+
343+
func returnAssocTypeB() -> B
344+
func returnPrimaryAssocTypeA() -> A
345+
func returnAssocTypeCollection() -> any Collection<A>
346+
}
347+
348+
func testPrimaryAssocReturn(p: any U<String>) {
349+
let _ = p.returnAssocTypeB() // expected-error {{inferred result type 'C2<(any U<String>).A>' requires explicit coercion due to loss of generic requirements}} {{29-29=as C2<(any U<String>).A>}}
350+
}
351+
352+
func testPrimaryAssocReturn(p: any U<Int>) {
353+
let _ = p.returnPrimaryAssocTypeA()
354+
}
355+
356+
func testPrimaryAssocCollection(p: any U<Float>) -> any Collection {
357+
let x = p.returnAssocTypeCollection()
358+
return x
359+
}

test/decl/protocol/existential_member_accesses_self_assoctype.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -914,31 +914,31 @@ do {
914914
let _: Any = exist.method1()
915915
let _: AnyObject = exist.method2()
916916
let _: any CovariantAssocTypeErasure = exist.method3()
917-
let _: Class2Base = exist.method4()
918-
let _: Class2Base = exist.method5()
917+
let _: Class2Base = exist.method4() // expected-error {{inferred result type 'Class2Base' requires explicit coercion due to loss of generic requirements}}
918+
let _: Class2Base = exist.method5() // expected-error {{inferred result type 'Class2Derived<any CovariantAssocTypeErasure>' requires explicit coercion due to loss of generic requirements}}
919919
let _: any Class2Base & CovariantAssocTypeErasure = exist.method6()
920920
let _: any Class2Base & CovariantAssocTypeErasure = exist.method7()
921921

922-
let _: Any? = exist.method8()
922+
let _: Any? = exist.method8() // expected-error {{inferred result type 'Optional<Any>' requires explicit coercion due to loss of generic requirements}}
923923
let _: (AnyObject, Bool) = exist.method9()
924924
let _: any CovariantAssocTypeErasure.Type = exist.method10()
925-
let _: Array<Class2Base> = exist.method11()
926-
let _: Dictionary<String, Class2Base> = exist.method12()
925+
let _: Array<Class2Base> = exist.method11() // expected-error {{inferred result type 'Array<Class2Base>' requires explicit coercion due to loss of generic requirements}}
926+
let _: Dictionary<String, Class2Base> = exist.method12() //expected-error {{inferred result type 'Dictionary<String, Class2Derived<any CovariantAssocTypeErasure>>' requires explicit coercion due to loss of generic requirements}}
927927
}
928928
do {
929929
let exist: any CovariantAssocTypeErasureDerived
930930

931931
let _: any CovariantAssocTypeErasureDerived = exist.method1()
932-
let _: Class2Base = exist.method2()
932+
let _: Class2Base = exist.method2() //expected-error {{inferred result type 'Class2Base' requires explicit coercion due to loss of generic requirements}}
933933
let _: any CovariantAssocTypeErasureDerived = exist.method3()
934934
let _: any Class2Base & CovariantAssocTypeErasureDerived = exist.method4()
935935
let _: any Class2Base & CovariantAssocTypeErasureDerived = exist.method5()
936936
let _: any Class2Base & CovariantAssocTypeErasureDerived = exist.method6()
937937
let _: any Class2Base & CovariantAssocTypeErasure & Sequence = exist.method7()
938938

939-
let _: (any CovariantAssocTypeErasureDerived)? = exist.method8()
939+
let _: (any CovariantAssocTypeErasureDerived)? = exist.method8() //expected-error {{inferred result type 'Optional<any CovariantAssocTypeErasureDerived>' requires explicit coercion due to loss of generic requirements}}
940940
let _: (Class2Base, Bool) = exist.method9()
941941
let _: any CovariantAssocTypeErasureDerived.Type = exist.method10()
942-
let _: Array<any Class2Base & CovariantAssocTypeErasureDerived> = exist.method11()
943-
let _: Dictionary<String, any Class2Base & CovariantAssocTypeErasureDerived> = exist.method12()
942+
let _: Array<any Class2Base & CovariantAssocTypeErasureDerived> = exist.method11() //expected-error {{inferred result type 'Array<any Class2Base & CovariantAssocTypeErasureDerived>' requires explicit coercion due to loss of generic requirements}}
943+
let _: Dictionary<String, any Class2Base & CovariantAssocTypeErasureDerived> = exist.method12() //expected-error {{inferred result type 'Dictionary<String, any Class2Derived<any CovariantAssocTypeErasureDerived> & CovariantAssocTypeErasureDerived>' requires explicit coercion due to loss of generic requirements}}
944944
}

test/type/parameterized_existential.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,14 @@ func protocolCompositionNotSupported1(_: SomeProto & Sequence<Int>) {}
9292
func protocolCompositionNotSupported2(_: any SomeProto & Sequence<Int>) {}
9393
// expected-error@-1 {{non-protocol, non-class type 'Sequence<Int>' cannot be used within a protocol-constrained type}}
9494

95-
func increment(n : any Sequence<Float>) {
95+
func increment(_ n : any Collection<Float>) {
9696
for value in n {
9797
_ = value + 1
9898
}
9999
}
100+
101+
func genericIncrement<T: Numeric>(_ n : any Collection<T>) {
102+
for value in n {
103+
_ = value + 1
104+
}
105+
}

0 commit comments

Comments
 (0)