@@ -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,45 @@ 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
+ for ref <- refs do
273
+ var i = 0
274
+ var diff = 0
275
+ while i < filled && diff == 0 do
276
+ diff = compare(ref, top(i))(using ctx.retractMode(Mode .ImplicitsEnabled ))
277
+ if diff > 0 then
278
+ rest += top(i)
279
+ top(i) = ref
280
+ i += 1
281
+ end while
282
+ if diff == 0 && filled < n then
283
+ top(filled) = ref
284
+ filled += 1
285
+ else if diff <= 0 then
286
+ rest += ref
287
+ end for
288
+ val remaining =
289
+ if filled < n && rest.nonEmpty then rest.toList.best(n - filled)
290
+ else Nil
291
+ top.take(filled).toList ++ remaining
292
+ end best
293
+
252
294
/** An addendum to an error message where the error might be fixed
253
295
* by some implicit value of type `pt` that is however not found.
254
296
* The addendum suggests given imports that might fix the problem.
@@ -265,15 +307,11 @@ trait ImportSuggestions:
265
307
s " import ${ctx.printer.toTextRef(ref).show}"
266
308
val suggestions = suggestedRefs
267
309
.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
310
+ .filter((ref, str) => str.contains('.' )) // must be a real import with `.`
311
+ .sortBy(_._2) // sort first alphabetically for stability
312
+ .distinctRefs // TermRefs might be different but generate the same strings
313
+ .best(MaxSuggestions ) // take MaxSuggestions best references according to specificity
314
+ .map(importString)
277
315
if suggestions.isEmpty then " "
278
316
else
279
317
val fix =
0 commit comments