@@ -14,7 +14,7 @@ import Flags._
14
14
import TypeErasure .{erasure , hasStableErasure }
15
15
import Mode .ImplicitsEnabled
16
16
import NameOps ._
17
- import NameKinds .{ LazyImplicitName , FlatName }
17
+ import NameKinds .LazyImplicitName
18
18
import Symbols ._
19
19
import Denotations ._
20
20
import Types ._
@@ -37,8 +37,6 @@ import config.Printers.{implicits, implicitsDetailed}
37
37
import collection .mutable
38
38
import reporting .trace
39
39
import annotation .tailrec
40
- import scala .util .control .NonFatal
41
- import java .util .{Timer , TimerTask }
42
40
43
41
import scala .annotation .internal .sharable
44
42
import scala .annotation .threadUnsafe
@@ -69,12 +67,6 @@ object Implicits {
69
67
final val Extension = 4
70
68
}
71
69
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
-
78
70
/** If `expected` is a selection prototype, does `tp` have an extension
79
71
* method with the selecting name? False otherwise.
80
72
*/
@@ -695,235 +687,6 @@ trait Implicits { self: Typer =>
695
687
}
696
688
}
697
689
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
-
927
690
/** Handlers to synthesize implicits for special types */
928
691
type SpecialHandler = (Type , Span ) => Context => Tree
929
692
type SpecialHandlers = List [(ClassSymbol , SpecialHandler )]
0 commit comments