@@ -72,6 +72,13 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
7272 */
7373 private var importedFromRoot : Set [Symbol ] = Set ()
7474
75+ /** Temporary data item for single call to typed ident:
76+ * This symbol would be found under Scala2 mode, but is not
77+ * in dotty (because dotty conforms to spec section 2
78+ * wrt to package member resolution but scalac doe not).
79+ */
80+ private var foundUnderScala2 : Type = NoType
81+
7582 def newLikeThis : Typer = new Typer
7683
7784 /** Attribute an identifier consisting of a simple name or wildcard
@@ -133,14 +140,20 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
133140 * imported by <tree>
134141 * or defined in <symbol>
135142 */
136- def bindingString (prec : Int , whereFound : Context , qualifier : String = " " ) =
143+ def bindingString (prec : Int , whereFound : Context , qualifier : String = " " )( implicit ctx : Context ) =
137144 if (prec == wildImport || prec == namedImport) ex " imported $qualifier by ${whereFound.importInfo}"
138145 else ex " defined $qualifier in ${whereFound.owner}"
139146
140147 /** Check that any previously found result from an inner context
141148 * does properly shadow the new one from an outer context.
149+ * @param found The newly found result
150+ * @param newPrec Its precedence
151+ * @param scala2pkg Special mode where we check members of the same package, but defined
152+ * in different compilation units under Scala2. If set, and the
153+ * previous and new contexts do not have the same scope, we select
154+ * the previous (inner) definition. This models what scalac does.
142155 */
143- def checkNewOrShadowed (found : Type , newPrec : Int ): Type =
156+ def checkNewOrShadowed (found : Type , newPrec : Int , scala2pkg : Boolean = false )( implicit ctx : Context ): Type =
144157 if (! previous.exists || ctx.typeComparer.isSameRef(previous, found)) found
145158 else if ((prevCtx.scope eq ctx.scope) &&
146159 (newPrec == definition ||
@@ -150,7 +163,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
150163 found
151164 }
152165 else {
153- if (! previous.isError && ! found.isError) {
166+ if (! scala2pkg && ! previous.isError && ! found.isError) {
154167 error(
155168 ex """ reference to $name is ambiguous;
156169 |it is both ${bindingString(newPrec, ctx, " " )}
@@ -163,7 +176,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
163176 /** The type representing a named import with enclosing name when imported
164177 * from given `site` and `selectors`.
165178 */
166- def namedImportRef (site : Type , selectors : List [untpd.Tree ]): Type = {
179+ def namedImportRef (site : Type , selectors : List [untpd.Tree ])( implicit ctx : Context ) : Type = {
167180 def checkUnambiguous (found : Type ) = {
168181 val other = namedImportRef(site, selectors.tail)
169182 if (other.exists && found.exists && (found != other))
@@ -190,7 +203,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
190203 /** The type representing a wildcard import with enclosing name when imported
191204 * from given import info
192205 */
193- def wildImportRef (imp : ImportInfo ): Type = {
206+ def wildImportRef (imp : ImportInfo )( implicit ctx : Context ) : Type = {
194207 if (imp.isWildcardImport) {
195208 val pre = imp.site
196209 if (! isDisabled(imp, pre) && ! (imp.excluded contains name.toTermName) && name != nme.CONSTRUCTOR ) {
@@ -204,54 +217,71 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
204217 /** Is (some alternative of) the given predenotation `denot`
205218 * defined in current compilation unit?
206219 */
207- def isDefinedInCurrentUnit (denot : Denotation ): Boolean = denot match {
220+ def isDefinedInCurrentUnit (denot : Denotation )( implicit ctx : Context ) : Boolean = denot match {
208221 case MultiDenotation (d1, d2) => isDefinedInCurrentUnit(d1) || isDefinedInCurrentUnit(d2)
209222 case denot : SingleDenotation => denot.symbol.sourceFile == ctx.source.file
210223 }
211224
212225 /** Is `denot` the denotation of a self symbol? */
213- def isSelfDenot (denot : Denotation ) = denot match {
226+ def isSelfDenot (denot : Denotation )( implicit ctx : Context ) = denot match {
214227 case denot : SymDenotation => denot is SelfName
215228 case _ => false
216229 }
217230
218- // begin findRef
219- if (ctx.scope == null ) previous
220- else {
221- val outer = ctx.outer
222- if ((ctx.scope ne outer.scope) || (ctx.owner ne outer.owner)) {
223- val defDenot = ctx.denotNamed(name)
224- if (qualifies(defDenot)) {
225- val curOwner = ctx.owner
226- val found =
227- if (isSelfDenot(defDenot)) curOwner.enclosingClass.thisType
228- else curOwner.thisType.select(name, defDenot)
229- if (! (curOwner is Package ) || isDefinedInCurrentUnit(defDenot))
230- return checkNewOrShadowed(found, definition) // no need to go further out, we found highest prec entry
231- else if (defDenot.symbol is Package )
232- return checkNewOrShadowed(previous orElse found, packageClause)
233- else if (prevPrec < packageClause)
234- return findRef(found, packageClause, ctx)(outer)
231+ /** Would import of kind `prec` be not shadowed by a nested higher-precedence definition? */
232+ def isPossibleImport (prec : Int )(implicit ctx : Context ) =
233+ prevPrec < prec || prevPrec == prec && (prevCtx.scope eq ctx.scope)
234+
235+ @ tailrec def loop (implicit ctx : Context ): Type = {
236+ if (ctx.scope == null ) previous
237+ else {
238+ val outer = ctx.outer
239+ var result : Type = NoType
240+
241+ // find definition
242+ if ((ctx.scope ne outer.scope) || (ctx.owner ne outer.owner)) {
243+ val defDenot = ctx.denotNamed(name)
244+ if (qualifies(defDenot)) {
245+ val curOwner = ctx.owner
246+ val found =
247+ if (isSelfDenot(defDenot)) curOwner.enclosingClass.thisType
248+ else curOwner.thisType.select(name, defDenot)
249+ if (! (curOwner is Package ) || isDefinedInCurrentUnit(defDenot))
250+ result = checkNewOrShadowed(found, definition) // no need to go further out, we found highest prec entry
251+ else {
252+ if (ctx.scala2Mode && ! foundUnderScala2.exists)
253+ foundUnderScala2 = checkNewOrShadowed(found, definition, scala2pkg = true )
254+ if (defDenot.symbol is Package )
255+ result = checkNewOrShadowed(previous orElse found, packageClause)
256+ else if (prevPrec < packageClause)
257+ result = findRef(found, packageClause, ctx)(outer)
258+ }
259+ }
235260 }
236- }
237- val curImport = ctx.importInfo
238- if (ctx.owner.is(Package ) && curImport != null && curImport.isRootImport && previous.exists)
239- return previous // no more conflicts possible in this case
240- // would import of kind `prec` be not shadowed by a nested higher-precedence definition?
241- def isPossibleImport (prec : Int ) =
242- prevPrec < prec || prevPrec == prec && (prevCtx.scope eq ctx.scope)
243- if (isPossibleImport(namedImport) && (curImport ne outer.importInfo) && ! curImport.sym.isCompleting) {
244- val namedImp = namedImportRef(curImport.site, curImport.selectors)
245- if (namedImp.exists)
246- return findRef(checkNewOrShadowed(namedImp, namedImport), namedImport, ctx)(outer)
247- if (isPossibleImport(wildImport)) {
248- val wildImp = wildImportRef(curImport)
249- if (wildImp.exists)
250- return findRef(checkNewOrShadowed(wildImp, wildImport), wildImport, ctx)(outer)
261+
262+ if (result.exists) result
263+ else { // find import
264+ val curImport = ctx.importInfo
265+ if (ctx.owner.is(Package ) && curImport != null && curImport.isRootImport && previous.exists)
266+ previous // no more conflicts possible in this case
267+ else if (isPossibleImport(namedImport) && (curImport ne outer.importInfo) && ! curImport.sym.isCompleting) {
268+ val namedImp = namedImportRef(curImport.site, curImport.selectors)
269+ if (namedImp.exists)
270+ findRef(checkNewOrShadowed(namedImp, namedImport), namedImport, ctx)(outer)
271+ else if (isPossibleImport(wildImport)) {
272+ val wildImp = wildImportRef(curImport)
273+ if (wildImp.exists)
274+ findRef(checkNewOrShadowed(wildImp, wildImport), wildImport, ctx)(outer)
275+ else loop(outer)
276+ }
277+ else loop(outer)
278+ }
279+ else loop(outer)
251280 }
252281 }
253- findRef(previous, prevPrec, prevCtx)(outer)
254282 }
283+
284+ loop
255285 }
256286
257287 // begin typedIdent
@@ -264,12 +294,28 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
264294 return typed(desugar.patternVar(tree), pt)
265295 }
266296
267- val saved = importedFromRoot
268- importedFromRoot = Set .empty
269297
270- val rawType =
271- try findRef(NoType , BindingPrec .nothingBound, NoContext )
272- finally importedFromRoot = saved
298+ val rawType = {
299+ val saved1 = importedFromRoot
300+ val saved2 = foundUnderScala2
301+ importedFromRoot = Set .empty
302+ foundUnderScala2 = NoType
303+ try {
304+ var found = findRef(NoType , BindingPrec .nothingBound, NoContext )
305+ if (foundUnderScala2.exists && ! (foundUnderScala2 =:= found)) {
306+ ctx.migrationWarning(
307+ ex """ Name resolution will change.
308+ | currently selected : $foundUnderScala2
309+ | in the future, without -language:Scala2: $found""" , tree.pos)
310+ found = foundUnderScala2
311+ }
312+ found
313+ }
314+ finally {
315+ importedFromRoot = saved1
316+ foundUnderScala2 = saved2
317+ }
318+ }
273319
274320 val ownType =
275321 if (rawType.exists)
0 commit comments