Skip to content

Commit

Permalink
Refactor stopAtStatic
Browse files Browse the repository at this point in the history
Introduce a third boundary for stopping at packages
  • Loading branch information
odersky committed Jun 14, 2021
1 parent fcd837a commit 9a998d4
Show file tree
Hide file tree
Showing 9 changed files with 28 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ trait ConstraintHandling {
val bound = dropWildcards(rawBound)
val oldBounds @ TypeBounds(lo, hi) = constraint.nonParamBounds(param)
val equalBounds = (if isUpper then lo else hi) eq bound
if equalBounds && !bound.existsPart(_ eq param, stopAtStatic = true) then
if equalBounds && !bound.existsPart(_ eq param, StopAt.Static) then
// The narrowed bounds are equal and not recursive,
// so we can remove `param` from the constraint.
constraint = constraint.replace(param, bound)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1391,7 +1391,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
*/
def canCompare(ts: Set[Type]) =
ctx.phase.isTyper
|| !ts.exists(_.existsPart(_.isInstanceOf[SkolemType], stopAtStatic = true))
|| !ts.exists(_.existsPart(_.isInstanceOf[SkolemType], StopAt.Static))

def verified(result: Boolean): Boolean =
if Config.checkAtomsComparisons then
Expand Down
30 changes: 20 additions & 10 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -439,23 +439,23 @@ object Types {

/** Does this type contain wildcard types? */
final def containsWildcardTypes(using Context) =
existsPart(_.isInstanceOf[WildcardType], stopAtStatic = true, forceLazy = false)
existsPart(_.isInstanceOf[WildcardType], StopAt.Static, forceLazy = false)

// ----- Higher-order combinators -----------------------------------

/** Returns true if there is a part of this type that satisfies predicate `p`.
*/
final def existsPart(p: Type => Boolean, stopAtStatic: Boolean = false, forceLazy: Boolean = true)(using Context): Boolean =
new ExistsAccumulator(p, stopAtStatic, forceLazy).apply(false, this)
final def existsPart(p: Type => Boolean, stopAt: StopAt = StopAt.None, forceLazy: Boolean = true)(using Context): Boolean =
new ExistsAccumulator(p, stopAt, forceLazy).apply(false, this)

/** Returns true if all parts of this type satisfy predicate `p`.
*/
final def forallParts(p: Type => Boolean)(using Context): Boolean =
!existsPart(!p(_))

/** Performs operation on all parts of this type */
final def foreachPart(p: Type => Unit, stopAtStatic: Boolean = false)(using Context): Unit =
new ForeachAccumulator(p, stopAtStatic).apply((), this)
final def foreachPart(p: Type => Unit, stopAt: StopAt = StopAt.None)(using Context): Unit =
new ForeachAccumulator(p, stopAt).apply((), this)

/** The parts of this type which are type or term refs and which
* satisfy predicate `p`.
Expand Down Expand Up @@ -5199,6 +5199,12 @@ object Types {

// ----- TypeMaps --------------------------------------------------------------------

/** Where a traversal should stop */
enum StopAt:
case None // traverse everything
case Package // stop at package references
case Static // stop at static references

/** Common base class of TypeMap and TypeAccumulator */
abstract class VariantTraversal:
protected[core] var variance: Int = 1
Expand All @@ -5211,7 +5217,7 @@ object Types {
res
}

protected def stopAtStatic: Boolean = true
protected def stopAt: StopAt = StopAt.Static

/** Can the prefix of this static reference be omitted if the reference
* itself can be omitted? Overridden in TypeOps#avoid.
Expand All @@ -5220,7 +5226,11 @@ object Types {

protected def stopBecauseStaticOrLocal(tp: NamedType)(using Context): Boolean =
(tp.prefix eq NoPrefix)
|| stopAtStatic && tp.currentSymbol.isStatic && isStaticPrefix(tp.prefix)
|| {
val stop = stopAt
stop == StopAt.Static && tp.currentSymbol.isStatic && isStaticPrefix(tp.prefix)
|| stop == StopAt.Package && tp.currentSymbol.is(Package)
}
end VariantTraversal

abstract class TypeMap(implicit protected var mapCtx: Context)
Expand Down Expand Up @@ -5409,7 +5419,7 @@ object Types {
derivedClassInfo(tp, this(tp.prefix))

def andThen(f: Type => Type): TypeMap = new TypeMap {
override def stopAtStatic = thisMap.stopAtStatic
override def stopAt = thisMap.stopAt
def apply(tp: Type) = f(thisMap(tp))
}
}
Expand Down Expand Up @@ -5831,12 +5841,12 @@ object Types {

class ExistsAccumulator(
p: Type => Boolean,
override val stopAtStatic: Boolean,
override val stopAt: StopAt,
forceLazy: Boolean)(using Context) extends TypeAccumulator[Boolean]:
def apply(x: Boolean, tp: Type): Boolean =
x || p(tp) || (forceLazy || !tp.isInstanceOf[LazyRef]) && foldOver(x, tp)

class ForeachAccumulator(p: Type => Unit, override val stopAtStatic: Boolean)(using Context) extends TypeAccumulator[Unit] {
class ForeachAccumulator(p: Type => Unit, override val stopAt: StopAt)(using Context) extends TypeAccumulator[Unit] {
def apply(x: Unit, tp: Type): Unit = foldOver(p(tp), tp)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -700,7 +700,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
}
// Cannot use standard `existsPart` method because it calls `lookupRefined`
// which can cause CyclicReference errors.
val isBoundAccumulator = new ExistsAccumulator(isBound, stopAtStatic = true, forceLazy = true):
val isBoundAccumulator = new ExistsAccumulator(isBound, StopAt.Static, forceLazy = true):
override def foldOver(x: Boolean, tp: Type): Boolean = tp match
case tp: TypeRef => applyToPrefix(x, tp)
case _ => super.foldOver(x, tp)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1088,7 +1088,7 @@ trait Checking {
}
case _ =>
}
tp.foreachPart(check, stopAtStatic = true)
tp.foreachPart(check, StopAt.Static)
if (ok) tp else UnspecifiedErrorType
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,7 @@ trait ImplicitRunInfo:
case null =>
record(i"implicitScope")
val liftToAnchors = new TypeMap:
override def stopAtStatic = true
override def stopAt = StopAt.Static
private val seen = util.HashSet[Type]()

def applyToUnderlying(t: TypeProxy) =
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Inliner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -669,7 +669,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
/** Register type of leaf node */
private def registerLeaf(tree: Tree): Unit = tree match {
case _: This | _: Ident | _: TypeTree =>
tree.typeOpt.foreachPart(registerType, stopAtStatic = true)
tree.typeOpt.foreachPart(registerType, StopAt.Static)
case _ =>
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1519,7 +1519,7 @@ class Namer { typer: Typer =>
approxTp.stripPoly match
case atp @ defn.ContextFunctionType(_, resType, _)
if !defn.isNonRefinedFunction(atp) // in this case `resType` is lying, gives us only the non-dependent upper bound
|| resType.existsPart(_.isInstanceOf[WildcardType], stopAtStatic = true, forceLazy = false) =>
|| resType.existsPart(_.isInstanceOf[WildcardType], StopAt.Static, forceLazy = false) =>
originalTp
case _ =>
approxTp
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2803,7 +2803,7 @@ class Typer extends Namer
// see tests/pos/i7778b.scala

val paramTypes = {
val hasWildcard = formals.exists(_.existsPart(_.isInstanceOf[WildcardType], stopAtStatic = true))
val hasWildcard = formals.exists(_.existsPart(_.isInstanceOf[WildcardType], StopAt.Static))
if hasWildcard then formals.map(_ => untpd.TypeTree())
else formals.map(untpd.TypeTree)
}
Expand Down

0 comments on commit 9a998d4

Please sign in to comment.