Skip to content

[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

Merged

Conversation

rintaro
Copy link
Member

@rintaro rintaro commented Jun 3, 2022

Existential types cannot be instantiated.

rdar://94369218

@rintaro
Copy link
Member Author

rintaro commented Jun 3, 2022

@swift-ci Please smoke test

@rintaro rintaro requested a review from bnbarham June 3, 2022 23:07
@rintaro
Copy link
Member Author

rintaro commented Jun 8, 2022

@swift-ci Please smoke test

Comment on lines -2020 to +2027
for (auto *protocol : GP->getConformingProtocols())
addConstructorCallsForType(protocol->getDeclaredInterfaceType(),
GP->getName(), Reason, dynamicLookupInfo);
auto type =
CurrDeclContext->mapTypeIntoContext(GP->getDeclaredInterfaceType());
addConstructorCallsForType(type, GP->getName(), Reason,
dynamicLookupInfo);
Copy link
Member Author

@rintaro rintaro Jun 8, 2022

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.

@rintaro rintaro requested a review from bnbarham June 8, 2022 20:49
@rintaro rintaro force-pushed the ide-completion-existentialinit-rdar94369218 branch from 5f31057 to 8142ea7 Compare June 9, 2022 21:29
@rintaro
Copy link
Member Author

rintaro commented Jun 9, 2022

@swift-ci Please smoke test

@AnthonyLatsis
Copy link
Collaborator

AnthonyLatsis commented Jun 9, 2022

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>
}

Comment on lines 2022 to 2027
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);
Copy link
Member Author

@rintaro rintaro Jun 9, 2022

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()).

Copy link
Contributor

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?

Copy link
Member Author

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?

Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Member Author

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?

Copy link
Contributor

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.

Copy link
Member Author

@rintaro rintaro Jun 10, 2022

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 :)

Copy link
Contributor

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.

Copy link
Member Author

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!

@rintaro
Copy link
Member Author

rintaro commented Jun 9, 2022

@AnthonyLatsis

Do we still show inits for an existential metatype base? For example,

This change doesn't affect member completions like expr.<HERE> so it still show initializers on it.
As for meta(<HERE>, yeah maybe we should suggest initializers, could you file an issue?

@rintaro rintaro force-pushed the ide-completion-existentialinit-rdar94369218 branch from 8142ea7 to cfac36a Compare June 10, 2022 03:14
Existential types cannot be instantiated.

rdar://94369218
@rintaro rintaro force-pushed the ide-completion-existentialinit-rdar94369218 branch from cfac36a to 89761de Compare June 10, 2022 03:15
@rintaro
Copy link
Member Author

rintaro commented Jun 10, 2022

@swift-ci Please smoke test

@rintaro rintaro merged commit 314fe2b into swiftlang:main Jun 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants