@@ -78,7 +78,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
78
78
* in dotty (because dotty conforms to spec section 2
79
79
* wrt to package member resolution but scalac doe not).
80
80
*/
81
- private var foundUnderScala2 : Type = _
81
+ private var foundUnderScala2 : Type = NoType
82
82
83
83
def newLikeThis : Typer = new Typer
84
84
@@ -141,14 +141,20 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
141
141
* imported by <tree>
142
142
* or defined in <symbol>
143
143
*/
144
- def bindingString (prec : Int , whereFound : Context , qualifier : String = " " ) =
144
+ def bindingString (prec : Int , whereFound : Context , qualifier : String = " " )( implicit ctx : Context ) =
145
145
if (prec == wildImport || prec == namedImport) ex " imported $qualifier by ${whereFound.importInfo}"
146
146
else ex " defined $qualifier in ${whereFound.owner}"
147
147
148
148
/** Check that any previously found result from an inner context
149
149
* 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.
150
156
*/
151
- def checkNewOrShadowed (found : Type , newPrec : Int ): Type =
157
+ def checkNewOrShadowed (found : Type , newPrec : Int , scala2pkg : Boolean = false )( implicit ctx : Context ): Type =
152
158
if (! previous.exists || ctx.typeComparer.isSameRef(previous, found)) found
153
159
else if ((prevCtx.scope eq ctx.scope) &&
154
160
(newPrec == definition ||
@@ -158,7 +164,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
158
164
found
159
165
}
160
166
else {
161
- if (! previous.isError && ! found.isError) {
167
+ if (! scala2pkg && ! previous.isError && ! found.isError) {
162
168
error(
163
169
ex """ reference to $name is ambiguous;
164
170
|it is both ${bindingString(newPrec, ctx, " " )}
@@ -171,7 +177,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
171
177
/** The type representing a named import with enclosing name when imported
172
178
* from given `site` and `selectors`.
173
179
*/
174
- def namedImportRef (site : Type , selectors : List [untpd.Tree ]): Type = {
180
+ def namedImportRef (site : Type , selectors : List [untpd.Tree ])( implicit ctx : Context ) : Type = {
175
181
def checkUnambiguous (found : Type ) = {
176
182
val other = namedImportRef(site, selectors.tail)
177
183
if (other.exists && found.exists && (found != other))
@@ -198,7 +204,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
198
204
/** The type representing a wildcard import with enclosing name when imported
199
205
* from given import info
200
206
*/
201
- def wildImportRef (imp : ImportInfo ): Type = {
207
+ def wildImportRef (imp : ImportInfo )( implicit ctx : Context ) : Type = {
202
208
if (imp.isWildcardImport) {
203
209
val pre = imp.site
204
210
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
212
218
/** Is (some alternative of) the given predenotation `denot`
213
219
* defined in current compilation unit?
214
220
*/
215
- def isDefinedInCurrentUnit (denot : Denotation ): Boolean = denot match {
221
+ def isDefinedInCurrentUnit (denot : Denotation )( implicit ctx : Context ) : Boolean = denot match {
216
222
case MultiDenotation (d1, d2) => isDefinedInCurrentUnit(d1) || isDefinedInCurrentUnit(d2)
217
223
case denot : SingleDenotation => denot.symbol.sourceFile == ctx.source.file
218
224
}
219
225
220
226
/** 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 {
222
228
case denot : SymDenotation => denot is SelfName
223
229
case _ => false
224
230
}
225
231
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
+ }
246
260
}
247
261
}
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)
263
281
}
264
282
}
265
- findRef(previous, prevPrec, prevCtx)(outer)
266
283
}
284
+
285
+ loop
267
286
}
268
287
269
288
// begin typedIdent
@@ -276,21 +295,27 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
276
295
return typed(desugar.patternVar(tree), pt)
277
296
}
278
297
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
287
298
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
+ }
294
319
}
295
320
296
321
val ownType =
0 commit comments