-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[CodeCompletion] Missing init completions for dotExpr #16868
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
Changes from 2 commits
927598f
7ef24b1
45c9038
931dac8
ff4d061
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2606,10 +2606,18 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { | |
assert(isa<ConstructorDecl>(CurrDeclContext) && | ||
"can call super.init only inside a constructor"); | ||
needInit = true; | ||
} else if (addName.empty() && HaveDot && | ||
Reason == DeclVisibilityKind::MemberOfCurrentNominal) { | ||
// This case is querying the init function as member | ||
needInit = true; | ||
} else if (addName.empty()) { | ||
auto ReasonIsValid = | ||
Reason == DeclVisibilityKind::MemberOfCurrentNominal || | ||
Reason == DeclVisibilityKind::MemberOfSuper || | ||
Reason == DeclVisibilityKind::MemberOfProtocolImplementedByCurrentNominal; | ||
auto instTy = ExprType->castTo<AnyMetatypeType>()->getInstanceType(); | ||
|
||
if (ReasonIsValid && (HaveDot || | ||
!(instTy->is<ArchetypeType>() || IsStaticMetatype))) { | ||
// This case is querying the init function as member | ||
needInit = true; | ||
} | ||
} | ||
|
||
// If we won't be able to provide a result, bail out. | ||
|
@@ -2638,7 +2646,6 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { | |
addTypeAnnotation(Builder, MemberType); | ||
return; | ||
} | ||
assert(ConstructorType); | ||
|
||
if (!HaveLParen) | ||
Builder.addLeftParen(); | ||
|
@@ -2943,38 +2950,24 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { | |
return; | ||
} | ||
|
||
if (auto MT = ExprType->getRValueType()->getAs<AnyMetatypeType>()) { | ||
if (HaveDot) { | ||
Type Ty; | ||
for (Ty = MT; Ty && Ty->is<AnyMetatypeType>(); | ||
Ty = Ty->getAs<AnyMetatypeType>()->getInstanceType()); | ||
assert(Ty && "Cannot find instance type."); | ||
|
||
// Add init() as member of the metatype. | ||
if (Reason == DeclVisibilityKind::MemberOfCurrentNominal) { | ||
if (IsStaticMetatype || CD->isRequired() || | ||
!Ty->is<ClassType>()) | ||
addConstructorCall(CD, Reason, None, None); | ||
} | ||
return; | ||
} | ||
} | ||
|
||
if (auto MT = ExprType->getAs<AnyMetatypeType>()) { | ||
if (HaveDot) | ||
return; | ||
Type Ty = MT->getInstanceType(); | ||
assert(Ty && "Cannot find instance type."); | ||
|
||
// If instance type is type alias, showing users that the constructed | ||
// If instance type is type alias, show users that the constructed | ||
// type is the typealias instead of the underlying type of the alias. | ||
Optional<Type> Result = None; | ||
if (auto AT = MT->getInstanceType()) { | ||
if (!CD->getInterfaceType()->is<ErrorType>() && | ||
(isa<NameAliasType>(AT.getPointer()) && | ||
AT->getDesugaredType() == | ||
CD->getResultInterfaceType().getPointer())) | ||
Result = AT; | ||
if (!CD->getInterfaceType()->is<ErrorType>() && | ||
isa<NameAliasType>(Ty.getPointer()) && | ||
Ty->getDesugaredType() == | ||
CD->getResultInterfaceType().getPointer()) { | ||
Result = Ty; | ||
} | ||
addConstructorCall(CD, Reason, None, Result); | ||
if (IsStaticMetatype || CD->isRequired() || IsSelfRefExpr || | ||
Ty->is<ArchetypeType>() || | ||
!(Ty->is<ClassType>() || HaveLParen)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This condition needs a comment explaining what's going on. For example, why are we checking There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree. In fact I got it wrong and I might have avoided mistakes with a comment. I will add failing tests to make sure the correct expression doesn't break without consequences. |
||
addConstructorCall(CD, Reason, None, Result); | ||
return; | ||
} | ||
if (IsSuperRefExpr || IsSelfRefExpr) { | ||
if (!isa<ConstructorDecl>(CurrDeclContext)) | ||
|
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.
We shouldn't be using
ExprType
directly here, since we don't know its relation to this call toaddConstructorCall
- seeaddConstructorCallsFromType
for example where we don't know whatExprType
will be. It looks like the intention was that this code either usesBaseType
(if it is specified) orExprType
- e.g. inside ofgetTypeOfMember
. That's pretty hard to understand, and in practice it looks likeBaseType
won't always be a metatype even though it setsIsOnMetatype=true
.How do you feel about the following?
BaseType
required whenIsOnMetatype=true
and pass inExprType
when we call this method.BaseType
and handle that explicitly (e.g. if it's a metatype, get the instance type otherwise use the type directly), or require callers to always provide one or the other and assert that (e.g. always pass a metatype or always pass a non-metatype).Uh oh!
There was an error while loading. Please reload this page.
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.
To be honest I don't like the name
isOnMetatype
at all. We don't call initializers on metatypes to begin with, right? I renamed it toisOnType
, made some clean-up and changed the code not to have a need to useExprType
here. I decided not to touch anything else yet, sincegetTypeOfMember
, which is the only place wherebaseType
is used, is incorrectly used as well (see SR-7802). After fixing that, we might not needbaseType
anymore.