Skip to content

Commit 1e71185

Browse files
authored
Merge pull request #24805 from rintaro/ide-completion-unresolvedarg-rdar50696432
[CodeCompletion] Call argument completion for implicit member expression
2 parents 3c25d99 + e9e5134 commit 1e71185

File tree

7 files changed

+271
-97
lines changed

7 files changed

+271
-97
lines changed

include/swift/Parse/CodeCompletionCallbacks.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ class CodeCompletionCallbacks {
209209

210210
virtual void completeAssignmentRHS(AssignExpr *E) {};
211211

212-
virtual void completeCallArg(CodeCompletionExpr *E) {};
212+
virtual void completeCallArg(CodeCompletionExpr *E, bool isFirst) {};
213213

214214
virtual void completeReturnStmt(CodeCompletionExpr *E) {};
215215

lib/IDE/CodeCompletion.cpp

Lines changed: 44 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,7 +1379,7 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks {
13791379
void completeUnresolvedMember(CodeCompletionExpr *E,
13801380
SourceLoc DotLoc) override;
13811381
void completeAssignmentRHS(AssignExpr *E) override;
1382-
void completeCallArg(CodeCompletionExpr *E) override;
1382+
void completeCallArg(CodeCompletionExpr *E, bool isFirst) override;
13831383
void completeReturnStmt(CodeCompletionExpr *E) override;
13841384
void completeYieldStmt(CodeCompletionExpr *E,
13851385
Optional<unsigned> yieldIndex) override;
@@ -3710,81 +3710,14 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
37103710
return;
37113711

37123712
ModuleDecl *CurrModule = CurrDeclContext->getParentModule();
3713+
DeclContext *DC = const_cast<DeclContext *>(CurrDeclContext);
37133714

37143715
// We can only say .foo where foo is a static member of the contextual
37153716
// type and has the same type (or if the member is a function, then the
37163717
// same result type) as the contextual type.
37173718
FilteredDeclConsumer consumer(*this, [=](ValueDecl *VD,
37183719
DeclVisibilityKind Reason) {
3719-
3720-
if (VD->isOperator())
3721-
return false;
3722-
3723-
if (!VD->hasInterfaceType()) {
3724-
TypeResolver->resolveDeclSignature(VD);
3725-
if (!VD->hasInterfaceType())
3726-
return false;
3727-
}
3728-
3729-
if (T->getOptionalObjectType() &&
3730-
VD->getModuleContext()->isStdlibModule()) {
3731-
// In optional context, ignore '.init(<some>)', 'init(nilLiteral:)',
3732-
if (isa<ConstructorDecl>(VD))
3733-
return false;
3734-
// TODO: Ignore '.some(<Wrapped>)' and '.none' too *in expression
3735-
// context*. They are useful in pattern context though.
3736-
}
3737-
3738-
// Enum element decls can always be referenced by implicit member
3739-
// expression.
3740-
if (isa<EnumElementDecl>(VD))
3741-
return true;
3742-
3743-
// Only non-failable constructors are implicitly referenceable.
3744-
if (auto CD = dyn_cast<ConstructorDecl>(VD)) {
3745-
switch (CD->getFailability()) {
3746-
case OTK_None:
3747-
case OTK_ImplicitlyUnwrappedOptional:
3748-
return true;
3749-
case OTK_Optional:
3750-
return false;
3751-
}
3752-
}
3753-
3754-
// Otherwise, check the result type matches the contextual type.
3755-
auto declTy = T->getTypeOfMember(CurrModule, VD);
3756-
if (declTy->is<ErrorType>())
3757-
return false;
3758-
3759-
DeclContext *DC = const_cast<DeclContext *>(CurrDeclContext);
3760-
3761-
// Member types can also be implicitly referenceable as long as it's
3762-
// convertible to the contextual type.
3763-
if (auto CD = dyn_cast<TypeDecl>(VD)) {
3764-
declTy = declTy->getMetatypeInstanceType();
3765-
3766-
// Emit construction for the same type via typealias doesn't make sense
3767-
// because we are emitting all `.init()`s.
3768-
if (declTy->isEqual(T))
3769-
return false;
3770-
return swift::isConvertibleTo(declTy, T, *DC);
3771-
}
3772-
3773-
// Only static member can be referenced.
3774-
if (!VD->isStatic())
3775-
return false;
3776-
3777-
if (isa<FuncDecl>(VD)) {
3778-
// Strip '(Self.Type) ->' and parameters.
3779-
declTy = declTy->castTo<AnyFunctionType>()->getResult();
3780-
declTy = declTy->castTo<AnyFunctionType>()->getResult();
3781-
} else if (auto FT = declTy->getAs<AnyFunctionType>()) {
3782-
// The compiler accepts 'static var factory: () -> T' for implicit
3783-
// member expression.
3784-
// FIXME: This emits just 'factory'. We should emit 'factory()' instead.
3785-
declTy = FT->getResult();
3786-
}
3787-
return declTy->isEqual(T) || swift::isConvertibleTo(declTy, T, *DC);
3720+
return isReferenceableByImplicitMemberExpr(CurrModule, DC, T, VD);
37883721
});
37893722

37903723
auto baseType = MetatypeType::get(T);
@@ -4700,10 +4633,26 @@ void CodeCompletionCallbacksImpl::completeAssignmentRHS(AssignExpr *E) {
47004633
Kind = CompletionKind::AssignmentRHS;
47014634
}
47024635

4703-
void CodeCompletionCallbacksImpl::completeCallArg(CodeCompletionExpr *E) {
4636+
void CodeCompletionCallbacksImpl::completeCallArg(CodeCompletionExpr *E,
4637+
bool isFirst) {
47044638
CurDeclContext = P.CurDeclContext;
47054639
CodeCompleteTokenExpr = E;
47064640
Kind = CompletionKind::CallArg;
4641+
4642+
ShouldCompleteCallPatternAfterParen = false;
4643+
if (isFirst) {
4644+
ShouldCompleteCallPatternAfterParen = true;
4645+
if (Context.LangOpts.CodeCompleteCallPatternHeuristics) {
4646+
// Lookahead one token to decide what kind of call completions to provide.
4647+
// When it appears that there is already code for the call present, just
4648+
// complete values and/or argument labels. Otherwise give the entire call
4649+
// pattern.
4650+
Token next = P.peekToken();
4651+
if (!next.isAtStartOfLine() && !next.is(tok::eof) && !next.is(tok::r_paren)) {
4652+
ShouldCompleteCallPatternAfterParen = false;
4653+
}
4654+
}
4655+
}
47074656
}
47084657

47094658
void CodeCompletionCallbacksImpl::completeReturnStmt(CodeCompletionExpr *E) {
@@ -5408,13 +5357,32 @@ void CodeCompletionCallbacksImpl::doneParsing() {
54085357
}
54095358
case CompletionKind::CallArg : {
54105359
ExprContextInfo ContextInfo(CurDeclContext, CodeCompleteTokenExpr);
5411-
if (!ContextInfo.getPossibleNames().empty()) {
5360+
5361+
bool shouldPerformGlobalCompletion = true;
5362+
5363+
if (ShouldCompleteCallPatternAfterParen &&
5364+
!ContextInfo.getPossibleCallees().empty()) {
5365+
Lookup.setHaveLParen(true);
5366+
for (auto &typeAndDecl : ContextInfo.getPossibleCallees())
5367+
Lookup.tryFunctionCallCompletions(typeAndDecl.first,
5368+
typeAndDecl.second);
5369+
Lookup.setHaveLParen(false);
5370+
5371+
shouldPerformGlobalCompletion =
5372+
!Lookup.FoundFunctionCalls ||
5373+
(Lookup.FoundFunctionCalls &&
5374+
Lookup.FoundFunctionsWithoutFirstKeyword);
5375+
} else if (!ContextInfo.getPossibleNames().empty()) {
54125376
Lookup.addArgNameCompletionResults(ContextInfo.getPossibleNames());
5413-
break;
5377+
5378+
shouldPerformGlobalCompletion = !ContextInfo.getPossibleTypes().empty();
5379+
}
5380+
5381+
if (shouldPerformGlobalCompletion) {
5382+
Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(),
5383+
ContextInfo.isSingleExpressionBody());
5384+
DoPostfixExprBeginning();
54145385
}
5415-
Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(),
5416-
ContextInfo.isSingleExpressionBody());
5417-
DoPostfixExprBeginning();
54185386
break;
54195387
}
54205388

lib/IDE/ExprContextAnalysis.cpp

Lines changed: 144 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/AST/Initializer.h"
2121
#include "swift/AST/LazyResolver.h"
2222
#include "swift/AST/Module.h"
23+
#include "swift/AST/ParameterList.h"
2324
#include "swift/AST/Pattern.h"
2425
#include "swift/AST/Stmt.h"
2526
#include "swift/AST/Type.h"
@@ -289,7 +290,9 @@ static void collectPossibleCalleesByQualifiedLookup(
289290
Type declaredMemberType = VD->getInterfaceType();
290291
if (VD->getDeclContext()->isTypeContext()) {
291292
if (isa<FuncDecl>(VD)) {
292-
if (!isOnMetaType)
293+
if (!isOnMetaType && VD->isStatic())
294+
continue;
295+
if (isOnMetaType == VD->isStatic())
293296
declaredMemberType =
294297
declaredMemberType->castTo<AnyFunctionType>()->getResult();
295298
} else if (isa<ConstructorDecl>(VD)) {
@@ -349,8 +352,13 @@ static bool collectPossibleCalleesForApply(
349352
auto *fnExpr = callExpr->getFn();
350353

351354
if (auto type = fnExpr->getType()) {
352-
if (auto *funcType = type->getAs<AnyFunctionType>())
353-
candidates.emplace_back(funcType, fnExpr->getReferencedDecl().getDecl());
355+
if (auto *funcType = type->getAs<AnyFunctionType>()) {
356+
auto refDecl = fnExpr->getReferencedDecl();
357+
if (!refDecl)
358+
if (auto apply = dyn_cast<ApplyExpr>(fnExpr))
359+
refDecl = apply->getFn()->getReferencedDecl();
360+
candidates.emplace_back(funcType, refDecl.getDecl());
361+
}
354362
} else if (auto *DRE = dyn_cast<DeclRefExpr>(fnExpr)) {
355363
if (auto *decl = DRE->getDecl()) {
356364
auto declType = decl->getInterfaceType();
@@ -407,6 +415,31 @@ static bool collectPossibleCalleesForSubscript(
407415
return !candidates.empty();
408416
}
409417

418+
/// For the given \p unresolvedMemberExpr, collect possible callee types and
419+
/// declarations.
420+
static bool collectPossibleCalleesForUnresolvedMember(
421+
DeclContext &DC, UnresolvedMemberExpr *unresolvedMemberExpr,
422+
SmallVectorImpl<FunctionTypeAndDecl> &candidates) {
423+
auto currModule = DC.getParentModule();
424+
auto baseName = unresolvedMemberExpr->getName().getBaseName();
425+
426+
// Get the context of the expression itself.
427+
ExprContextInfo contextInfo(&DC, unresolvedMemberExpr);
428+
for (auto expectedTy : contextInfo.getPossibleTypes()) {
429+
if (!expectedTy->mayHaveMembers())
430+
continue;
431+
SmallVector<FunctionTypeAndDecl, 2> members;
432+
collectPossibleCalleesByQualifiedLookup(DC, MetatypeType::get(expectedTy),
433+
baseName, members);
434+
for (auto member : members) {
435+
if (isReferenceableByImplicitMemberExpr(currModule, &DC, expectedTy,
436+
member.second))
437+
candidates.push_back(member);
438+
}
439+
}
440+
return !candidates.empty();
441+
}
442+
410443
/// Get index of \p CCExpr in \p Args. \p Args is usually a \c TupleExpr
411444
/// or \c ParenExpr.
412445
/// \returns \c true if success, \c false if \p CCExpr is not a part of \p Args.
@@ -470,6 +503,11 @@ class ExprContextAnalyzer {
470503
if (!collectPossibleCalleesForSubscript(*DC, subscriptExpr, Candidates))
471504
return false;
472505
Arg = subscriptExpr->getIndex();
506+
} else if (auto *unresolvedMemberExpr = dyn_cast<UnresolvedMemberExpr>(E)) {
507+
if (!collectPossibleCalleesForUnresolvedMember(*DC, unresolvedMemberExpr,
508+
Candidates))
509+
return false;
510+
Arg = unresolvedMemberExpr->getArgument();
473511
} else {
474512
llvm_unreachable("unexpected expression kind");
475513
}
@@ -484,7 +522,8 @@ class ExprContextAnalyzer {
484522
// Collect possible types (or labels) at the position.
485523
{
486524
bool MayNeedName = !HasName && !E->isImplicit() &&
487-
(isa<CallExpr>(E) | isa<SubscriptExpr>(E));
525+
(isa<CallExpr>(E) | isa<SubscriptExpr>(E) ||
526+
isa<UnresolvedMemberExpr>(E));
488527
SmallPtrSet<TypeBase *, 4> seenTypes;
489528
SmallPtrSet<Identifier, 4> seenNames;
490529
for (auto &typeAndDecl : Candidates) {
@@ -493,18 +532,30 @@ class ExprContextAnalyzer {
493532
memberDC = typeAndDecl.second->getInnermostDeclContext();
494533

495534
auto Params = typeAndDecl.first->getParams();
496-
if (Position >= Params.size())
497-
continue;
498-
const auto &Param = Params[Position];
499-
if (Param.hasLabel() && MayNeedName) {
500-
if (seenNames.insert(Param.getLabel()).second)
501-
recordPossibleName(Param.getLabel().str());
502-
} else {
503-
Type ty = Param.getOldType();
504-
if (memberDC && ty->hasTypeParameter())
505-
ty = memberDC->mapTypeIntoContext(ty);
506-
if (seenTypes.insert(ty.getPointer()).second)
507-
recordPossibleType(ty);
535+
ParameterList *paramList = nullptr;
536+
if (auto VD = typeAndDecl.second) {
537+
if (auto FD = dyn_cast<AbstractFunctionDecl>(VD))
538+
paramList = FD->getParameters();
539+
else if (auto SD = dyn_cast<SubscriptDecl>(VD))
540+
paramList = SD->getIndices();
541+
if (paramList && paramList->size() != Params.size())
542+
paramList = nullptr;
543+
}
544+
for (auto Pos = Position; Pos < Params.size(); ++Pos) {
545+
const auto &Param = Params[Pos];
546+
if (Param.hasLabel() && MayNeedName) {
547+
if (seenNames.insert(Param.getLabel()).second)
548+
recordPossibleName(Param.getLabel().str());
549+
if (paramList && paramList->get(Position)->isDefaultArgument())
550+
continue;
551+
} else {
552+
Type ty = Param.getOldType();
553+
if (memberDC && ty->hasTypeParameter())
554+
ty = memberDC->mapTypeIntoContext(ty);
555+
if (seenTypes.insert(ty.getPointer()).second)
556+
recordPossibleType(ty);
557+
}
558+
break;
508559
}
509560
}
510561
}
@@ -515,6 +566,7 @@ class ExprContextAnalyzer {
515566
switch (Parent->getKind()) {
516567
case ExprKind::Call:
517568
case ExprKind::Subscript:
569+
case ExprKind::UnresolvedMember:
518570
case ExprKind::Binary:
519571
case ExprKind::PrefixUnary: {
520572
analyzeApplyExpr(Parent);
@@ -706,11 +758,14 @@ class ExprContextAnalyzer {
706758
case ExprKind::Assign:
707759
case ExprKind::Array:
708760
return true;
761+
case ExprKind::UnresolvedMember:
762+
return true;
709763
case ExprKind::Tuple: {
710764
auto ParentE = Parent.getAsExpr();
711765
return !ParentE ||
712766
(!isa<CallExpr>(ParentE) && !isa<SubscriptExpr>(ParentE) &&
713-
!isa<BinaryExpr>(ParentE));
767+
!isa<BinaryExpr>(ParentE) &&
768+
!isa<UnresolvedMemberExpr>(ParentE));
714769
}
715770
case ExprKind::Closure:
716771
return isSingleExpressionBodyForCodeCompletion(
@@ -779,3 +834,75 @@ ExprContextInfo::ExprContextInfo(DeclContext *DC, Expr *TargetExpr) {
779834
PossibleCallees, singleExpressionBody);
780835
Analyzer.Analyze();
781836
}
837+
838+
//===----------------------------------------------------------------------===//
839+
// isReferenceableByImplicitMemberExpr(ModuleD, DeclContext, Type, ValueDecl)
840+
//===----------------------------------------------------------------------===//
841+
842+
bool swift::ide::isReferenceableByImplicitMemberExpr(
843+
ModuleDecl *CurrModule, DeclContext *DC, Type T, ValueDecl *VD) {
844+
845+
if (VD->isOperator())
846+
return false;
847+
848+
if (!VD->hasInterfaceType())
849+
return false;
850+
851+
if (T->getOptionalObjectType() &&
852+
VD->getModuleContext()->isStdlibModule()) {
853+
// In optional context, ignore '.init(<some>)', 'init(nilLiteral:)',
854+
if (isa<ConstructorDecl>(VD))
855+
return false;
856+
// TODO: Ignore '.some(<Wrapped>)' and '.none' too *in expression
857+
// context*. They are useful in pattern context though.
858+
}
859+
860+
// Enum element decls can always be referenced by implicit member
861+
// expression.
862+
if (isa<EnumElementDecl>(VD))
863+
return true;
864+
865+
// Only non-failable constructors are implicitly referenceable.
866+
if (auto CD = dyn_cast<ConstructorDecl>(VD)) {
867+
switch (CD->getFailability()) {
868+
case OTK_None:
869+
case OTK_ImplicitlyUnwrappedOptional:
870+
return true;
871+
case OTK_Optional:
872+
return false;
873+
}
874+
}
875+
876+
// Otherwise, check the result type matches the contextual type.
877+
auto declTy = T->getTypeOfMember(CurrModule, VD);
878+
if (declTy->is<ErrorType>())
879+
return false;
880+
881+
// Member types can also be implicitly referenceable as long as it's
882+
// convertible to the contextual type.
883+
if (auto CD = dyn_cast<TypeDecl>(VD)) {
884+
declTy = declTy->getMetatypeInstanceType();
885+
886+
// Emit construction for the same type via typealias doesn't make sense
887+
// because we are emitting all `.init()`s.
888+
if (declTy->isEqual(T))
889+
return false;
890+
return swift::isConvertibleTo(declTy, T, *DC);
891+
}
892+
893+
// Only static member can be referenced.
894+
if (!VD->isStatic())
895+
return false;
896+
897+
if (isa<FuncDecl>(VD)) {
898+
// Strip '(Self.Type) ->' and parameters.
899+
declTy = declTy->castTo<AnyFunctionType>()->getResult();
900+
declTy = declTy->castTo<AnyFunctionType>()->getResult();
901+
} else if (auto FT = declTy->getAs<AnyFunctionType>()) {
902+
// The compiler accepts 'static var factory: () -> T' for implicit
903+
// member expression.
904+
// FIXME: This emits just 'factory'. We should emit 'factory()' instead.
905+
declTy = FT->getResult();
906+
}
907+
return declTy->isEqual(T) || swift::isConvertibleTo(declTy, T, *DC);
908+
}

0 commit comments

Comments
 (0)