Skip to content

Commit 6dabdf5

Browse files
authored
Merge pull request #34499 from slavapestov/opaque-result-with-existential-base
Sema: Ban references to protocol extension members with opaque result types on an existential base
2 parents 343f746 + b7bdca2 commit 6dabdf5

File tree

2 files changed

+30
-0
lines changed

2 files changed

+30
-0
lines changed

lib/AST/Decl.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4795,6 +4795,11 @@ findProtocolSelfReferences(const ProtocolDecl *proto, Type type,
47954795
return info;
47964796
}
47974797

4798+
// Opaque result types of protocol extension members contain an invariant
4799+
// reference to 'Self'.
4800+
if (type->is<OpaqueTypeArchetypeType>())
4801+
return SelfReferenceInfo::forSelfRef(SelfReferencePosition::Invariant);
4802+
47984803
// A direct reference to 'Self'.
47994804
if (proto->getSelfInterfaceType()->isEqual(type))
48004805
return SelfReferenceInfo::forSelfRef(position);

test/type/opaque.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,3 +485,28 @@ protocol SomeProtocolA {}
485485
protocol SomeProtocolB {}
486486
struct SomeStructC: SomeProtocolA, SomeProtocolB {}
487487
let someProperty: SomeProtocolA & some SomeProtocolB = SomeStructC() // expected-error {{'some' should appear at the beginning of a composition}}{{35-40=}}{{19-19=some }}
488+
489+
// An opaque result type on a protocol extension member effectively
490+
// contains an invariant reference to 'Self', and therefore cannot
491+
// be referenced on an existential type.
492+
493+
protocol OpaqueProtocol {}
494+
extension OpaqueProtocol {
495+
var asSome: some OpaqueProtocol { return self }
496+
func getAsSome() -> some OpaqueProtocol { return self }
497+
subscript(_: Int) -> some OpaqueProtocol { return self }
498+
}
499+
500+
func takesOpaqueProtocol(existential: OpaqueProtocol) {
501+
// this is not allowed:
502+
_ = existential.asSome // expected-error{{member 'asSome' cannot be used on value of protocol type 'OpaqueProtocol'; use a generic constraint instead}}
503+
_ = existential.getAsSome() // expected-error{{member 'getAsSome' cannot be used on value of protocol type 'OpaqueProtocol'; use a generic constraint instead}}
504+
_ = existential[0] // expected-error{{member 'subscript' cannot be used on value of protocol type 'OpaqueProtocol'; use a generic constraint instead}}
505+
}
506+
507+
func takesOpaqueProtocol<T : OpaqueProtocol>(generic: T) {
508+
// these are all OK:
509+
_ = generic.asSome
510+
_ = generic.getAsSome()
511+
_ = generic[0]
512+
}

0 commit comments

Comments
 (0)