Skip to content

[CodeCompletion] Migrate CaseStmtBeginning to solver-based #41921

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions include/swift/IDE/ExprCompletion.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ class ExprTypeCheckCompletionCallback : public TypeCheckCompletionCallback {
/// functions is supported.
bool IsInAsyncContext;

/// If unresolved member lookup is enabled in the completion callback,
/// the type that the unresolved member lookup should be performed on,
/// otherwise a null type.
Type UnresolvedMemberBaseType;

/// Types of variables that were determined in the solution that produced
/// this result. This in particular includes parameters of closures that
/// were type-checked with the code completion expression.
Expand All @@ -54,6 +59,11 @@ class ExprTypeCheckCompletionCallback : public TypeCheckCompletionCallback {
/// in almost all cases and acceptable results in the other cases.
SmallVector<Type, 4> ExpectedTypes;

/// When \c true, unresolved member completions of the expected types are
/// also reported when delivering results. Used in places that frequently
/// use unresolved members such as enum cases.
bool AddUnresolvedMemberCompletions;

SmallVector<Result, 4> Results;

/// Adds the given type to \c ExpectedTypes unless \c ExpectedTypes already
Expand All @@ -62,17 +72,22 @@ class ExprTypeCheckCompletionCallback : public TypeCheckCompletionCallback {

/// Adds the result with the given parameters to \c Results unless \c Results
/// already contains an entry with exactly the same values.
/// If \c AddUnresolvedMemberCompletions is false, the
/// \p UnresolvedMemberBaseType is ignored.
void addResult(
bool IsImplicitSingleExpressionReturn, bool IsInAsyncContext,
Type UnresolvedMemberBaseType,
llvm::SmallDenseMap<const VarDecl *, Type> SolutionSpecificVarTypes);

void sawSolutionImpl(const constraints::Solution &solution) override;

public:
/// \param DC The decl context in which the \p CompletionExpr occurs.
ExprTypeCheckCompletionCallback(CodeCompletionExpr *CompletionExpr,
DeclContext *DC)
: CompletionExpr(CompletionExpr), DC(DC) {}
DeclContext *DC,
bool AddUnresolvedMemberCompletions)
: CompletionExpr(CompletionExpr), DC(DC),
AddUnresolvedMemberCompletions(AddUnresolvedMemberCompletions) {}

/// \param CCLoc The location of the code completion token.
void deliverResults(SourceLoc CCLoc,
Expand Down
18 changes: 6 additions & 12 deletions lib/IDE/CodeCompletion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1405,13 +1405,16 @@ bool CodeCompletionCallbacksImpl::trySolverCompletion(bool MaybeFuncBody) {
return true;
}
case CompletionKind::AccessorBeginning:
case CompletionKind::CaseStmtBeginning:
case CompletionKind::ForEachSequence:
case CompletionKind::PostfixExprBeginning:
case CompletionKind::StmtOrExpr: {
assert(CurDeclContext);

ExprTypeCheckCompletionCallback Lookup(CodeCompleteTokenExpr,
CurDeclContext);
bool AddUnresolvedMemberCompletions =
(Kind == CompletionKind::CaseStmtBeginning);
ExprTypeCheckCompletionCallback Lookup(
CodeCompleteTokenExpr, CurDeclContext, AddUnresolvedMemberCompletions);
if (CodeCompleteTokenExpr) {
// 'CodeCompletionTokenExpr == nullptr' happens when completing e.g.
// var x: Int {
Expand Down Expand Up @@ -1583,6 +1586,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
case CompletionKind::PostfixExprBeginning:
case CompletionKind::AfterPoundExpr:
case CompletionKind::AccessorBeginning:
case CompletionKind::CaseStmtBeginning:
llvm_unreachable("should be already handled");
return;

Expand Down Expand Up @@ -1681,16 +1685,6 @@ void CodeCompletionCallbacksImpl::doneParsing() {
break;
}

case CompletionKind::CaseStmtBeginning: {
ExprContextInfo ContextInfo(CurDeclContext, CodeCompleteTokenExpr);
Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(),
ContextInfo.isImplicitSingleExpressionReturn());
Lookup.setIdealExpectedType(CodeCompleteTokenExpr->getType());
Lookup.getUnresolvedMemberCompletions(ContextInfo.getPossibleTypes());
DoPostfixExprBeginning();
break;
}

case CompletionKind::NominalMemberBeginning: {
CompletionOverrideLookup OverrideLookup(CompletionContext.getResultSink(),
P.Context, CurDeclContext,
Expand Down
2 changes: 2 additions & 0 deletions lib/IDE/CompletionLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2683,6 +2683,8 @@ void CompletionLookup::getUnresolvedMemberCompletions(Type T) {
if (!T->mayHaveMembers())
return;

NeedLeadingDot = !HaveDot;

if (auto objT = T->getOptionalObjectType()) {
// Add 'nil' keyword with erasing '.' instruction.
unsigned bytesToErase = 0;
Expand Down
15 changes: 13 additions & 2 deletions lib/IDE/ExprCompletion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ bool ExprTypeCheckCompletionCallback::Result::operator==(
return IsImplicitSingleExpressionReturn ==
Other.IsImplicitSingleExpressionReturn &&
IsInAsyncContext == Other.IsInAsyncContext &&
nullableTypesEqual(UnresolvedMemberBaseType,
Other.UnresolvedMemberBaseType) &&
solutionSpecificVarTypesEqual(SolutionSpecificVarTypes,
Other.SolutionSpecificVarTypes);
}
Expand All @@ -58,9 +60,13 @@ void ExprTypeCheckCompletionCallback::addExpectedType(Type ExpectedType) {

void ExprTypeCheckCompletionCallback::addResult(
bool IsImplicitSingleExpressionReturn, bool IsInAsyncContext,
Type UnresolvedMemberBaseType,
llvm::SmallDenseMap<const VarDecl *, Type> SolutionSpecificVarTypes) {
if (!AddUnresolvedMemberCompletions) {
UnresolvedMemberBaseType = Type();
}
Result NewResult = {IsImplicitSingleExpressionReturn, IsInAsyncContext,
SolutionSpecificVarTypes};
UnresolvedMemberBaseType, SolutionSpecificVarTypes};
if (llvm::is_contained(Results, NewResult)) {
return;
}
Expand All @@ -80,10 +86,12 @@ void ExprTypeCheckCompletionCallback::sawSolutionImpl(
llvm::SmallDenseMap<const VarDecl *, Type> SolutionSpecificVarTypes;
getSolutionSpecificVarTypes(S, SolutionSpecificVarTypes);

addResult(ImplicitReturn, IsAsync, SolutionSpecificVarTypes);
addResult(ImplicitReturn, IsAsync, ExpectedTy, SolutionSpecificVarTypes);
addExpectedType(ExpectedTy);

if (auto PatternMatchType = getPatternMatchType(S, CompletionExpr)) {
addResult(ImplicitReturn, IsAsync, PatternMatchType,
SolutionSpecificVarTypes);
addExpectedType(PatternMatchType);
}
}
Expand All @@ -104,6 +112,9 @@ void ExprTypeCheckCompletionCallback::deliverResults(

Lookup.getValueCompletionsInDeclContext(CCLoc);
Lookup.getSelfTypeCompletionInDeclContext(CCLoc, /*isForDeclResult=*/false);
if (Result.UnresolvedMemberBaseType) {
Lookup.getUnresolvedMemberCompletions(Result.UnresolvedMemberBaseType);
}
}

deliverCompletionResults(CompletionCtx, Lookup, DC, Consumer);
Expand Down
10 changes: 5 additions & 5 deletions test/IDE/complete_enum_elements.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ enum FooEnum: CaseIterable {
}

// FOO_ENUM_TYPE_CONTEXT: Begin completions
// FOO_ENUM_TYPE_CONTEXT-DAG: Decl[EnumElement]/CurrNominal/Flair[ExprSpecific]/TypeRelation[Identical]: .Foo1[#FooEnum#]{{; name=.+$}}
// FOO_ENUM_TYPE_CONTEXT-DAG: Decl[EnumElement]/CurrNominal/Flair[ExprSpecific]/TypeRelation[Identical]: .Foo2[#FooEnum#]{{; name=.+$}}
// FOO_ENUM_TYPE_CONTEXT-DAG: Decl[StaticVar]/CurrNominal/Flair[ExprSpecific]/TypeRelation[Identical]: .alias1[#FooEnum#]; name=alias1
// FOO_ENUM_TYPE_CONTEXT-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: .Foo1[#FooEnum#]{{; name=.+$}}
// FOO_ENUM_TYPE_CONTEXT-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: .Foo2[#FooEnum#]{{; name=.+$}}
// FOO_ENUM_TYPE_CONTEXT-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: .alias1[#FooEnum#]; name=alias1
// FOO_ENUM_TYPE_CONTEXT: End completions

// FOO_ENUM_NO_DOT: Begin completions
Expand Down Expand Up @@ -202,8 +202,8 @@ enum QuxEnum : Int {
}

// QUX_ENUM_TYPE_CONTEXT: Begin completions
// QUX_ENUM_TYPE_CONTEXT-DAG: Decl[EnumElement]/CurrNominal/Flair[ExprSpecific]/TypeRelation[Identical]: .Qux1[#QuxEnum#]{{; name=.+$}}
// QUX_ENUM_TYPE_CONTEXT-DAG: Decl[EnumElement]/CurrNominal/Flair[ExprSpecific]/TypeRelation[Identical]: .Qux2[#QuxEnum#]{{; name=.+$}}
// QUX_ENUM_TYPE_CONTEXT-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: .Qux1[#QuxEnum#]{{; name=.+$}}
// QUX_ENUM_TYPE_CONTEXT-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: .Qux2[#QuxEnum#]{{; name=.+$}}
// QUX_ENUM_TYPE_CONTEXT: End completions

// QUX_ENUM_NO_DOT: Begin completions, 7 items
Expand Down