@@ -52,9 +52,14 @@ import Nullables._
5252import NullOpsDecorator ._
5353import cc .CheckCaptures
5454import config .Config
55+ import java .io .File
5556
5657import scala .annotation .constructorOnly
5758import dotty .tools .dotc .rewrites .Rewrites
59+ import java .nio .file .Files
60+ import java .nio .file .Path
61+ import java .nio .file .Paths
62+ import java .nio .file .StandardOpenOption
5863
5964object Typer {
6065
@@ -67,6 +72,32 @@ object Typer {
6772 def isImportPrec = this == NamedImport || this == WildImport
6873 }
6974
75+
76+ sealed trait TypeResolution :
77+ def result : Type
78+ def exists = result.exists
79+ def isError (using Context ) = result.isError
80+ def prec : BindingPrec
81+
82+ import BindingPrec ._
83+ case object NoTypeResolution extends TypeResolution :
84+ def result = NoType
85+ def prec = NothingBound
86+
87+ case class NamedImportedType (result : Type , from : ImportInfo ) extends TypeResolution :
88+ def prec = NamedImport
89+
90+ case class WildImportedType (result : Type , from : ImportInfo ) extends TypeResolution :
91+ def prec = WildImport
92+
93+ case class DefinitionType (result : Type ) extends TypeResolution :
94+ def prec = Definition
95+
96+ case class PackageClauseType (result : Type ) extends TypeResolution :
97+ def prec = PackageClause
98+
99+
100+
70101 /** Assert tree has a position, unless it is empty or a typed splice */
71102 def assertPositioned (tree : untpd.Tree )(using Context ): Unit =
72103 if (! tree.isEmpty && ! tree.isInstanceOf [untpd.TypedSplice ] && ctx.typerState.isGlobalCommittable)
@@ -166,7 +197,22 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
166197 * a reference for `m` is searched. `null` in all other situations.
167198 */
168199 def findRef (name : Name , pt : Type , required : FlagSet , excluded : FlagSet , pos : SrcPos ,
169- altImports : mutable.ListBuffer [TermRef ] | Null = null )(using Context ): Type = {
200+ altImports : mutable.ListBuffer [TermRef ] | Null = null )(using Context ): Type =
201+ findRefResolution(name, pt, required, excluded, pos, altImports).result
202+
203+ /** Find the type of an identifier with given `name` in given context `ctx`.
204+ * @param name the name of the identifier
205+ * @param pt the expected type
206+ * @param required flags the result's symbol must have
207+ * @param excluded flags the result's symbol must not have
208+ * @param pos indicates position to use for error reporting
209+ * @param altImports a ListBuffer in which alternative imported references are
210+ * collected in case `findRef` is called from an expansion of
211+ * an extension method, i.e. when `e.m` is expanded to `m(e)` and
212+ * a reference for `m` is searched. `null` in all other situations.
213+ */
214+ def findRefResolution (name : Name , pt : Type , required : FlagSet , excluded : FlagSet , pos : SrcPos ,
215+ altImports : mutable.ListBuffer [TermRef ] | Null = null )(using Context ): TypeResolution = {
170216 val refctx = ctx
171217 val noImports = ctx.mode.is(Mode .InPackageClauseName )
172218 def suppressErrors = excluded.is(ConstructorProxy )
@@ -211,7 +257,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
211257 * @param prevCtx The context of the previous denotation,
212258 * or else `NoContext` if nothing was found yet.
213259 */
214- def findRefRecur (previous : Type , prevPrec : BindingPrec , prevCtx : Context )(using Context ): Type = {
260+ def findRefRecur (previous : TypeResolution , prevCtx : Context )(using Context ): TypeResolution = {
215261 import BindingPrec ._
216262
217263 /** Check that any previously found result from an inner context
@@ -223,18 +269,18 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
223269 * previous and new contexts do not have the same scope, we select
224270 * the previous (inner) definition. This models what scalac does.
225271 */
226- def checkNewOrShadowed (found : Type , newPrec : BindingPrec , scala2pkg : Boolean = false )(using Context ): Type =
227- if ! previous.exists || TypeComparer .isSameRef(previous, found) then
272+ def checkNewOrShadowed (found : TypeResolution , scala2pkg : Boolean = false )(using Context ): TypeResolution =
273+ if ! previous.exists || TypeComparer .isSameRef(previous.result , found.result ) then
228274 found
229275 else if (prevCtx.scope eq ctx.scope)
230- && (newPrec == Definition || newPrec == NamedImport && prevPrec == WildImport )
276+ && (found.prec == Definition || found.prec == NamedImport && previous.prec == WildImport )
231277 then
232278 // special cases: definitions beat imports, and named imports beat
233279 // wildcard imports, provided both are in contexts with same scope
234280 found
235281 else
236282 if ! scala2pkg && ! previous.isError && ! found.isError then
237- fail(AmbiguousReference (name, newPrec, prevPrec , prevCtx))
283+ fail(AmbiguousReference (name, found.prec, previous.prec , prevCtx))
238284 previous
239285
240286 /** Assemble and check alternatives to an imported reference. This implies:
@@ -253,10 +299,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
253299 * @param prevCtx the context in which the reference was found
254300 * @param using_Context the outer context of `precCtx`
255301 */
256- def checkImportAlternatives (previous : Type , prevPrec : BindingPrec , prevCtx : Context )(using Context ): Type =
302+ def checkImportAlternatives (previous : TypeResolution , prevCtx : Context )(using Context ): TypeResolution =
257303
258304 def addAltImport (altImp : TermRef ) =
259- if ! TypeComparer .isSameRef(previous, altImp)
305+ if ! TypeComparer .isSameRef(previous.result , altImp)
260306 && ! altImports.uncheckedNN.exists(TypeComparer .isSameRef(_, altImp))
261307 then
262308 altImports.uncheckedNN += altImp
@@ -265,22 +311,22 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
265311 val curImport = ctx.importInfo.uncheckedNN
266312 namedImportRef(curImport) match
267313 case altImp : TermRef =>
268- if prevPrec == WildImport then
314+ if previous.prec == WildImport then
269315 // Discard all previously found references and continue with `altImp`
270316 altImports.clear()
271- checkImportAlternatives(altImp, NamedImport , ctx)(using ctx.outer)
317+ checkImportAlternatives(NamedImportedType ( altImp, curImport) , ctx)(using ctx.outer)
272318 else
273319 addAltImport(altImp)
274- checkImportAlternatives(previous, prevPrec, prevCtx)(using ctx.outer)
320+ checkImportAlternatives(previous, prevCtx)(using ctx.outer)
275321 case _ =>
276- if prevPrec == WildImport then
322+ if previous.prec == WildImport then
277323 wildImportRef(curImport) match
278324 case altImp : TermRef => addAltImport(altImp)
279325 case _ =>
280- checkImportAlternatives(previous, prevPrec, prevCtx)(using ctx.outer)
326+ checkImportAlternatives(previous, prevCtx)(using ctx.outer)
281327 else
282- val found = findRefRecur(previous, prevPrec, prevCtx)
283- if found eq previous then checkNewOrShadowed(found, prevPrec )(using prevCtx)
328+ val found = findRefRecur(previous, prevCtx)
329+ if found eq previous then checkNewOrShadowed(previous )(using prevCtx)
284330 else found
285331 end checkImportAlternatives
286332
@@ -369,12 +415,12 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
369415 /** Would import of kind `prec` be not shadowed by a nested higher-precedence definition? */
370416 def isPossibleImport (prec : BindingPrec )(using Context ) =
371417 ! noImports &&
372- (prevPrec. ordinal < prec.ordinal || prevPrec == prec && (prevCtx.scope eq ctx.scope))
418+ (previous.prec. ordinal < prec.ordinal || previous.prec == prec && (prevCtx.scope eq ctx.scope))
373419
374- @ tailrec def loop (lastCtx : Context )(using Context ): Type =
420+ @ tailrec def loop (lastCtx : Context )(using Context ): TypeResolution =
375421 if (ctx.scope eq EmptyScope ) previous
376422 else {
377- var result : Type = NoType
423+ var result : TypeResolution = NoTypeResolution
378424 val curOwner = ctx.owner
379425
380426 /** Is curOwner a package object that should be skipped?
@@ -469,19 +515,19 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
469515 effectiveOwner.thisType.select(name, defDenot)
470516 }
471517 if ! curOwner.is(Package ) || isDefinedInCurrentUnit(defDenot) then
472- result = checkNewOrShadowed(found, Definition ) // no need to go further out, we found highest prec entry
518+ result = checkNewOrShadowed(DefinitionType ( found) ) // no need to go further out, we found highest prec entry
473519 found match
474520 case found : NamedType
475521 if curOwner.isClass && isInherited(found.denot) && ! ctx.compilationUnit.isJava =>
476522 checkNoOuterDefs(found.denot, ctx, ctx)
477523 case _ =>
478524 else
479525 if migrateTo3 && ! foundUnderScala2.exists then
480- foundUnderScala2 = checkNewOrShadowed(found, Definition , scala2pkg = true )
526+ foundUnderScala2 = checkNewOrShadowed(DefinitionType ( found), scala2pkg = true ).result
481527 if (defDenot.symbol.is(Package ))
482- result = checkNewOrShadowed(previous orElse found, PackageClause )
483- else if (prevPrec .ordinal < PackageClause .ordinal)
484- result = findRefRecur(found, PackageClause , ctx)(using ctx.outer)
528+ result = checkNewOrShadowed(PackageClauseType ( previous.result orElse found) )
529+ else if (previous.prec .ordinal < PackageClause .ordinal)
530+ result = findRefRecur(PackageClauseType ( found) , ctx)(using ctx.outer)
485531 }
486532
487533 if result.exists then result
@@ -493,13 +539,14 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
493539 if (curOwner.is(Package ) && curImport != null && curImport.isRootImport && previous.exists)
494540 previous // no more conflicts possible in this case
495541 else if (isPossibleImport(NamedImport ) && (curImport nen outer.importInfo)) {
496- val namedImp = namedImportRef(curImport.uncheckedNN)
542+ val curImportNN = curImport.uncheckedNN
543+ val namedImp = namedImportRef(curImportNN)
497544 if (namedImp.exists)
498- checkImportAlternatives(namedImp, NamedImport , ctx)(using outer)
545+ checkImportAlternatives(NamedImportedType ( namedImp, curImportNN) , ctx)(using outer)
499546 else if (isPossibleImport(WildImport ) && ! curImport.nn.importSym.isCompleting) {
500- val wildImp = wildImportRef(curImport.uncheckedNN )
547+ val wildImp = wildImportRef(curImportNN )
501548 if (wildImp.exists)
502- checkImportAlternatives(wildImp, WildImport , ctx)(using outer)
549+ checkImportAlternatives(WildImportedType ( wildImp, curImportNN) , ctx)(using outer)
503550 else {
504551 updateUnimported()
505552 loop(ctx)(using outer)
@@ -518,7 +565,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
518565 loop(NoContext )
519566 }
520567
521- findRefRecur(NoType , BindingPrec . NothingBound , NoContext )
568+ findRefRecur(NoTypeResolution , NoContext )
522569 }
523570
524571 /** If `tree`'s type is a `TermRef` identified by flow typing to be non-null, then
@@ -573,20 +620,20 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
573620 checkLegalValue(tree2, pt)
574621 return tree2
575622
576- val rawType =
623+ val ( rawType, directlyImported) =
577624 val saved1 = unimported
578625 val saved2 = foundUnderScala2
579626 unimported = Set .empty
580627 foundUnderScala2 = NoType
581628 try
582- val found = findRef (name, pt, EmptyFlags , EmptyFlags , tree.srcPos)
583- if foundUnderScala2.exists && ! (foundUnderScala2 =:= found) then
629+ val found = findRefResolution (name, pt, EmptyFlags , EmptyFlags , tree.srcPos)
630+ if foundUnderScala2.exists && ! (foundUnderScala2 =:= found.result ) then
584631 report.migrationWarning(
585632 em """ Name resolution will change.
586633 | currently selected : $foundUnderScala2
587- | in the future, without -source 3.0-migration: $found""" , tree.srcPos)
588- foundUnderScala2
589- else found
634+ | in the future, without -source 3.0-migration: ${ found.result} """ , tree.srcPos)
635+ ( foundUnderScala2, false )
636+ else ( found.result, found.prec == BindingPrec . NamedImport )
590637 finally
591638 unimported = saved1
592639 foundUnderScala2 = saved2
@@ -618,10 +665,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
618665 case _ =>
619666 ownType
620667
621- def setType (ownType : Type ): Tree =
668+ def setType (ownType : Type , directlyImported : Boolean ): Tree =
622669 val checkedType = checkNotShadowed(ownType)
623670 val tree1 = checkedType match
624- case checkedType : NamedType if ! prefixIsElidable(checkedType) =>
671+ case checkedType : NamedType if ! prefixIsElidable(checkedType) && ! directlyImported =>
625672 ref(checkedType).withSpan(tree.span)
626673 case _ =>
627674 tree.withType(checkedType)
@@ -649,13 +696,13 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
649696 val selection = untpd.cpy.Select (tree)(qualifier, name)
650697 typed(selection, pt)
651698 else if rawType.exists then
652- setType(ensureAccessible(rawType, superAccess = false , tree.srcPos))
699+ setType(ensureAccessible(rawType, superAccess = false , tree.srcPos), directlyImported )
653700 else if name == nme._scope then
654701 // gross hack to support current xml literals.
655702 // awaiting a better implicits based solution for library-supported xml
656703 ref(defn.XMLTopScopeModule .termRef)
657704 else if name.toTermName == nme.ERROR then
658- setType(UnspecifiedErrorType )
705+ setType(UnspecifiedErrorType , false )
659706 else if ctx.owner.isConstructor && ! ctx.owner.isPrimaryConstructor
660707 && ctx.owner.owner.unforcedDecls.lookup(tree.name).exists
661708 then // we are in the arguments of a this(...) constructor call
0 commit comments