@@ -314,56 +314,46 @@ object messages {
314
314
315
315
val msg : String = {
316
316
import core .Flags ._
317
- val maxDist = 3
318
- val decls = site.decls.toList
319
- .filter(_.isType == name.isTypeName)
320
- .flatMap { sym =>
321
- if (sym.flagsUNSAFE.isOneOf(Synthetic | PrivateLocal ) || sym.isConstructor) Nil
322
- else List ((sym.name.show, sym))
323
- }
317
+ val maxDist = 3 // maximal number of differences to be considered for a hint
318
+ val missing = name.show
319
+
320
+ // The names of all non-synthetic, non-private members of `site`
321
+ // that are of the same type/term kind as the missing member.
322
+ def candidates : Set [String ] =
323
+ for
324
+ bc <- site.widen.baseClasses.toSet
325
+ sym <- bc.info.decls.filter(sym =>
326
+ sym.isType == name.isTypeName
327
+ && ! sym.isConstructor
328
+ && ! sym.flagsUNSAFE.isOneOf(Synthetic | Private ))
329
+ yield sym.name.show
324
330
325
331
// Calculate Levenshtein distance
326
- def distance (n1 : Iterable [? ], n2 : Iterable [? ]) =
327
- n1.foldLeft(List .range(0 , n2.size)) { (prev, x) =>
328
- (prev zip prev.tail zip n2).scanLeft(prev.head + 1 ) {
329
- case (h, ((d, v), y)) => math.min(
330
- math.min(h + 1 , v + 1 ),
331
- if (x == y) d else d + 1
332
- )
333
- }
334
- }.last
335
-
336
- // Count number of wrong characters
337
- def incorrectChars (x : (String , Int , Symbol )): (String , Symbol , Int ) = {
338
- val (currName, _, sym) = x
339
- val matching = name.show.zip(currName).foldLeft(0 ) {
340
- case (acc, (x,y)) => if (x != y) acc + 1 else acc
341
- }
342
- (currName, sym, matching)
343
- }
344
-
345
- // Get closest match in `site`
346
- def closest : List [String ] =
347
- decls
348
- .map { (n, sym) => (n, distance(n, name.show), sym) }
349
- .collect {
350
- case (n, dist, sym)
351
- if dist <= maxDist && dist < (name.toString.length min n.length) =>
352
- (n, dist, sym)
353
- }
354
- .groupBy(_._2).toList
355
- .sortBy(_._1)
356
- .headOption.map(_._2).getOrElse(Nil )
357
- .map(incorrectChars).toList
358
- .sortBy(_._3)
359
- .map(_._1)
360
- // [Martin] Note: I have no idea what this does. This shows the
361
- // pitfalls of not naming things, functional or not.
332
+ def distance (s1 : String , s2 : String ): Int =
333
+ val dist = Array .ofDim[Int ](s2.length + 1 , s1.length + 1 )
334
+ for
335
+ j <- 0 to s2.length
336
+ i <- 0 to s1.length
337
+ do
338
+ dist(j)(i) =
339
+ if j == 0 then i
340
+ else if i == 0 then j
341
+ else if s2(j - 1 ) == s1(i - 1 ) then dist(j - 1 )(i - 1 )
342
+ else (dist(j - 1 )(i) min dist(j)(i - 1 ) min dist(j - 1 )(i - 1 )) + 1
343
+ dist(s2.length)(s1.length)
344
+
345
+ // A list of possible candidate strings with their Levenstein distances
346
+ // to the name of the missing member
347
+ def closest : List [(Int , String )] = candidates
348
+ .toList
349
+ .map(n => (distance(n.show, missing), n))
350
+ .filter((d, n) => d <= maxDist && d < missing.length && d < n.length)
351
+ .sorted // sort by distance first, alphabetically second
362
352
363
353
val finalAddendum =
364
354
if addendum.nonEmpty then addendum
365
355
else closest match {
366
- case n :: _ =>
356
+ case (d, n) :: _ =>
367
357
val siteName = site match
368
358
case site : NamedType => site.name.show
369
359
case site => i " $site"
0 commit comments