@@ -19,6 +19,9 @@ import collection.mutable
19
19
trait ImportSuggestions :
20
20
this : Typer =>
21
21
22
+ /** The maximal number of suggested imports to make */
23
+ inline val MaxSuggestions = 10
24
+
22
25
import tpd ._
23
26
24
27
/** Timeout to test a single implicit value as a suggestion, in ms */
@@ -249,6 +252,46 @@ trait ImportSuggestions:
249
252
finally timer.cancel()
250
253
end importSuggestions
251
254
255
+ /** The `ref` parts of this list of pairs, discarding subsequent elements that
256
+ * have the same String part. Elements are sorted by their String parts.
257
+ */
258
+ def (refs : List [(TermRef , String )]).distinctRefs(using Context ): List [TermRef ] = refs match
259
+ case (ref, str) :: refs1 =>
260
+ ref :: refs1.dropWhile(_._2 == str).distinctRefs
261
+ case Nil =>
262
+ Nil
263
+
264
+ /** The best `n` references in `refs`, according to `compare`
265
+ * `compare` is a partial order. If there's a tie, we take elements
266
+ * in the order thy appear in the list.
267
+ */
268
+ def (refs : List [TermRef ]).best(n : Int )(using Context ): List [TermRef ] =
269
+ val top = new Array [TermRef ](n)
270
+ var filled = 0
271
+ val rest = new mutable.ListBuffer [TermRef ]
272
+ val noImplicitsCtx = ctx.retractMode(Mode .ImplicitsEnabled )
273
+ for ref <- refs do
274
+ var i = 0
275
+ var diff = 0
276
+ while i < filled && diff == 0 do
277
+ diff = compare(ref, top(i))(using noImplicitsCtx)
278
+ if diff > 0 then
279
+ rest += top(i)
280
+ top(i) = ref
281
+ i += 1
282
+ end while
283
+ if diff == 0 && filled < n then
284
+ top(filled) = ref
285
+ filled += 1
286
+ else if diff <= 0 then
287
+ rest += ref
288
+ end for
289
+ val remaining =
290
+ if filled < n && rest.nonEmpty then rest.toList.best(n - filled)
291
+ else Nil
292
+ top.take(filled).toList ++ remaining
293
+ end best
294
+
252
295
/** An addendum to an error message where the error might be fixed
253
296
* by some implicit value of type `pt` that is however not found.
254
297
* The addendum suggests given imports that might fix the problem.
@@ -265,15 +308,11 @@ trait ImportSuggestions:
265
308
s " import ${ctx.printer.toTextRef(ref).show}"
266
309
val suggestions = suggestedRefs
267
310
.zip(suggestedRefs.map(importString))
268
- .filter((ref, str) => str.contains('.' ))
269
- .sortWith { (x, y) =>
270
- // sort by specificity first, alphabetically second
271
- val ((ref1, str1), (ref2, str2)) = (x, y)
272
- val diff = compare(ref1, ref2)
273
- diff > 0 || diff == 0 && str1 < str2
274
- }
275
- .map((ref, str) => str)
276
- .distinct // TermRefs might be different but generate the same strings
311
+ .filter((ref, str) => str.contains('.' )) // must be a real import with `.`
312
+ .sortBy(_._2) // sort first alphabetically for stability
313
+ .distinctRefs // TermRefs might be different but generate the same strings
314
+ .best(MaxSuggestions ) // take MaxSuggestions best references according to specificity
315
+ .map(importString)
277
316
if suggestions.isEmpty then " "
278
317
else
279
318
val fix =
0 commit comments