Skip to content

Remove AndOrType #3986

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
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
6 changes: 4 additions & 2 deletions compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,9 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
rname == tree.name || hasRefinement(parent)
case tp: TypeProxy =>
hasRefinement(tp.underlying)
case tp: AndOrType =>
case tp: AndType =>
hasRefinement(tp.tp1) || hasRefinement(tp.tp2)
case tp: OrType =>
hasRefinement(tp.tp1) || hasRefinement(tp.tp2)
case _ =>
false
Expand Down Expand Up @@ -731,4 +733,4 @@ object TreeInfo {
val Pure = new PurityLevel(2)
val Idempotent = new PurityLevel(1)
val Impure = new PurityLevel(0)
}
}
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/core/CheckRealizable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ class CheckRealizable(implicit ctx: Context) {
def isConcrete(tp: Type): Boolean = tp.dealias match {
case tp: TypeRef => tp.symbol.isClass
case tp: TypeProxy => isConcrete(tp.underlying)
case tp: AndOrType => isConcrete(tp.tp1) && isConcrete(tp.tp2)
case tp: AndType => isConcrete(tp.tp1) && isConcrete(tp.tp2)
case tp: OrType => isConcrete(tp.tp1) && isConcrete(tp.tp2)
case _ => false
}
if (!isConcrete(tp)) NotConcrete
Expand Down
64 changes: 45 additions & 19 deletions compiler/src/dotty/tools/dotc/core/Constants.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,28 +23,10 @@ object Constants {
final val EnumTag = 13
final val ScalaSymbolTag = 14

case class Constant(value: Any) extends printing.Showable {
class Constant(val value: Any, val tag: Int) extends printing.Showable with Product1[Any] {
import java.lang.Double.doubleToRawLongBits
import java.lang.Float.floatToRawIntBits

val tag: Int = value match {
case null => NullTag
case x: Unit => UnitTag
case x: Boolean => BooleanTag
case x: Byte => ByteTag
case x: Short => ShortTag
case x: Int => IntTag
case x: Long => LongTag
case x: Float => FloatTag
case x: Double => DoubleTag
case x: String => StringTag
case x: Char => CharTag
case x: Type => ClazzTag
case x: Symbol => EnumTag
case x: scala.Symbol => ScalaSymbolTag
case _ => throw new Error("bad constant value: " + value + " of class " + value.getClass)
}

def isByteRange: Boolean = isIntRange && Byte.MinValue <= intValue && intValue <= Byte.MaxValue
def isShortRange: Boolean = isIntRange && Short.MinValue <= intValue && intValue <= Short.MaxValue
def isCharRange: Boolean = isIntRange && Char.MinValue <= intValue && intValue <= Char.MaxValue
Expand Down Expand Up @@ -235,5 +217,49 @@ object Constants {
h = mix(h, equalHashValue.##)
finalizeHash(h, length = 2)
}

override def toString = s"Constant($value)"
def canEqual(x: Any) = true
def get = value
def isEmpty = false
def _1 = value
}

object Constant {
def apply(x: Null) = new Constant(x, NullTag)
def apply(x: Unit) = new Constant(x, UnitTag)
def apply(x: Boolean) = new Constant(x, BooleanTag)
def apply(x: Byte) = new Constant(x, ByteTag)
def apply(x: Short) = new Constant(x, ShortTag)
def apply(x: Int) = new Constant(x, IntTag)
def apply(x: Long) = new Constant(x, LongTag)
def apply(x: Float) = new Constant(x, FloatTag)
def apply(x: Double) = new Constant(x, DoubleTag)
def apply(x: String) = new Constant(x, StringTag)
def apply(x: Char) = new Constant(x, CharTag)
def apply(x: Type) = new Constant(x, ClazzTag)
def apply(x: Symbol) = new Constant(x, EnumTag)
def apply(x: scala.Symbol) = new Constant(x, ScalaSymbolTag)
def apply(value: Any) =
new Constant(value,
value match {
case null => NullTag
case x: Unit => UnitTag
case x: Boolean => BooleanTag
case x: Byte => ByteTag
case x: Short => ShortTag
case x: Int => IntTag
case x: Long => LongTag
case x: Float => FloatTag
case x: Double => DoubleTag
case x: String => StringTag
case x: Char => CharTag
case x: Type => ClazzTag
case x: Symbol => EnumTag
case x: scala.Symbol => ScalaSymbolTag
}
)

def unapply(c: Constant) = c
}
}
15 changes: 11 additions & 4 deletions compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ trait ConstraintHandling {
val b = bound.dealias
(b eq param) || {
b match {
case b: AndOrType => occursIn(b.tp1) || occursIn(b.tp2)
case b: AndType => occursIn(b.tp1) || occursIn(b.tp2)
case b: OrType => occursIn(b.tp1) || occursIn(b.tp2)
case b: TypeVar => occursIn(b.origin)
case b: TermRef => occursIn(b.underlying)
case _ => false
Expand Down Expand Up @@ -256,7 +257,8 @@ trait ConstraintHandling {
def isFullyDefined(tp: Type): Boolean = tp match {
case tp: TypeVar => tp.isInstantiated && isFullyDefined(tp.instanceOpt)
case tp: TypeProxy => isFullyDefined(tp.underlying)
case tp: AndOrType => isFullyDefined(tp.tp1) && isFullyDefined(tp.tp2)
case tp: AndType => isFullyDefined(tp.tp1) && isFullyDefined(tp.tp2)
case tp: OrType => isFullyDefined(tp.tp1) && isFullyDefined(tp.tp2)
case _ => true
}
def isOrType(tp: Type): Boolean = tp.stripTypeVar.dealias match {
Expand Down Expand Up @@ -430,10 +432,15 @@ trait ConstraintHandling {
* @return The pruned type if all `addLess` calls succeed, `NoType` otherwise.
*/
def prune(bound: Type): Type = bound match {
case bound: AndOrType =>
case bound: AndType =>
val p1 = prune(bound.tp1)
val p2 = prune(bound.tp2)
if (p1.exists && p2.exists) bound.derivedAndOrType(p1, p2)
if (p1.exists && p2.exists) bound.derivedAndType(p1, p2)
else NoType
case bound: OrType =>
val p1 = prune(bound.tp1)
val p2 = prune(bound.tp2)
if (p1.exists && p2.exists) bound.derivedOrType(p1, p2)
else NoType
case bound: TypeVar if constraint contains bound.origin =>
prune(bound.underlying)
Expand Down
39 changes: 26 additions & 13 deletions compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,8 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
def dependentParams(tp: Type, isUpper: Boolean): List[TypeParamRef] = tp match {
case param: TypeParamRef if contains(param) =>
param :: (if (isUpper) upper(param) else lower(param))
case tp: AndOrType =>
val ps1 = dependentParams(tp.tp1, isUpper)
val ps2 = dependentParams(tp.tp2, isUpper)
if (isUpper == tp.isAnd) ps1.union(ps2) else ps1.intersect(ps2)
case tp: AndType => dependentParams(tp.tp1, isUpper).union (dependentParams(tp.tp2, isUpper))
case tp: OrType => dependentParams(tp.tp1, isUpper).intersect(dependentParams(tp.tp2, isUpper))
case _ =>
Nil
}
Expand Down Expand Up @@ -260,11 +258,18 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
case param: TypeParamRef if contains(param) =>
if (!paramBuf.contains(param)) paramBuf += param
NoType
case tp: AndOrType if isUpper == tp.isAnd =>
case tp: AndType if isUpper =>
val tp1 = stripParams(tp.tp1, paramBuf, isUpper)
val tp2 = stripParams(tp.tp2, paramBuf, isUpper)
if (tp1.exists)
if (tp2.exists) tp.derivedAndOrType(tp1, tp2)
if (tp2.exists) tp.derivedAndType(tp1, tp2)
else tp1
else tp2
case tp: OrType if !isUpper =>
val tp1 = stripParams(tp.tp1, paramBuf, isUpper)
val tp2 = stripParams(tp.tp2, paramBuf, isUpper)
if (tp1.exists)
if (tp2.exists) tp.derivedOrType(tp1, tp2)
else tp1
else tp2
case _ =>
Expand Down Expand Up @@ -395,24 +400,32 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
def replaceParam(tp: Type, atPoly: TypeLambda, atIdx: Int): Type = tp match {
case bounds @ TypeBounds(lo, hi) =>

def recombine(andor: AndOrType, op: (Type, Boolean) => Type, isUpper: Boolean): Type = {
val tp1 = op(andor.tp1, isUpper)
val tp2 = op(andor.tp2, isUpper)
if ((tp1 eq andor.tp1) && (tp2 eq andor.tp2)) andor
else if (andor.isAnd) tp1 & tp2
def recombineAnd(and: AndType, op: (Type, Boolean) => Type, isUpper: Boolean): Type = {
val tp1 = op(and.tp1, isUpper)
val tp2 = op(and.tp2, isUpper)
if (tp1.eq(and.tp1) && tp2.eq(and.tp2)) and
else tp1 & tp2
}

def recombineOr(or: OrType, op: (Type, Boolean) => Type, isUpper: Boolean): Type = {
val tp1 = op(or.tp1, isUpper)
val tp2 = op(or.tp2, isUpper)
if (tp1.eq(or.tp1) && tp2.eq(or.tp2)) or
else tp1 | tp2
}

def normalize(tp: Type, isUpper: Boolean): Type = tp match {
case p: TypeParamRef if p.binder == atPoly && p.paramNum == atIdx =>
if (isUpper) defn.AnyType else defn.NothingType
case tp: AndOrType if isUpper == tp.isAnd => recombine(tp, normalize, isUpper)
case tp: AndType if isUpper => recombineAnd(tp, normalize, isUpper)
case tp: OrType if !isUpper => recombineOr (tp, normalize, isUpper)
case _ => tp
}

def replaceIn(tp: Type, isUpper: Boolean): Type = tp match {
case `param` => normalize(replacement, isUpper)
case tp: AndOrType if isUpper == tp.isAnd => recombine(tp, replaceIn, isUpper)
case tp: AndType if isUpper => recombineAnd(tp, replaceIn, isUpper)
case tp: OrType if !isUpper => recombineOr (tp, replaceIn, isUpper)
case _ => tp.substParam(param, replacement)
}

Expand Down
7 changes: 4 additions & 3 deletions compiler/src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1202,7 +1202,8 @@ object SymDenotations {
case tp: ExprType => hasSkolems(tp.resType)
case tp: AppliedType => hasSkolems(tp.tycon) || tp.args.exists(hasSkolems)
case tp: LambdaType => tp.paramInfos.exists(hasSkolems) || hasSkolems(tp.resType)
case tp: AndOrType => hasSkolems(tp.tp1) || hasSkolems(tp.tp2)
case tp: AndType => hasSkolems(tp.tp1) || hasSkolems(tp.tp2)
case tp: OrType => hasSkolems(tp.tp1) || hasSkolems(tp.tp2)
case tp: AnnotatedType => hasSkolems(tp.tpe)
case _ => false
}
Expand Down Expand Up @@ -1641,9 +1642,9 @@ object SymDenotations {
case tp: TypeRef if tp.symbol.isClass => true
case tp: TypeVar => tp.inst.exists && inCache(tp.inst)
//case tp: TypeProxy => inCache(tp.underlying) // disabled, can re-enable insyead of last two lines for performance testing
//case tp: AndOrType => inCache(tp.tp1) && inCache(tp.tp2)
case tp: TypeProxy => isCachable(tp.underlying, btrCache)
case tp: AndOrType => isCachable(tp.tp1, btrCache) && isCachable(tp.tp2, btrCache)
case tp: AndType => isCachable(tp.tp1, btrCache) && isCachable(tp.tp2, btrCache)
case tp: OrType => isCachable(tp.tp1, btrCache) && isCachable(tp.tp2, btrCache)
case _ => true
}
}
Expand Down
6 changes: 4 additions & 2 deletions compiler/src/dotty/tools/dotc/core/TypeApplications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -374,8 +374,10 @@ class TypeApplications(val self: Type) extends AnyVal {
tryReduce
case dealiased: PolyType =>
dealiased.instantiate(args)
case dealiased: AndOrType =>
dealiased.derivedAndOrType(dealiased.tp1.appliedTo(args), dealiased.tp2.appliedTo(args))
case dealiased: AndType =>
dealiased.derivedAndType(dealiased.tp1.appliedTo(args), dealiased.tp2.appliedTo(args))
case dealiased: OrType =>
dealiased.derivedOrType(dealiased.tp1.appliedTo(args), dealiased.tp2.appliedTo(args))
case dealiased: TypeAlias =>
dealiased.derivedTypeAlias(dealiased.alias.appliedTo(args))
case dealiased: TypeBounds =>
Expand Down
12 changes: 7 additions & 5 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -925,7 +925,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
case tp @ RefinedType(parent, rname, rinfo) => tp.derivedRefinedType(fix(parent), rname, rinfo)
case tp: TypeParamRef => fixOrElse(bounds(tp).hi, tp)
case tp: TypeProxy => fixOrElse(tp.underlying, tp)
case tp: AndOrType => tp.derivedAndOrType(fix(tp.tp1), fix(tp.tp2))
case tp: AndType => tp.derivedAndType(fix(tp.tp1), fix(tp.tp2))
case tp: OrType => tp.derivedOrType (fix(tp.tp1), fix(tp.tp2))
case tp => tp
}
def fixOrElse(tp: Type, fallback: Type) = {
Expand Down Expand Up @@ -1075,7 +1076,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
case tp: AppliedType => isCovered(tp.tycon)
case tp: RefinedOrRecType => isCovered(tp.parent)
case tp: AnnotatedType => isCovered(tp.underlying)
case tp: AndOrType => isCovered(tp.tp1) && isCovered(tp.tp2)
case tp: AndType => isCovered(tp.tp1) && isCovered(tp.tp2)
case tp: OrType => isCovered(tp.tp1) && isCovered(tp.tp2)
case _ => false
}

Expand Down Expand Up @@ -1323,18 +1325,18 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
Nil
}

private def recombineAndOr(tp: AndOrType, tp1: Type, tp2: Type) =
private def recombineAnd(tp: AndType, tp1: Type, tp2: Type) =
if (!tp1.exists) tp2
else if (!tp2.exists) tp1
else tp.derivedAndOrType(tp1, tp2)
else tp.derivedAndType(tp1, tp2)

/** If some (&-operand of) this type is a supertype of `sub` replace it with `NoType`.
*/
private def dropIfSuper(tp: Type, sub: Type): Type =
if (isSubTypeWhenFrozen(sub, tp)) NoType
else tp match {
case tp @ AndType(tp1, tp2) =>
recombineAndOr(tp, dropIfSuper(tp1, sub), dropIfSuper(tp2, sub))
recombineAnd(tp, dropIfSuper(tp1, sub), dropIfSuper(tp2, sub))
case _ =>
tp
}
Expand Down
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/core/TypeErasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,8 @@ object TypeErasure {
case tp: TypeParamRef => false
case tp: TypeBounds => false
case tp: TypeProxy => hasStableErasure(tp.superType)
case tp: AndOrType => hasStableErasure(tp.tp1) && hasStableErasure(tp.tp2)
case tp: AndType => hasStableErasure(tp.tp1) && hasStableErasure(tp.tp2)
case tp: OrType => hasStableErasure(tp.tp1) && hasStableErasure(tp.tp2)
case _ => false
}
}
Expand Down
Loading