@@ -35,6 +35,11 @@ trait Contexts { self: Analyzer =>
35
35
val completeList = JavaLangPackage :: ScalaPackage :: PredefModule :: Nil
36
36
}
37
37
38
+ def ambiguousImports (imp1 : ImportInfo , imp2 : ImportInfo ) =
39
+ LookupAmbiguous (s " it is imported twice in the same scope by \n $imp1\n and $imp2" )
40
+ def ambiguousDefnAndImport (owner : Symbol , imp : ImportInfo ) =
41
+ LookupAmbiguous (s " it is both defined in $owner and imported subsequently by \n $imp" )
42
+
38
43
private val startContext = {
39
44
NoContext .make(
40
45
Template (List (), emptyValDef, List ()) setSymbol global.NoSymbol setType global.NoType ,
@@ -480,8 +485,7 @@ trait Contexts { self: Analyzer =>
480
485
c
481
486
}
482
487
483
- /** Is `sym` accessible as a member of tree `site` with type
484
- * `pre` in current context?
488
+ /** Is `sym` accessible as a member of `pre` in current context?
485
489
*/
486
490
def isAccessible (sym : Symbol , pre : Type , superAccess : Boolean = false ): Boolean = {
487
491
lastAccessCheckDetails = " "
@@ -632,7 +636,7 @@ trait Contexts { self: Analyzer =>
632
636
case ImportSelector (from, _, to, _) :: sels1 =>
633
637
var impls = collect(sels1) filter (info => info.name != from)
634
638
if (to != nme.WILDCARD ) {
635
- for (sym <- imp.importedSymbol( to).alternatives)
639
+ for (sym <- importedAccessibleSymbol(imp, to).alternatives)
636
640
if (isQualifyingImplicit(to, sym, pre, imported = true ))
637
641
impls = new ImplicitInfo (to, pre, sym) :: impls
638
642
}
@@ -678,6 +682,241 @@ trait Contexts { self: Analyzer =>
678
682
implicitsCache
679
683
}
680
684
685
+ /** It's possible that seemingly conflicting identifiers are
686
+ * identifiably the same after type normalization. In such cases,
687
+ * allow compilation to proceed. A typical example is:
688
+ * package object foo { type InputStream = java.io.InputStream }
689
+ * import foo._, java.io._
690
+ */
691
+ def isAmbiguousImport (imp1 : ImportInfo , imp2 : ImportInfo , name : Name ): Boolean = {
692
+ // The imported symbols from each import.
693
+ def imp1Symbol = importedAccessibleSymbol(imp1, name)
694
+ def imp2Symbol = importedAccessibleSymbol(imp2, name)
695
+ // The types of the qualifiers from which the ambiguous imports come.
696
+ // If the ambiguous name is a value, these must be the same.
697
+ def t1 = imp1.qual.tpe
698
+ def t2 = imp2.qual.tpe
699
+ // The types of the ambiguous symbols, seen as members of their qualifiers.
700
+ // If the ambiguous name is a monomorphic type, we can relax this far.
701
+ def mt1 = t1 memberType imp1Symbol
702
+ def mt2 = t2 memberType imp2Symbol
703
+
704
+ def characterize = List (
705
+ s " types: $t1 =:= $t2 ${t1 =:= t2} members: ${mt1 =:= mt2}" ,
706
+ s " member type 1: $mt1" ,
707
+ s " member type 2: $mt2"
708
+ ).mkString(" \n " )
709
+
710
+ imp1Symbol.exists && imp2Symbol.exists && (
711
+ // The symbol names are checked rather than the symbols themselves because
712
+ // each time an overloaded member is looked up it receives a new symbol.
713
+ // So foo.member("x") != foo.member("x") if x is overloaded. This seems
714
+ // likely to be the cause of other bugs too...
715
+ if (t1 =:= t2 && imp1Symbol.name == imp2Symbol.name) {
716
+ log(s " Suppressing ambiguous import: $t1 =:= $t2 && $imp1Symbol == $imp2Symbol" )
717
+ false
718
+ }
719
+ // Monomorphism restriction on types is in part because type aliases could have the
720
+ // same target type but attach different variance to the parameters. Maybe it can be
721
+ // relaxed, but doesn't seem worth it at present.
722
+ else if (mt1 =:= mt2 && name.isTypeName && imp1Symbol.isMonomorphicType && imp2Symbol.isMonomorphicType) {
723
+ log(s " Suppressing ambiguous import: $mt1 =:= $mt2 && $imp1Symbol and $imp2Symbol are equivalent " )
724
+ false
725
+ }
726
+ else {
727
+ log(s " Import is genuinely ambiguous: \n " + characterize)
728
+ true
729
+ }
730
+ )
731
+ }
732
+
733
+ /** The symbol with name `name` imported via the import in `imp`,
734
+ * if any such symbol is accessible from this context.
735
+ */
736
+ def importedAccessibleSymbol (imp : ImportInfo , name : Name ) = {
737
+ imp importedSymbol name filter (s => isAccessible(s, imp.qual.tpe, superAccess = false ))
738
+ }
739
+
740
+ /** Is `sym` defined in package object of package `pkg`?
741
+ * Since sym may be defined in some parent of the package object,
742
+ * we cannot inspect its owner only; we have to go through the
743
+ * info of the package object. However to avoid cycles we'll check
744
+ * what other ways we can before pushing that way.
745
+ */
746
+ def isInPackageObject (sym : Symbol , pkg : Symbol ) = {
747
+ val pkgClass = if (pkg.isTerm) pkg.moduleClass else pkg
748
+ def matchesInfo = (
749
+ pkg.isInitialized && {
750
+ // need to be careful here to not get a cyclic reference during bootstrap
751
+ val module = pkg.info member nme.PACKAGEkw
752
+ module.isInitialized && (module.info.member(sym.name).alternatives contains sym)
753
+ }
754
+ )
755
+ def inPackageObject (sym : Symbol ) = (
756
+ ! sym.isPackage
757
+ && ! sym.owner.isPackageClass
758
+ && (sym.owner ne NoSymbol )
759
+ && (sym.owner.owner == pkgClass || matchesInfo)
760
+ )
761
+
762
+ pkgClass.isPackageClass && (
763
+ if (sym.isOverloaded) sym.alternatives forall inPackageObject
764
+ else inPackageObject(sym)
765
+ )
766
+ }
767
+
768
+ /** Find the symbol of a simple name starting from this context.
769
+ * All names are filtered through the "qualifies" predicate,
770
+ * the search continuing as long as no qualifying name is found.
771
+ */
772
+ def lookupSymbol (name : Name , qualifies : Symbol => Boolean ): NameLookup = {
773
+ var lookupError : NameLookup = null // set to non-null if a definite error is encountered
774
+ var inaccessible : NameLookup = null // records inaccessible symbol for error reporting in case none is found
775
+ var defEntry : ScopeEntry = null // the scope entry of defSym, if defined in a local scope
776
+ var defSym : Symbol = NoSymbol // the directly found symbol
777
+ var pre : Type = NoPrefix // the prefix type of defSym, if a class member
778
+ var cx : Context = this
779
+ var needsQualifier = false // working around package object overloading bug
780
+
781
+ def defEntrySymbol = if (defEntry eq null ) NoSymbol else defEntry.sym
782
+ def localScopeDepth = if (defEntry eq null ) 0 else cx.scope.nestingLevel - defEntry.owner.nestingLevel
783
+
784
+ def finish (qual : Tree , sym : Symbol ): NameLookup = (
785
+ if (lookupError ne null ) lookupError
786
+ else sym match {
787
+ case NoSymbol if inaccessible ne null => inaccessible
788
+ case NoSymbol => LookupNotFound
789
+ case _ => LookupSucceeded (qual, sym)
790
+ }
791
+ )
792
+ def isPackageOwnedInDifferentUnit (s : Symbol ) = (
793
+ s.isDefinedInPackage && (
794
+ ! currentRun.compiles(s)
795
+ || unit.exists && s.sourceFile != unit.source.file
796
+ )
797
+ )
798
+ def requiresQualifier (s : Symbol ) = needsQualifier || (
799
+ s.owner.isClass
800
+ && ! s.owner.isPackageClass
801
+ && ! s.isTypeParameterOrSkolem
802
+ )
803
+ def lookupInPrefix (name : Name ) = pre member name filter qualifies
804
+ def accessibleInPrefix (s : Symbol ) = isAccessible(s, pre, superAccess = false )
805
+
806
+ def correctForPackageObject (sym : Symbol ): Symbol = {
807
+ if (sym.isTerm && isInPackageObject(sym, pre.typeSymbol)) {
808
+ val sym1 = lookupInPrefix(sym.name)
809
+ if ((sym1 eq NoSymbol ) || (sym eq sym1)) sym else {
810
+ needsQualifier = true
811
+ log(s """
812
+ | !!! Overloaded package object member resolved incorrectly.
813
+ | prefix: $pre
814
+ | Discarded: ${sym.defString}
815
+ | Using: ${sym1.defString}
816
+ """ .stripMargin)
817
+ sym1
818
+ }
819
+ }
820
+ else sym
821
+ }
822
+
823
+ def searchPrefix = {
824
+ cx = cx.enclClass
825
+ val found0 = lookupInPrefix(name)
826
+ val found1 = found0 filter accessibleInPrefix
827
+ if (found0.exists && ! found1.exists && inaccessible == null )
828
+ inaccessible = LookupInaccessible (found0, analyzer.lastAccessCheckDetails)
829
+
830
+ found1
831
+ }
832
+ // cx.scope eq null arises during FixInvalidSyms in Duplicators
833
+ while (defSym == NoSymbol && (cx ne NoContext ) && (cx.scope ne null )) {
834
+ pre = cx.enclClass.prefix
835
+ // !!! FIXME. This call to lookupEntry is at the root of all the
836
+ // bad behavior with overloading in package objects. lookupEntry
837
+ // just takes the first symbol it finds in scope, ignoring the rest.
838
+ // When a selection on a package object arrives here, the first
839
+ // overload is always chosen. "correctForPackageObject" exists to
840
+ // undo that decision. Obviously it would be better not to do it in
841
+ // the first place; however other things seem to be tied to obtaining
842
+ // that ScopeEntry, specifically calculating the nesting depth.
843
+ defEntry = cx.scope lookupEntry name
844
+ defSym = defEntrySymbol filter qualifies map correctForPackageObject orElse searchPrefix
845
+ if (! defSym.exists)
846
+ cx = cx.outer
847
+ }
848
+
849
+ val symbolDepth = cx.depth - localScopeDepth
850
+ var impSym : Symbol = NoSymbol
851
+ var imports = Context .this .imports // impSym != NoSymbol => it is imported from imports.head
852
+ def imp1 = imports.head
853
+
854
+ while (! qualifies(impSym) && imports.nonEmpty && imp1.depth > symbolDepth) {
855
+ impSym = importedAccessibleSymbol(imp1, name)
856
+ if (! impSym.exists)
857
+ imports = imports.tail
858
+ }
859
+ if (defSym.exists && impSym.exists) {
860
+ // imported symbols take precedence over package-owned symbols in different compilation units.
861
+ if (isPackageOwnedInDifferentUnit(defSym))
862
+ defSym = NoSymbol
863
+ // Defined symbols take precedence over erroneous imports.
864
+ else if (impSym.isError || impSym.name == nme.CONSTRUCTOR )
865
+ impSym = NoSymbol
866
+ // Otherwise they are irreconcilably ambiguous
867
+ else
868
+ return ambiguousDefnAndImport(defSym.owner, imp1)
869
+ }
870
+
871
+ // At this point only one or the other of defSym and impSym might be set.
872
+ if (defSym.exists) {
873
+ if (requiresQualifier(defSym))
874
+ finish(gen.mkAttributedQualifier(pre), defSym)
875
+ else
876
+ finish(EmptyTree , defSym)
877
+ }
878
+ else if (impSym.exists) {
879
+ // Imports against which we will test impSym for any ambiguities
880
+ var importsTail = imports.tail
881
+ val imp1Explicit = imp1 isExplicitImport name
882
+ def imp2 = importsTail.head
883
+ def sameDepth = imp1.depth == imp2.depth
884
+ def isDone = importsTail.isEmpty || imp1Explicit && ! sameDepth
885
+
886
+ while (lookupError == null && ! isDone) {
887
+ val other = importedAccessibleSymbol(imp2, name)
888
+ // Ambiguity check between imports.
889
+ // The same name imported again is potentially ambiguous if the name is:
890
+ // - after explicit import, explicitly imported again at the same or lower depth
891
+ // - after explicit import, wildcard imported at lower depth
892
+ // - after wildcard import, wildcard imported at the same depth
893
+ // Under all such conditions isAmbiguousImport is called, which will
894
+ // examine the imports in case they are importing the same thing; if that
895
+ // can't be established conclusively, an error is issued.
896
+ if (qualifies(other)) {
897
+ val imp2Explicit = imp2 isExplicitImport name
898
+ val needsCheck = (
899
+ if (sameDepth) imp1Explicit == imp2Explicit
900
+ else imp1Explicit || imp2Explicit
901
+ )
902
+ log(s " Import ambiguity: imp1= $imp1, imp2= $imp2, sameDepth= $sameDepth, needsCheck= $needsCheck" )
903
+ if (needsCheck && isAmbiguousImport(imp1, imp2, name))
904
+ lookupError = ambiguousImports(imp1, imp2)
905
+ else if (imp2Explicit) {
906
+ // if we weren't ambiguous and imp2 is explicit, imp2 replaces imp1
907
+ // as the current winner.
908
+ impSym = other
909
+ imports = importsTail
910
+ }
911
+ }
912
+ importsTail = importsTail.tail
913
+ }
914
+ // optimization: don't write out package prefixes
915
+ finish(resetPos(imp1.qual.duplicate), impSym)
916
+ }
917
+ else finish(EmptyTree , NoSymbol )
918
+ }
919
+
681
920
/**
682
921
* Find a symbol in this context or one of its outers.
683
922
*
@@ -705,8 +944,8 @@ trait Contexts { self: Analyzer =>
705
944
/** The prefix expression */
706
945
def qual : Tree = tree.symbol.info match {
707
946
case ImportType (expr) => expr
708
- case ErrorType => tree setType NoType // fix for #2870
709
- case _ => throw new FatalError (" symbol " + tree.symbol + " has bad type: " + tree.symbol.info) // debug
947
+ case ErrorType => tree setType NoType // fix for #2870
948
+ case _ => throw new FatalError (" symbol " + tree.symbol + " has bad type: " + tree.symbol.info) // debug
710
949
}
711
950
712
951
/** Is name imported explicitly, not via wildcard? */
0 commit comments