Skip to content
Draft
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
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
Original file line number Diff line number Diff line change
Expand Up @@ -715,8 +715,8 @@ trait ConstraintHandling {
tp.rebind(tp.parent.hardenUnions)
case tp: HKTypeLambda =>
tp.derivedLambdaType(resType = tp.resType.hardenUnions)
case tp: FlexibleType =>
tp.derivedFlexibleType(tp.hi.hardenUnions)
case tp @ FlexibleType(hi) =>
FlexibleType.derivedFlexibleType(tp, hi.hardenUnions)
case tp: OrType =>
val tp1 = tp.stripNull(stripFlexibleTypes = false)
if tp1 ne tp then tp.derivedOrType(tp1.hardenUnions, defn.NullType, soft = false)
Expand Down
15 changes: 13 additions & 2 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,17 @@ class Definitions {
newPermanentSymbol(OpsPackageClass, tpnme.FromJavaObject, JavaDefined, TypeAlias(ObjectType)).entered
def FromJavaObjectType: TypeRef = FromJavaObjectSymbol.typeRef

@tu lazy val FlexibleTypeSymbol: TypeSymbol =
newPermanentSymbol(ScalaPackageClass, tpnme.FlexibleType, EmptyFlags, TypeBounds(
HKTypeLambda(TypeBounds.empty :: Nil)(
tl => OrNull(tl.paramRefs(0))
),
HKTypeLambda(TypeBounds.empty :: Nil)(
tl => tl.paramRefs(0)
)
)).entered
def FlexibleTypeType: TypeRef = FlexibleTypeSymbol.typeRef

@tu lazy val AnyRefAlias: TypeSymbol = enterAliasType(tpnme.AnyRef, ObjectType)
def AnyRefType: TypeRef = AnyRefAlias.typeRef

Expand Down Expand Up @@ -1980,8 +1991,8 @@ class Definitions {
asContextFunctionType(TypeComparer.bounds(tp1).hiBound)
case tp1 @ PolyFunctionOf(mt: MethodType) if mt.isContextualMethod =>
tp1
case tp: FlexibleType =>
asContextFunctionType(tp.hi)
case FlexibleType(hi) =>
asContextFunctionType(hi)
case tp1 =>
if tp1.typeSymbol.name.isContextFunction && isFunctionNType(tp1) then tp1
else NoType
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/core/ImplicitNullInterop.scala
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ object ImplicitNullInterop:
state = savedState
if isNullAnnot then parent2
else parent2 match
case FlexibleType(_, parent2a) =>
case FlexibleType(parent2a) =>
FlexibleType(derivedAnnotatedType(tp, parent2a, tp.annot))
case OrNull(parent2a) =>
OrNull(derivedAnnotatedType(tp, parent2a, tp.annot))
Expand Down Expand Up @@ -236,7 +236,7 @@ object ImplicitNullInterop:
// This keeps the result minimal and avoids duplicating `| Null`
// on both sides and at the outer level.
(this(tp.tp1), this(tp.tp2)) match
case (FlexibleType(_, t1), FlexibleType(_, t2)) if ctx.flexibleTypes =>
case (FlexibleType(t1), FlexibleType(t2)) if ctx.flexibleTypes =>
FlexibleType(derivedAndOrType(tp, t1, t2))
case (OrNull(t1), OrNull(t2)) =>
OrNull(derivedAndOrType(tp, t1, t2))
Expand All @@ -256,7 +256,7 @@ object ImplicitNullInterop:

// If the parent type becomes nullable, then we pop the nullification to the outer level.
parent2 match
case FlexibleType(_, parent2a) =>
case FlexibleType(parent2a) =>
FlexibleType(derivedRefinedType(tp, parent2a, refinedInfo2))
case OrNull(parent2a) =>
OrNull(derivedRefinedType(tp, parent2a, refinedInfo2))
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/core/NullOpsDecorator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ object NullOpsDecorator:
if (tp1s ne tp1) && (tp2s ne tp2) then
tp.derivedAndType(tp1s, tp2s)
else tp
case tp: FlexibleType =>
val hi1 = strip(tp.hi)
if stripFlexibleTypes then hi1 else tp.derivedFlexibleType(hi1)
case tp @ FlexibleType(hi) =>
val hi1 = strip(hi)
if stripFlexibleTypes then hi1 else FlexibleType.derivedFlexibleType(tp, hi1)
case tp @ TypeBounds(lo, hi) =>
tp.derivedTypeBounds(strip(lo), strip(hi))
case tp => tp
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala
Original file line number Diff line number Diff line change
Expand Up @@ -558,8 +558,8 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
if underlying1 ne tp.underlying then underlying1 else tp
case CapturingType(parent, refs) =>
tp.derivedCapturingType(recur(parent), refs)
case tp: FlexibleType =>
tp.derivedFlexibleType(recur(tp.hi))
case tp @ FlexibleType(hi) =>
FlexibleType.derivedFlexibleType(tp, recur(hi))
case tp: AnnotatedType =>
tp.derivedAnnotatedType(recur(tp.parent), tp.annot)
case _ =>
Expand Down Expand Up @@ -755,7 +755,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
case tp: TypeVar if contains(tp.origin) => withHard(tp)
case tp: TypeParamRef if contains(tp) => hardenTypeVars(typeVarOfParam(tp))
case tp: AndOrType => hardenTypeVars(tp.tp1).hardenTypeVars(tp.tp2)
case tp: FlexibleType => hardenTypeVars(tp.hi)
case FlexibleType(hi) => hardenTypeVars(hi)
case _ => this

def remove(pt: TypeLambda)(using Context): This = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ trait PatternTypeConstrainer { self: TypeComparer =>
// additional trait - argument-less enum cases desugar to vals.
// See run/enum-Tree.scala.
if tp.classSymbol.exists then tp else tp.info
case tp: FlexibleType => dealiasDropNonmoduleRefs(tp.underlying)
case FlexibleType(hi) => dealiasDropNonmoduleRefs(hi)
case tp => tp
}

Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ object StdNames {
final val NotNull: N = "NotNull"
final val Null: N = "Null"
final val Object: N = "Object"
final val FlexibleType : N = "<FlexibleType>"
final val FromJavaObject: N = "<FromJavaObject>"
final val Record: N = "Record"
final val Product: N = "Product"
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/TypeApplications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -552,8 +552,8 @@ class TypeApplications(val self: Type) extends AnyVal {
* Existential types in arguments are returned as TypeBounds instances.
*/
final def argInfos(using Context): List[Type] = self.stripped match
case FlexibleType(hi) => hi.argInfos
case AppliedType(tycon, args) => args
case tp: FlexibleType => tp.underlying.argInfos
case _ => Nil

/** If this is an encoding of a function type, return its arguments, otherwise return Nil.
Expand Down
8 changes: 4 additions & 4 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,8 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
}

def thirdTry: Boolean = tp2 match {
case FlexibleType(hi2) =>
recur(tp1, OrNull(hi2))
case tp2 @ AppliedType(tycon2, args2) =>
compareAppliedType2(tp2, tycon2, args2)
case tp2: NamedType =>
Expand Down Expand Up @@ -915,8 +917,6 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
false
}
compareClassInfo
case tp2: FlexibleType =>
recur(tp1, tp2.lo)
case _ =>
fourthTry
}
Expand Down Expand Up @@ -977,6 +977,8 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
else fourthTry

def fourthTry: Boolean = tp1 match {
case FlexibleType(hi1) =>
recur(hi1, tp2)
case tp1: TypeRef =>
tp1.info match {
case info1 @ TypeBounds(lo1, hi1) =>
Expand Down Expand Up @@ -1129,8 +1131,6 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
case tp1: ExprType if ctx.phaseId > gettersPhase.id =>
// getters might have converted T to => T, need to compensate.
recur(tp1.widenExpr, tp2)
case tp1: FlexibleType =>
recur(tp1.hi, tp2)
case _ =>
false
}
Expand Down
86 changes: 45 additions & 41 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ object Types extends TypeUtils {
isRef(defn.ObjectClass) && (typeSymbol eq defn.FromJavaObjectSymbol)

def containsFromJavaObject(using Context): Boolean = this match
case tp: FlexibleType => tp.underlying.containsFromJavaObject
case FlexibleType(hi) => hi.containsFromJavaObject
case tp: OrType => tp.tp1.containsFromJavaObject || tp.tp2.containsFromJavaObject
case tp: AndType => tp.tp1.containsFromJavaObject && tp.tp2.containsFromJavaObject
case _ => isFromJavaObject
Expand Down Expand Up @@ -382,7 +382,7 @@ object Types extends TypeUtils {
/** Is this type guaranteed not to have `null` as a value? */
final def isNotNull(using Context): Boolean = this match {
case tp: ConstantType => tp.value.value != null
case tp: FlexibleType => false
case FlexibleType(_) => false
case tp: ClassInfo => !tp.cls.isNullableClass && !tp.isNothingType
case tp: AppliedType => tp.superType.isNotNull
case tp: TypeBounds => tp.hi.isNotNull
Expand All @@ -398,7 +398,7 @@ object Types extends TypeUtils {
case OrType(l, r) => r.admitsNull || l.admitsNull
case AndType(l, r) => r.admitsNull && l.admitsNull
case TypeBounds(lo, hi) => lo.admitsNull
case FlexibleType(lo, hi) => true
case FlexibleType(_) => true
case tp: TypeProxy => tp.underlying.admitsNull
case _ => false
)
Expand All @@ -423,7 +423,7 @@ object Types extends TypeUtils {
case AppliedType(tycon, args) => tycon.unusableForInference || args.exists(_.unusableForInference)
case RefinedType(parent, _, rinfo) => parent.unusableForInference || rinfo.unusableForInference
case TypeBounds(lo, hi) => lo.unusableForInference || hi.unusableForInference
case tp: FlexibleType => tp.underlying.unusableForInference
case FlexibleType(hi) => hi.unusableForInference
case tp: AndOrType => tp.tp1.unusableForInference || tp.tp2.unusableForInference
case tp: LambdaType => tp.resultType.unusableForInference || tp.paramInfos.exists(_.unusableForInference)
case WildcardType(optBounds) => optBounds.unusableForInference
Expand Down Expand Up @@ -464,8 +464,9 @@ object Types extends TypeUtils {
(new isGroundAccumulator).apply(true, this)

/** Is this a type of a repeated parameter? */
def isRepeatedParam(using Context): Boolean =
typeSymbol eq defn.RepeatedParamClass
def isRepeatedParam(using Context): Boolean = this match
case FlexibleType(hi) => hi.isRepeatedParam
case _ => typeSymbol eq defn.RepeatedParamClass

/** Is this type of the form `compiletime.into[T]`, which means it can be the
* target of an implicit converson without requiring a language import?
Expand Down Expand Up @@ -1471,8 +1472,8 @@ object Types extends TypeUtils {
tp.rebind(tp.parent.widenUnion)
case tp: HKTypeLambda =>
tp.derivedLambdaType(resType = tp.resType.widenUnion)
case tp: FlexibleType =>
tp.derivedFlexibleType(tp.hi.widenUnionWithoutNull)
case tp @ FlexibleType(hi) =>
FlexibleType.derivedFlexibleType(tp, hi.widenUnionWithoutNull)
case tp =>
tp

Expand Down Expand Up @@ -1902,8 +1903,8 @@ object Types extends TypeUtils {
t
case t @ SAMType(_, _) =>
t
case ft: FlexibleType =>
ft.underlying.findFunctionType
case FlexibleType(hi) =>
hi.findFunctionType
case _ =>
NoType

Expand Down Expand Up @@ -3474,24 +3475,24 @@ object Types extends TypeUtils {
* `T | Null .. T`, so that `T | Null <: FlexibleType(T) <: T`.
* A flexible type will be erased to its original type `T`.
*/
case class FlexibleType protected(lo: Type, hi: Type) extends CachedProxyType with ValueType {
// case class FlexibleType protected(lo: Type, hi: Type) extends CachedProxyType with ValueType {

override def underlying(using Context): Type = hi
// override def underlying(using Context): Type = hi

def derivedFlexibleType(hi: Type)(using Context): Type =
if hi eq this.hi then this else FlexibleType.make(hi)
// def derivedFlexibleType(hi: Type)(using Context): Type =
// if hi eq this.hi then this else FlexibleType.make(hi)

override def computeHash(bs: Binders): Int = doHash(bs, hi)
// override def computeHash(bs: Binders): Int = doHash(bs, hi)

override final def baseClasses(using Context): List[ClassSymbol] = hi.baseClasses
}
// override final def baseClasses(using Context): List[ClassSymbol] = hi.baseClasses
// }

object FlexibleType:
def apply(tp: Type)(using Context): FlexibleType =
def apply(tp: Type)(using Context): Type =
assert(tp.isValueType, s"Should not flexify ${tp}")
tp match
case ft: FlexibleType => ft
case _ => FlexibleType(OrNull(tp), tp)
case ft @ FlexibleType(hi) => ft
case _ => AppliedType(defn.FlexibleTypeType, tp :: Nil)
// val tp1 = tp.stripNull()
// if tp1.isNullType then
// // (Null)? =:= ? >: Null <: (Object & Null)
Expand All @@ -3508,8 +3509,19 @@ object Types extends TypeUtils {
// It is not necessary according to the use cases, so we choose to use a simpler
// rule.

def unapply(tp: Type)(using Context): Option[Type] = tp match
case AppliedType(tycon, args) if tycon.isRef(defn.FlexibleTypeSymbol) => Some(args.head)
case _ => None

def isInstance(tp: Type)(using Context): Boolean = unapply(tp).isDefined

def derivedFlexibleType(tp: Type, hi: Type)(using Context): Type =
tp match
case FlexibleType(hi0) if hi eq hi0 => tp
case _ => FlexibleType.make(hi)

def make(tp: Type)(using Context): Type = tp match
case _: FlexibleType => tp // tp is already flexible
case tp @ FlexibleType(hi) => tp // tp is already flexible
case SimpleOrNull(_) => tp // tp is already nullable
case TypeBounds(lo, hi) => TypeBounds(FlexibleType.make(lo), FlexibleType.make(hi))
case wt: WildcardType => wt.optBounds match
Expand Down Expand Up @@ -6154,8 +6166,8 @@ object Types extends TypeUtils {
samClass(tp.underlying)
case tp: AnnotatedType =>
samClass(tp.underlying)
case tp: FlexibleType =>
samClass(tp.underlying)
case FlexibleType(hi) =>
samClass(hi)
case _ =>
NoSymbol

Expand Down Expand Up @@ -6313,8 +6325,6 @@ object Types extends TypeUtils {
tp.derivedJavaArrayType(elemtp)
protected def derivedExprType(tp: ExprType, restpe: Type): Type =
tp.derivedExprType(restpe)
protected def derivedFlexibleType(tp: FlexibleType, hi: Type): Type =
tp.derivedFlexibleType(hi)
// note: currying needed because Scala2 does not support param-dependencies
protected def derivedLambdaType(tp: LambdaType)(formals: List[tp.PInfo], restpe: Type): Type =
tp.derivedLambdaType(tp.paramNames, formals, restpe)
Expand Down Expand Up @@ -6512,9 +6522,6 @@ object Types extends TypeUtils {
case tp: OrType =>
derivedOrType(tp, this(tp.tp1), this(tp.tp2))

case tp: FlexibleType =>
derivedFlexibleType(tp, this(tp.hi))

case tp: MatchType =>
val bound1 = this(tp.bound)
val scrut1 = atVariance(0)(this(tp.scrutinee))
Expand Down Expand Up @@ -6759,6 +6766,16 @@ object Types extends TypeUtils {

override protected def derivedAppliedType(tp: AppliedType, tycon: Type, args: List[Type]): Type =
tycon match {
case tr if tr.isRef(defn.FlexibleTypeSymbol) =>
val hi = args.head
hi match {
case Range(lo, hi) =>
// We know FlexibleType(t).hi = t and FlexibleType(t).lo = OrNull(t)
range(OrNull(lo), hi)
case _ =>
if (hi.isExactlyNothing) hi
else FlexibleType.derivedFlexibleType(tp, hi)
}
case Range(tyconLo, tyconHi) =>
range(derivedAppliedType(tp, tyconLo, args), derivedAppliedType(tp, tyconHi, args))
case _ =>
Expand Down Expand Up @@ -6826,16 +6843,6 @@ object Types extends TypeUtils {
else tp.derivedAnnotatedType(underlying, annot)
}

override protected def derivedFlexibleType(tp: FlexibleType, hi: Type): Type =
hi match {
case Range(lo, hi) =>
// We know FlexibleType(t).hi = t and FlexibleType(t).lo = OrNull(t)
range(OrNull(lo), hi)
case _ =>
if (hi.isExactlyNothing) hi
else tp.derivedFlexibleType(hi)
}

override protected def derivedCapturingType(tp: Type, parent: Type, refs: CaptureSet): Type =
parent match // TODO ^^^ handle ranges in capture sets as well
case Range(lo, hi) =>
Expand Down Expand Up @@ -6975,9 +6982,6 @@ object Types extends TypeUtils {
case tp: TypeVar =>
this(x, tp.underlying)

case tp: FlexibleType =>
this(x, tp.underlying)

case ExprType(restpe) =>
this(x, restpe)

Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) {
}

private def pickleNewType(tpe: Type, richTypes: Boolean)(using Context): Unit = tpe match {
case FlexibleType(hi) =>
writeByte(FLEXIBLEtype)
withLength { pickleType(hi, richTypes) }
case AppliedType(tycon, args) =>
if tycon.typeSymbol == defn.MatchCaseClass then
writeByte(MATCHCASEtype)
Expand Down Expand Up @@ -296,9 +299,6 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) {
case tpe: OrType =>
writeByte(ORtype)
withLength { pickleType(tpe.tp1, richTypes); pickleType(tpe.tp2, richTypes) }
case tpe: FlexibleType =>
writeByte(FLEXIBLEtype)
withLength { pickleType(tpe.underlying, richTypes) }
case tpe: ExprType =>
writeByte(BYNAMEtype)
pickleType(tpe.underlying)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ class PlainPrinter(_ctx: Context) extends Printer {
toText(tpe)
case _ =>
toTextLocal(tpe) ~ " " ~ toText(annot)
case FlexibleType(_, tpe) =>
case FlexibleType(tpe) =>
"(" ~ toText(tpe) ~ ")?"
case tp: TypeVar =>
def toTextCaret(tp: Type) = if printDebug then toTextLocal(tp) ~ Str("^") else toText(tp)
Expand Down
Loading
Loading