Skip to content

Commit 14d2f7c

Browse files
committed
[CodeCompletion] Enable context type analysis for implict member expression
At argument part of implict member expression, we need context type analysis to complete arguments. rdar://problem/50696432
1 parent 60ee952 commit 14d2f7c

File tree

3 files changed

+143
-84
lines changed

3 files changed

+143
-84
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 2 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -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);

lib/IDE/ExprContextAnalysis.cpp

Lines changed: 137 additions & 15 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)) {
@@ -407,6 +410,31 @@ static bool collectPossibleCalleesForSubscript(
407410
return !candidates.empty();
408411
}
409412

413+
/// For the given \p unresolvedMemberExpr, collect possible callee types and
414+
/// declarations.
415+
static bool collectPossibleCalleesForUnresolvedMember(
416+
DeclContext &DC, UnresolvedMemberExpr *unresolvedMemberExpr,
417+
SmallVectorImpl<FunctionTypeAndDecl> &candidates) {
418+
auto currModule = DC.getParentModule();
419+
auto baseName = unresolvedMemberExpr->getName().getBaseName();
420+
421+
// Get the context of the expression itself.
422+
ExprContextInfo contextInfo(&DC, unresolvedMemberExpr);
423+
for (auto expectedTy : contextInfo.getPossibleTypes()) {
424+
if (!expectedTy->mayHaveMembers())
425+
continue;
426+
SmallVector<FunctionTypeAndDecl, 2> members;
427+
collectPossibleCalleesByQualifiedLookup(DC, MetatypeType::get(expectedTy),
428+
baseName, members);
429+
for (auto member : members) {
430+
if (isReferenceableByImplicitMemberExpr(currModule, &DC, expectedTy,
431+
member.second))
432+
candidates.push_back(member);
433+
}
434+
}
435+
return !candidates.empty();
436+
}
437+
410438
/// Get index of \p CCExpr in \p Args. \p Args is usually a \c TupleExpr
411439
/// or \c ParenExpr.
412440
/// \returns \c true if success, \c false if \p CCExpr is not a part of \p Args.
@@ -470,6 +498,11 @@ class ExprContextAnalyzer {
470498
if (!collectPossibleCalleesForSubscript(*DC, subscriptExpr, Candidates))
471499
return false;
472500
Arg = subscriptExpr->getIndex();
501+
} else if (auto *unresolvedMemberExpr = dyn_cast<UnresolvedMemberExpr>(E)) {
502+
if (!collectPossibleCalleesForUnresolvedMember(*DC, unresolvedMemberExpr,
503+
Candidates))
504+
return false;
505+
Arg = unresolvedMemberExpr->getArgument();
473506
} else {
474507
llvm_unreachable("unexpected expression kind");
475508
}
@@ -484,7 +517,8 @@ class ExprContextAnalyzer {
484517
// Collect possible types (or labels) at the position.
485518
{
486519
bool MayNeedName = !HasName && !E->isImplicit() &&
487-
(isa<CallExpr>(E) | isa<SubscriptExpr>(E));
520+
(isa<CallExpr>(E) | isa<SubscriptExpr>(E) ||
521+
isa<UnresolvedMemberExpr>(E));
488522
SmallPtrSet<TypeBase *, 4> seenTypes;
489523
SmallPtrSet<Identifier, 4> seenNames;
490524
for (auto &typeAndDecl : Candidates) {
@@ -493,18 +527,30 @@ class ExprContextAnalyzer {
493527
memberDC = typeAndDecl.second->getInnermostDeclContext();
494528

495529
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);
530+
ParameterList *paramList = nullptr;
531+
if (auto VD = typeAndDecl.second) {
532+
if (auto FD = dyn_cast<AbstractFunctionDecl>(VD))
533+
paramList = FD->getParameters();
534+
else if (auto SD = dyn_cast<SubscriptDecl>(VD))
535+
paramList = SD->getIndices();
536+
if (paramList && paramList->size() != Params.size())
537+
paramList = nullptr;
538+
}
539+
for (auto Pos = Position; Pos < Params.size(); ++Pos) {
540+
const auto &Param = Params[Pos];
541+
if (Param.hasLabel() && MayNeedName) {
542+
if (seenNames.insert(Param.getLabel()).second)
543+
recordPossibleName(Param.getLabel().str());
544+
if (paramList && paramList->get(Position)->isDefaultArgument())
545+
continue;
546+
} else {
547+
Type ty = Param.getOldType();
548+
if (memberDC && ty->hasTypeParameter())
549+
ty = memberDC->mapTypeIntoContext(ty);
550+
if (seenTypes.insert(ty.getPointer()).second)
551+
recordPossibleType(ty);
552+
}
553+
break;
508554
}
509555
}
510556
}
@@ -515,6 +561,7 @@ class ExprContextAnalyzer {
515561
switch (Parent->getKind()) {
516562
case ExprKind::Call:
517563
case ExprKind::Subscript:
564+
case ExprKind::UnresolvedMember:
518565
case ExprKind::Binary:
519566
case ExprKind::PrefixUnary: {
520567
analyzeApplyExpr(Parent);
@@ -706,11 +753,14 @@ class ExprContextAnalyzer {
706753
case ExprKind::Assign:
707754
case ExprKind::Array:
708755
return true;
756+
case ExprKind::UnresolvedMember:
757+
return true;
709758
case ExprKind::Tuple: {
710759
auto ParentE = Parent.getAsExpr();
711760
return !ParentE ||
712761
(!isa<CallExpr>(ParentE) && !isa<SubscriptExpr>(ParentE) &&
713-
!isa<BinaryExpr>(ParentE));
762+
!isa<BinaryExpr>(ParentE) &&
763+
!isa<UnresolvedMemberExpr>(ParentE));
714764
}
715765
case ExprKind::Closure:
716766
return isSingleExpressionBodyForCodeCompletion(
@@ -779,3 +829,75 @@ ExprContextInfo::ExprContextInfo(DeclContext *DC, Expr *TargetExpr) {
779829
PossibleCallees, singleExpressionBody);
780830
Analyzer.Analyze();
781831
}
832+
833+
//===----------------------------------------------------------------------===//
834+
// isReferenceableByImplicitMemberExpr(ModuleD, DeclContext, Type, ValueDecl)
835+
//===----------------------------------------------------------------------===//
836+
837+
bool swift::ide::isReferenceableByImplicitMemberExpr(
838+
ModuleDecl *CurrModule, DeclContext *DC, Type T, ValueDecl *VD) {
839+
840+
if (VD->isOperator())
841+
return false;
842+
843+
if (!VD->hasInterfaceType())
844+
return false;
845+
846+
if (T->getOptionalObjectType() &&
847+
VD->getModuleContext()->isStdlibModule()) {
848+
// In optional context, ignore '.init(<some>)', 'init(nilLiteral:)',
849+
if (isa<ConstructorDecl>(VD))
850+
return false;
851+
// TODO: Ignore '.some(<Wrapped>)' and '.none' too *in expression
852+
// context*. They are useful in pattern context though.
853+
}
854+
855+
// Enum element decls can always be referenced by implicit member
856+
// expression.
857+
if (isa<EnumElementDecl>(VD))
858+
return true;
859+
860+
// Only non-failable constructors are implicitly referenceable.
861+
if (auto CD = dyn_cast<ConstructorDecl>(VD)) {
862+
switch (CD->getFailability()) {
863+
case OTK_None:
864+
case OTK_ImplicitlyUnwrappedOptional:
865+
return true;
866+
case OTK_Optional:
867+
return false;
868+
}
869+
}
870+
871+
// Otherwise, check the result type matches the contextual type.
872+
auto declTy = T->getTypeOfMember(CurrModule, VD);
873+
if (declTy->is<ErrorType>())
874+
return false;
875+
876+
// Member types can also be implicitly referenceable as long as it's
877+
// convertible to the contextual type.
878+
if (auto CD = dyn_cast<TypeDecl>(VD)) {
879+
declTy = declTy->getMetatypeInstanceType();
880+
881+
// Emit construction for the same type via typealias doesn't make sense
882+
// because we are emitting all `.init()`s.
883+
if (declTy->isEqual(T))
884+
return false;
885+
return swift::isConvertibleTo(declTy, T, *DC);
886+
}
887+
888+
// Only static member can be referenced.
889+
if (!VD->isStatic())
890+
return false;
891+
892+
if (isa<FuncDecl>(VD)) {
893+
// Strip '(Self.Type) ->' and parameters.
894+
declTy = declTy->castTo<AnyFunctionType>()->getResult();
895+
declTy = declTy->castTo<AnyFunctionType>()->getResult();
896+
} else if (auto FT = declTy->getAs<AnyFunctionType>()) {
897+
// The compiler accepts 'static var factory: () -> T' for implicit
898+
// member expression.
899+
// FIXME: This emits just 'factory'. We should emit 'factory()' instead.
900+
declTy = FT->getResult();
901+
}
902+
return declTy->isEqual(T) || swift::isConvertibleTo(declTy, T, *DC);
903+
}

lib/IDE/ExprContextAnalysis.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ class ExprContextInfo {
7171
}
7272
};
7373

74+
/// Returns whether \p VD is referenceable with implicit member expression.
75+
bool isReferenceableByImplicitMemberExpr(
76+
ModuleDecl *CurrModule, DeclContext *DC, Type T, ValueDecl *VD);
77+
7478
} // namespace ide
7579
} // namespace swift
7680

0 commit comments

Comments
 (0)