@@ -49,7 +49,7 @@ object Typer {
4949 * accessed by an Ident.
5050 */
5151 enum BindingPrec {
52- case NothingBound , PackageClause , WildImport , NamedImport , Definition
52+ case NothingBound , PackageClause , WildImport , NamedImport , Inheritance , Definition
5353
5454 def isImportPrec = this == NamedImport || this == WildImport
5555 }
@@ -125,6 +125,9 @@ class Typer extends Namer
125125 val refctx = ctx
126126 val noImports = ctx.mode.is(Mode .InPackageClauseName )
127127
128+ def ambiguous (newPrec : BindingPrec , prevPrec : BindingPrec , prevCtx : Context )(using Context ) =
129+ refctx.error(AmbiguousReference (name, newPrec, prevPrec, prevCtx), posd.sourcePos)
130+
128131 /** A symbol qualifies if it really exists and is not a package class.
129132 * In addition, if we are in a constructor of a pattern, we ignore all definitions
130133 * which are methods and not accessors (note: if we don't do that
@@ -135,10 +138,9 @@ class Typer extends Namer
135138 * package as a type from source is always an error.
136139 */
137140 def qualifies (denot : Denotation ): Boolean =
138- reallyExists(denot) &&
139- ! (pt.isInstanceOf [UnapplySelectionProto ] &&
140- (denot.symbol is (Method , butNot = Accessor ))) &&
141- ! (denot.symbol.is(PackageClass ))
141+ reallyExists(denot)
142+ && ! (pt.isInstanceOf [UnapplySelectionProto ] && denot.symbol.is(Method , butNot = Accessor ))
143+ && ! denot.symbol.is(PackageClass )
142144
143145 /** Find the denotation of enclosing `name` in given context `ctx`.
144146 * @param previous A denotation that was found in a more deeply nested scope,
@@ -161,18 +163,18 @@ class Typer extends Namer
161163 * the previous (inner) definition. This models what scalac does.
162164 */
163165 def checkNewOrShadowed (found : Type , newPrec : BindingPrec , scala2pkg : Boolean = false )(implicit ctx : Context ): Type =
164- if (! previous.exists || ctx.typeComparer.isSameRef(previous, found)) found
165- else if ((prevCtx.scope eq ctx.scope) &&
166- (newPrec == Definition ||
167- newPrec == NamedImport && prevPrec == WildImport ))
166+ if ! previous.exists || ctx.typeComparer.isSameRef(previous, found) then
167+ found
168+ else if (prevCtx.scope eq ctx.scope)
169+ && (newPrec == Definition || newPrec == NamedImport && prevPrec == WildImport )
170+ then
168171 // special cases: definitions beat imports, and named imports beat
169172 // wildcard imports, provided both are in contexts with same scope
170173 found
171- else {
172- if ( ! scala2pkg && ! previous.isError && ! found.isError)
173- refctx.error( AmbiguousImport (name, newPrec, prevPrec, prevCtx), posd.sourcePos )
174+ else
175+ if ! scala2pkg && ! previous.isError && ! found.isError then
176+ ambiguous( newPrec, prevPrec, prevCtx)
174177 previous
175- }
176178
177179 /** Recurse in outer context. If final result is same as `previous`, check that it
178180 * is new or shadowed. This order of checking is necessary since an
@@ -192,7 +194,8 @@ class Typer extends Namer
192194 NoType
193195 else
194196 val pre = imp.site
195- var denot = pre.memberBasedOnFlags(name, required, EmptyFlags ).accessibleFrom(pre)(refctx)
197+ var denot = pre.memberBasedOnFlags(name, required, EmptyFlags )
198+ .accessibleFrom(pre)(using refctx)
196199 // Pass refctx so that any errors are reported in the context of the
197200 // reference instead of the context of the import scope
198201 if checkBounds && denot.exists then
@@ -290,11 +293,35 @@ class Typer extends Namer
290293 // with an error on CI which I cannot replicate locally (not even
291294 // with the exact list of files given).
292295 val isNewDefScope =
293- if (curOwner.is(Package ) && ! curOwner.isRoot) curOwner ne ctx.outer.owner
294- else ((ctx.scope ne lastCtx.scope) || (curOwner ne lastCtx.owner)) &&
295- ! isTransparentPackageObject
296+ if curOwner.is(Package ) && ! curOwner.isRoot then
297+ curOwner ne ctx.outer.owner
298+ else
299+ ((ctx.scope ne lastCtx.scope) || (curOwner ne lastCtx.owner))
300+ && ! isTransparentPackageObject
301+
302+ // Does reference `tp` refer only to inherited symbols?
303+ def isInherited (denot : Denotation ) =
304+ def isCurrent (mbr : SingleDenotation ): Boolean =
305+ ! mbr.symbol.exists || mbr.symbol.owner == ctx.owner
306+ denot match
307+ case denot : SingleDenotation => ! isCurrent(denot)
308+ case denot => ! denot.hasAltWith(isCurrent)
309+
310+ def checkNoOuterDefs (denot : Denotation , last : Context , prevCtx : Context ): Unit =
311+ val outer = last.outer
312+ val owner = outer.owner
313+ if (owner eq last.owner) && (outer.scope eq last.scope) then
314+ checkNoOuterDefs(denot, outer, prevCtx)
315+ else if ! owner.is(Package ) then
316+ val scope = if owner.isClass then owner.info.decls else outer.scope
317+ if scope.lookup(name).exists then
318+ val symsMatch = scope.lookupAll(name).exists(denot.containsSym)
319+ if ! symsMatch then
320+ ambiguous(Definition , Inheritance , prevCtx)(using outer)
321+ else
322+ checkNoOuterDefs(denot, outer, prevCtx)
296323
297- if ( isNewDefScope) {
324+ if isNewDefScope then
298325 val defDenot = ctx.denotNamed(name, required)
299326 if (qualifies(defDenot)) {
300327 val found =
@@ -309,20 +336,22 @@ class Typer extends Namer
309336 curOwner
310337 effectiveOwner.thisType.select(name, defDenot)
311338 }
312- if ( ! curOwner.is(Package ) || isDefinedInCurrentUnit(defDenot))
339+ if ! curOwner.is(Package ) || isDefinedInCurrentUnit(defDenot) then
313340 result = checkNewOrShadowed(found, Definition ) // no need to go further out, we found highest prec entry
314- else {
341+ found match
342+ case found : NamedType if ctx.owner.isClass && isInherited(found.denot) =>
343+ checkNoOuterDefs(found.denot, ctx, ctx)
344+ case _ =>
345+ else
315346 if (ctx.scala2CompatMode && ! foundUnderScala2.exists)
316347 foundUnderScala2 = checkNewOrShadowed(found, Definition , scala2pkg = true )
317348 if (defDenot.symbol.is(Package ))
318349 result = checkNewOrShadowed(previous orElse found, PackageClause )
319350 else if (prevPrec.ordinal < PackageClause .ordinal)
320351 result = findRefRecur(found, PackageClause , ctx)(ctx.outer)
321- }
322352 }
323- }
324353
325- if ( result.exists) result
354+ if result.exists then result
326355 else { // find import
327356 val outer = ctx.outer
328357 val curImport = ctx.importInfo
0 commit comments