@@ -52,9 +52,14 @@ import Nullables._
52
52
import NullOpsDecorator ._
53
53
import cc .CheckCaptures
54
54
import config .Config
55
+ import java .io .File
55
56
56
57
import scala .annotation .constructorOnly
57
58
import 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
58
63
59
64
object Typer {
60
65
@@ -67,6 +72,32 @@ object Typer {
67
72
def isImportPrec = this == NamedImport || this == WildImport
68
73
}
69
74
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
+
70
101
/** Assert tree has a position, unless it is empty or a typed splice */
71
102
def assertPositioned (tree : untpd.Tree )(using Context ): Unit =
72
103
if (! tree.isEmpty && ! tree.isInstanceOf [untpd.TypedSplice ] && ctx.typerState.isGlobalCommittable)
@@ -166,7 +197,22 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
166
197
* a reference for `m` is searched. `null` in all other situations.
167
198
*/
168
199
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 = {
170
216
val refctx = ctx
171
217
val noImports = ctx.mode.is(Mode .InPackageClauseName )
172
218
def suppressErrors = excluded.is(ConstructorProxy )
@@ -211,7 +257,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
211
257
* @param prevCtx The context of the previous denotation,
212
258
* or else `NoContext` if nothing was found yet.
213
259
*/
214
- def findRefRecur (previous : Type , prevPrec : BindingPrec , prevCtx : Context )(using Context ): Type = {
260
+ def findRefRecur (previous : TypeResolution , prevCtx : Context )(using Context ): TypeResolution = {
215
261
import BindingPrec ._
216
262
217
263
/** Check that any previously found result from an inner context
@@ -223,18 +269,18 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
223
269
* previous and new contexts do not have the same scope, we select
224
270
* the previous (inner) definition. This models what scalac does.
225
271
*/
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
228
274
found
229
275
else if (prevCtx.scope eq ctx.scope)
230
- && (newPrec == Definition || newPrec == NamedImport && prevPrec == WildImport )
276
+ && (found.prec == Definition || found.prec == NamedImport && previous.prec == WildImport )
231
277
then
232
278
// special cases: definitions beat imports, and named imports beat
233
279
// wildcard imports, provided both are in contexts with same scope
234
280
found
235
281
else
236
282
if ! scala2pkg && ! previous.isError && ! found.isError then
237
- fail(AmbiguousReference (name, newPrec, prevPrec , prevCtx))
283
+ fail(AmbiguousReference (name, found.prec, previous.prec , prevCtx))
238
284
previous
239
285
240
286
/** Assemble and check alternatives to an imported reference. This implies:
@@ -253,10 +299,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
253
299
* @param prevCtx the context in which the reference was found
254
300
* @param using_Context the outer context of `precCtx`
255
301
*/
256
- def checkImportAlternatives (previous : Type , prevPrec : BindingPrec , prevCtx : Context )(using Context ): Type =
302
+ def checkImportAlternatives (previous : TypeResolution , prevCtx : Context )(using Context ): TypeResolution =
257
303
258
304
def addAltImport (altImp : TermRef ) =
259
- if ! TypeComparer .isSameRef(previous, altImp)
305
+ if ! TypeComparer .isSameRef(previous.result , altImp)
260
306
&& ! altImports.uncheckedNN.exists(TypeComparer .isSameRef(_, altImp))
261
307
then
262
308
altImports.uncheckedNN += altImp
@@ -265,22 +311,22 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
265
311
val curImport = ctx.importInfo.uncheckedNN
266
312
namedImportRef(curImport) match
267
313
case altImp : TermRef =>
268
- if prevPrec == WildImport then
314
+ if previous.prec == WildImport then
269
315
// Discard all previously found references and continue with `altImp`
270
316
altImports.clear()
271
- checkImportAlternatives(altImp, NamedImport , ctx)(using ctx.outer)
317
+ checkImportAlternatives(NamedImportedType ( altImp, curImport) , ctx)(using ctx.outer)
272
318
else
273
319
addAltImport(altImp)
274
- checkImportAlternatives(previous, prevPrec, prevCtx)(using ctx.outer)
320
+ checkImportAlternatives(previous, prevCtx)(using ctx.outer)
275
321
case _ =>
276
- if prevPrec == WildImport then
322
+ if previous.prec == WildImport then
277
323
wildImportRef(curImport) match
278
324
case altImp : TermRef => addAltImport(altImp)
279
325
case _ =>
280
- checkImportAlternatives(previous, prevPrec, prevCtx)(using ctx.outer)
326
+ checkImportAlternatives(previous, prevCtx)(using ctx.outer)
281
327
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)
284
330
else found
285
331
end checkImportAlternatives
286
332
@@ -369,12 +415,12 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
369
415
/** Would import of kind `prec` be not shadowed by a nested higher-precedence definition? */
370
416
def isPossibleImport (prec : BindingPrec )(using Context ) =
371
417
! 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))
373
419
374
- @ tailrec def loop (lastCtx : Context )(using Context ): Type =
420
+ @ tailrec def loop (lastCtx : Context )(using Context ): TypeResolution =
375
421
if (ctx.scope eq EmptyScope ) previous
376
422
else {
377
- var result : Type = NoType
423
+ var result : TypeResolution = NoTypeResolution
378
424
val curOwner = ctx.owner
379
425
380
426
/** Is curOwner a package object that should be skipped?
@@ -469,19 +515,19 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
469
515
effectiveOwner.thisType.select(name, defDenot)
470
516
}
471
517
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
473
519
found match
474
520
case found : NamedType
475
521
if curOwner.isClass && isInherited(found.denot) && ! ctx.compilationUnit.isJava =>
476
522
checkNoOuterDefs(found.denot, ctx, ctx)
477
523
case _ =>
478
524
else
479
525
if migrateTo3 && ! foundUnderScala2.exists then
480
- foundUnderScala2 = checkNewOrShadowed(found, Definition , scala2pkg = true )
526
+ foundUnderScala2 = checkNewOrShadowed(DefinitionType ( found), scala2pkg = true ).result
481
527
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)
485
531
}
486
532
487
533
if result.exists then result
@@ -493,13 +539,14 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
493
539
if (curOwner.is(Package ) && curImport != null && curImport.isRootImport && previous.exists)
494
540
previous // no more conflicts possible in this case
495
541
else if (isPossibleImport(NamedImport ) && (curImport nen outer.importInfo)) {
496
- val namedImp = namedImportRef(curImport.uncheckedNN)
542
+ val curImportNN = curImport.uncheckedNN
543
+ val namedImp = namedImportRef(curImportNN)
497
544
if (namedImp.exists)
498
- checkImportAlternatives(namedImp, NamedImport , ctx)(using outer)
545
+ checkImportAlternatives(NamedImportedType ( namedImp, curImportNN) , ctx)(using outer)
499
546
else if (isPossibleImport(WildImport ) && ! curImport.nn.importSym.isCompleting) {
500
- val wildImp = wildImportRef(curImport.uncheckedNN )
547
+ val wildImp = wildImportRef(curImportNN )
501
548
if (wildImp.exists)
502
- checkImportAlternatives(wildImp, WildImport , ctx)(using outer)
549
+ checkImportAlternatives(WildImportedType ( wildImp, curImportNN) , ctx)(using outer)
503
550
else {
504
551
updateUnimported()
505
552
loop(ctx)(using outer)
@@ -518,7 +565,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
518
565
loop(NoContext )
519
566
}
520
567
521
- findRefRecur(NoType , BindingPrec . NothingBound , NoContext )
568
+ findRefRecur(NoTypeResolution , NoContext )
522
569
}
523
570
524
571
/** 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
573
620
checkLegalValue(tree2, pt)
574
621
return tree2
575
622
576
- val rawType =
623
+ val ( rawType, directlyImported) =
577
624
val saved1 = unimported
578
625
val saved2 = foundUnderScala2
579
626
unimported = Set .empty
580
627
foundUnderScala2 = NoType
581
628
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
584
631
report.migrationWarning(
585
632
em """ Name resolution will change.
586
633
| 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 )
590
637
finally
591
638
unimported = saved1
592
639
foundUnderScala2 = saved2
@@ -618,10 +665,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
618
665
case _ =>
619
666
ownType
620
667
621
- def setType (ownType : Type ): Tree =
668
+ def setType (ownType : Type , directlyImported : Boolean ): Tree =
622
669
val checkedType = checkNotShadowed(ownType)
623
670
val tree1 = checkedType match
624
- case checkedType : NamedType if ! prefixIsElidable(checkedType) =>
671
+ case checkedType : NamedType if ! prefixIsElidable(checkedType) && ! directlyImported =>
625
672
ref(checkedType).withSpan(tree.span)
626
673
case _ =>
627
674
tree.withType(checkedType)
@@ -649,13 +696,13 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
649
696
val selection = untpd.cpy.Select (tree)(qualifier, name)
650
697
typed(selection, pt)
651
698
else if rawType.exists then
652
- setType(ensureAccessible(rawType, superAccess = false , tree.srcPos))
699
+ setType(ensureAccessible(rawType, superAccess = false , tree.srcPos), directlyImported )
653
700
else if name == nme._scope then
654
701
// gross hack to support current xml literals.
655
702
// awaiting a better implicits based solution for library-supported xml
656
703
ref(defn.XMLTopScopeModule .termRef)
657
704
else if name.toTermName == nme.ERROR then
658
- setType(UnspecifiedErrorType )
705
+ setType(UnspecifiedErrorType , false )
659
706
else if ctx.owner.isConstructor && ! ctx.owner.isPrimaryConstructor
660
707
&& ctx.owner.owner.unforcedDecls.lookup(tree.name).exists
661
708
then // we are in the arguments of a this(...) constructor call
0 commit comments