aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/dotc/ast/TreeTypeMap.scala3
-rw-r--r--src/dotty/tools/dotc/config/ScalaSettings.scala12
-rw-r--r--src/dotty/tools/dotc/core/Flags.scala2
-rw-r--r--src/dotty/tools/dotc/core/Hashable.scala4
-rw-r--r--src/dotty/tools/dotc/core/Types.scala2
-rw-r--r--src/dotty/tools/dotc/transform/Constructors.scala14
-rw-r--r--src/dotty/tools/dotc/transform/ExpandPrivate.scala5
-rw-r--r--src/dotty/tools/dotc/transform/ExplicitOuter.scala41
-rw-r--r--src/dotty/tools/dotc/transform/FirstTransform.scala2
-rw-r--r--src/dotty/tools/dotc/transform/Mixin.scala36
-rw-r--r--src/dotty/tools/dotc/transform/PostTyper.scala9
-rw-r--r--src/dotty/tools/dotc/transform/TreeChecker.scala5
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala55
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala3
14 files changed, 111 insertions, 82 deletions
diff --git a/src/dotty/tools/dotc/ast/TreeTypeMap.scala b/src/dotty/tools/dotc/ast/TreeTypeMap.scala
index d714a3d21..a35fe2e8f 100644
--- a/src/dotty/tools/dotc/ast/TreeTypeMap.scala
+++ b/src/dotty/tools/dotc/ast/TreeTypeMap.scala
@@ -82,7 +82,8 @@ final class TreeTypeMap(
constr = tmap.transformSub(constr),
parents = parents mapconserve transform,
self = tmap.transformSub(self),
- body = impl.body mapconserve tmap.transform
+ body = impl.body mapconserve
+ (tmap.transform(_)(ctx.withOwner(mapOwner(impl.symbol.owner))))
).withType(tmap.mapType(impl.tpe))
case tree1 =>
tree1.withType(mapType(tree1.tpe)) match {
diff --git a/src/dotty/tools/dotc/config/ScalaSettings.scala b/src/dotty/tools/dotc/config/ScalaSettings.scala
index aa264329c..b1d53c90d 100644
--- a/src/dotty/tools/dotc/config/ScalaSettings.scala
+++ b/src/dotty/tools/dotc/config/ScalaSettings.scala
@@ -105,10 +105,10 @@ class ScalaSettings extends Settings.SettingGroup {
val YcheckMods = BooleanSetting("-Ycheck-mods", "Check that symbols and their defining trees have modifiers in sync")
val YcheckTypedTrees = BooleanSetting("-YcheckTypedTrees", "Check all constructured typed trees for type correctness")
val Yshow = PhasesSetting("-Yshow", "(Requires -Xshow-class or -Xshow-object) Show after")
- val Xcloselim = BooleanSetting("-Yclosure-elim", "Perform closure elimination.")
+ val Ycloselim = BooleanSetting("-Yclosure-elim", "Perform closure elimination.")
val Ycompacttrees = BooleanSetting("-Ycompact-trees", "Use compact tree printer when displaying trees.")
val noCompletion = BooleanSetting("-Yno-completion", "Disable tab-completion in the REPL.")
- val Xdce = BooleanSetting("-Ydead-code", "Perform dead code elimination.")
+ val Ydce = BooleanSetting("-Ydead-code", "Perform dead code elimination.")
val debug = BooleanSetting("-Ydebug", "Increase the quantity of debugging output.")
val debugNames = BooleanSetting("-YdebugNames", "Show name-space indicators when printing names")
val debugTrace = BooleanSetting("-Ydebug-trace", "Trace core operations")
@@ -119,7 +119,7 @@ class ScalaSettings extends Settings.SettingGroup {
val inline = BooleanSetting("-Yinline", "Perform inlining when possible.")
val inlineHandlers = BooleanSetting("-Yinline-handlers", "Perform exception handler inlining when possible.")
val YinlinerWarnings = BooleanSetting("-Yinline-warnings", "Emit inlining warnings. (Normally surpressed due to high volume)")
- val Xlinearizer = ChoiceSetting("-Ylinearizer", "which", "Linearizer to use", List("normal", "dfs", "rpo", "dump"), "rpo")
+ val Ylinearizer = ChoiceSetting("-Ylinearizer", "which", "Linearizer to use", List("normal", "dfs", "rpo", "dump"), "rpo")
val log = PhasesSetting("-Ylog", "Log operations during")
val Ylogcp = BooleanSetting("-Ylog-classpath", "Output information about what classpath is being applied.")
val Ynogenericsig = BooleanSetting("-Yno-generic-signatures", "Suppress generation of generic signatures for Java.")
@@ -127,9 +127,9 @@ class ScalaSettings extends Settings.SettingGroup {
val nopredef = BooleanSetting("-Yno-predef", "Compile without importing Predef.")
val noAdaptedArgs = BooleanSetting("-Yno-adapted-args", "Do not adapt an argument list (either by inserting () or creating a tuple) to match the receiver.")
val selfInAnnots = BooleanSetting("-Yself-in-annots", "Include a \"self\" identifier inside of annotations.")
- val Xshowtrees = BooleanSetting("-Yshow-trees", "(Requires -Xprint:) Print detailed ASTs in formatted form.")
- val XshowtreesCompact = BooleanSetting("-Yshow-trees-compact", "(Requires -Xprint:) Print detailed ASTs in compact form.")
- val XshowtreesStringified = BooleanSetting("-Yshow-trees-stringified", "(Requires -Xprint:) Print stringifications along with detailed ASTs.")
+ val Yshowtrees = BooleanSetting("-Yshow-trees", "(Requires -Xprint:) Print detailed ASTs in formatted form.")
+ val YshowtreesCompact = BooleanSetting("-Yshow-trees-compact", "(Requires -Xprint:) Print detailed ASTs in compact form.")
+ val YshowtreesStringified = BooleanSetting("-Yshow-trees-stringified", "(Requires -Xprint:) Print stringifications along with detailed ASTs.")
val Yshowsyms = BooleanSetting("-Yshow-syms", "Print the AST symbol hierarchy after each phase.")
val Yshowsymkinds = BooleanSetting("-Yshow-symkinds", "Print abbreviated symbol kinds next to symbol names.")
val Yskip = PhasesSetting("-Yskip", "Skip")
diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala
index ebf4c637a..f866621f2 100644
--- a/src/dotty/tools/dotc/core/Flags.scala
+++ b/src/dotty/tools/dotc/core/Flags.scala
@@ -448,7 +448,7 @@ object Flags {
final val FromStartFlags =
AccessFlags | Module | Package | Deferred | Final | MethodOrHKCommon | Param | ParamAccessor | Scala2ExistentialCommon |
InSuperCall | Touched | JavaStatic | CovariantOrOuter | ContravariantOrLabel | ExpandedName | AccessorOrSealed |
- CaseAccessorOrBaseTypeArg | Fresh | Frozen | Erroneous | ImplicitCommon | Permanent |
+ CaseAccessorOrBaseTypeArg | Fresh | Frozen | Erroneous | ImplicitCommon | Permanent | Synthetic |
LazyOrTrait | SuperAccessorOrScala2x | SelfNameOrImplClass
assert(FromStartFlags.isTermFlags && FromStartFlags.isTypeFlags)
diff --git a/src/dotty/tools/dotc/core/Hashable.scala b/src/dotty/tools/dotc/core/Hashable.scala
index 6a64f8655..12a408fbd 100644
--- a/src/dotty/tools/dotc/core/Hashable.scala
+++ b/src/dotty/tools/dotc/core/Hashable.scala
@@ -92,7 +92,9 @@ trait Hashable {
protected final def doHash(x1: Int, x2: Int): Int =
finishHash(hashing.mix(hashing.mix(hashSeed, x1), x2), 1)
- protected final def addDelta(hc: Int, delta: Int) = avoidNotCached(hc + delta)
+ protected final def addDelta(elemHash: Int, delta: Int) =
+ if (elemHash == NotCached) NotCached
+ else avoidNotCached(elemHash + delta)
private def avoidNotCached(h: Int) = if (h == NotCached) NotCachedAlt else h
}
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index dd12a0188..17c2ec4ca 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -2479,7 +2479,7 @@ object Types {
def copyBoundType(bt: BT) = new MethodParamImpl(bt, paramNum)
// need to customize hashCode and equals to prevent infinite recursion for dep meth types.
- override def computeHash = addDelta(System.identityHashCode(binder), paramNum)
+ override def computeHash = addDelta(binder.identityHash, paramNum)
override def equals(that: Any) = that match {
case that: MethodParam =>
(this.binder eq that.binder) && this.paramNum == that.paramNum
diff --git a/src/dotty/tools/dotc/transform/Constructors.scala b/src/dotty/tools/dotc/transform/Constructors.scala
index b6ebd7d90..44638ce48 100644
--- a/src/dotty/tools/dotc/transform/Constructors.scala
+++ b/src/dotty/tools/dotc/transform/Constructors.scala
@@ -26,7 +26,7 @@ import collection.mutable
* - also moves private fields that are accessed only from constructor
* into the constructor if possible.
*/
-class Constructors extends MiniPhaseTransform with SymTransformer { thisTransform =>
+class Constructors extends MiniPhaseTransform with IdentityDenotTransformer { thisTransform =>
import tpd._
override def phaseName: String = "constructors"
@@ -99,18 +99,6 @@ class Constructors extends MiniPhaseTransform with SymTransformer { thisTransfor
}
}
- /** Symbols that are owned by either <local dummy> or a class field move into the
- * primary constructor.
- */
- override def transformSym(sym: SymDenotation)(implicit ctx: Context): SymDenotation = {
- def ownerBecomesConstructor(owner: Symbol): Boolean =
- (owner.isLocalDummy || owner.isTerm && !owner.is(MethodOrLazy)) &&
- owner.owner.isClass
- if (ownerBecomesConstructor(sym.owner))
- sym.copySymDenotation(owner = sym.owner.enclosingClass.primaryConstructor)
- else sym
- }
-
/** @return true if after ExplicitOuter, all references from this tree go via an
* outer link, so no parameter accessors need to be rewired to parameters
*/
diff --git a/src/dotty/tools/dotc/transform/ExpandPrivate.scala b/src/dotty/tools/dotc/transform/ExpandPrivate.scala
index f44be3958..a6f203478 100644
--- a/src/dotty/tools/dotc/transform/ExpandPrivate.scala
+++ b/src/dotty/tools/dotc/transform/ExpandPrivate.scala
@@ -57,8 +57,11 @@ class ExpandPrivate extends MiniPhaseTransform with IdentityDenotTransformer { t
* static members of the companion class, we should tighten the condition below.
*/
private def ensurePrivateAccessible(d: SymDenotation)(implicit ctx: Context) =
- if (d.is(PrivateTerm) && d.owner != ctx.owner.enclosingClass)
+ if (d.is(PrivateTerm) && d.owner != ctx.owner.enclosingClass) {
+ assert(d.symbol.sourceFile == ctx.source.file,
+ i"private ${d.symbol.showLocated} in ${d.symbol.sourceFile} accessed from ${ctx.owner.showLocated} in ${ctx.source.file}")
d.ensureNotPrivate.installAfter(thisTransform)
+ }
override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo) = {
ensurePrivateAccessible(tree.symbol)
diff --git a/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/src/dotty/tools/dotc/transform/ExplicitOuter.scala
index 4cf076c45..9170cd277 100644
--- a/src/dotty/tools/dotc/transform/ExplicitOuter.scala
+++ b/src/dotty/tools/dotc/transform/ExplicitOuter.scala
@@ -212,27 +212,34 @@ object ExplicitOuter {
/** Tree references an outer class of `cls` which is not a static owner.
*/
def referencesOuter(cls: Symbol, tree: Tree)(implicit ctx: Context): Boolean = {
- def isOuter(sym: Symbol) =
+ def isOuterSym(sym: Symbol) =
!sym.isStaticOwner && cls.isProperlyContainedIn(sym)
+ def isOuterRef(ref: Type): Boolean = ref match {
+ case ref: ThisType =>
+ isOuterSym(ref.cls)
+ case ref: TermRef =>
+ if (ref.prefix ne NoPrefix)
+ !ref.symbol.isStatic && isOuterRef(ref.prefix)
+ else if (ref.symbol is Hoistable)
+ // ref.symbol will be placed in enclosing class scope by LambdaLift, so it might need
+ // an outer path then.
+ isOuterSym(ref.symbol.owner.enclosingClass)
+ else
+ // ref.symbol will get a proxy in immediately enclosing class. If this properly
+ // contains the current class, it needs an outer path.
+ ctx.owner.enclosingClass.owner.enclosingClass.isContainedIn(ref.symbol.owner)
+ case _ => false
+ }
+ def hasOuterPrefix(tp: Type) = tp match {
+ case TypeRef(prefix, _) => isOuterRef(prefix)
+ case _ => false
+ }
tree match {
- case thisTree @ This(_) =>
- isOuter(thisTree.symbol)
- case id: Ident =>
- id.tpe match {
- case ref @ TermRef(NoPrefix, _) =>
- if (ref.symbol is Hoistable)
- // ref.symbol will be placed in enclosing class scope by LambdaLift, so it might need
- // an outer path then.
- isOuter(ref.symbol.owner.enclosingClass)
- else
- // ref.symbol will get a proxy in immediately enclosing class. If this properly
- // contains the current class, it needs an outer path.
- ctx.owner.enclosingClass.owner.enclosingClass.isContainedIn(ref.symbol.owner)
- case _ => false
- }
+ case _: This | _: Ident => isOuterRef(tree.tpe)
case nw: New =>
val newCls = nw.tpe.classSymbol
- isOuter(newCls.owner.enclosingClass) ||
+ isOuterSym(newCls.owner.enclosingClass) ||
+ hasOuterPrefix(nw.tpe) ||
newCls.owner.isTerm && cls.isProperlyContainedIn(newCls)
// newCls might get proxies for free variables. If current class is
// properly contained in newCls, it needs an outer path to newCls access the
diff --git a/src/dotty/tools/dotc/transform/FirstTransform.scala b/src/dotty/tools/dotc/transform/FirstTransform.scala
index 6b13d46b2..37ae1d94e 100644
--- a/src/dotty/tools/dotc/transform/FirstTransform.scala
+++ b/src/dotty/tools/dotc/transform/FirstTransform.scala
@@ -124,7 +124,7 @@ class FirstTransform extends MiniPhaseTransform with IdentityDenotTransformer wi
private def newCompanion(name: TermName, forClass: Symbol)(implicit ctx: Context) = {
val modul = ctx.newCompleteModuleSymbol(forClass.owner, name, Synthetic, Synthetic,
- defn.ObjectType :: Nil, Scopes.newScope)
+ defn.ObjectType :: Nil, Scopes.newScope, assocFile = forClass.asClass.assocFile)
val mc = modul.moduleClass
val mcComp = ctx.synthesizeCompanionMethod(nme.COMPANION_CLASS_METHOD, forClass, mc)
diff --git a/src/dotty/tools/dotc/transform/Mixin.scala b/src/dotty/tools/dotc/transform/Mixin.scala
index 32b268fc7..b0d1e5c5f 100644
--- a/src/dotty/tools/dotc/transform/Mixin.scala
+++ b/src/dotty/tools/dotc/transform/Mixin.scala
@@ -98,8 +98,12 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>
override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[Erasure])
override def transformSym(sym: SymDenotation)(implicit ctx: Context): SymDenotation =
- if (sym.is(Accessor, butNot = Deferred | Lazy) && sym.owner.is(Trait))
- sym.copySymDenotation(initFlags = sym.flags &~ ParamAccessor | Deferred).ensureNotPrivate
+ if (sym.is(Accessor, butNot = Deferred) && sym.owner.is(Trait)) {
+ val sym1 =
+ if (sym is Lazy) sym
+ else sym.copySymDenotation(initFlags = sym.flags &~ ParamAccessor | Deferred)
+ sym1.ensureNotPrivate
+ }
else if (sym.isConstructor && sym.owner.is(Trait))
sym.copySymDenotation(
name = nme.TRAIT_CONSTRUCTOR,
@@ -108,17 +112,19 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>
sym
private def initializer(sym: Symbol)(implicit ctx: Context): TermSymbol = {
- val initName = if(!sym.is(Lazy)) InitializerName(sym.name.asTermName) else sym.name.asTermName
- sym.owner.info.decl(initName).suchThat(_.is(Lazy) == sym.is(Lazy)).symbol
- .orElse(
- ctx.newSymbol(
- sym.owner,
- initName,
- Protected | Synthetic | Method,
- sym.info,
- coord = sym.symbol.coord).enteredAfter(thisTransform))
- .asTerm
- }
+ if (sym is Lazy) sym
+ else {
+ val initName = InitializerName(sym.name.asTermName)
+ sym.owner.info.decl(initName).symbol
+ .orElse(
+ ctx.newSymbol(
+ sym.owner,
+ initName,
+ Protected | Synthetic | Method,
+ sym.info,
+ coord = sym.symbol.coord).enteredAfter(thisTransform))
+ }
+ }.asTerm
override def transformTemplate(impl: Template)(implicit ctx: Context, info: TransformerInfo) = {
val cls = impl.symbol.owner.asClass
@@ -134,8 +140,8 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>
val vsym = stat.symbol
val isym = initializer(vsym)
val rhs = Block(
- initBuf.toList.map(_.changeOwner(impl.symbol, isym)),
- stat.rhs.changeOwner(vsym, isym).wildcardToDefault)
+ initBuf.toList.map(_.changeOwnerAfter(impl.symbol, isym, thisTransform)),
+ stat.rhs.changeOwnerAfter(vsym, isym, thisTransform).wildcardToDefault)
initBuf.clear()
cpy.DefDef(stat)(rhs = EmptyTree) :: DefDef(isym, rhs) :: Nil
case stat: DefDef if stat.symbol.isSetter =>
diff --git a/src/dotty/tools/dotc/transform/PostTyper.scala b/src/dotty/tools/dotc/transform/PostTyper.scala
index ea5c28fb1..01f9f6317 100644
--- a/src/dotty/tools/dotc/transform/PostTyper.scala
+++ b/src/dotty/tools/dotc/transform/PostTyper.scala
@@ -131,8 +131,13 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
annot.derivedAnnotation(transformAnnot(annot.tree))
private def transformMemberDef(tree: MemberDef)(implicit ctx: Context): Unit = {
- tree.symbol.transformAnnotations(transformAnnot)
- Checking.checkNoPrivateLeaks(tree)
+ val sym = tree.symbol
+ sym.transformAnnotations(transformAnnot)
+ if (!sym.is(SyntheticOrPrivate) && sym.owner.isClass) {
+ val info1 = Checking.checkNoPrivateLeaks(sym, tree.pos)
+ if (info1 ne sym.info)
+ sym.copySymDenotation(info = info1).installAfter(thisTransformer)
+ }
}
private def transformSelect(tree: Select, targs: List[Tree])(implicit ctx: Context): Tree = {
diff --git a/src/dotty/tools/dotc/transform/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala
index 150a632a1..a260963e9 100644
--- a/src/dotty/tools/dotc/transform/TreeChecker.scala
+++ b/src/dotty/tools/dotc/transform/TreeChecker.scala
@@ -282,7 +282,10 @@ class TreeChecker extends Phase with SymTransformer {
val symbolsNotDefined = cls.classInfo.decls.toSet.filter(isNonMagicalMethod) -- impl.body.map(_.symbol) - constr.symbol
- assert(symbolsNotDefined.isEmpty, i" $cls tree does not define methods: $symbolsNotDefined")
+ assert(symbolsNotDefined.isEmpty,
+ i" $cls tree does not define methods: ${symbolsNotDefined.toList}%, %\n" +
+ i"expected: ${cls.classInfo.decls.toSet.filter(isNonMagicalMethod).toList}%, %\n" +
+ i"defined: ${impl.body.map(_.symbol)}%, %")
super.typedClassDef(cdef, cls)
}
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
index 0ca121925..9b1f756b7 100644
--- a/src/dotty/tools/dotc/typer/Checking.scala
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -327,40 +327,53 @@ object Checking {
* to a private type or value which is invisible at a point where `M` is still
* visible. As an exception, we allow references to type aliases if the underlying
* type of the alias is not a leak. So type aliases are transparent as far as
- * leak testing is concerned. See 997.scala for tests.
+ * leak testing is concerned.
+ * @return The `info` of `sym`, with problematic aliases expanded away.
+ * See i997.scala for tests, i1130.scala for a case where it matters that we
+ * transform leaky aliases away.
*/
- def checkNoPrivateLeaks(tree: MemberDef)(implicit ctx: Context): Unit = {
- type Errors = List[(String, Position)]
- val sym = tree.symbol
- val notPrivate = new TypeAccumulator[Errors] {
+ def checkNoPrivateLeaks(sym: Symbol, pos: Position)(implicit ctx: Context): Type = {
+ class NotPrivate extends TypeMap {
+ type Errors = List[(String, Position)]
+ var errors: Errors = Nil
def accessBoundary(sym: Symbol): Symbol =
if (sym.is(Private)) sym.owner
else if (sym.privateWithin.exists) sym.privateWithin
else if (sym.is(Package)) sym
else accessBoundary(sym.owner)
- def apply(errors: Errors, tp: Type): Errors = tp match {
+ def apply(tp: Type): Type = tp match {
case tp: NamedType =>
- val errors1 =
+ val prevErrors = errors
+ var tp1 =
if (tp.symbol.is(Private) &&
- !accessBoundary(sym).isContainedIn(tp.symbol.owner)) {
- (d"non-private $sym refers to private ${tp.symbol}\n in its type signature ${sym.info}", tree.pos) :: errors
- } else foldOver(errors, tp)
- if ((errors1 ne errors) && tp.info.isAlias) {
+ !accessBoundary(sym).isContainedIn(tp.symbol.owner)) {
+ errors = (d"non-private $sym refers to private ${tp.symbol}\n in its type signature ${sym.info}",
+ pos) :: errors
+ tp
+ }
+ else mapOver(tp)
+ if ((errors ne prevErrors) && tp.info.isAlias) {
// try to dealias to avoid a leak error
- val errors2 = apply(errors, tp.info.bounds.hi)
- if (errors2 eq errors) errors2
- else errors1
- } else errors1
+ val savedErrors = errors
+ errors = prevErrors
+ val tp2 = apply(tp.info.bounds.hi)
+ if (errors eq prevErrors) tp1 = tp2
+ else errors = savedErrors
+ }
+ tp1
case tp: ClassInfo =>
- (apply(errors, tp.prefix) /: tp.parentsWithArgs)(apply)
+ tp.derivedClassInfo(
+ prefix = apply(tp.prefix),
+ classParents = tp.parentsWithArgs.map(p =>
+ apply(p).underlyingClassRef(refinementOK = false).asInstanceOf[TypeRef]))
case _ =>
- foldOver(errors, tp)
+ mapOver(tp)
}
}
- if (!sym.is(SyntheticOrPrivate) && sym.owner.isClass) {
- val errors = notPrivate(Nil, sym.info)
- errors.foreach { case (msg, pos) => ctx.errorOrMigrationWarning(msg, pos) }
- }
+ val notPrivate = new NotPrivate
+ val info = notPrivate(sym.info)
+ notPrivate.errors.foreach { case (msg, pos) => ctx.errorOrMigrationWarning(msg, pos) }
+ info
}
}
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 84344dbb1..fdb92a40b 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -232,7 +232,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
}
val curImport = ctx.importInfo
- if (curImport != null && curImport.isRootImport && previous.exists) return previous
+ if (ctx.owner.is(Package) && curImport != null && curImport.isRootImport && previous.exists)
+ return previous // no more conflicts possible in this case
// would import of kind `prec` be not shadowed by a nested higher-precedence definition?
def isPossibleImport(prec: Int) =
prevPrec < prec || prevPrec == prec && (prevCtx.scope eq ctx.scope)