Skip to content

Commit 1d30c8b

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 (cherry picked from commit 14d2f7c) Conflicts: lib/IDE/ExprContextAnalysis.cpp
1 parent 0d1f8b5 commit 1d30c8b

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
@@ -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);

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"
@@ -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)) {
@@ -454,6 +457,31 @@ bool collectPossibleCalleesForSubscript(
454457
return !candidates.empty();
455458
}
456459

460+
/// For the given \p unresolvedMemberExpr, collect possible callee types and
461+
/// declarations.
462+
static bool collectPossibleCalleesForUnresolvedMember(
463+
DeclContext &DC, UnresolvedMemberExpr *unresolvedMemberExpr,
464+
SmallVectorImpl<FunctionTypeAndDecl> &candidates) {
465+
auto currModule = DC.getParentModule();
466+
auto baseName = unresolvedMemberExpr->getName().getBaseName();
467+
468+
// Get the context of the expression itself.
469+
ExprContextInfo contextInfo(&DC, unresolvedMemberExpr);
470+
for (auto expectedTy : contextInfo.getPossibleTypes()) {
471+
if (!expectedTy->mayHaveMembers())
472+
continue;
473+
SmallVector<FunctionTypeAndDecl, 2> members;
474+
collectPossibleCalleesByQualifiedLookup(DC, MetatypeType::get(expectedTy),
475+
baseName, members);
476+
for (auto member : members) {
477+
if (isReferenceableByImplicitMemberExpr(currModule, &DC, expectedTy,
478+
member.second))
479+
candidates.push_back(member);
480+
}
481+
}
482+
return !candidates.empty();
483+
}
484+
457485
/// Get index of \p CCExpr in \p Args. \p Args is usually a \c TupleExpr,
458486
/// \c ParenExpr, or a \c ArgumentShuffleExpr.
459487
/// \returns \c true if success, \c false if \p CCExpr is not a part of \p Args.
@@ -552,6 +580,11 @@ class ExprContextAnalyzer {
552580
if (!collectPossibleCalleesForSubscript(*DC, subscriptExpr, Candidates))
553581
return false;
554582
Arg = subscriptExpr->getIndex();
583+
} else if (auto *unresolvedMemberExpr = dyn_cast<UnresolvedMemberExpr>(E)) {
584+
if (!collectPossibleCalleesForUnresolvedMember(*DC, unresolvedMemberExpr,
585+
Candidates))
586+
return false;
587+
Arg = unresolvedMemberExpr->getArgument();
555588
} else {
556589
llvm_unreachable("unexpected expression kind");
557590
}
@@ -568,7 +601,8 @@ class ExprContextAnalyzer {
568601
// Collect possible types (or labels) at the position.
569602
{
570603
bool MayNeedName = !HasName && !E->isImplicit() &&
571-
(isa<CallExpr>(E) | isa<SubscriptExpr>(E));
604+
(isa<CallExpr>(E) | isa<SubscriptExpr>(E) ||
605+
isa<UnresolvedMemberExpr>(E));
572606
SmallPtrSet<TypeBase *, 4> seenTypes;
573607
SmallPtrSet<Identifier, 4> seenNames;
574608
for (auto &typeAndDecl : Candidates) {
@@ -577,18 +611,30 @@ class ExprContextAnalyzer {
577611
memberDC = typeAndDecl.second->getInnermostDeclContext();
578612

579613
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);
614+
ParameterList *paramList = nullptr;
615+
if (auto VD = typeAndDecl.second) {
616+
if (auto FD = dyn_cast<AbstractFunctionDecl>(VD))
617+
paramList = FD->getParameters();
618+
else if (auto SD = dyn_cast<SubscriptDecl>(VD))
619+
paramList = SD->getIndices();
620+
if (paramList && paramList->size() != Params.size())
621+
paramList = nullptr;
622+
}
623+
for (auto Pos = Position; Pos < Params.size(); ++Pos) {
624+
const auto &Param = Params[Pos];
625+
if (Param.hasLabel() && MayNeedName) {
626+
if (seenNames.insert(Param.getLabel()).second)
627+
recordPossibleName(Param.getLabel().str());
628+
if (paramList && paramList->get(Position)->isDefaultArgument())
629+
continue;
630+
} else {
631+
Type ty = Param.getOldType();
632+
if (memberDC && ty->hasTypeParameter())
633+
ty = memberDC->mapTypeIntoContext(ty);
634+
if (seenTypes.insert(ty.getPointer()).second)
635+
recordPossibleType(ty);
636+
}
637+
break;
592638
}
593639
}
594640
}
@@ -599,6 +645,7 @@ class ExprContextAnalyzer {
599645
switch (Parent->getKind()) {
600646
case ExprKind::Call:
601647
case ExprKind::Subscript:
648+
case ExprKind::UnresolvedMember:
602649
case ExprKind::Binary:
603650
case ExprKind::PrefixUnary: {
604651
analyzeApplyExpr(Parent);
@@ -783,11 +830,14 @@ class ExprContextAnalyzer {
783830
case ExprKind::PrefixUnary:
784831
case ExprKind::Assign:
785832
return true;
833+
case ExprKind::UnresolvedMember:
834+
return true;
786835
case ExprKind::Tuple: {
787836
auto ParentE = Parent.getAsExpr();
788837
return !ParentE ||
789838
(!isa<CallExpr>(ParentE) && !isa<SubscriptExpr>(ParentE) &&
790-
!isa<BinaryExpr>(ParentE) && !isa<ArgumentShuffleExpr>(ParentE));
839+
!isa<BinaryExpr>(ParentE) && !isa<ArgumentShuffleExpr>(ParentE) &&
840+
!isa<UnresolvedMemberExpr>(ParentE));
791841
}
792842
case ExprKind::Closure:
793843
return isSingleExpressionBodyForCodeCompletion(
@@ -856,3 +906,75 @@ ExprContextInfo::ExprContextInfo(DeclContext *DC, Expr *TargetExpr) {
856906
PossibleCallees, singleExpressionBody);
857907
Analyzer.Analyze();
858908
}
909+
910+
//===----------------------------------------------------------------------===//
911+
// isReferenceableByImplicitMemberExpr(ModuleD, DeclContext, Type, ValueDecl)
912+
//===----------------------------------------------------------------------===//
913+
914+
bool swift::ide::isReferenceableByImplicitMemberExpr(
915+
ModuleDecl *CurrModule, DeclContext *DC, Type T, ValueDecl *VD) {
916+
917+
if (VD->isOperator())
918+
return false;
919+
920+
if (!VD->hasInterfaceType())
921+
return false;
922+
923+
if (T->getOptionalObjectType() &&
924+
VD->getModuleContext()->isStdlibModule()) {
925+
// In optional context, ignore '.init(<some>)', 'init(nilLiteral:)',
926+
if (isa<ConstructorDecl>(VD))
927+
return false;
928+
// TODO: Ignore '.some(<Wrapped>)' and '.none' too *in expression
929+
// context*. They are useful in pattern context though.
930+
}
931+
932+
// Enum element decls can always be referenced by implicit member
933+
// expression.
934+
if (isa<EnumElementDecl>(VD))
935+
return true;
936+
937+
// Only non-failable constructors are implicitly referenceable.
938+
if (auto CD = dyn_cast<ConstructorDecl>(VD)) {
939+
switch (CD->getFailability()) {
940+
case OTK_None:
941+
case OTK_ImplicitlyUnwrappedOptional:
942+
return true;
943+
case OTK_Optional:
944+
return false;
945+
}
946+
}
947+
948+
// Otherwise, check the result type matches the contextual type.
949+
auto declTy = T->getTypeOfMember(CurrModule, VD);
950+
if (declTy->is<ErrorType>())
951+
return false;
952+
953+
// Member types can also be implicitly referenceable as long as it's
954+
// convertible to the contextual type.
955+
if (auto CD = dyn_cast<TypeDecl>(VD)) {
956+
declTy = declTy->getMetatypeInstanceType();
957+
958+
// Emit construction for the same type via typealias doesn't make sense
959+
// because we are emitting all `.init()`s.
960+
if (declTy->isEqual(T))
961+
return false;
962+
return swift::isConvertibleTo(declTy, T, *DC);
963+
}
964+
965+
// Only static member can be referenced.
966+
if (!VD->isStatic())
967+
return false;
968+
969+
if (isa<FuncDecl>(VD)) {
970+
// Strip '(Self.Type) ->' and parameters.
971+
declTy = declTy->castTo<AnyFunctionType>()->getResult();
972+
declTy = declTy->castTo<AnyFunctionType>()->getResult();
973+
} else if (auto FT = declTy->getAs<AnyFunctionType>()) {
974+
// The compiler accepts 'static var factory: () -> T' for implicit
975+
// member expression.
976+
// FIXME: This emits just 'factory'. We should emit 'factory()' instead.
977+
declTy = FT->getResult();
978+
}
979+
return declTy->isEqual(T) || swift::isConvertibleTo(declTy, T, *DC);
980+
}

lib/IDE/ExprContextAnalysis.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ class ExprContextInfo {
7676
}
7777
};
7878

79+
/// Returns whether \p VD is referenceable with implicit member expression.
80+
bool isReferenceableByImplicitMemberExpr(
81+
ModuleDecl *CurrModule, DeclContext *DC, Type T, ValueDecl *VD);
82+
7983
} // namespace ide
8084
} // namespace swift
8185

0 commit comments

Comments
 (0)