@@ -78,7 +78,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
7878 * in dotty (because dotty conforms to spec section 2
7979 * wrt to package member resolution but scalac doe not).
8080 */
81- private var foundUnderScala2 : Type = _
81+ private var foundUnderScala2 : Type = NoType
8282
8383 def newLikeThis : Typer = new Typer
8484
@@ -141,14 +141,20 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
141141 * imported by <tree>
142142 * or defined in <symbol>
143143 */
144- def bindingString (prec : Int , whereFound : Context , qualifier : String = " " ) =
144+ def bindingString (prec : Int , whereFound : Context , qualifier : String = " " )( implicit ctx : Context ) =
145145 if (prec == wildImport || prec == namedImport) ex " imported $qualifier by ${whereFound.importInfo}"
146146 else ex " defined $qualifier in ${whereFound.owner}"
147147
148148 /** Check that any previously found result from an inner context
149149 * does properly shadow the new one from an outer context.
150+ * @param found The newly found result
151+ * @param newPrec Its precedence
152+ * @param scala2pkg Special mode where we check members of the same package, but defined
153+ * in different compilation units under Scala2. If set, and the
154+ * previous and new contexts do not have the same scope, we select
155+ * the previous (inner) definition. This models what scalac does.
150156 */
151- def checkNewOrShadowed (found : Type , newPrec : Int ): Type =
157+ def checkNewOrShadowed (found : Type , newPrec : Int , scala2pkg : Boolean = false )( implicit ctx : Context ): Type =
152158 if (! previous.exists || ctx.typeComparer.isSameRef(previous, found)) found
153159 else if ((prevCtx.scope eq ctx.scope) &&
154160 (newPrec == definition ||
@@ -158,7 +164,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
158164 found
159165 }
160166 else {
161- if (! previous.isError && ! found.isError) {
167+ if (! scala2pkg && ! previous.isError && ! found.isError) {
162168 error(
163169 ex """ reference to $name is ambiguous;
164170 |it is both ${bindingString(newPrec, ctx, " " )}
@@ -171,7 +177,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
171177 /** The type representing a named import with enclosing name when imported
172178 * from given `site` and `selectors`.
173179 */
174- def namedImportRef (site : Type , selectors : List [untpd.Tree ]): Type = {
180+ def namedImportRef (site : Type , selectors : List [untpd.Tree ])( implicit ctx : Context ) : Type = {
175181 def checkUnambiguous (found : Type ) = {
176182 val other = namedImportRef(site, selectors.tail)
177183 if (other.exists && found.exists && (found != other))
@@ -198,7 +204,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
198204 /** The type representing a wildcard import with enclosing name when imported
199205 * from given import info
200206 */
201- def wildImportRef (imp : ImportInfo ): Type = {
207+ def wildImportRef (imp : ImportInfo )( implicit ctx : Context ) : Type = {
202208 if (imp.isWildcardImport) {
203209 val pre = imp.site
204210 if (! isDisabled(imp, pre) && ! (imp.excluded contains name.toTermName) && name != nme.CONSTRUCTOR ) {
@@ -212,58 +218,71 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
212218 /** Is (some alternative of) the given predenotation `denot`
213219 * defined in current compilation unit?
214220 */
215- def isDefinedInCurrentUnit (denot : Denotation ): Boolean = denot match {
221+ def isDefinedInCurrentUnit (denot : Denotation )( implicit ctx : Context ) : Boolean = denot match {
216222 case MultiDenotation (d1, d2) => isDefinedInCurrentUnit(d1) || isDefinedInCurrentUnit(d2)
217223 case denot : SingleDenotation => denot.symbol.sourceFile == ctx.source.file
218224 }
219225
220226 /** Is `denot` the denotation of a self symbol? */
221- def isSelfDenot (denot : Denotation ) = denot match {
227+ def isSelfDenot (denot : Denotation )( implicit ctx : Context ) = denot match {
222228 case denot : SymDenotation => denot is SelfName
223229 case _ => false
224230 }
225231
226- // begin findRef
227- if (ctx.scope == null ) previous
228- else {
229- val outer = ctx.outer
230- if ((ctx.scope ne outer.scope) || (ctx.owner ne outer.owner)) {
231- val defDenot = ctx.denotNamed(name)
232- if (qualifies(defDenot)) {
233- val curOwner = ctx.owner
234- val found =
235- if (isSelfDenot(defDenot)) curOwner.enclosingClass.thisType
236- else curOwner.thisType.select(name, defDenot)
237- if (! (curOwner is Package ) || isDefinedInCurrentUnit(defDenot))
238- return checkNewOrShadowed(found, definition) // no need to go further out, we found highest prec entry
239- else {
240- if (ctx.scala2Mode)
241- foundUnderScala2 = checkNewOrShadowed(found, definition)
242- if (defDenot.symbol is Package )
243- return checkNewOrShadowed(previous orElse found, packageClause)
244- else if (prevPrec < packageClause)
245- return findRef(found, packageClause, ctx)(outer)
232+ /** Would import of kind `prec` be not shadowed by a nested higher-precedence definition? */
233+ def isPossibleImport (prec : Int )(implicit ctx : Context ) =
234+ prevPrec < prec || prevPrec == prec && (prevCtx.scope eq ctx.scope)
235+
236+ @ tailrec def loop (implicit ctx : Context ): Type = {
237+ if (ctx.scope == null ) previous
238+ else {
239+ val outer = ctx.outer
240+ var result : Type = NoType
241+
242+ // find definition
243+ if ((ctx.scope ne outer.scope) || (ctx.owner ne outer.owner)) {
244+ val defDenot = ctx.denotNamed(name)
245+ if (qualifies(defDenot)) {
246+ val curOwner = ctx.owner
247+ val found =
248+ if (isSelfDenot(defDenot)) curOwner.enclosingClass.thisType
249+ else curOwner.thisType.select(name, defDenot)
250+ if (! (curOwner is Package ) || isDefinedInCurrentUnit(defDenot))
251+ result = checkNewOrShadowed(found, definition) // no need to go further out, we found highest prec entry
252+ else {
253+ if (ctx.scala2Mode && ! foundUnderScala2.exists)
254+ foundUnderScala2 = checkNewOrShadowed(found, definition, scala2pkg = true )
255+ if (defDenot.symbol is Package )
256+ result = checkNewOrShadowed(previous orElse found, packageClause)
257+ else if (prevPrec < packageClause)
258+ result = findRef(found, packageClause, ctx)(outer)
259+ }
246260 }
247261 }
248- }
249- val curImport = ctx.importInfo
250- if (ctx.owner.is(Package ) && curImport != null && curImport.isRootImport && previous.exists)
251- return previous // no more conflicts possible in this case
252- // would import of kind `prec` be not shadowed by a nested higher-precedence definition?
253- def isPossibleImport (prec : Int ) =
254- prevPrec < prec || prevPrec == prec && (prevCtx.scope eq ctx.scope)
255- if (isPossibleImport(namedImport) && (curImport ne outer.importInfo) && ! curImport.sym.isCompleting) {
256- val namedImp = namedImportRef(curImport.site, curImport.selectors)
257- if (namedImp.exists)
258- return findRef(checkNewOrShadowed(namedImp, namedImport), namedImport, ctx)(outer)
259- if (isPossibleImport(wildImport)) {
260- val wildImp = wildImportRef(curImport)
261- if (wildImp.exists)
262- return findRef(checkNewOrShadowed(wildImp, wildImport), wildImport, ctx)(outer)
262+
263+ if (result.exists) result
264+ else { // find import
265+ val curImport = ctx.importInfo
266+ if (ctx.owner.is(Package ) && curImport != null && curImport.isRootImport && previous.exists)
267+ previous // no more conflicts possible in this case
268+ else if (isPossibleImport(namedImport) && (curImport ne outer.importInfo) && ! curImport.sym.isCompleting) {
269+ val namedImp = namedImportRef(curImport.site, curImport.selectors)
270+ if (namedImp.exists)
271+ findRef(checkNewOrShadowed(namedImp, namedImport), namedImport, ctx)(outer)
272+ else if (isPossibleImport(wildImport)) {
273+ val wildImp = wildImportRef(curImport)
274+ if (wildImp.exists)
275+ findRef(checkNewOrShadowed(wildImp, wildImport), wildImport, ctx)(outer)
276+ else loop(outer)
277+ }
278+ else loop(outer)
279+ }
280+ else loop(outer)
263281 }
264282 }
265- findRef(previous, prevPrec, prevCtx)(outer)
266283 }
284+
285+ loop
267286 }
268287
269288 // begin typedIdent
@@ -276,21 +295,27 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
276295 return typed(desugar.patternVar(tree), pt)
277296 }
278297
279- val saved = importedFromRoot
280- importedFromRoot = Set .empty
281-
282- foundUnderScala2 = NoType
283-
284- var rawType =
285- try findRef(NoType , BindingPrec .nothingBound, NoContext )
286- finally importedFromRoot = saved
287298
288- if (foundUnderScala2.exists && (foundUnderScala2 ne rawType)) {
289- ctx.migrationWarning(
290- ex """ Name resolution will change.
291- | currently selected : $foundUnderScala2
292- | in the future, without -language:Scala2: $rawType""" , tree.pos)
293- rawType = foundUnderScala2
299+ val rawType = {
300+ val saved1 = importedFromRoot
301+ val saved2 = foundUnderScala2
302+ importedFromRoot = Set .empty
303+ foundUnderScala2 = NoType
304+ try {
305+ var found = findRef(NoType , BindingPrec .nothingBound, NoContext )
306+ if (foundUnderScala2.exists && ! (foundUnderScala2 =:= found)) {
307+ ctx.migrationWarning(
308+ ex """ Name resolution will change.
309+ | currently selected : $foundUnderScala2
310+ | in the future, without -language:Scala2: $found""" , tree.pos)
311+ found = foundUnderScala2
312+ }
313+ found
314+ }
315+ finally {
316+ importedFromRoot = saved1
317+ foundUnderScala2 = saved2
318+ }
294319 }
295320
296321 val ownType =
0 commit comments