Skip to content

Commit 2b6b3fd

Browse files
authored
Merge pull request #68079 from ahoppen/ahoppen/return-solver-based
[CodeCompletion] Migrate completions after `return` and `yield` to solver-based
2 parents 0dd3157 + 4702f82 commit 2b6b3fd

File tree

6 files changed

+66
-34
lines changed

6 files changed

+66
-34
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,25 @@ static void addObserverKeywords(CodeCompletionResultSink &Sink) {
890890
addKeyword(Sink, "didSet", CodeCompletionKeywordKind::None);
891891
}
892892

893+
static void addKeywordsAfterReturn(CodeCompletionResultSink &Sink, DeclContext *DC) {
894+
// `return nil` is not actually represented as a `ReturnExpr` in the AST but
895+
// gets translated to a `FailStmt`. We thus can't produce the 'nil' completion
896+
// using the solver-based implementation. Add the result manually.
897+
if (auto ctor = dyn_cast_or_null<ConstructorDecl>(DC->getAsDecl())) {
898+
if (ctor->isFailable()) {
899+
CodeCompletionResultBuilder Builder(Sink, CodeCompletionResultKind::Literal,
900+
SemanticContextKind::None);
901+
Builder.setLiteralKind(CodeCompletionLiteralKind::NilLiteral);
902+
Builder.addKeyword("nil");
903+
Builder.addTypeAnnotation(ctor->getResultInterfaceType(), {});
904+
Builder.setResultTypes(ctor->getResultInterfaceType());
905+
ExpectedTypeContext TypeContext;
906+
TypeContext.setPossibleTypes({ctor->getResultInterfaceType()});
907+
Builder.setTypeContext(TypeContext, DC);
908+
}
909+
}
910+
}
911+
893912
void swift::ide::addExprKeywords(CodeCompletionResultSink &Sink,
894913
DeclContext *DC) {
895914
// Expression is invalid at top-level of non-script files.
@@ -1026,6 +1045,8 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
10261045

10271046
LLVM_FALLTHROUGH;
10281047
case CompletionKind::ReturnStmtExpr:
1048+
addKeywordsAfterReturn(Sink, CurDeclContext);
1049+
LLVM_FALLTHROUGH;
10291050
case CompletionKind::YieldStmtExpr:
10301051
case CompletionKind::ForEachSequence:
10311052
addSuperKeyword(Sink, CurDeclContext);
@@ -1533,7 +1554,9 @@ bool CodeCompletionCallbacksImpl::trySolverCompletion(bool MaybeFuncBody) {
15331554
case CompletionKind::CaseStmtBeginning:
15341555
case CompletionKind::ForEachSequence:
15351556
case CompletionKind::PostfixExprBeginning:
1536-
case CompletionKind::StmtOrExpr: {
1557+
case CompletionKind::StmtOrExpr:
1558+
case CompletionKind::ReturnStmtExpr:
1559+
case CompletionKind::YieldStmtExpr: {
15371560
assert(CurDeclContext);
15381561

15391562
bool AddUnresolvedMemberCompletions =
@@ -1705,6 +1728,8 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
17051728
case CompletionKind::CaseStmtBeginning:
17061729
case CompletionKind::PostfixExprParen:
17071730
case CompletionKind::PostfixExpr:
1731+
case CompletionKind::ReturnStmtExpr:
1732+
case CompletionKind::YieldStmtExpr:
17081733
llvm_unreachable("should be already handled");
17091734
return;
17101735

@@ -1953,29 +1978,6 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
19531978
break;
19541979
}
19551980

1956-
case CompletionKind::ReturnStmtExpr : {
1957-
SourceLoc Loc = P.Context.SourceMgr.getIDEInspectionTargetLoc();
1958-
SmallVector<Type, 2> possibleReturnTypes;
1959-
collectPossibleReturnTypesFromContext(CurDeclContext, possibleReturnTypes);
1960-
Lookup.setExpectedTypes(possibleReturnTypes,
1961-
/*isImplicitSingleExpressionReturn*/ false);
1962-
Lookup.getValueCompletionsInDeclContext(Loc);
1963-
break;
1964-
}
1965-
1966-
case CompletionKind::YieldStmtExpr: {
1967-
SourceLoc Loc = P.Context.SourceMgr.getIDEInspectionTargetLoc();
1968-
if (auto FD = dyn_cast<AccessorDecl>(CurDeclContext)) {
1969-
if (FD->isCoroutine()) {
1970-
// TODO: handle multi-value yields.
1971-
Lookup.setExpectedTypes(FD->getStorage()->getValueInterfaceType(),
1972-
/*isImplicitSingleExpressionReturn*/ false);
1973-
}
1974-
}
1975-
Lookup.getValueCompletionsInDeclContext(Loc);
1976-
break;
1977-
}
1978-
19791981
case CompletionKind::AfterPoundDirective: {
19801982
addPoundDirectives(CompletionContext.getResultSink());
19811983

lib/IDE/PostfixCompletion.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,6 @@ void PostfixCompletionCallback::sawSolutionImpl(
178178
auto *Locator = CS.getConstraintLocator(SemanticExpr);
179179
Type ExpectedTy = getTypeForCompletion(S, CompletionExpr);
180180
Expr *ParentExpr = CS.getParentExpr(CompletionExpr);
181-
if (!ParentExpr && !ExpectedTy)
182-
ExpectedTy = CS.getContextualType(CompletionExpr, /*forConstraint=*/false);
183181

184182
auto *CalleeLocator = S.getCalleeLocator(Locator);
185183
ValueDecl *ReferencedDecl = nullptr;

lib/IDE/TypeCheckCompletionCallback.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ void TypeCheckCompletionCallback::fallbackTypeCheck(DeclContext *DC) {
4747

4848
Type swift::ide::getTypeForCompletion(const constraints::Solution &S,
4949
ASTNode Node) {
50+
if (auto ContextualType = S.getContextualType(Node)) {
51+
return ContextualType;
52+
}
53+
5054
if (!S.hasType(Node)) {
5155
assert(false && "Expression wasn't type checked?");
5256
return nullptr;
@@ -60,9 +64,6 @@ Type swift::ide::getTypeForCompletion(const constraints::Solution &S,
6064
Result = S.getResolvedType(Node);
6165
}
6266

63-
if (!Result || Result->is<UnresolvedType>())
64-
Result = S.getContextualType(Node);
65-
6667
if (Result && Result->is<UnresolvedType>()) {
6768
Result = Type();
6869
}

lib/Parse/ParseStmt.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -880,9 +880,10 @@ ParserResult<Stmt> Parser::parseStmtYield(SourceLoc tryLoc) {
880880
}
881881

882882
auto expr = parseExpr(diag::expected_expr_yield);
883-
if (expr.hasCodeCompletion())
884-
return makeParserCodeCompletionResult<Stmt>();
885-
if (expr.isParseErrorOrHasCompletion()) {
883+
if (expr.hasCodeCompletion() && expr.isNonNull()) {
884+
status |= expr;
885+
yields.push_back(expr.get());
886+
} else if (expr.isParseErrorOrHasCompletion()) {
886887
auto endLoc = (Tok.getLoc() == beginLoc ? beginLoc : PreviousLoc);
887888
yields.push_back(
888889
new (Context) ErrorExpr(SourceRange(beginLoc, endLoc)));

test/IDE/complete_constructor.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,8 @@ class DependentTypeInClosure<Data: DataType> {
312312
func testDependentTypeInClosure() {
313313
let _: DependentTypeInClosure = .#^DEPENDENT_IN_CLOSURE_3^#
314314
// DEPENDENT_IN_CLOSURE_3: Begin completions, 2 items
315-
// DEPENDENT_IN_CLOSURE_3-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Convertible]: init({#(arg): DataType#}, {#fn: (Data.Content) -> Void##(Data.Content) -> Void#})[#DependentTypeInClosure<DataType>#];
316-
// DEPENDENT_IN_CLOSURE_3-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Convertible]: init({#arg: DataType#}, {#fn: () -> Data.Content##() -> Data.Content#})[#DependentTypeInClosure<DataType>#];
315+
// DEPENDENT_IN_CLOSURE_3-DAG: Decl[Constructor]/CurrNominal: init({#(arg): DataType#}, {#fn: (DataType.Content) -> Void##(DataType.Content) -> Void#})[#DependentTypeInClosure<DataType>#];
316+
// DEPENDENT_IN_CLOSURE_3-DAG: Decl[Constructor]/CurrNominal: init({#arg: DataType#}, {#fn: () -> DataType.Content##() -> DataType.Content#})[#DependentTypeInClosure<DataType>#];
317317

318318
let _ = DependentTypeInClosure(#^DEPENDENT_IN_CLOSURE_1^#)
319319
// DEPENDENT_IN_CLOSURE_1-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#(arg): DataType#}, {#fn: (_) -> Void##(_) -> Void#}[')'][#DependentTypeInClosure<DataType>#];

test/IDE/complete_yield.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-ide-test -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t
3+
4+
struct YieldVariables {
5+
var stringValue: String
6+
7+
var property: String {
8+
_read {
9+
yield #^IN_READ^#
10+
// IN_READ-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Convertible]: stringValue[#String#]; name=stringValue
11+
}
12+
_modify {
13+
var localString = ""
14+
yield #^IN_MODIFY^#
15+
// IN_MODIFY-DAG: Decl[InstanceVar]/CurrNominal: stringValue[#String#]; name=stringValue
16+
// IN_MODIFY-DAG: Decl[LocalVar]/Local: localString[#String#]; name=localString
17+
}
18+
}
19+
20+
var otherProperty: String {
21+
_modify {
22+
var localString = ""
23+
yield &#^IN_MODIFY_WITH_REF^#
24+
// FIXME: We should probably be returning a convertible type relation here.
25+
// IN_MODIFY_WITH_REF: Decl[LocalVar]/Local: localString[#String#]; name=localString
26+
// IN_MODIFY_WITH_REF: Decl[InstanceVar]/CurrNominal: stringValue[#String#]; name=stringValue
27+
}
28+
}
29+
}
30+

0 commit comments

Comments
 (0)