Skip to content

Fix #9224: Refine stopAtStatic criterion #9230

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions compiler/src/dotty/tools/dotc/core/TypeOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,14 @@ object TypeOps:
@threadUnsafe lazy val forbidden = symsToAvoid.toSet
def toAvoid(sym: Symbol) = !sym.isStatic && forbidden.contains(sym)
def partsToAvoid = new NamedPartsAccumulator(tp => toAvoid(tp.symbol))

/** True iff all NamedTypes on this prefix are static */
override def isStaticPrefix(pre: Type)(using Context): Boolean = pre match
case pre: NamedType =>
val sym = pre.currentSymbol
sym.is(Package) || sym.isStatic && isStaticPrefix(pre.prefix)
case _ => true

def apply(tp: Type): Type = tp match {
case tp: TermRef
if toAvoid(tp.symbol) || partsToAvoid(mutable.Set.empty, tp.info).nonEmpty =>
Expand Down
33 changes: 18 additions & 15 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4850,7 +4850,7 @@ object Types {
// ----- TypeMaps --------------------------------------------------------------------

/** Common base class of TypeMap and TypeAccumulator */
abstract class VariantTraversal {
abstract class VariantTraversal:
protected[core] var variance: Int = 1

inline protected def atVariance[T](v: Int)(op: => T): T = {
Expand All @@ -4860,13 +4860,22 @@ object Types {
variance = saved
res
}
}

protected def stopAtStatic: Boolean = true

/** Can the prefix of this static reference be omitted if the reference
* itself can be omitted? Overridden in TypeOps#avoid.
*/
protected def isStaticPrefix(pre: Type)(using Context): Boolean = true

protected def stopBecauseStaticOrLocal(tp: NamedType)(using Context): Boolean =
(tp.prefix eq NoPrefix)
|| stopAtStatic && tp.currentSymbol.isStatic && isStaticPrefix(tp.prefix)
end VariantTraversal

abstract class TypeMap(implicit protected var mapCtx: Context)
extends VariantTraversal with (Type => Type) { thisMap =>

protected def stopAtStatic: Boolean = true

def apply(tp: Type): Type

protected def derivedSelect(tp: NamedType, pre: Type): Type =
Expand Down Expand Up @@ -4912,8 +4921,8 @@ object Types {
implicit val ctx = this.mapCtx
tp match {
case tp: NamedType =>
if (stopAtStatic && tp.symbol.isStatic || (tp.prefix `eq` NoPrefix)) tp
else {
if stopBecauseStaticOrLocal(tp) then tp
else
val prefix1 = atVariance(variance max 0)(this(tp.prefix))
// A prefix is never contravariant. Even if say `p.A` is used in a contravariant
// context, we cannot assume contravariance for `p` because `p`'s lower
Expand All @@ -4922,7 +4931,6 @@ object Types {
// if `p <: q` then `p.A <: q.A`, and well-formedness requires that `A` is a member
// of `p`'s upper bound.
derivedSelect(tp, prefix1)
}
case _: ThisType
| _: BoundType
| NoPrefix => tp
Expand Down Expand Up @@ -5077,7 +5085,6 @@ object Types {
}

@sharable object IdentityTypeMap extends TypeMap()(NoContext) {
override def stopAtStatic: Boolean = true
def apply(tp: Type): Type = tp
}

Expand Down Expand Up @@ -5334,8 +5341,6 @@ object Types {
abstract class TypeAccumulator[T](implicit protected val accCtx: Context)
extends VariantTraversal with ((T, Type) => T) {

protected def stopAtStatic: Boolean = true

def apply(x: T, tp: Type): T

protected def applyToAnnot(x: T, annot: Annotation): T = x // don't go into annotations
Expand All @@ -5348,11 +5353,10 @@ object Types {
record(s"foldOver total")
tp match {
case tp: TypeRef =>
if (stopAtStatic && tp.symbol.isStatic || (tp.prefix `eq` NoPrefix)) x
else {
if stopBecauseStaticOrLocal(tp) then x
else
val tp1 = tp.prefix.lookupRefined(tp.name)
if (tp1.exists) this(x, tp1) else applyToPrefix(x, tp)
}

case tp @ AppliedType(tycon, args) =>
@tailrec def foldArgs(x: T, tparams: List[ParamInfo], args: List[Type]): T =
Expand All @@ -5378,8 +5382,7 @@ object Types {
this(y, restpe)

case tp: TermRef =>
if (stopAtStatic && tp.currentSymbol.isStatic || (tp.prefix `eq` NoPrefix)) x
else applyToPrefix(x, tp)
if stopBecauseStaticOrLocal(tp) then x else applyToPrefix(x, tp)

case tp: TypeVar =>
this(x, tp.underlying)
Expand Down
3 changes: 3 additions & 0 deletions tests/pos/i9224.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
object foo { def test = 23 }

def bar(x: Any) = x match { case m: foo.type => m.test } // need to call m.test