Skip to content

Commit 24c19d4

Browse files
committed
Sema: Enable covariant erasure for dependent member types
1 parent c47f99a commit 24c19d4

File tree

6 files changed

+152
-66
lines changed

6 files changed

+152
-66
lines changed

include/swift/AST/Types.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,7 @@ class alignas(1 << TypeAlignInBits) TypeBase
621621

622622
/// Determine whether the type involves the given opened existential
623623
/// archetype.
624-
bool hasOpenedExistential(const OpenedArchetypeType *opened);
624+
bool hasOpenedExistentialWithRoot(const OpenedArchetypeType *root) const;
625625

626626
/// Determine whether the type involves an opaque type.
627627
bool hasOpaqueArchetype() const {

include/swift/Sema/ConstraintSystem.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5298,9 +5298,8 @@ class ConstraintSystem {
52985298

52995299
/// Determine whether referencing the given member on the
53005300
/// given existential base type is supported. This is the case only if the
5301-
/// type of the member, spelled in the context of \p baseTy,
5302-
/// - does not contain any 'Self'-rooted dependent member types, and
5303-
/// - does not contain 'Self' in non-covariant position.
5301+
/// type of the member, spelled in the context of \p baseTy, does not contain
5302+
/// 'Self' or 'Self'-rooted dependent member types in non-covariant position.
53045303
bool isMemberAvailableOnExistential(Type baseTy,
53055304
const ValueDecl *member) const;
53065305

lib/AST/Type.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -439,12 +439,19 @@ bool TypeBase::isSpecialized() {
439439
return false;
440440
}
441441

442-
bool TypeBase::hasOpenedExistential(const OpenedArchetypeType *opened) {
442+
bool TypeBase::hasOpenedExistentialWithRoot(
443+
const OpenedArchetypeType *root) const {
444+
assert(root->isRoot() && "Expected a root archetype");
445+
443446
if (!hasOpenedExistential())
444447
return false;
445448

446449
return getCanonicalType().findIf([&](Type type) -> bool {
447-
return opened == dyn_cast<OpenedArchetypeType>(type.getPointer());
450+
auto *opened = dyn_cast<OpenedArchetypeType>(type.getPointer());
451+
if (!opened)
452+
return false;
453+
454+
return opened->getRoot() == root;
448455
});
449456
}
450457

lib/Sema/CSApply.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1004,7 +1004,7 @@ namespace {
10041004
// If we had a return type of 'Self', erase it.
10051005
Type resultTy;
10061006
resultTy = cs.getType(result);
1007-
if (resultTy->hasOpenedExistential(record.Archetype)) {
1007+
if (resultTy->hasOpenedExistentialWithRoot(record.Archetype)) {
10081008
Type erasedTy =
10091009
resultTy->typeEraseOpenedArchetypesWithRoot(record.Archetype);
10101010
auto range = result->getSourceRange();

lib/Sema/ConstraintSystem.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5991,11 +5991,12 @@ bool ConstraintSystem::isMemberAvailableOnExistential(
59915991
Type baseTy, const ValueDecl *member) const {
59925992
assert(member->getDeclContext()->getSelfProtocolDecl());
59935993

5994-
// If the type of the member references 'Self' in non-covariant position, or
5995-
// an associated type in any position, we cannot make use of the member.
5994+
// If the type of the member references 'Self' or a 'Self'-rooted associated
5995+
// type in non-covariant position, we cannot reference the member.
59965996
const auto info = member->findExistentialSelfReferences(
59975997
baseTy, /*treatNonResultCovariantSelfAsInvariant=*/false);
5998-
if (info.selfRef > TypePosition::Covariant || info.assocTypeRef) {
5998+
if (info.selfRef > TypePosition::Covariant ||
5999+
info.assocTypeRef > TypePosition::Covariant) {
59996000
return false;
60006001
}
60016002

test/decl/protocol/protocols_with_self_or_assoc_reqs.swift

Lines changed: 135 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -248,14 +248,19 @@ do {
248248
{ (_: () -> (any P1)?) in }
249249
)
250250

251-
arg.covariantAssoc1() // expected-error {{member 'covariantAssoc1' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
252-
arg.covariantAssoc2() // expected-error {{member 'covariantAssoc2' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
253-
arg.covariantAssoc3() // expected-error {{member 'covariantAssoc3' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
254-
arg.covariantAssoc4() // expected-error {{member 'covariantAssoc4' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
255-
arg.covariantAssoc5() // expected-error {{member 'covariantAssoc5' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
256-
arg.covariantAssoc6() // expected-error {{member 'covariantAssoc6' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
257-
_ = arg.covariantAssoc7 // expected-error {{member 'covariantAssoc7' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
258-
_ = arg.covariantAssocComplex // expected-error {{member 'covariantAssocComplex' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
251+
let _: Any = arg.covariantAssoc1()
252+
let _: Any? = arg.covariantAssoc2()
253+
let _: Any.Type = arg.covariantAssoc3()
254+
let _: (Any, Any) = arg.covariantAssoc4()
255+
let _: Array<Any> = arg.covariantAssoc5()
256+
let _: [String : Any] = arg.covariantAssoc6()
257+
arg.covariantAssoc7 { (_: Any) in }
258+
let _: [String : () -> (Any, Any)] = arg.covariantAssocComplex(
259+
{ (_: Any.Type) in },
260+
{ (_: Array<Any>) in },
261+
{ (_: Array<Array<Any>?>) in },
262+
{ (_: () -> Any?) in }
263+
)
259264

260265
let _: any P1 = arg.covariantSelfProp1
261266
let _: (any P1)? = arg.covariantSelfProp2
@@ -271,14 +276,19 @@ do {
271276
(() -> (any P1)?) -> Void
272277
) -> [String : () -> (any P1, any P1)] = arg.covariantSelfPropComplex
273278

274-
arg.covariantAssocProp1 // expected-error {{member 'covariantAssocProp1' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
275-
arg.covariantAssocProp2 // expected-error {{member 'covariantAssocProp2' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
276-
arg.covariantAssocProp3 // expected-error {{member 'covariantAssocProp3' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
277-
arg.covariantAssocProp4 // expected-error {{member 'covariantAssocProp4' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
278-
arg.covariantAssocProp5 // expected-error {{member 'covariantAssocProp5' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
279-
arg.covariantAssocProp6 // expected-error {{member 'covariantAssocProp6' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
280-
arg.covariantAssocProp7 // expected-error {{member 'covariantAssocProp7' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
281-
arg.covariantAssocPropComplex // expected-error {{member 'covariantAssocPropComplex' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
279+
let _: Any = arg.covariantAssocProp1
280+
let _: Any? = arg.covariantAssocProp2
281+
let _: Any.Type = arg.covariantAssocProp3
282+
let _: (Any, Any) = arg.covariantAssocProp4
283+
let _: Array<Any> = arg.covariantAssocProp5
284+
let _: [String : Any] = arg.covariantAssocProp6
285+
let _: ((Any) -> Void) -> Void = arg.covariantAssocProp7
286+
let _: (
287+
(Any.Type) -> Void,
288+
(Array<Any>) -> Void,
289+
(Array<Array<Any>?>) -> Void,
290+
(() -> Any?) -> Void
291+
) -> [String : () -> (Any, Any)] = arg.covariantAssocPropComplex
282292

283293
let _: any P1 = arg[covariantSelfSubscript1: ()]
284294
let _: (any P1)? = arg[covariantSelfSubscript2: ()]
@@ -294,14 +304,19 @@ do {
294304
{ (_: () -> (any P1)?) in }
295305
]
296306

297-
arg[covariantAssocSubscript1: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
298-
arg[covariantAssocSubscript2: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
299-
arg[covariantAssocSubscript3: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
300-
arg[covariantAssocSubscript4: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
301-
arg[covariantAssocSubscript5: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
302-
arg[covariantAssocSubscript6: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
303-
arg[covariantAssocSubscript7: { _ in }] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
304-
arg[covariantAssocSubscriptComplex: { _ in }, { _ in }, { _ in }, { _ in }] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
307+
let _: Any = arg[covariantAssocSubscript1: ()]
308+
let _: Any? = arg[covariantAssocSubscript2: ()]
309+
let _: Any.Type = arg[covariantAssocSubscript3: ()]
310+
let _: (Any, Any) = arg[covariantAssocSubscript4: ()]
311+
let _: Array<Any> = arg[covariantAssocSubscript5: ()]
312+
let _: [String : Any] = arg[covariantAssocSubscript6: ()]
313+
let _: Any = arg[covariantAssocSubscript7: { (_: Any) in }]
314+
let _: [String : () -> (Any, Any)] = arg[
315+
covariantAssocSubscriptComplex: { (_: Any.Type) in },
316+
{ (_: Array<Any>) in },
317+
{ (_: Array<Array<Any>?>) in },
318+
{ (_: () -> Any?) in }
319+
]
305320

306321
arg.contravariantSelf1(0) // expected-error {{member 'contravariantSelf1' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
307322
arg.contravariantSelf2(0) // expected-error {{member 'contravariantSelf2' cannot be used on value of protocol type 'P1'; use a generic constraint instead}}
@@ -633,36 +648,24 @@ func takesP2(p2: any P2) {
633648
}
634649

635650
protocol MiscTestsProto {
636-
associatedtype Assoc
637-
func runce<A>(_: A)
638-
func spoon(_: Self)
639-
640651
associatedtype R : IteratorProtocol, Sequence
641652
func getR() -> R
642653

643-
subscript(intToAssoc _: Int) -> Assoc { get }
644-
subscript(intToInt _: Int) -> Int { get }
654+
associatedtype Assoc
655+
subscript() -> Assoc { get }
656+
var getAssoc: Assoc? { get }
645657
}
646658
do {
647-
func miscTests(_ arg: any MiscTestsProto) { // ok
648-
arg.runce(5)
649-
650-
do {
651-
// FIXME: Crummy diagnostics.
652-
var x = arg.getR() // expected-error{{member 'getR' cannot be used on value of protocol type 'MiscTestsProto'; use a generic constraint instead}}
653-
x.makeIterator()
654-
x.next()
655-
x.nonexistent()
656-
}
657-
658-
var _: Int = arg[intToInt: 17]
659-
_ = arg[intToAssoc: 17] // expected-error{{member 'subscript' cannot be used on value of protocol type 'MiscTestsProto'; use a generic constraint instead}}
660-
}
661-
662-
func existentialSequence(_ e: any Sequence) {
663-
var x = e.makeIterator() // expected-error{{member 'makeIterator' cannot be used on value of protocol type 'Sequence'; use a generic constraint instead}}
664-
x.next()
665-
x.nonexistent()
659+
func miscTests(_ arg: any MiscTestsProto) {
660+
var r: any Sequence & IteratorProtocol = arg.getR()
661+
r.makeIterator() // expected-warning {{result of call to 'makeIterator()' is unused}}
662+
// FIXME: We are leaking an implementation detail in this warning.
663+
r.next() // expected-warning {{expression of type '(IteratorProtocol & Sequence).Element' is unused}}
664+
r.nonexistent() // expected-error {{value of type 'IteratorProtocol & Sequence' has no member 'nonexistent'}}
665+
666+
// FIXME: We are leaking an implementation detail in this warning.
667+
arg[] // expected-warning {{expression of type '(MiscTestsProto).Assoc' is unused}}
668+
arg.getAssoc // expected-warning {{expression of type '(MiscTestsProto).Assoc' is unused}}
666669
}
667670
}
668671

@@ -679,7 +682,7 @@ protocol CovariantMetatypes {
679682
var covariantSelfMetatypeProp1: Self.Type.Type.Type { get }
680683
var covariantSelfMetatypeProp2: (Self.Type, Self.Type.Type) { get }
681684

682-
var covariantAssocMetatypeProp1: (Q.Type.Type.Type) -> Void { get }
685+
var covariantAssocMetatypeProp1: Q.Type.Type.Type { get }
683686
var covariantAssocMetatypeProp2: (Q.Type, Q.Type.Type) { get }
684687

685688
subscript(covariantSelfMetatypeSubscript1 _: (Self.Type.Type.Type) -> Void) -> Self.Type { get }
@@ -693,20 +696,20 @@ do {
693696
arg.covariantSelfMetatype1 { (_: any CovariantMetatypes.Type.Type.Type) in }
694697
let _: (any CovariantMetatypes.Type, any CovariantMetatypes.Type.Type) = arg.covariantSelfMetatype2()
695698

696-
arg.covariantAssocMetatype1 // expected-error {{member 'covariantAssocMetatype1' cannot be used on value of protocol type 'CovariantMetatypes'; use a generic constraint instead}}
697-
arg.covariantAssocMetatype2 // expected-error {{member 'covariantAssocMetatype2' cannot be used on value of protocol type 'CovariantMetatypes'; use a generic constraint instead}}
699+
arg.covariantAssocMetatype1 { (_: Any.Type.Type.Type) in }
700+
let _: (Any.Type, Any.Type.Type) = arg.covariantAssocMetatype2()
698701

699702
let _: any CovariantMetatypes.Type.Type.Type = arg.covariantSelfMetatypeProp1
700703
let _: (any CovariantMetatypes.Type, any CovariantMetatypes.Type.Type) = arg.covariantSelfMetatypeProp2
701704

702-
arg.covariantAssocMetatypeProp1 // expected-error {{member 'covariantAssocMetatypeProp1' cannot be used on value of protocol type 'CovariantMetatypes'; use a generic constraint instead}}
703-
arg.covariantAssocMetatypeProp2 // expected-error {{member 'covariantAssocMetatypeProp2' cannot be used on value of protocol type 'CovariantMetatypes'; use a generic constraint instead}}
705+
let _: Any.Type.Type.Type = arg.covariantAssocMetatypeProp1
706+
let _: (Any.Type, Any.Type.Type) = arg.covariantAssocMetatypeProp2
704707

705708
let _: any CovariantMetatypes.Type = arg[covariantSelfMetatypeSubscript1: { (_: any CovariantMetatypes.Type.Type.Type) in }]
706709
let _: (any CovariantMetatypes.Type, any CovariantMetatypes.Type.Type) = arg[covariantSelfMetatypeSubscript2: ()]
707710

708-
arg[covariantAssocMetatypeSubscript1: { _ in }] // expected-error {{member 'subscript' cannot be used on value of protocol type 'CovariantMetatypes'; use a generic constraint instead}}
709-
arg[covariantAssocMetatypeSubscript2: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'CovariantMetatypes'; use a generic constraint instead}}
711+
let _: Any.Type = arg[covariantAssocMetatypeSubscript1: { (_: Any.Type.Type.Type) in }]
712+
let _: (Any.Type, Any.Type.Type) = arg[covariantAssocMetatypeSubscript2: ()]
710713
}
711714
}
712715

@@ -831,3 +834,79 @@ do {
831834
let exist: any CompositionBrokenClassConformance_b & BadConformanceClass
832835
exist.method(false) // expected-error {{type of expression is ambiguous without more context}}
833836
}
837+
838+
/// Covariant Associated Type Erasure
839+
840+
class Class2Base {}
841+
class Class2Derived<T>: Class2Base {}
842+
protocol CovariantAssocTypeErasure {
843+
associatedtype A1
844+
associatedtype A2: AnyObject
845+
associatedtype A3: CovariantAssocTypeErasure
846+
associatedtype A4: Class2Base
847+
associatedtype A5: Class2Derived<Self>
848+
associatedtype A6: CovariantAssocTypeErasure & Class2Base
849+
associatedtype A7: Class2Derived<Self> & CovariantAssocTypeErasure
850+
851+
associatedtype B1 where B1 == Optional<A1>
852+
associatedtype B2 where B2 == (A2, Bool)
853+
associatedtype B3 where B3 == A3.Type
854+
associatedtype B4 where B4 == Array<A4>
855+
associatedtype B5 where B5 == Dictionary<String, A5>
856+
857+
func method1() -> A1
858+
func method2() -> A2
859+
func method3() -> A3
860+
func method4() -> A4
861+
func method5() -> A5
862+
func method6() -> A6
863+
func method7() -> A7
864+
865+
func method8() -> B1
866+
func method9() -> B2
867+
func method10() -> B3
868+
func method11() -> B4
869+
func method12() -> B5
870+
}
871+
protocol CovariantAssocTypeErasureDerived: CovariantAssocTypeErasure
872+
where A1: CovariantAssocTypeErasureDerived,
873+
A2: Class2Base,
874+
A3: CovariantAssocTypeErasureDerived,
875+
A4: CovariantAssocTypeErasureDerived,
876+
A5: CovariantAssocTypeErasureDerived,
877+
A6: CovariantAssocTypeErasureDerived,
878+
A7: Sequence {}
879+
do {
880+
let exist: any CovariantAssocTypeErasure
881+
882+
let _: Any = exist.method1()
883+
let _: AnyObject = exist.method2()
884+
let _: any CovariantAssocTypeErasure = exist.method3()
885+
let _: Class2Base = exist.method4()
886+
let _: Class2Base = exist.method5()
887+
let _: any Class2Base & CovariantAssocTypeErasure = exist.method6()
888+
let _: any Class2Base & CovariantAssocTypeErasure = exist.method7()
889+
890+
let _: Any? = exist.method8()
891+
let _: (AnyObject, Bool) = exist.method9()
892+
let _: any CovariantAssocTypeErasure.Type = exist.method10()
893+
let _: Array<Class2Base> = exist.method11()
894+
let _: Dictionary<String, Class2Base> = exist.method12()
895+
}
896+
do {
897+
let exist: any CovariantAssocTypeErasureDerived
898+
899+
let _: any CovariantAssocTypeErasureDerived = exist.method1()
900+
let _: Class2Base = exist.method2()
901+
let _: any CovariantAssocTypeErasureDerived = exist.method3()
902+
let _: any Class2Base & CovariantAssocTypeErasureDerived = exist.method4()
903+
let _: any Class2Base & CovariantAssocTypeErasureDerived = exist.method5()
904+
let _: any Class2Base & CovariantAssocTypeErasureDerived = exist.method6()
905+
let _: any Class2Base & CovariantAssocTypeErasure & Sequence = exist.method7()
906+
907+
let _: (any CovariantAssocTypeErasureDerived)? = exist.method8()
908+
let _: (Class2Base, Bool) = exist.method9()
909+
let _: any CovariantAssocTypeErasureDerived.Type = exist.method10()
910+
let _: Array<any Class2Base & CovariantAssocTypeErasureDerived> = exist.method11()
911+
let _: Dictionary<String, any Class2Base & CovariantAssocTypeErasureDerived> = exist.method12()
912+
}

0 commit comments

Comments
 (0)