mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[CodeCompletion] Suggest static members on protocol extensions with Self bound in unresolved member lookup
rdar://122758029
This commit is contained in:
@@ -116,6 +116,31 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/// Returns `true` if `ED` is an extension of `PD` that binds `Self` to a
|
||||
/// concrete type, like `extension MyProto where Self == MyStruct {}`.
|
||||
///
|
||||
/// In these cases, it is possible to access static members defined in the
|
||||
/// extension when perfoming unresolved member lookup in a type context of
|
||||
/// `PD`.
|
||||
static bool isExtensionWithSelfBound(const ExtensionDecl *ED,
|
||||
ProtocolDecl *PD) {
|
||||
if (!ED || !PD) {
|
||||
return false;
|
||||
}
|
||||
if (ED->getExtendedNominal() != PD) {
|
||||
return false;
|
||||
}
|
||||
GenericSignature genericSig = ED->getGenericSignature();
|
||||
Type selfType = genericSig->getConcreteType(ED->getSelfInterfaceType());
|
||||
if (!selfType) {
|
||||
return false;
|
||||
}
|
||||
if (selfType->is<ExistentialType>()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool isExtensionAppliedInternal(const DeclContext *DC, Type BaseTy,
|
||||
const ExtensionDecl *ED) {
|
||||
// We can't do anything if the base type has unbound generic parameters.
|
||||
@@ -130,8 +155,20 @@ static bool isExtensionAppliedInternal(const DeclContext *DC, Type BaseTy,
|
||||
if (!ED->isConstrainedExtension())
|
||||
return true;
|
||||
|
||||
GenericSignature genericSig = ED->getGenericSignature();
|
||||
ProtocolDecl *BaseTypeProtocolDecl = nullptr;
|
||||
if (auto opaqueType = dyn_cast<OpaqueTypeArchetypeType>(BaseTy)) {
|
||||
if (opaqueType->getConformsTo().size() == 1) {
|
||||
BaseTypeProtocolDecl = opaqueType->getConformsTo().front();
|
||||
}
|
||||
} else {
|
||||
BaseTypeProtocolDecl = dyn_cast_or_null<ProtocolDecl>(BaseTy->getAnyNominal());
|
||||
}
|
||||
|
||||
if (isExtensionWithSelfBound(ED, BaseTypeProtocolDecl)) {
|
||||
return true;
|
||||
}
|
||||
auto *module = DC->getParentModule();
|
||||
GenericSignature genericSig = ED->getGenericSignature();
|
||||
SubstitutionMap substMap = BaseTy->getContextSubstitutionMap(
|
||||
module, ED->getExtendedNominal());
|
||||
return checkRequirements(module,
|
||||
@@ -142,7 +179,10 @@ static bool isExtensionAppliedInternal(const DeclContext *DC, Type BaseTy,
|
||||
|
||||
static bool isMemberDeclAppliedInternal(const DeclContext *DC, Type BaseTy,
|
||||
const ValueDecl *VD) {
|
||||
if (BaseTy->isExistentialType() && VD->isStatic())
|
||||
if (BaseTy->isExistentialType() && VD->isStatic() &&
|
||||
!isExtensionWithSelfBound(
|
||||
dyn_cast<ExtensionDecl>(VD->getDeclContext()),
|
||||
dyn_cast_or_null<ProtocolDecl>(BaseTy->getAnyNominal())))
|
||||
return false;
|
||||
|
||||
// We can't leak type variables into another constraint system.
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
// RUN: %batch-code-completion
|
||||
|
||||
protocol MyProto {}
|
||||
protocol MyOtherProto: MyProto {}
|
||||
struct MyStruct : MyProto {}
|
||||
extension MyProto where Self == MyStruct {
|
||||
static var constrainedOnMyStruct: MyStruct { fatalError() }
|
||||
}
|
||||
extension MyProto where Self: MyOtherProto {
|
||||
static var constrainedOnMyInheritanceOfOtherProto: MyOtherProto { fatalError() }
|
||||
}
|
||||
extension MyProto where Self == MyOtherProto {
|
||||
static var constrainedOnMyEqualityOfOtherProto: MyOtherProto { fatalError() }
|
||||
}
|
||||
|
||||
|
||||
func testOnMyProto() {
|
||||
let _: MyProto = .#^ON_MY_PROTO^#
|
||||
// ON_MY_PROTO: Begin completions, 1 items
|
||||
// ON_MY_PROTO-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Convertible]: constrainedOnMyStruct[#MyStruct#];
|
||||
}
|
||||
|
||||
func testOnMyOtherProto() {
|
||||
// constrainedOnMyStruct is not valid here
|
||||
let _: MyOtherProto = .#^ON_MY_OTHER_PROTO^#
|
||||
// ON_MY_OTHER_PROTO-NOT: Begin completions
|
||||
}
|
||||
|
||||
func testOpaqueMyProto() -> some MyProto {
|
||||
return .#^IN_OPAQUE_PROTOCOL_POS?check=ON_MY_PROTO^#
|
||||
}
|
||||
Reference in New Issue
Block a user