Skip to content

Commit 5799b0a

Browse files
committed
[Sema] Erase existential PATs to reduced type
When opening an existential return or parameter type that has a primaray associated type, the primmary asssociated type should be preserved if the type can be reduced to a concrete type. Otherwise, we should erase the existential to a type with no dependent members or generic parameters and diagnose explicit coercion is needed.
1 parent a2777f4 commit 5799b0a

File tree

7 files changed

+101
-48
lines changed

7 files changed

+101
-48
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5532,7 +5532,8 @@ Expr *getArgumentLabelTargetExpr(Expr *fn);
55325532
/// variable and anything that depends on it to their non-dependent bounds.
55335533
Type typeEraseOpenedExistentialReference(Type type, Type existentialBaseType,
55345534
TypeVariableType *openedTypeVar,
5535-
TypePosition outermostPosition);
5535+
TypePosition outermostPosition,
5536+
bool wantNonDependentBound = true);
55365537

55375538
Type transformFn(Type type, Type existentialBaseType,
55385539
TypePosition initialPos);

lib/AST/GenericSignature.cpp

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -632,23 +632,26 @@ Type GenericSignatureImpl::getNonDependentUpperBounds(Type type) const {
632632

633633
llvm::SmallVector<Type, 2> types;
634634
if (Type superclass = getSuperclassBound(type)) {
635-
// If the class contains a type parameter, try looking for a non-dependent
636-
// superclass.
637-
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-
635+
// If the class contains a type parameter that cannot be reduced,
636+
// try looking for a non-dependent superclass.
637+
while (superclass &&
638+
superclass->hasTypeParameter()) { // check if the current protocol
639+
// has an associated type]
640+
auto *boundgeneric = superclass->castTo<BoundGenericClassType>();
641+
642+
SmallVector<Type, 2> argTypes;
643+
644+
for (Type argTy : boundgeneric->getGenericArgs()) {
645+
argTypes.push_back(getReducedType(argTy));
646+
}
647+
648+
boundgeneric = BoundGenericClassType::get(
649+
boundgeneric->getDecl(), boundgeneric->getParent(), argTypes);
650+
if (!boundgeneric->hasDependentMember() &&
651+
!boundgeneric->hasTypeParameter()) {
652+
superclass = boundgeneric;
653+
break;
654+
}
652655
superclass = superclass->getSuperclass();
653656
}
654657
if (superclass) {
@@ -746,8 +749,20 @@ Type GenericSignatureImpl::getDependentUpperBounds(Type type) const {
746749
// FIXME: If the superclass bound is implied by one of our protocols, we
747750
// shouldn't add it to the constraint type.
748751
if (Type superclass = getSuperclassBound(type)) {
749-
types.push_back(superclass);
750752
hasExplicitAnyObject = false;
753+
754+
if (auto *boundgeneric = superclass->getAs<BoundGenericClassType>()) {
755+
SmallVector<Type, 2> argTypes;
756+
757+
for (Type argTy : boundgeneric->getGenericArgs()) {
758+
argTypes.push_back(getReducedType(argTy));
759+
}
760+
boundgeneric = BoundGenericClassType::get(
761+
boundgeneric->getDecl(), boundgeneric->getParent(), argTypes);
762+
types.push_back(boundgeneric);
763+
} else {
764+
types.push_back(superclass);
765+
}
751766
}
752767

753768
for (auto proto : getRequiredProtocols(type)) {

lib/Sema/CSDiagnostics.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8760,6 +8760,10 @@ bool MissingExplicitExistentialCoercion::fixItRequiresParens() const {
87608760

87618761
void MissingExplicitExistentialCoercion::fixIt(
87628762
InFlightDiagnostic &diagnostic) const {
8763+
8764+
if (ErasedResultType->hasDependentMember())
8765+
return;
8766+
87638767
bool requiresParens = fixItRequiresParens();
87648768

87658769
auto callRange = getSourceRange();

lib/Sema/CSFix.cpp

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2496,8 +2496,10 @@ bool AddExplicitExistentialCoercion::isRequired(
24962496
if (!existentialType)
24972497
return Action::SkipChildren;
24982498

2499+
// let's grab the dependent upper bound here instead of nondependent
24992500
auto erasedMemberTy = typeEraseOpenedExistentialReference(
2500-
Type(member), *existentialType, typeVar, TypePosition::Covariant);
2501+
Type(member), *existentialType, typeVar, TypePosition::Covariant,
2502+
false);
25012503

25022504
// If result is an existential type and the base has `where` clauses
25032505
// associated with its associated types, the call needs a coercion.
@@ -2506,13 +2508,17 @@ bool AddExplicitExistentialCoercion::isRequired(
25062508
RequiresCoercion = true;
25072509
return Action::Stop;
25082510
}
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-
}
2511+
2512+
if (erasedMemberTy->isExistentialType() &&
2513+
(erasedMemberTy->hasDependentMember() ||
2514+
erasedMemberTy->hasTypeParameter())) {
2515+
RequiresCoercion = true;
2516+
return Action::Stop;
2517+
}
2518+
2519+
if (erasedMemberTy->hasTypeVariable()) {
2520+
RequiresCoercion = true;
2521+
return Action::Stop;
25162522
}
25172523

25182524
return Action::SkipChildren;

lib/Sema/CSSimplify.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12653,6 +12653,7 @@ ConstraintSystem::simplifyApplicableFnConstraint(
1265312653
// `as` coercion.
1265412654
if (AddExplicitExistentialCoercion::isRequired(
1265512655
*this, func2->getResult(), openedExistentials, locator)) {
12656+
1265612657
if (!shouldAttemptFixes())
1265712658
return SolutionKind::Error;
1265812659

lib/Sema/ConstraintSystem.cpp

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1998,9 +1998,9 @@ static bool isMainDispatchQueueMember(ConstraintLocator *locator) {
19981998
/// \note If a 'Self'-rooted type parameter is bound to a concrete type, this
19991999
/// routine will recurse into the concrete type.
20002000
static Type
2001-
typeEraseExistentialSelfReferences(
2002-
Type refTy, Type baseTy,
2003-
TypePosition outermostPosition) {
2001+
typeEraseExistentialSelfReferences(Type refTy, Type baseTy,
2002+
TypePosition outermostPosition,
2003+
bool wantNonDependentBound = true) {
20042004
assert(baseTy->isExistentialType());
20052005
if (!refTy->hasTypeParameter()) {
20062006
return refTy;
@@ -2103,7 +2103,9 @@ typeEraseExistentialSelfReferences(
21032103
if (t->is<GenericTypeParamType>()) {
21042104
erasedTy = baseTy;
21052105
} else {
2106-
erasedTy = existentialSig->getNonDependentUpperBounds(t);
2106+
erasedTy = wantNonDependentBound
2107+
? existentialSig->getNonDependentUpperBounds(t)
2108+
: existentialSig->getDependentUpperBounds(t);
21072109
}
21082110

21092111
if (metatypeDepth) {
@@ -2114,12 +2116,12 @@ typeEraseExistentialSelfReferences(
21142116
return erasedTy;
21152117
});
21162118
};
2117-
return transformFn(refTy, outermostPosition);
2119+
return transformFn(refTy, outermostPosition);
21182120
}
21192121

21202122
Type constraints::typeEraseOpenedExistentialReference(
21212123
Type type, Type existentialBaseType, TypeVariableType *openedTypeVar,
2122-
TypePosition outermostPosition) {
2124+
TypePosition outermostPosition, bool wantNonDependentBound) {
21232125
Type selfGP = GenericTypeParamType::get(false, 0, 0, type->getASTContext());
21242126

21252127
// First, temporarily reconstitute the 'Self' generic parameter.
@@ -2136,8 +2138,8 @@ Type constraints::typeEraseOpenedExistentialReference(
21362138
});
21372139

21382140
// Then, type-erase occurrences of covariant 'Self'-rooted type parameters.
2139-
type = typeEraseExistentialSelfReferences(type, existentialBaseType,
2140-
outermostPosition);
2141+
type = typeEraseExistentialSelfReferences(
2142+
type, existentialBaseType, outermostPosition, wantNonDependentBound);
21412143

21422144
// Finally, swap the 'Self'-corresponding type variable back in.
21432145
return type.transformRec([&](TypeBase *t) -> Optional<Type> {
@@ -2242,16 +2244,25 @@ Type ConstraintSystem::getMemberReferenceTypeFromOpenedType(
22422244
const auto selfGP = cast<GenericTypeParamType>(
22432245
outerDC->getSelfInterfaceType()->getCanonicalType());
22442246
auto openedTypeVar = replacements.lookup(selfGP);
2247+
22452248
type = typeEraseOpenedExistentialReference(type, baseObjTy, openedTypeVar,
22462249
TypePosition::Covariant);
22472250

2251+
Type contextualTy;
2252+
2253+
if (auto *anchor = getAsExpr(simplifyLocatorToAnchor(locator))) {
2254+
contextualTy =
2255+
getContextualType(getParentExpr(anchor), /*forConstraint=*/false);
2256+
}
2257+
22482258
if (!hasFixFor(locator) &&
22492259
AddExplicitExistentialCoercion::isRequired(
22502260
*this, nonErasedResultTy,
22512261
[&](TypeVariableType *typeVar) {
22522262
return openedTypeVar == typeVar ? baseObjTy : Optional<Type>();
22532263
},
2254-
locator)) {
2264+
locator) &&
2265+
!contextualTy) {
22552266
recordFix(AddExplicitExistentialCoercion::create(
22562267
*this, getResultType(type), locator));
22572268
}

test/decl/protocol/existential_member_accesses_self_assoctype.swift

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,7 @@ do {
637637
let exist: any InvalidTypeParameters
638638

639639
exist.method1() // expected-error {{instance method 'method1()' requires that 'Self.A' conform to 'InvalidTypeParameters'}}
640+
// expected-error@-1 {{inferred result type '(any InvalidTypeParameters).A.A' requires explicit coercion due to loss of generic requirements}}{{16-16=as (any InvalidTypeParameters).A.A}}
640641
exist.method2(false) // expected-error {{instance method 'method2' requires that 'Self.A' conform to 'InvalidTypeParameters'}}
641642
exist.method3(false, false) // expected-error {{instance method 'method3' requires that 'Self.A' conform to 'InvalidTypeParameters'}}
642643
// expected-error@-1 {{member 'method3' cannot be used on value of type 'any InvalidTypeParameters'; consider using a generic constraint instead}}
@@ -794,14 +795,14 @@ do {
794795

795796
let _: (
796797
Struct<Bool>, (any ConcreteAssocTypes).Type, () -> Bool
797-
) -> any Class<Struct<Bool>.Inner> & ConcreteAssocTypes = arg.method4
798+
) -> any Class<Struct<Bool>.Inner> & ConcreteAssocTypes = arg.method4 // expected-error {{inferred result type 'any Class<Struct<(any ConcreteAssocTypes).A7>.Inner> & ConcreteAssocTypes' requires explicit coercion due to loss of generic requirements}}{{74-74=as any Class<Struct<(any ConcreteAssocTypes).A7>.Inner> & ConcreteAssocTypes}}
798799

799800
let _: (
800801
Struct<Bool>, (any ConcreteAssocTypes).Type, () -> Bool
801802
) -> any Class<Struct<Bool>.Inner> & ConcreteAssocTypes = arg.property4
802803

803804
let _: any Class<Struct<Bool>.Inner> & ConcreteAssocTypes =
804-
arg[
805+
arg[ // expected-error {{inferred result type 'any Class<Struct<(any ConcreteAssocTypes).A7>.Inner> & ConcreteAssocTypes' requires explicit coercion due to loss of generic requirements}}{{7-7=(}} {{807:8-8=as any Class<Struct<(any ConcreteAssocTypes).A7>.Inner> & ConcreteAssocTypes)}}
805806
subscript4: Struct<Bool>(), (any ConcreteAssocTypes).self, { true }
806807
]
807808
}
@@ -914,31 +915,45 @@ do {
914915
let _: Any = exist.method1()
915916
let _: AnyObject = exist.method2()
916917
let _: any CovariantAssocTypeErasure = exist.method3()
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}}
918+
let _: Class2Base = exist.method4()
919+
let _: Class2Base = exist.method5()
919920
let _: any Class2Base & CovariantAssocTypeErasure = exist.method6()
920921
let _: any Class2Base & CovariantAssocTypeErasure = exist.method7()
921-
922-
let _: Any? = exist.method8() // expected-error {{inferred result type 'Optional<Any>' requires explicit coercion due to loss of generic requirements}}
922+
let _: Any? = exist.method8()
923923
let _: (AnyObject, Bool) = exist.method9()
924924
let _: any CovariantAssocTypeErasure.Type = exist.method10()
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}}
925+
let _: Array<Class2Base> = exist.method11()
926+
let _: Dictionary<String, Class2Base> = exist.method12()
927+
928+
let _ = exist.method1()
929+
let _ = exist.method2()
930+
let _ = exist.method3()
931+
let _ = exist.method4()
932+
let _ = exist.method5() // expected-error {{inferred result type 'Class2Base' requires explicit coercion due to loss of generic requirements}}{{24-24=as Class2Base}}
933+
let _ = exist.method6()
934+
let _ = exist.method7() // expected-error {{inferred result type 'any Class2Base & CovariantAssocTypeErasure' requires explicit coercion due to loss of generic requirements}}{{24-24=as any Class2Base & CovariantAssocTypeErasure}}
935+
let _ = exist.method8()
936+
let _ = exist.method9()
937+
let _ = exist.method10()
938+
let _ = exist.method11()
939+
let _ = exist.method12() // expected-error {{inferred result type 'Dictionary<String, Class2Base>' requires explicit coercion due to loss of generic requirements}}{{25-25=as Dictionary<String, Class2Base>}}
940+
941+
927942
}
928943
do {
929944
let exist: any CovariantAssocTypeErasureDerived
930945

931946
let _: any CovariantAssocTypeErasureDerived = exist.method1()
932-
let _: Class2Base = exist.method2() //expected-error {{inferred result type 'Class2Base' requires explicit coercion due to loss of generic requirements}}
947+
let _: Class2Base = exist.method2()
933948
let _: any CovariantAssocTypeErasureDerived = exist.method3()
934949
let _: any Class2Base & CovariantAssocTypeErasureDerived = exist.method4()
935950
let _: any Class2Base & CovariantAssocTypeErasureDerived = exist.method5()
936951
let _: any Class2Base & CovariantAssocTypeErasureDerived = exist.method6()
937952
let _: any Class2Base & CovariantAssocTypeErasure & Sequence = exist.method7()
938953

939-
let _: (any CovariantAssocTypeErasureDerived)? = exist.method8() //expected-error {{inferred result type 'Optional<any CovariantAssocTypeErasureDerived>' requires explicit coercion due to loss of generic requirements}}
954+
let _: (any CovariantAssocTypeErasureDerived)? = exist.method8()
940955
let _: (Class2Base, Bool) = exist.method9()
941956
let _: any CovariantAssocTypeErasureDerived.Type = exist.method10()
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}}
957+
let _: Array<any Class2Base & CovariantAssocTypeErasureDerived> = exist.method11()
958+
let _: Dictionary<String, any Class2Base & CovariantAssocTypeErasureDerived> = exist.method12()
944959
}

0 commit comments

Comments
 (0)