@@ -241,40 +241,44 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
241
241
! owner.isEmptyPackage || ctx.owner.enclosingPackageClass.isEmptyPackage
242
242
}
243
243
244
- import BindingPrec .*
245
- type Result = (Type , BindingPrec )
246
- val NoResult = (NoType , NothingBound )
247
-
248
244
/** Find the denotation of enclosing `name` in given context `ctx`.
249
- * @param prevResult A type that was found in a more deeply nested scope,
250
- * and its precedence, or NoResult if nothing was found yet.
245
+ * @param previous A denotation that was found in a more deeply nested scope,
246
+ * or else `NoDenotation` if nothing was found yet.
247
+ * @param prevPrec The binding precedence of the previous denotation,
248
+ * or else `nothingBound` if nothing was found yet.
251
249
* @param prevCtx The context of the previous denotation,
252
250
* or else `NoContext` if nothing was found yet.
253
251
*/
254
- def findRefRecur (prevResult : Result , prevCtx : Context )(using Context ): Result = {
255
- val (previous, prevPrec) = prevResult
252
+ def findRefRecur (previous : Type , prevPrec : BindingPrec , prevCtx : Context )(using Context ): Type = {
253
+ import BindingPrec . *
256
254
257
255
/** Check that any previously found result from an inner context
258
256
* does properly shadow the new one from an outer context.
259
- * @param newResult The newly found type and its precedence.
257
+ * @param found The newly found result
258
+ * @param newPrec Its precedence
260
259
* @param scala2pkg Special mode where we check members of the same package, but defined
261
260
* in different compilation units under Scala2. If set, and the
262
261
* previous and new contexts do not have the same scope, we select
263
262
* the previous (inner) definition. This models what scalac does.
264
263
*/
265
- def checkNewOrShadowed (newResult : Result , scala2pkg : Boolean = false )(using Context ): Result =
266
- val (found, newPrec) = newResult
264
+ def checkNewOrShadowed (found : Type , newPrec : BindingPrec , scala2pkg : Boolean = false )(using Context ): Type =
267
265
if ! previous.exists || TypeComparer .isSameRef(previous, found) then
268
- newResult
266
+ found
269
267
else if (prevCtx.scope eq ctx.scope) && newPrec.beats(prevPrec) then
270
268
// special cases: definitions beat imports, and named imports beat
271
269
// wildcard imports, provided both are in contexts with same scope
272
- newResult
270
+ found
271
+ else if newPrec == WildImport && ctx.outersIterator.exists: ctx =>
272
+ ctx.isImportContext && namedImportRef(ctx.importInfo.uncheckedNN).exists
273
+ then
274
+ // Don't let two ambiguous wildcard imports rule over
275
+ // a winning named import. See pos/i18529.
276
+ found
273
277
else
274
278
if ! scala2pkg && ! previous.isError && ! found.isError then
275
279
fail(AmbiguousReference (name, newPrec, prevPrec, prevCtx,
276
280
isExtension = previous.termSymbol.is(ExtensionMethod ) && found.termSymbol.is(ExtensionMethod )))
277
- prevResult
281
+ previous
278
282
279
283
/** Assemble and check alternatives to an imported reference. This implies:
280
284
* - If we expand an extension method (i.e. altImports != null),
@@ -287,13 +291,12 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
287
291
* shadowed. This order of checking is necessary since an outer package-level
288
292
* definition might trump two conflicting inner imports, so no error should be
289
293
* issued in that case. See i7876.scala.
290
- * @param prevResult the previously found reference (which is an import), and
291
- * the precedence of the reference (either NamedImport or WildImport)
294
+ * @param previous the previously found reference (which is an import)
295
+ * @param prevPrec the precedence of the reference (either NamedImport or WildImport)
292
296
* @param prevCtx the context in which the reference was found
293
297
* @param using_Context the outer context of `precCtx`
294
298
*/
295
- def checkImportAlternatives (prevResult : Result , prevCtx : Context )(using Context ): Result =
296
- val (previous, prevPrec) = prevResult
299
+ def checkImportAlternatives (previous : Type , prevPrec : BindingPrec , prevCtx : Context )(using Context ): Type =
297
300
298
301
def addAltImport (altImp : TermRef ) =
299
302
if ! TypeComparer .isSameRef(previous, altImp)
@@ -308,20 +311,20 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
308
311
if prevPrec == WildImport then
309
312
// Discard all previously found references and continue with `altImp`
310
313
altImports.clear()
311
- checkImportAlternatives(( altImp, NamedImport ) , ctx)(using ctx.outer)
314
+ checkImportAlternatives(altImp, NamedImport , ctx)(using ctx.outer)
312
315
else
313
316
addAltImport(altImp)
314
- checkImportAlternatives(prevResult , prevCtx)(using ctx.outer)
317
+ checkImportAlternatives(previous, prevPrec , prevCtx)(using ctx.outer)
315
318
case _ =>
316
319
if prevPrec == WildImport then
317
320
wildImportRef(curImport) match
318
321
case altImp : TermRef => addAltImport(altImp)
319
322
case _ =>
320
- checkImportAlternatives(prevResult , prevCtx)(using ctx.outer)
323
+ checkImportAlternatives(previous, prevPrec , prevCtx)(using ctx.outer)
321
324
else
322
- val foundResult = findRefRecur(prevResult , prevCtx)
323
- if foundResult._1 eq previous then checkNewOrShadowed(foundResult )(using prevCtx)
324
- else foundResult
325
+ val found = findRefRecur(previous, prevPrec , prevCtx)
326
+ if found eq previous then checkNewOrShadowed(found, prevPrec )(using prevCtx)
327
+ else found
325
328
end checkImportAlternatives
326
329
327
330
def selection (imp : ImportInfo , name : Name , checkBounds : Boolean ): Type =
@@ -411,10 +414,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
411
414
! noImports &&
412
415
(prevPrec.ordinal < prec.ordinal || prevPrec == prec && (prevCtx.scope eq ctx.scope))
413
416
414
- @ tailrec def loop (lastCtx : Context )(using Context ): Result =
415
- if (ctx.scope eq EmptyScope ) prevResult
417
+ @ tailrec def loop (lastCtx : Context )(using Context ): Type =
418
+ if (ctx.scope eq EmptyScope ) previous
416
419
else {
417
- var result : Result = NoResult
420
+ var result : Type = NoType
418
421
val curOwner = ctx.owner
419
422
420
423
/** Is curOwner a package object that should be skipped?
@@ -513,36 +516,37 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
513
516
effectiveOwner.thisType.select(name, defDenot).makePackageObjPrefixExplicit
514
517
}
515
518
if ! curOwner.is(Package ) || isDefinedInCurrentUnit(defDenot) then
516
- result = checkNewOrShadowed(( found, Definition ) ) // no need to go further out, we found highest prec entry
519
+ result = checkNewOrShadowed(found, Definition ) // no need to go further out, we found highest prec entry
517
520
found match
518
521
case found : NamedType
519
522
if curOwner.isClass && isInherited(found.denot) && ! ctx.compilationUnit.isJava =>
520
523
checkNoOuterDefs(found.denot, ctx, ctx)
521
524
case _ =>
522
525
else
523
526
if migrateTo3 && ! foundUnderScala2.exists then
524
- foundUnderScala2 = checkNewOrShadowed(( found, Definition ) , scala2pkg = true )._1
527
+ foundUnderScala2 = checkNewOrShadowed(found, Definition , scala2pkg = true )
525
528
if (defDenot.symbol.is(Package ))
526
- result = checkNewOrShadowed(( previous orElse found, PackageClause ) )
529
+ result = checkNewOrShadowed(previous orElse found, PackageClause )
527
530
else if (prevPrec.ordinal < PackageClause .ordinal)
528
- result = findRefRecur(( found, PackageClause ) , ctx)(using ctx.outer)
531
+ result = findRefRecur(found, PackageClause , ctx)(using ctx.outer)
529
532
}
530
533
531
- if result._1. exists then result
534
+ if result.exists then result
532
535
else { // find import
533
536
val outer = ctx.outer
534
537
val curImport = ctx.importInfo
538
+ def updateUnimported () =
539
+ if (curImport.nn.unimported ne NoSymbol ) unimported += curImport.nn.unimported
535
540
if (curOwner.is(Package ) && curImport != null && curImport.isRootImport && previous.exists)
536
- prevResult // no more conflicts possible in this case
537
- else if (isPossibleImport(NamedImport ) && curImport != null && (curImport ne outer.importInfo)) {
538
- def updateUnimported () = if curImport.unimported ne NoSymbol then unimported += curImport.unimported
539
- val namedImp = namedImportRef(curImport)
541
+ previous // no more conflicts possible in this case
542
+ else if (isPossibleImport(NamedImport ) && (curImport nen outer.importInfo)) {
543
+ val namedImp = namedImportRef(curImport.uncheckedNN)
540
544
if (namedImp.exists)
541
- checkImportAlternatives(( namedImp, NamedImport ) , ctx)(using outer)
542
- else if (isPossibleImport(WildImport ) && ! curImport.importSym.isCompleting) {
543
- val wildImp = wildImportRef(curImport)
545
+ checkImportAlternatives(namedImp, NamedImport , ctx)(using outer)
546
+ else if (isPossibleImport(WildImport ) && ! curImport.nn. importSym.isCompleting) {
547
+ val wildImp = wildImportRef(curImport.uncheckedNN )
544
548
if (wildImp.exists)
545
- checkImportAlternatives(( wildImp, WildImport ) , ctx)(using outer)
549
+ checkImportAlternatives(wildImp, WildImport , ctx)(using outer)
546
550
else {
547
551
updateUnimported()
548
552
loop(ctx)(using outer)
@@ -561,8 +565,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
561
565
loop(NoContext )
562
566
}
563
567
564
- val (foundRef, foundPrec) = findRefRecur(NoResult , NoContext )
565
- foundRef
568
+ findRefRecur(NoType , BindingPrec .NothingBound , NoContext )
566
569
}
567
570
568
571
/** If `tree`'s type is a `TermRef` identified by flow typing to be non-null, then
0 commit comments