@@ -14,7 +14,7 @@ import Flags._
1414import TypeErasure .{erasure , hasStableErasure }
1515import Mode .ImplicitsEnabled
1616import NameOps ._
17- import NameKinds .{ LazyImplicitName , FlatName }
17+ import NameKinds .LazyImplicitName
1818import Symbols ._
1919import Denotations ._
2020import Types ._
@@ -37,8 +37,6 @@ import config.Printers.{implicits, implicitsDetailed}
3737import collection .mutable
3838import reporting .trace
3939import annotation .tailrec
40- import scala .util .control .NonFatal
41- import java .util .{Timer , TimerTask }
4240
4341import scala .annotation .internal .sharable
4442import scala .annotation .threadUnsafe
@@ -69,12 +67,6 @@ object Implicits {
6967 final val Extension = 4
7068 }
7169
72- /** Timeout to test a single implicit value as a suggestion, in ms */
73- val testOneImplicitTimeOut = 500
74-
75- /** Global timeout to stop looking for further implicit suggestions, in ms */
76- val suggestImplicitTimeOut = 10000
77-
7870 /** If `expected` is a selection prototype, does `tp` have an extension
7971 * method with the selecting name? False otherwise.
8072 */
@@ -695,235 +687,6 @@ trait Implicits { self: Typer =>
695687 }
696688 }
697689
698- /** A list of TermRefs referring to the roots where suggestions for
699- * imports of givens or extension methods that might fix a type error
700- * are searched.
701- *
702- * These roots are the smallest set of objects and packages that includes
703- *
704- * - any object that is a defined in an enclosing scope,
705- * - any object that is a member of an enclosing class,
706- * - any enclosing package (including the root package),
707- * - any object that is a member of a searched object or package,
708- * - any object or package from which something is imported in an enclosing scope,
709- * - any package that is nested in a searched package, provided
710- * the package was accessed in some way previously.
711- *
712- * Excluded from the root set are:
713- *
714- * - Objects that contain `$`s in their name. These have to
715- * be omitted since they might be inner Java class files which
716- * cannot be read by the ClassfileParser without crashing.
717- * - Any members of static parts of Java classes.
718- * - Any members of the empty package. These should be
719- * skipped since the empty package often contains unrelated junk files
720- * that should not be used for suggestions.
721- * - Any members of the java or java.lang packages. These are
722- * skipped as an optimization, since they won't contain implicits anyway.
723- */
724- private def suggestionRoots (given Context ) =
725- val seen = mutable.Set [TermRef ]()
726-
727- def lookInside (root : Symbol )(given Context ): Boolean =
728- if root.is(Package ) then root.isTerm && root.isCompleted
729- else ! root.name.is(FlatName )
730- && ! root.name.lastPart.contains('$' )
731- && root.is(ModuleVal , butNot = JavaDefined )
732-
733- def nestedRoots (site : Type )(given Context ): List [Symbol ] =
734- val seenNames = mutable.Set [Name ]()
735- site.baseClasses.flatMap { bc =>
736- bc.info.decls.filter { dcl =>
737- lookInside(dcl)
738- && ! seenNames.contains(dcl.name)
739- && { seenNames += dcl.name; true }
740- }
741- }
742-
743- def rootsStrictlyIn (ref : Type )(given Context ): List [TermRef ] =
744- val site = ref.widen
745- val refSym = site.typeSymbol
746- val nested =
747- if refSym.is(Package ) then
748- if refSym == defn.EmptyPackageClass // Don't search the empty package
749- || refSym == defn.JavaPackageClass // As an optimization, don't search java...
750- || refSym == defn.JavaLangPackageClass // ... or java.lang.
751- then Nil
752- else refSym.info.decls.filter(lookInside)
753- else
754- if ! refSym.is(Touched ) then refSym.ensureCompleted() // JavaDefined is reliably known only after completion
755- if refSym.is(JavaDefined ) then Nil
756- else nestedRoots(site)
757- nested
758- .map(mbr => TermRef (ref, mbr.asTerm))
759- .flatMap(rootsIn)
760- .toList
761-
762- def rootsIn (ref : TermRef )(given Context ): List [TermRef ] =
763- if seen.contains(ref) then Nil
764- else
765- implicits.println(i " search for suggestions in ${ref.symbol.fullName}" )
766- seen += ref
767- ref :: rootsStrictlyIn(ref)
768-
769- def rootsOnPath (tp : Type )(given Context ): List [TermRef ] = tp match
770- case ref : TermRef => rootsIn(ref) ::: rootsOnPath(ref.prefix)
771- case _ => Nil
772-
773- def recur (given ctx : Context ): List [TermRef ] =
774- if ctx.owner.exists then
775- val defined =
776- if ctx.owner.isClass then
777- if ctx.owner eq ctx.outer.owner then Nil
778- else rootsStrictlyIn(ctx.owner.thisType)
779- else
780- if ctx.scope eq ctx.outer.scope then Nil
781- else ctx.scope
782- .filter(lookInside(_))
783- .flatMap(sym => rootsIn(sym.termRef))
784- val imported =
785- if ctx.importInfo eq ctx.outer.importInfo then Nil
786- else ctx.importInfo.sym.info match
787- case ImportType (expr) => rootsOnPath(expr.tpe)
788- case _ => Nil
789- defined ++ imported ++ recur(given ctx .outer)
790- else Nil
791-
792- recur
793- end suggestionRoots
794-
795- /** Given an expected type `pt`, return two lists of TermRefs:
796- *
797- * 1. The _fully matching_ given instances that can be completed
798- * to a full synthesized given term that matches the expected type `pt`.
799- *
800- * 2. The _head matching_ given instances, that conform to the
801- * expected type `pt`, ignoring any dependent implicit arguments.
802- *
803- * If there are no fully matching given instances under (1), and `pt` is
804- * a view prototype of a selection of the form `T ?=>? { name: ... }`,
805- * return instead a list of all possible references to extension methods named
806- * `name` that are applicable to `T`.
807- */
808- private def importSuggestions (pt : Type )(given ctx : Context ): (List [TermRef ], List [TermRef ]) =
809- val timer = new Timer ()
810- val deadLine = System .currentTimeMillis() + suggestImplicitTimeOut
811-
812- /** Test whether the head of a given instance matches the expected type `pt`,
813- * ignoring any dependent implicit arguments.
814- */
815- def shallowTest (ref : TermRef ): Boolean =
816- System .currentTimeMillis < deadLine
817- && (ref <:< pt)(given ctx .fresh.setExploreTyperState())
818-
819- /** Test whether a full given term can be synthesized that matches
820- * the expected type `pt`.
821- */
822- def deepTest (ref : TermRef ): Boolean =
823- System .currentTimeMillis < deadLine
824- && {
825- val task = new TimerTask with
826- def run () =
827- println(i " Cancelling test of $ref when making suggestions for error in ${ctx.source}" )
828- ctx.run.isCancelled = true
829- val span = ctx.owner.sourcePos.span
830- val (expectedType, argument, kind) = pt match
831- case ViewProto (argType, resType) =>
832- (resType,
833- untpd.Ident (ref.name).withSpan(span).withType(argType),
834- if hasExtMethod(ref, resType) then Candidate .Extension
835- else Candidate .Conversion )
836- case _ =>
837- (pt, EmptyTree , Candidate .Value )
838- val candidate = Candidate (ref, kind, 0 )
839- try
840- timer.schedule(task, testOneImplicitTimeOut)
841- typedImplicit(candidate, expectedType, argument, span)(
842- given ctx .fresh.setExploreTyperState()).isSuccess
843- finally
844- task.cancel()
845- ctx.run.isCancelled = false
846- }
847- end deepTest
848-
849- /** Optionally, an extension method reference `site.name` that is
850- * applicable to `argType`.
851- */
852- def extensionMethod (site : TermRef , name : TermName , argType : Type ): Option [TermRef ] =
853- site.member(name)
854- .alternatives
855- .map(mbr => TermRef (site, mbr.symbol))
856- .filter(ref =>
857- ref.symbol.is(Extension )
858- && isApplicableMethodRef(ref, argType :: Nil , WildcardType ))
859- .headOption
860-
861- try
862- val roots = suggestionRoots
863- .filterNot(root => defn.RootImportTypes .exists(_.symbol == root.symbol))
864- // don't suggest things that are imported by default
865-
866- def extensionImports = pt match
867- case ViewProto (argType, SelectionProto (name : TermName , _, _, _)) =>
868- roots.flatMap(extensionMethod(_, name, argType))
869- case _ =>
870- Nil
871-
872- roots
873- .flatMap(_.implicitMembers.filter(shallowTest))
874- // filter whether the head of the implicit can match
875- .partition(deepTest)
876- // partition into full matches and head matches
877- match
878- case (Nil , partials) => (extensionImports, partials)
879- case givenImports => givenImports
880- catch
881- case ex : Throwable =>
882- if ctx.settings.Ydebug .value then
883- println(" caught exception when searching for suggestions" )
884- ex.printStackTrace()
885- (Nil , Nil )
886- finally timer.cancel()
887- end importSuggestions
888-
889- /** An addendum to an error message where the error might be fixed
890- * by some implicit value of type `pt` that is however not found.
891- * The addendum suggests given imports that might fix the problem.
892- * If there's nothing to suggest, an empty string is returned.
893- */
894- override def importSuggestionAddendum (pt : Type )(given ctx : Context ): String =
895- val (fullMatches, headMatches) =
896- importSuggestions(pt)(given ctx .fresh.setExploreTyperState())
897- implicits.println(i " suggestions for $pt in ${ctx.owner} = ( $fullMatches%, %, $headMatches%, %) " )
898- val (suggestedRefs, help) =
899- if fullMatches.nonEmpty then (fullMatches, " fix" )
900- else (headMatches, " make progress towards fixing" )
901- def importString (ref : TermRef ): String =
902- s " import ${ctx.printer.toTextRef(ref).show}"
903- val suggestions = suggestedRefs
904- .zip(suggestedRefs.map(importString))
905- .filter((ref, str) => str.contains('.' ))
906- .sortWith { (x, y) =>
907- // sort by specificity first, alphabetically second
908- val ((ref1, str1), (ref2, str2)) = (x, y)
909- val diff = compare(ref1, ref2)
910- diff > 0 || diff == 0 && str1 < str2
911- }
912- .map((ref, str) => str)
913- .distinct // TermRefs might be different but generate the same strings
914- if suggestions.isEmpty then " "
915- else
916- val fix =
917- if suggestions.tail.isEmpty then " The following import"
918- else " One of the following imports"
919- i """
920- |
921- | $fix might $help the problem:
922- |
923- | $suggestions%\n%
924- """
925- end importSuggestionAddendum
926-
927690 /** Handlers to synthesize implicits for special types */
928691 type SpecialHandler = (Type , Span ) => Context => Tree
929692 type SpecialHandlers = List [(ClassSymbol , SpecialHandler )]
0 commit comments