Skip to content

WIP: [CodeCompletion] Only filter based on fixes when constraint system contains a type var for the code completion token #42024

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

Closed
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
25 changes: 21 additions & 4 deletions include/swift/Sema/ConstraintSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -3168,10 +3168,25 @@ class ConstraintSystem {
if (solutions.size() < 2)
return;

if (auto best = findBestSolution(solutions, minimize)) {
if (*best != 0)
solutions[0] = std::move(solutions[*best]);
solutions.erase(solutions.begin() + 1, solutions.end());
if (hasCodeCompletionTypeVar()) {
// For code completion remove solutions that have more fixes than the
// minimum but don't filter based on the lower-priority scores because we
// want to show all options even if they need to go through more
// conversions.
Score minScore = std::min_element(solutions.begin(), solutions.end(),
[](const Solution &a, const Solution &b) {
return a.getFixedScore() < b.getFixedScore();
})->getFixedScore();

llvm::erase_if(solutions, [&](const Solution &S) {
return S.getFixedScore().Data[SK_Fix] > minScore.Data[SK_Fix];
});
} else {
if (auto best = findBestSolution(solutions, minimize)) {
if (*best != 0)
solutions[0] = std::move(solutions[*best]);
solutions.erase(solutions.begin() + 1, solutions.end());
}
}
}

Expand Down Expand Up @@ -3234,6 +3249,8 @@ class ConstraintSystem {
bool containsCodeCompletionLoc(ASTNode node) const;
bool containsCodeCompletionLoc(const ArgumentList *args) const;

bool hasCodeCompletionTypeVar() const;

/// Marks the argument \p Arg as being ignored because it occurs after the
/// code completion token. This assumes that the argument is not type checked
/// (by assigning it a fresh type variable) and prevents fixes from being
Expand Down
15 changes: 13 additions & 2 deletions lib/Sema/CSRanking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,21 @@ bool ConstraintSystem::worseThanBestSolution() const {
if (getASTContext().TypeCheckerOpts.DisableConstraintSolverPerformanceHacks)
return false;

if (!solverState || !solverState->BestScore ||
CurrentScore <= *solverState->BestScore)
if (!solverState || !solverState->BestScore)
return false;

if (hasCodeCompletionTypeVar()) {
// For code completion, we only filter based on SK_Fix, not the entire
// score. See ConstraintSystem::filterSolutions.
if (CurrentScore.Data[SK_Fix] <= solverState->BestScore->Data[SK_Fix]) {
return false;
}
} else {
if (CurrentScore <= *solverState->BestScore) {
return false;
}
}

if (isDebugMode()) {
llvm::errs().indent(solverState->depth * 2)
<< "(solution is worse than the best solution)\n";
Expand Down
10 changes: 8 additions & 2 deletions lib/Sema/CSSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,14 @@ Solution ConstraintSystem::finalize() {

// Update the best score we've seen so far.
auto &ctx = getASTContext();
assert(ctx.TypeCheckerOpts.DisableConstraintSolverPerformanceHacks ||
!solverState->BestScore || CurrentScore <= *solverState->BestScore);
if (hasCodeCompletionTypeVar()) {
assert(ctx.TypeCheckerOpts.DisableConstraintSolverPerformanceHacks ||
!solverState->BestScore ||
CurrentScore.Data[SK_Fix] <= solverState->BestScore->Data[SK_Fix]);
} else {
assert(ctx.TypeCheckerOpts.DisableConstraintSolverPerformanceHacks ||
!solverState->BestScore || CurrentScore <= *solverState->BestScore);
}

if (!solverState->BestScore || CurrentScore <= *solverState->BestScore) {
solverState->BestScore = CurrentScore;
Expand Down
9 changes: 9 additions & 0 deletions lib/Sema/ConstraintSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,15 @@ bool ConstraintSystem::containsCodeCompletionLoc(
return Context.SourceMgr.rangeContainsCodeCompletionLoc(range);
}

bool ConstraintSystem::hasCodeCompletionTypeVar() const {
for (auto ty : TypeVariables) {
if (ty->getImpl().isCodeCompletionToken()) {
return true;
}
}
return false;
}

ConstraintLocator *ConstraintSystem::getConstraintLocator(
ASTNode anchor, ArrayRef<ConstraintLocator::PathElement> path) {
auto summaryFlags = ConstraintLocator::getSummaryFlagsForPath(path);
Expand Down
2 changes: 1 addition & 1 deletion test/IDE/complete_ambiguous.swift
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ func testBestSolutionGeneric() {
func genAndInt(_ x: Int) -> Int { return 1 }
func genAndInt<T>(_ x: T) -> Test1 { return Test1() }

genAndInt(2).#^BEST_SOLUTION_FILTER_GEN?xfail=rdar73282163^#
genAndInt(2).#^BEST_SOLUTION_FILTER_GEN^#
}

// BEST_SOLUTION_FILTER_GEN: Begin completions
Expand Down
20 changes: 10 additions & 10 deletions test/IDE/complete_assignment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,10 @@ func f2() {

// ASSIGN_2-DAG: Begin completions
// ASSIGN_2-DAG: Decl[LocalVar]/Local/TypeRelation[Identical]: I3[#Int?#]; name=I3
// ASSIGN_2-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Convertible]: I1[#Int#]; name=I1
// ASSIGN_2-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Convertible]: I2[#Int#]; name=I2
// ASSIGN_2-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Identical]: I1[#Int#]; name=I1
// ASSIGN_2-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Identical]: I2[#Int#]; name=I2
// ASSIGN_2-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Identical]: IO1[#Int?#]; name=IO1
// ASSIGN_2-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Convertible]: IntGenerator()[#Int#]; name=IntGenerator()
// ASSIGN_2-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: IntGenerator()[#Int#]; name=IntGenerator()
// ASSIGN_2-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: IntOpGenerator()[#Int?#]; name=IntOpGenerator()
// ASSIGN_2-DAG: Decl[InstanceVar]/CurrNominal: S1[#String#]; name=S1

Expand All @@ -114,10 +114,10 @@ func f2() {

// ASSIGN_4-DAG: Begin completions
// ASSIGN_4-DAG: Decl[LocalVar]/Local/TypeRelation[Identical]: S4[#String?#]; name=S4
// ASSIGN_4-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Convertible]: S1[#String#]; name=S1
// ASSIGN_4-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Convertible]: S2[#String#]; name=S2
// ASSIGN_4-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Identical]: S1[#String#]; name=S1
// ASSIGN_4-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Identical]: S2[#String#]; name=S2
// ASSIGN_4-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Identical]: SO1[#String?#]; name=SO1
// ASSIGN_4-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Convertible]: StringGenerator()[#String#]; name=StringGenerator()
// ASSIGN_4-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: StringGenerator()[#String#]; name=StringGenerator()
// ASSIGN_4-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: StringOpGenerator()[#String?#]; name=StringOpGenerator()
// ASSIGN_4-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: VoidGen()[#Void#]; name=VoidGen()
// ASSIGN_4-DAG: Decl[InstanceVar]/CurrNominal: I1[#Int#]; name=I1
Expand Down Expand Up @@ -160,7 +160,7 @@ func f2() {
}

// ASSIGN_8: Begin completions
// ASSIGN_8-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Convertible]: IntGen()[#Int#]
// ASSIGN_8-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: IntGen()[#Int#]
// ASSIGN_8-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: IntOpGen()[#Int?#]
// ASSIGN_8-DAG: Decl[InstanceMethod]/CurrNominal: D1Gen()[#D1#]
// ASSIGN_8-DAG: Decl[InstanceMethod]/CurrNominal: D2Gen()[#D2#]
Expand Down Expand Up @@ -233,10 +233,10 @@ func f2() {
}

// ASSIGN_14-DAG: Begin completions
// ASSIGN_14-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Convertible]: I1[#Int#]; name=I1
// ASSIGN_14-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Convertible]: I2[#Int#]; name=I2
// ASSIGN_14-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Identical]: I1[#Int#]; name=I1
// ASSIGN_14-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Identical]: I2[#Int#]; name=I2
// ASSIGN_14-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Identical]: IO1[#Int?#]; name=IO1
// ASSIGN_14-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Convertible]: IntGenerator()[#Int#]; name=IntGenerator()
// ASSIGN_14-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: IntGenerator()[#Int#]; name=IntGenerator()
// ASSIGN_14-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: IntOpGenerator()[#Int?#]; name=IntOpGenerator()
// ASSIGN_14-DAG: Decl[InstanceVar]/CurrNominal: S1[#String#]; name=S1

Expand Down
10 changes: 5 additions & 5 deletions test/IDE/complete_call_arg.swift
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ class C4 {
}

// MEMBER1: Begin completions
// MEMBER1-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Convertible]: IntGen()[#Int#]; name=IntGen()
// MEMBER1-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: IntGen()[#Int#]; name=IntGen()
// MEMBER1-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: IntOpGen()[#Int?#]; name=IntOpGen()
// MEMBER1-DAG: Decl[InstanceMethod]/CurrNominal: StringGen()[#String#]; name=StringGen()
// MEMBER1-DAG: Decl[InstanceMethod]/CurrNominal: StringOpGen()[#String?#]; name=StringOpGen()
Expand All @@ -349,7 +349,7 @@ class C4 {
// MEMBER3: Begin completions
// MEMBER3-DAG: Decl[InstanceMethod]/CurrNominal: IntGen()[#Int#]; name=IntGen()
// MEMBER3-DAG: Decl[InstanceMethod]/CurrNominal: IntOpGen()[#Int?#]; name=IntOpGen()
// MEMBER3-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Convertible]: StringGen()[#String#]; name=StringGen()
// MEMBER3-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: StringGen()[#String#]; name=StringGen()
// MEMBER3-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: StringOpGen()[#String?#]; name=StringOpGen()
// MEMBER3-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: IntTaker({#(i1): Int#}, {#i2: Int#})[#Void#]; name=IntTaker(:i2:)
// MEMBER3-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: StringTaker({#(s1): String#}, {#s2: String#})[#Void#]; name=StringTaker(:s2:)
Expand All @@ -365,11 +365,11 @@ class C4 {
// MEMBER7: Begin completions
// MEMBER7-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem/TypeRelation[Invalid]: removeAll()[#Void#]; name=removeAll()
// MEMBER7-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem/TypeRelation[Invalid]: removeAll({#keepingCapacity: Bool#})[#Void#]; name=removeAll(keepingCapacity:)
// MEMBER7-DAG: Decl[InstanceVar]/CurrNominal/IsSystem/TypeRelation[Convertible]: count[#Int#]; name=count
// MEMBER7-DAG: Decl[InstanceVar]/CurrNominal/IsSystem/TypeRelation[Convertible]: capacity[#Int#]; name=capacity
// MEMBER7-DAG: Decl[InstanceVar]/CurrNominal/IsSystem/TypeRelation[Identical]: count[#Int#]; name=count
// MEMBER7-DAG: Decl[InstanceVar]/CurrNominal/IsSystem/TypeRelation[Identical]: capacity[#Int#]; name=capacity

// MEMBER8: Begin completions
// MEMBER8-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Convertible]: InternalIntGen()[#Int#]; name=InternalIntGen()
// MEMBER8-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: InternalIntGen()[#Int#]; name=InternalIntGen()
// MEMBER8-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: InternalIntOpGen()[#Int?#]; name=InternalIntOpGen()
// MEMBER8-DAG: Decl[InstanceMethod]/CurrNominal: InternalStringGen()[#String#]; name=InternalStringGen()
// MEMBER8-DAG: Decl[InstanceMethod]/CurrNominal: InternalStringOpGen()[#String?#]; name=InternalStringOpGen()
Expand Down
20 changes: 18 additions & 2 deletions test/IDE/complete_return.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=RETURN_TR2_STATICMETHOD | %FileCheck %s -check-prefix=RETURN_TR2
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=RETURN_TR3_STATICMETHOD | %FileCheck %s -check-prefix=RETURN_TR3
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=RETURN_TR1_CLOSURE | %FileCheck %s -check-prefix=RETURN_TR1
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=RETURN_TR2_CLOSURE | %FileCheck %s -check-prefix=RETURN_TR2
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=RETURN_TR3_CLOSURE | %FileCheck %s -check-prefix=RETURN_TR3
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=RETURN_TR2_CLOSURE | %FileCheck %s -check-prefix=RETURN_TR2_CLOSURE
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=RETURN_TR3_CLOSURE | %FileCheck %s -check-prefix=RETURN_TR3_CLOSURE

struct FooStruct {
var instanceVar : Int
Expand Down Expand Up @@ -153,7 +153,23 @@ func testClosures(_ g: Gen) {
_ = { () -> Int? in
return g.#^RETURN_TR2_CLOSURE^#
}
// RETURN_TR2_CLOSURE: Begin completions
// RETURN_TR2_CLOSURE-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: IntGen()[#Int#]{{; name=.+$}}
// RETURN_TR2_CLOSURE-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: IntOpGen()[#Int?#]{{; name=.+$}}
// RETURN_TR2_CLOSURE-DAG: Decl[InstanceMethod]/CurrNominal: StringGen()[#String#]{{; name=.+$}}
// RETURN_TR2_CLOSURE-DAG: Decl[InstanceMethod]/CurrNominal: StringOpGen()[#String?#]{{; name=.+$}}
// RETURN_TR2_CLOSURE-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: IntTaker({#(i1): Int#}, {#i2: Int#})[#Void#]{{; name=.+$}}
// RETURN_TR2_CLOSURE-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: StringTaker({#(s1): String#}, {#s2: String#})[#Void#]{{; name=.+$}}

_ = { () -> Int? in
return g.IG.#^RETURN_TR3_CLOSURE^#
}
// RETURN_TR3_CLOSURE: Begin completions
// RETURN_TR3_CLOSURE-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: InternalIntGen()[#Int#]{{; name=.+$}}
// RETURN_TR3_CLOSURE-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: InternalIntOpGen()[#Int?#]{{; name=.+$}}
// RETURN_TR3_CLOSURE-DAG: Decl[InstanceMethod]/CurrNominal: InternalStringGen()[#String#]{{; name=.+$}}
// RETURN_TR3_CLOSURE-DAG: Decl[InstanceMethod]/CurrNominal: InternalStringOpGen()[#String?#]{{; name=.+$}}
// RETURN_TR3_CLOSURE-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: InternalIntTaker({#(i1): Int#}, {#i2: Int#})[#Void#]{{; name=.+$}}
// RETURN_TR3_CLOSURE-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: InternalStringTaker({#(s1): String#}, {#s2: String#})[#Void#]{{; name=.+$}}

}
Loading