@@ -490,30 +490,55 @@ object Implicits {
490
490
* the package was accessed in some way previously.
491
491
*/
492
492
class suggestions (qualifies : TermRef => Boolean ) with
493
+ private type RootRef = TermRef | ThisType
494
+
495
+ private def symbolOf (ref : RootRef )(given Context ) = ref match
496
+ case ref : TermRef => ref.symbol
497
+ case ref : ThisType => ref.cls
498
+
493
499
private val seen = mutable.Set [TermRef ]()
494
500
495
501
private def lookInside (root : Symbol )(given ctx : Context ): Boolean =
496
- if root.is(PackageVal ) then root.isCompleted
502
+ if root.is(Package ) then root.isTerm && root.isCompleted
497
503
else ! root.name.is(FlatName )
498
504
&& ! root.name.lastPart.contains('$' )
499
505
&& root.is(ModuleVal , butNot = JavaDefined )
500
506
507
+ def nestedRoots (ref : RootRef )(given Context ): List [Symbol ] =
508
+ val seenNames = mutable.Set [Name ]()
509
+ ref.widen.baseClasses.flatMap { bc =>
510
+ bc.info.decls.filter { dcl =>
511
+ lookInside(dcl)
512
+ && ! seenNames.contains(dcl.name)
513
+ && { seenNames += dcl.name; true }
514
+ }
515
+ }
516
+
517
+ private def rootsStrictlyIn (ref : RootRef )(given ctx : Context ): List [TermRef ] =
518
+ val refSym = symbolOf(ref)
519
+ val nested =
520
+ if refSym == defn.EmptyPackageClass // Don't search the empty package, either as enclosing package ...
521
+ || refSym == defn.EmptyPackageVal // ... or as a member of _root_.
522
+ || refSym == defn.JavaPackageVal // As an optimization, don't search java...
523
+ || refSym == defn.JavaLangPackageVal // ... or java.lang.
524
+ then Nil
525
+ else if refSym.is(Package ) || refSym.isPackageObject then
526
+ refSym.info.decls.filter(lookInside)
527
+ else
528
+ if ! refSym.is(Touched ) then refSym.ensureCompleted() // JavaDefined is reliably known only after completion
529
+ if refSym.is(JavaDefined ) then Nil
530
+ else nestedRoots(ref)
531
+ nested
532
+ .map(mbr => TermRef (ref, mbr.asTerm))
533
+ .flatMap(rootsIn)
534
+ .toList
535
+
501
536
private def rootsIn (ref : TermRef )(given ctx : Context ): List [TermRef ] =
502
537
if seen.contains(ref) then Nil
503
538
else
504
- implicitsDetailed .println(i " search for suggestions in ${ref.symbol.fullName}" )
539
+ implicits .println(i " search for suggestions in ${ref.symbol.fullName}" )
505
540
seen += ref
506
- val nested =
507
- if ref.symbol.is(Package ) then
508
- ref.info.decls.filter(lookInside)
509
- else
510
- ref.symbol.ensureCompleted() // JavaDefined in reliably known only after completion
511
- if ref.symbol.is(JavaDefined ) then Nil
512
- else ref.fields.map(_.symbol).filter(lookInside)
513
- ref :: nested
514
- .map(mbr => TermRef (ref, mbr.asTerm))
515
- .flatMap(rootsIn)
516
- .toList
541
+ ref :: rootsStrictlyIn(ref)
517
542
518
543
private def rootsOnPath (tp : Type )(given ctx : Context ): List [TermRef ] = tp match
519
544
case ref : TermRef => rootsIn(ref) ::: rootsOnPath(ref.prefix)
@@ -522,8 +547,15 @@ object Implicits {
522
547
private def roots (given ctx : Context ): List [TermRef ] =
523
548
if ctx.owner.exists then
524
549
val defined =
525
- if ctx.scope eq ctx.outer.scope then Nil
526
- else ctx.scope
550
+ if ctx.owner.isClass then
551
+ if ctx.owner eq ctx.outer.owner then Nil
552
+ else ctx.owner.thisType match
553
+ case ref : TermRef => rootsStrictlyIn(ref)
554
+ case ref : ThisType => rootsStrictlyIn(ref)
555
+ case _ => Nil
556
+ else if ctx.scope eq ctx.outer.scope then Nil
557
+ else
558
+ ctx.scope
527
559
.filter(lookInside(_))
528
560
.flatMap(sym => rootsIn(sym.termRef))
529
561
val imported =
@@ -543,7 +575,7 @@ object Implicits {
543
575
&& {
544
576
val task = new TimerTask {
545
577
def run () =
546
- implicitsDetailed .println(i " Cancelling test of $ref when making suggestions for error in ${ctx.source}" )
578
+ implicits .println(i " Cancelling test of $ref when making suggestions for error in ${ctx.source}" )
547
579
ctx.run.isCancelled = true
548
580
}
549
581
timer.schedule(task, testOneImplicitTimeOut)
@@ -558,6 +590,12 @@ object Implicits {
558
590
.filterNot(root => defn.RootImportTypes .exists(_.symbol == root.symbol))
559
591
// don't suggest things that are imported by default
560
592
.flatMap(_.implicitMembers.filter(test))
593
+ catch
594
+ case ex : Throwable =>
595
+ if ctx.settings.Ydebug .value then
596
+ println(" caught exceptioon when searching for suggestions" )
597
+ ex.printStackTrace()
598
+ Nil
561
599
finally timer.cancel()
562
600
end search
563
601
end suggestions
@@ -789,8 +827,7 @@ trait Implicits { self: Typer =>
789
827
*/
790
828
override def implicitSuggestionsFor (pt : Type )(given ctx : Context ): String =
791
829
val suggestedRefs =
792
- try Implicits .suggestions(_ <:< pt).search(given ctx .fresh.setExploreTyperState())
793
- catch case NonFatal (ex) => Nil
830
+ Implicits .suggestions(_ <:< pt).search(given ctx .fresh.setExploreTyperState())
794
831
def importString (ref : TermRef ): String =
795
832
s " import ${ctx.printer.toTextRef(ref).show}"
796
833
val suggestions = suggestedRefs.map(importString)
0 commit comments