Skip to content

Commit e996d5e

Browse files
authored
Merge pull request #24824 from rintaro/5.1-ide-completion-unresolvedarg-rdar50696432
[5.1][CodeCompletion] Call argument completion for implicit member expression
2 parents 65f9d5c + 4243b73 commit e996d5e

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
@@ -1381,7 +1381,7 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks {
13811381
void completeUnresolvedMember(CodeCompletionExpr *E,
13821382
SourceLoc DotLoc) override;
13831383
void completeAssignmentRHS(AssignExpr *E) override;
1384-
void completeCallArg(CodeCompletionExpr *E) override;
1384+
void completeCallArg(CodeCompletionExpr *E, bool isFirst) override;
13851385
void completeReturnStmt(CodeCompletionExpr *E) override;
13861386
void completeYieldStmt(CodeCompletionExpr *E,
13871387
Optional<unsigned> yieldIndex) override;
@@ -3713,81 +3713,14 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
37133713
return;
37143714

37153715
ModuleDecl *CurrModule = CurrDeclContext->getParentModule();
3716+
DeclContext *DC = const_cast<DeclContext *>(CurrDeclContext);
37163717

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

37933726
auto baseType = MetatypeType::get(T);
@@ -4703,10 +4636,26 @@ void CodeCompletionCallbacksImpl::completeAssignmentRHS(AssignExpr *E) {
47034636
Kind = CompletionKind::AssignmentRHS;
47044637
}
47054638

4706-
void CodeCompletionCallbacksImpl::completeCallArg(CodeCompletionExpr *E) {
4639+
void CodeCompletionCallbacksImpl::completeCallArg(CodeCompletionExpr *E,
4640+
bool isFirst) {
47074641
CurDeclContext = P.CurDeclContext;
47084642
CodeCompleteTokenExpr = E;
47094643
Kind = CompletionKind::CallArg;
4644+
4645+
ShouldCompleteCallPatternAfterParen = false;
4646+
if (isFirst) {
4647+
ShouldCompleteCallPatternAfterParen = true;
4648+
if (Context.LangOpts.CodeCompleteCallPatternHeuristics) {
4649+
// Lookahead one token to decide what kind of call completions to provide.
4650+
// When it appears that there is already code for the call present, just
4651+
// complete values and/or argument labels. Otherwise give the entire call
4652+
// pattern.
4653+
Token next = P.peekToken();
4654+
if (!next.isAtStartOfLine() && !next.is(tok::eof) && !next.is(tok::r_paren)) {
4655+
ShouldCompleteCallPatternAfterParen = false;
4656+
}
4657+
}
4658+
}
47104659
}
47114660

47124661
void CodeCompletionCallbacksImpl::completeReturnStmt(CodeCompletionExpr *E) {
@@ -5411,13 +5360,32 @@ void CodeCompletionCallbacksImpl::doneParsing() {
54115360
}
54125361
case CompletionKind::CallArg : {
54135362
ExprContextInfo ContextInfo(CurDeclContext, CodeCompleteTokenExpr);
5414-
if (!ContextInfo.getPossibleNames().empty()) {
5363+
5364+
bool shouldPerformGlobalCompletion = true;
5365+
5366+
if (ShouldCompleteCallPatternAfterParen &&
5367+
!ContextInfo.getPossibleCallees().empty()) {
5368+
Lookup.setHaveLParen(true);
5369+
for (auto &typeAndDecl : ContextInfo.getPossibleCallees())
5370+
Lookup.tryFunctionCallCompletions(typeAndDecl.first,
5371+
typeAndDecl.second);
5372+
Lookup.setHaveLParen(false);
5373+
5374+
shouldPerformGlobalCompletion =
5375+
!Lookup.FoundFunctionCalls ||
5376+
(Lookup.FoundFunctionCalls &&
5377+
Lookup.FoundFunctionsWithoutFirstKeyword);
5378+
} else if (!ContextInfo.getPossibleNames().empty()) {
54155379
Lookup.addArgNameCompletionResults(ContextInfo.getPossibleNames());
5416-
break;
5380+
5381+
shouldPerformGlobalCompletion = !ContextInfo.getPossibleTypes().empty();
5382+
}
5383+
5384+
if (shouldPerformGlobalCompletion) {
5385+
Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(),
5386+
ContextInfo.isSingleExpressionBody());
5387+
DoPostfixExprBeginning();
54175388
}
5418-
Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(),
5419-
ContextInfo.isSingleExpressionBody());
5420-
DoPostfixExprBeginning();
54215389
break;
54225390
}
54235391

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"
@@ -336,7 +337,9 @@ void collectPossibleCalleesByQualifiedLookup(
336337
Type declaredMemberType = VD->getInterfaceType();
337338
if (VD->getDeclContext()->isTypeContext()) {
338339
if (isa<FuncDecl>(VD)) {
339-
if (!isOnMetaType)
340+
if (!isOnMetaType && VD->isStatic())
341+
continue;
342+
if (isOnMetaType == VD->isStatic())
340343
declaredMemberType =
341344
declaredMemberType->castTo<AnyFunctionType>()->getResult();
342345
} else if (isa<ConstructorDecl>(VD)) {
@@ -396,8 +399,13 @@ bool collectPossibleCalleesForApply(
396399
auto *fnExpr = callExpr->getFn();
397400

398401
if (auto type = fnExpr->getType()) {
399-
if (auto *funcType = type->getAs<AnyFunctionType>())
400-
candidates.emplace_back(funcType, fnExpr->getReferencedDecl().getDecl());
402+
if (auto *funcType = type->getAs<AnyFunctionType>()) {
403+
auto refDecl = fnExpr->getReferencedDecl();
404+
if (!refDecl)
405+
if (auto apply = dyn_cast<ApplyExpr>(fnExpr))
406+
refDecl = apply->getFn()->getReferencedDecl();
407+
candidates.emplace_back(funcType, refDecl.getDecl());
408+
}
401409
} else if (auto *DRE = dyn_cast<DeclRefExpr>(fnExpr)) {
402410
if (auto *decl = DRE->getDecl()) {
403411
auto declType = decl->getInterfaceType();
@@ -454,6 +462,31 @@ bool collectPossibleCalleesForSubscript(
454462
return !candidates.empty();
455463
}
456464

465+
/// For the given \p unresolvedMemberExpr, collect possible callee types and
466+
/// declarations.
467+
static bool collectPossibleCalleesForUnresolvedMember(
468+
DeclContext &DC, UnresolvedMemberExpr *unresolvedMemberExpr,
469+
SmallVectorImpl<FunctionTypeAndDecl> &candidates) {
470+
auto currModule = DC.getParentModule();
471+
auto baseName = unresolvedMemberExpr->getName().getBaseName();
472+
473+
// Get the context of the expression itself.
474+
ExprContextInfo contextInfo(&DC, unresolvedMemberExpr);
475+
for (auto expectedTy : contextInfo.getPossibleTypes()) {
476+
if (!expectedTy->mayHaveMembers())
477+
continue;
478+
SmallVector<FunctionTypeAndDecl, 2> members;
479+
collectPossibleCalleesByQualifiedLookup(DC, MetatypeType::get(expectedTy),
480+
baseName, members);
481+
for (auto member : members) {
482+
if (isReferenceableByImplicitMemberExpr(currModule, &DC, expectedTy,
483+
member.second))
484+
candidates.push_back(member);
485+
}
486+
}
487+
return !candidates.empty();
488+
}
489+
457490
/// Get index of \p CCExpr in \p Args. \p Args is usually a \c TupleExpr,
458491
/// \c ParenExpr, or a \c ArgumentShuffleExpr.
459492
/// \returns \c true if success, \c false if \p CCExpr is not a part of \p Args.
@@ -552,6 +585,11 @@ class ExprContextAnalyzer {
552585
if (!collectPossibleCalleesForSubscript(*DC, subscriptExpr, Candidates))
553586
return false;
554587
Arg = subscriptExpr->getIndex();
588+
} else if (auto *unresolvedMemberExpr = dyn_cast<UnresolvedMemberExpr>(E)) {
589+
if (!collectPossibleCalleesForUnresolvedMember(*DC, unresolvedMemberExpr,
590+
Candidates))
591+
return false;
592+
Arg = unresolvedMemberExpr->getArgument();
555593
} else {
556594
llvm_unreachable("unexpected expression kind");
557595
}
@@ -568,7 +606,8 @@ class ExprContextAnalyzer {
568606
// Collect possible types (or labels) at the position.
569607
{
570608
bool MayNeedName = !HasName && !E->isImplicit() &&
571-
(isa<CallExpr>(E) | isa<SubscriptExpr>(E));
609+
(isa<CallExpr>(E) | isa<SubscriptExpr>(E) ||
610+
isa<UnresolvedMemberExpr>(E));
572611
SmallPtrSet<TypeBase *, 4> seenTypes;
573612
SmallPtrSet<Identifier, 4> seenNames;
574613
for (auto &typeAndDecl : Candidates) {
@@ -577,18 +616,30 @@ class ExprContextAnalyzer {
577616
memberDC = typeAndDecl.second->getInnermostDeclContext();
578617

579618
auto Params = typeAndDecl.first->getParams();
580-
if (Position >= Params.size())
581-
continue;
582-
const auto &Param = Params[Position];
583-
if (Param.hasLabel() && MayNeedName) {
584-
if (seenNames.insert(Param.getLabel()).second)
585-
recordPossibleName(Param.getLabel().str());
586-
} else {
587-
Type ty = Param.getOldType();
588-
if (memberDC && ty->hasTypeParameter())
589-
ty = memberDC->mapTypeIntoContext(ty);
590-
if (seenTypes.insert(ty.getPointer()).second)
591-
recordPossibleType(ty);
619+
ParameterList *paramList = nullptr;
620+
if (auto VD = typeAndDecl.second) {
621+
if (auto FD = dyn_cast<AbstractFunctionDecl>(VD))
622+
paramList = FD->getParameters();
623+
else if (auto SD = dyn_cast<SubscriptDecl>(VD))
624+
paramList = SD->getIndices();
625+
if (paramList && paramList->size() != Params.size())
626+
paramList = nullptr;
627+
}
628+
for (auto Pos = Position; Pos < Params.size(); ++Pos) {
629+
const auto &Param = Params[Pos];
630+
if (Param.hasLabel() && MayNeedName) {
631+
if (seenNames.insert(Param.getLabel()).second)
632+
recordPossibleName(Param.getLabel().str());
633+
if (paramList && paramList->get(Position)->isDefaultArgument())
634+
continue;
635+
} else {
636+
Type ty = Param.getOldType();
637+
if (memberDC && ty->hasTypeParameter())
638+
ty = memberDC->mapTypeIntoContext(ty);
639+
if (seenTypes.insert(ty.getPointer()).second)
640+
recordPossibleType(ty);
641+
}
642+
break;
592643
}
593644
}
594645
}
@@ -599,6 +650,7 @@ class ExprContextAnalyzer {
599650
switch (Parent->getKind()) {
600651
case ExprKind::Call:
601652
case ExprKind::Subscript:
653+
case ExprKind::UnresolvedMember:
602654
case ExprKind::Binary:
603655
case ExprKind::PrefixUnary: {
604656
analyzeApplyExpr(Parent);
@@ -783,11 +835,14 @@ class ExprContextAnalyzer {
783835
case ExprKind::PrefixUnary:
784836
case ExprKind::Assign:
785837
return true;
838+
case ExprKind::UnresolvedMember:
839+
return true;
786840
case ExprKind::Tuple: {
787841
auto ParentE = Parent.getAsExpr();
788842
return !ParentE ||
789843
(!isa<CallExpr>(ParentE) && !isa<SubscriptExpr>(ParentE) &&
790-
!isa<BinaryExpr>(ParentE) && !isa<ArgumentShuffleExpr>(ParentE));
844+
!isa<BinaryExpr>(ParentE) && !isa<ArgumentShuffleExpr>(ParentE) &&
845+
!isa<UnresolvedMemberExpr>(ParentE));
791846
}
792847
case ExprKind::Closure:
793848
return isSingleExpressionBodyForCodeCompletion(
@@ -856,3 +911,75 @@ ExprContextInfo::ExprContextInfo(DeclContext *DC, Expr *TargetExpr) {
856911
PossibleCallees, singleExpressionBody);
857912
Analyzer.Analyze();
858913
}
914+
915+
//===----------------------------------------------------------------------===//
916+
// isReferenceableByImplicitMemberExpr(ModuleD, DeclContext, Type, ValueDecl)
917+
//===----------------------------------------------------------------------===//
918+
919+
bool swift::ide::isReferenceableByImplicitMemberExpr(
920+
ModuleDecl *CurrModule, DeclContext *DC, Type T, ValueDecl *VD) {
921+
922+
if (VD->isOperator())
923+
return false;
924+
925+
if (!VD->hasInterfaceType())
926+
return false;
927+
928+
if (T->getOptionalObjectType() &&
929+
VD->getModuleContext()->isStdlibModule()) {
930+
// In optional context, ignore '.init(<some>)', 'init(nilLiteral:)',
931+
if (isa<ConstructorDecl>(VD))
932+
return false;
933+
// TODO: Ignore '.some(<Wrapped>)' and '.none' too *in expression
934+
// context*. They are useful in pattern context though.
935+
}
936+
937+
// Enum element decls can always be referenced by implicit member
938+
// expression.
939+
if (isa<EnumElementDecl>(VD))
940+
return true;
941+
942+
// Only non-failable constructors are implicitly referenceable.
943+
if (auto CD = dyn_cast<ConstructorDecl>(VD)) {
944+
switch (CD->getFailability()) {
945+
case OTK_None:
946+
case OTK_ImplicitlyUnwrappedOptional:
947+
return true;
948+
case OTK_Optional:
949+
return false;
950+
}
951+
}
952+
953+
// Otherwise, check the result type matches the contextual type.
954+
auto declTy = T->getTypeOfMember(CurrModule, VD);
955+
if (declTy->is<ErrorType>())
956+
return false;
957+
958+
// Member types can also be implicitly referenceable as long as it's
959+
// convertible to the contextual type.
960+
if (auto CD = dyn_cast<TypeDecl>(VD)) {
961+
declTy = declTy->getMetatypeInstanceType();
962+
963+
// Emit construction for the same type via typealias doesn't make sense
964+
// because we are emitting all `.init()`s.
965+
if (declTy->isEqual(T))
966+
return false;
967+
return swift::isConvertibleTo(declTy, T, *DC);
968+
}
969+
970+
// Only static member can be referenced.
971+
if (!VD->isStatic())
972+
return false;
973+
974+
if (isa<FuncDecl>(VD)) {
975+
// Strip '(Self.Type) ->' and parameters.
976+
declTy = declTy->castTo<AnyFunctionType>()->getResult();
977+
declTy = declTy->castTo<AnyFunctionType>()->getResult();
978+
} else if (auto FT = declTy->getAs<AnyFunctionType>()) {
979+
// The compiler accepts 'static var factory: () -> T' for implicit
980+
// member expression.
981+
// FIXME: This emits just 'factory'. We should emit 'factory()' instead.
982+
declTy = FT->getResult();
983+
}
984+
return declTy->isEqual(T) || swift::isConvertibleTo(declTy, T, *DC);
985+
}

0 commit comments

Comments
 (0)