@@ -241,40 +241,44 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
241241 ! owner.isEmptyPackage || ctx.owner.enclosingPackageClass.isEmptyPackage
242242 }
243243
244- import BindingPrec .*
245- type Result = (Type , BindingPrec )
246- val NoResult = (NoType , NothingBound )
247-
248244 /** 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.
251249 * @param prevCtx The context of the previous denotation,
252250 * or else `NoContext` if nothing was found yet.
253251 */
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 . *
256254
257255 /** Check that any previously found result from an inner context
258256 * 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
260259 * @param scala2pkg Special mode where we check members of the same package, but defined
261260 * in different compilation units under Scala2. If set, and the
262261 * previous and new contexts do not have the same scope, we select
263262 * the previous (inner) definition. This models what scalac does.
264263 */
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 =
267265 if ! previous.exists || TypeComparer .isSameRef(previous, found) then
268- newResult
266+ found
269267 else if (prevCtx.scope eq ctx.scope) && newPrec.beats(prevPrec) then
270268 // special cases: definitions beat imports, and named imports beat
271269 // 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
273277 else
274278 if ! scala2pkg && ! previous.isError && ! found.isError then
275279 fail(AmbiguousReference (name, newPrec, prevPrec, prevCtx,
276280 isExtension = previous.termSymbol.is(ExtensionMethod ) && found.termSymbol.is(ExtensionMethod )))
277- prevResult
281+ previous
278282
279283 /** Assemble and check alternatives to an imported reference. This implies:
280284 * - If we expand an extension method (i.e. altImports != null),
@@ -287,13 +291,12 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
287291 * shadowed. This order of checking is necessary since an outer package-level
288292 * definition might trump two conflicting inner imports, so no error should be
289293 * 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)
292296 * @param prevCtx the context in which the reference was found
293297 * @param using_Context the outer context of `precCtx`
294298 */
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 =
297300
298301 def addAltImport (altImp : TermRef ) =
299302 if ! TypeComparer .isSameRef(previous, altImp)
@@ -308,20 +311,20 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
308311 if prevPrec == WildImport then
309312 // Discard all previously found references and continue with `altImp`
310313 altImports.clear()
311- checkImportAlternatives(( altImp, NamedImport ) , ctx)(using ctx.outer)
314+ checkImportAlternatives(altImp, NamedImport , ctx)(using ctx.outer)
312315 else
313316 addAltImport(altImp)
314- checkImportAlternatives(prevResult , prevCtx)(using ctx.outer)
317+ checkImportAlternatives(previous, prevPrec , prevCtx)(using ctx.outer)
315318 case _ =>
316319 if prevPrec == WildImport then
317320 wildImportRef(curImport) match
318321 case altImp : TermRef => addAltImport(altImp)
319322 case _ =>
320- checkImportAlternatives(prevResult , prevCtx)(using ctx.outer)
323+ checkImportAlternatives(previous, prevPrec , prevCtx)(using ctx.outer)
321324 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
325328 end checkImportAlternatives
326329
327330 def selection (imp : ImportInfo , name : Name , checkBounds : Boolean ): Type =
@@ -411,10 +414,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
411414 ! noImports &&
412415 (prevPrec.ordinal < prec.ordinal || prevPrec == prec && (prevCtx.scope eq ctx.scope))
413416
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
416419 else {
417- var result : Result = NoResult
420+ var result : Type = NoType
418421 val curOwner = ctx.owner
419422
420423 /** Is curOwner a package object that should be skipped?
@@ -513,36 +516,37 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
513516 effectiveOwner.thisType.select(name, defDenot).makePackageObjPrefixExplicit
514517 }
515518 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
517520 found match
518521 case found : NamedType
519522 if curOwner.isClass && isInherited(found.denot) && ! ctx.compilationUnit.isJava =>
520523 checkNoOuterDefs(found.denot, ctx, ctx)
521524 case _ =>
522525 else
523526 if migrateTo3 && ! foundUnderScala2.exists then
524- foundUnderScala2 = checkNewOrShadowed(( found, Definition ) , scala2pkg = true )._1
527+ foundUnderScala2 = checkNewOrShadowed(found, Definition , scala2pkg = true )
525528 if (defDenot.symbol.is(Package ))
526- result = checkNewOrShadowed(( previous orElse found, PackageClause ) )
529+ result = checkNewOrShadowed(previous orElse found, PackageClause )
527530 else if (prevPrec.ordinal < PackageClause .ordinal)
528- result = findRefRecur(( found, PackageClause ) , ctx)(using ctx.outer)
531+ result = findRefRecur(found, PackageClause , ctx)(using ctx.outer)
529532 }
530533
531- if result._1. exists then result
534+ if result.exists then result
532535 else { // find import
533536 val outer = ctx.outer
534537 val curImport = ctx.importInfo
538+ def updateUnimported () =
539+ if (curImport.nn.unimported ne NoSymbol ) unimported += curImport.nn.unimported
535540 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)
540544 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 )
544548 if (wildImp.exists)
545- checkImportAlternatives(( wildImp, WildImport ) , ctx)(using outer)
549+ checkImportAlternatives(wildImp, WildImport , ctx)(using outer)
546550 else {
547551 updateUnimported()
548552 loop(ctx)(using outer)
@@ -561,8 +565,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
561565 loop(NoContext )
562566 }
563567
564- val (foundRef, foundPrec) = findRefRecur(NoResult , NoContext )
565- foundRef
568+ findRefRecur(NoType , BindingPrec .NothingBound , NoContext )
566569 }
567570
568571 /** If `tree`'s type is a `TermRef` identified by flow typing to be non-null, then
0 commit comments