@@ -77,7 +77,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
77
77
* in dotty (because dotty conforms to spec section 2
78
78
* wrt to package member resolution but scalac doe not).
79
79
*/
80
- private var foundUnderScala2 : Type = _
80
+ private var foundUnderScala2 : Type = NoType
81
81
82
82
def newLikeThis : Typer = new Typer
83
83
@@ -140,14 +140,20 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
140
140
* imported by <tree>
141
141
* or defined in <symbol>
142
142
*/
143
- def bindingString (prec : Int , whereFound : Context , qualifier : String = " " ) =
143
+ def bindingString (prec : Int , whereFound : Context , qualifier : String = " " )( implicit ctx : Context ) =
144
144
if (prec == wildImport || prec == namedImport) ex " imported $qualifier by ${whereFound.importInfo}"
145
145
else ex " defined $qualifier in ${whereFound.owner}"
146
146
147
147
/** Check that any previously found result from an inner context
148
148
* 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.
149
155
*/
150
- def checkNewOrShadowed (found : Type , newPrec : Int ): Type =
156
+ def checkNewOrShadowed (found : Type , newPrec : Int , scala2pkg : Boolean = false )( implicit ctx : Context ): Type =
151
157
if (! previous.exists || ctx.typeComparer.isSameRef(previous, found)) found
152
158
else if ((prevCtx.scope eq ctx.scope) &&
153
159
(newPrec == definition ||
@@ -157,7 +163,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
157
163
found
158
164
}
159
165
else {
160
- if (! previous.isError && ! found.isError) {
166
+ if (! scala2pkg && ! previous.isError && ! found.isError) {
161
167
error(
162
168
ex """ reference to $name is ambiguous;
163
169
|it is both ${bindingString(newPrec, ctx, " " )}
@@ -170,7 +176,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
170
176
/** The type representing a named import with enclosing name when imported
171
177
* from given `site` and `selectors`.
172
178
*/
173
- def namedImportRef (site : Type , selectors : List [untpd.Tree ]): Type = {
179
+ def namedImportRef (site : Type , selectors : List [untpd.Tree ])( implicit ctx : Context ) : Type = {
174
180
def checkUnambiguous (found : Type ) = {
175
181
val other = namedImportRef(site, selectors.tail)
176
182
if (other.exists && found.exists && (found != other))
@@ -197,7 +203,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
197
203
/** The type representing a wildcard import with enclosing name when imported
198
204
* from given import info
199
205
*/
200
- def wildImportRef (imp : ImportInfo ): Type = {
206
+ def wildImportRef (imp : ImportInfo )( implicit ctx : Context ) : Type = {
201
207
if (imp.isWildcardImport) {
202
208
val pre = imp.site
203
209
if (! isDisabled(imp, pre) && ! (imp.excluded contains name.toTermName) && name != nme.CONSTRUCTOR ) {
@@ -211,58 +217,71 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
211
217
/** Is (some alternative of) the given predenotation `denot`
212
218
* defined in current compilation unit?
213
219
*/
214
- def isDefinedInCurrentUnit (denot : Denotation ): Boolean = denot match {
220
+ def isDefinedInCurrentUnit (denot : Denotation )( implicit ctx : Context ) : Boolean = denot match {
215
221
case MultiDenotation (d1, d2) => isDefinedInCurrentUnit(d1) || isDefinedInCurrentUnit(d2)
216
222
case denot : SingleDenotation => denot.symbol.sourceFile == ctx.source.file
217
223
}
218
224
219
225
/** Is `denot` the denotation of a self symbol? */
220
- def isSelfDenot (denot : Denotation ) = denot match {
226
+ def isSelfDenot (denot : Denotation )( implicit ctx : Context ) = denot match {
221
227
case denot : SymDenotation => denot is SelfName
222
228
case _ => false
223
229
}
224
230
225
- // begin findRef
226
- if (ctx.scope == null ) previous
227
- else {
228
- val outer = ctx.outer
229
- if ((ctx.scope ne outer.scope) || (ctx.owner ne outer.owner)) {
230
- val defDenot = ctx.denotNamed(name)
231
- if (qualifies(defDenot)) {
232
- val curOwner = ctx.owner
233
- val found =
234
- if (isSelfDenot(defDenot)) curOwner.enclosingClass.thisType
235
- else curOwner.thisType.select(name, defDenot)
236
- if (! (curOwner is Package ) || isDefinedInCurrentUnit(defDenot))
237
- return checkNewOrShadowed(found, definition) // no need to go further out, we found highest prec entry
238
- else {
239
- if (ctx.scala2Mode)
240
- foundUnderScala2 = checkNewOrShadowed(found, definition)
241
- if (defDenot.symbol is Package )
242
- return checkNewOrShadowed(previous orElse found, packageClause)
243
- else if (prevPrec < packageClause)
244
- 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
+ }
245
259
}
246
260
}
247
- }
248
- val curImport = ctx.importInfo
249
- if (ctx.owner.is(Package ) && curImport != null && curImport.isRootImport && previous.exists)
250
- return previous // no more conflicts possible in this case
251
- // would import of kind `prec` be not shadowed by a nested higher-precedence definition?
252
- def isPossibleImport (prec : Int ) =
253
- prevPrec < prec || prevPrec == prec && (prevCtx.scope eq ctx.scope)
254
- if (isPossibleImport(namedImport) && (curImport ne outer.importInfo) && ! curImport.sym.isCompleting) {
255
- val namedImp = namedImportRef(curImport.site, curImport.selectors)
256
- if (namedImp.exists)
257
- return findRef(checkNewOrShadowed(namedImp, namedImport), namedImport, ctx)(outer)
258
- if (isPossibleImport(wildImport)) {
259
- val wildImp = wildImportRef(curImport)
260
- if (wildImp.exists)
261
- 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)
262
280
}
263
281
}
264
- findRef(previous, prevPrec, prevCtx)(outer)
265
282
}
283
+
284
+ loop
266
285
}
267
286
268
287
// begin typedIdent
@@ -275,21 +294,27 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
275
294
return typed(desugar.patternVar(tree), pt)
276
295
}
277
296
278
- val saved = importedFromRoot
279
- importedFromRoot = Set .empty
280
-
281
- foundUnderScala2 = NoType
282
-
283
- var rawType =
284
- try findRef(NoType , BindingPrec .nothingBound, NoContext )
285
- finally importedFromRoot = saved
286
297
287
- if (foundUnderScala2.exists && (foundUnderScala2 ne rawType)) {
288
- ctx.migrationWarning(
289
- ex """ Name resolution will change.
290
- | currently selected : $foundUnderScala2
291
- | in the future, without -language:Scala2: $rawType""" , tree.pos)
292
- rawType = foundUnderScala2
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
+ }
293
318
}
294
319
295
320
val ownType =
0 commit comments