[CS] Avoid increasing score for unbound outer type vars for completion

When doing code completion it's entirely expected we'll end up with 
ambiguities in the body of a closure if we're completing e.g
`someOverloadedFn(#^CC^#)`. As such we don't want to penalize the
solution for unbound type variables outside of the body since that 
will prevent us from being able to eagerly prune e.g disfavored
overloads in the outer scope. This gives up to a 7% perf win in the
stress tester.
This commit is contained in:
Hamish Knight
2025-09-01 10:56:45 +01:00
parent 57ae9ded43
commit ebad04f133
2 changed files with 40 additions and 1 deletions

View File

@@ -981,7 +981,15 @@ StepResult ConjunctionStep::resume(bool prevFailed) {
++numHoles;
}
}
CS.increaseScore(SK_Hole, Conjunction->getLocator(), numHoles);
// Increase the score for each hole we bind. Avoid doing this for
// completion since it's entirely expected we'll end up with
// ambiguities in the body of a closure if we're completing e.g
// `someOverloadedFn(#^CC^#)`. As such we don't want to penalize the
// solution for unbound type variables outside of the body since
// that will prevent us from being able to eagerly prune e.g
// disfavored overloads in the outer scope.
if (!CS.isForCodeCompletion())
CS.increaseScore(SK_Hole, Conjunction->getLocator(), numHoles);
}
if (CS.worseThanBestSolution())

View File

@@ -0,0 +1,31 @@
// RUN: %empty-directory(%t)
// RUN: %batch-code-completion -debug-constraints 2> %t/constraints.log
// RUN: %FileCheck %s -check-prefix CONSTRAINTS < %t/constraints.log
// RUN: %FileCheck %s -check-prefix CONSTRAINTS-NOT < %t/constraints.log
protocol P1 {}
protocol P2 {}
func foo<T: P1>(_ fn: () -> T) {}
@_disfavoredOverload
func foo<T: P2>(_ fn: () -> T) {}
func bar(_ x: Int) -> Int {}
func bar(_ x: String) -> String {}
// Make sure we eagerly prune the disfavored overload of 'foo', despite the
// ambiguity in the closure body.
foo {
let x = bar(#^COMPLETE^#)
// COMPLETE: Decl[FreeFunction]/CurrModule/Flair[ArgLabels]: ['(']{#(x): Int#}[')'][#Int#]; name=:
// COMPLETE: Decl[FreeFunction]/CurrModule/Flair[ArgLabels]: ['(']{#(x): String#}[')'][#String#]; name=:
return x
}
// CONSTRAINTS: attempting disjunction choice {{.*}}:12:6
// CONSTRAINTS: increasing 'disfavored overload' score
// CONSTRAINTS: solution is worse than the best solution
// CONSTRAINTS-NOT-NOT: increasing 'hole'