-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[CodeCompletion] Don't suggest initializers on existential types #59265
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[CodeCompletion] Don't suggest initializers on existential types #59265
Conversation
@swift-ci Please smoke test |
293dace
to
5f31057
Compare
@swift-ci Please smoke test |
for (auto *protocol : GP->getConformingProtocols()) | ||
addConstructorCallsForType(protocol->getDeclaredInterfaceType(), | ||
GP->getName(), Reason, dynamicLookupInfo); | ||
auto type = | ||
CurrDeclContext->mapTypeIntoContext(GP->getDeclaredInterfaceType()); | ||
addConstructorCallsForType(type, GP->getName(), Reason, | ||
dynamicLookupInfo); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bnbarham Could you re-review? I added this to fix an issue for generic parameters:
func foo<MyGeneric: MyProtocol>(_: MyGeneric) {
<HERE>
}
In this case, since this is a GenericTypeParamDecl
, the type passed to addConstructorCallsForType()
was a protocol type which is an existential type. But in this case we do want initializers for MyGeneric
.
5f31057
to
8142ea7
Compare
@swift-ci Please smoke test |
Do we still show inits on an existential metatype base? For example, protocol P {
init()
}
func test(meta: any P.Type) {
meta.<HERE>
// A bit of an aside: this syntax is not allowed on non-immediate
// metatypes, but arguably code completion should still yield
// results and lend the upcoming `.init` fix-it a helping hand.
meta(<HERE>
} |
lib/IDE/CompletionLookup.cpp
Outdated
if (auto *GP = dyn_cast<GenericTypeParamDecl>(D)) { | ||
addGenericTypeParamRef(GP, Reason, dynamicLookupInfo); | ||
for (auto *protocol : GP->getConformingProtocols()) | ||
addConstructorCallsForType(protocol->getDeclaredInterfaceType(), | ||
GP->getName(), Reason, dynamicLookupInfo); | ||
auto type = GP->getDeclContext()->mapTypeIntoContext( | ||
GP->getDeclaredInterfaceType()); | ||
addConstructorCallsForType(type, GP->getName(), Reason, | ||
dynamicLookupInfo); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@slavapestov Previously, I was doing
auto type = CurrDeclContext->mapTypeIntoContext(GP->getDeclaredInterfaceType())
But it didn't work (crashed) for cases like:
protocol P {
struct S {
func foo() { <HERE> }
}
}
It was crashing when GP
is Self
for P
. In this case, I believe that was because CurrDeclContext
(S.foo()
) doesn't have a valid generic environment because it's invalid anyway. So I updated it to:
auto type = GP->getDeclContext()->mapTypeIntoContext(GP->getDeclaredInterfaceType())
Do you think this is safe? Inside addConstructorCallsForType()
, We just swift::lookupSemanticMember(DC, type, DeclBaseName::createConstructor())
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The generic parameter Self
of protocol P
is not visible from inside struct S
. Why was it showing up here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, maybe lookupVisibleDecls()
is not working properly.
Do you mean Self
of protocol P
should be shadowed by Self
of struct S
? Or it should not be visible anyways?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not visible. Generic parameters are only visible from nested lexical scopes and never via protocol or superclass inheritance. It is also true that Self
inside of a concrete type means that concrete type, but the previous fact is true of all generic parameters not just Self
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now if you have a member of the protocol that is visible via the concrete type, eg
protocol P {
func foo() -> Self
}
struct S : P {
func bar() {
... completion here ...
}
}
Then the interface type of P.foo
is (Self) -> () -> Self
. To get the type of the reference from inside S.bar()
, you must apply a substitution:
auto fooType = fooDecl->getInterfaceType();
auto barSelfType = barDecl->getDeclContext()->getSelfInterfaceType();
auto substFooType = fooType->subst(barSelfType->getContextSubstitutionMap(fooDecl->getDeclContext()));
Now substFooType
is going to be (S) -> () -> S
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, thank you for explanation. I will look into lookupVisibleDecls()
.
If it doesn't emit generic parameter of outer types (including Self
), should we use CurDeclContext
for mapTypeIntoContext
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will report generic parameters of outer types, eg
struct Outer<T> {
struct Inner<U> {
// both T and U visible here
}
}
In this case, innerDC->mapTypeIntoContext(tDecl->getDeclaredInterfaceType())
will work.
What it shouldn't find is generic parameters of superclass types and protocols that each type conforms to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, this is not a superclass or conforming protocols issue.
protocol P {
struct S {
func foo() { <HERE> }
}
}
struct S
is just erroneously nested in protocol P
. It's invalid anyway, but I just want to avoid the crash.
struct Outer<T> { struct Inner<U> { // both T and U visible here } }
👍
What it shouldn't find is generic parameters of superclass types and protocols that each type conforms to.
Understood :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, this is why DeclContext::getParentForLookup() exists. When starting from inside S, lookupVisibleDecls() should be using getParentForLookup() instead of getParent(). This way it will never visit P and find the Self
parameter erroneously.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getParentForLookup()
in lookupVisibleDecls() seems to work. Thank you!
This change doesn't affect member completions like |
8142ea7
to
cfac36a
Compare
Existential types cannot be instantiated. rdar://94369218
cfac36a
to
89761de
Compare
@swift-ci Please smoke test |
Existential types cannot be instantiated.
rdar://94369218