@@ -72,6 +72,13 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
72
72
*/
73
73
private var importedFromRoot : Set [Symbol ] = Set ()
74
74
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
+
75
82
def newLikeThis : Typer = new Typer
76
83
77
84
/** 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
133
140
* imported by <tree>
134
141
* or defined in <symbol>
135
142
*/
136
- def bindingString (prec : Int , whereFound : Context , qualifier : String = " " ) =
143
+ def bindingString (prec : Int , whereFound : Context , qualifier : String = " " )( implicit ctx : Context ) =
137
144
if (prec == wildImport || prec == namedImport) ex " imported $qualifier by ${whereFound.importInfo}"
138
145
else ex " defined $qualifier in ${whereFound.owner}"
139
146
140
147
/** Check that any previously found result from an inner context
141
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.
142
155
*/
143
- def checkNewOrShadowed (found : Type , newPrec : Int ): Type =
156
+ def checkNewOrShadowed (found : Type , newPrec : Int , scala2pkg : Boolean = false )( implicit ctx : Context ): Type =
144
157
if (! previous.exists || ctx.typeComparer.isSameRef(previous, found)) found
145
158
else if ((prevCtx.scope eq ctx.scope) &&
146
159
(newPrec == definition ||
@@ -150,7 +163,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
150
163
found
151
164
}
152
165
else {
153
- if (! previous.isError && ! found.isError) {
166
+ if (! scala2pkg && ! previous.isError && ! found.isError) {
154
167
error(
155
168
ex """ reference to $name is ambiguous;
156
169
|it is both ${bindingString(newPrec, ctx, " " )}
@@ -163,7 +176,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
163
176
/** The type representing a named import with enclosing name when imported
164
177
* from given `site` and `selectors`.
165
178
*/
166
- def namedImportRef (site : Type , selectors : List [untpd.Tree ]): Type = {
179
+ def namedImportRef (site : Type , selectors : List [untpd.Tree ])( implicit ctx : Context ) : Type = {
167
180
def checkUnambiguous (found : Type ) = {
168
181
val other = namedImportRef(site, selectors.tail)
169
182
if (other.exists && found.exists && (found != other))
@@ -190,7 +203,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
190
203
/** The type representing a wildcard import with enclosing name when imported
191
204
* from given import info
192
205
*/
193
- def wildImportRef (imp : ImportInfo ): Type = {
206
+ def wildImportRef (imp : ImportInfo )( implicit ctx : Context ) : Type = {
194
207
if (imp.isWildcardImport) {
195
208
val pre = imp.site
196
209
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
204
217
/** Is (some alternative of) the given predenotation `denot`
205
218
* defined in current compilation unit?
206
219
*/
207
- def isDefinedInCurrentUnit (denot : Denotation ): Boolean = denot match {
220
+ def isDefinedInCurrentUnit (denot : Denotation )( implicit ctx : Context ) : Boolean = denot match {
208
221
case MultiDenotation (d1, d2) => isDefinedInCurrentUnit(d1) || isDefinedInCurrentUnit(d2)
209
222
case denot : SingleDenotation => denot.symbol.sourceFile == ctx.source.file
210
223
}
211
224
212
225
/** 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 {
214
227
case denot : SymDenotation => denot is SelfName
215
228
case _ => false
216
229
}
217
230
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
+ }
235
260
}
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)
251
280
}
252
281
}
253
- findRef(previous, prevPrec, prevCtx)(outer)
254
282
}
283
+
284
+ loop
255
285
}
256
286
257
287
// begin typedIdent
@@ -264,12 +294,28 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
264
294
return typed(desugar.patternVar(tree), pt)
265
295
}
266
296
267
- val saved = importedFromRoot
268
- importedFromRoot = Set .empty
269
297
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
+ }
273
319
274
320
val ownType =
275
321
if (rawType.exists)
0 commit comments