Skip to content

Commit 2101802

Browse files
committed
Refactor convertTo method for improved type handling with
union types
1 parent 93408e8 commit 2101802

File tree

2 files changed

+34
-40
lines changed

2 files changed

+34
-40
lines changed

compiler/src/dotty/tools/dotc/core/Constants.scala

Lines changed: 29 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -147,46 +147,35 @@ object Constants {
147147
case _ => throw new Error("value " + value + " is not a Double")
148148
}
149149

150-
/** Convert constant value to conform to given type.
151-
*/
152-
def convertTo(pt: Type)(using Context): Constant | Null = {
153-
def classBound(pt: Type): Type = pt.dealias.stripTypeVar.stripNull() match {
154-
case tref: TypeRef if !tref.symbol.isClass && tref.info.exists =>
155-
classBound(tref.info.bounds.lo)
156-
case param: TypeParamRef =>
157-
ctx.typerState.constraint.entry(param) match {
158-
case TypeBounds(lo, hi) =>
159-
if (hi.classSymbol.isPrimitiveValueClass) hi //constrain further with high bound
160-
else classBound(lo)
161-
case NoType => classBound(param.binder.paramInfos(param.paramNum).lo)
162-
case inst => classBound(inst)
163-
}
164-
case pt => pt
165-
}
166-
pt match
167-
case ConstantType(value) if value == this => this
168-
case _: SingletonType => null
169-
case _ =>
170-
val target = classBound(pt).typeSymbol
171-
if (target == tpe.typeSymbol)
172-
this
173-
else if ((target == defn.ByteClass) && isByteRange)
174-
Constant(byteValue)
175-
else if (target == defn.ShortClass && isShortRange)
176-
Constant(shortValue)
177-
else if (target == defn.CharClass && isCharRange)
178-
Constant(charValue)
179-
else if (target == defn.IntClass && isIntRange)
180-
Constant(intValue)
181-
else if (target == defn.LongClass && isLongRange)
182-
Constant(longValue)
183-
else if (target == defn.FloatClass && isFloatRange)
184-
Constant(floatValue)
185-
else if (target == defn.DoubleClass && isNumeric)
186-
Constant(doubleValue)
187-
else
188-
null
189-
}
150+
/** Convert constant value to conform to given type. */
151+
def convertTo(pt: Type)(using Context): Constant | Null = pt.dealias.stripTypeVar match
152+
case ConstantType(value) if value == this => this
153+
case _: SingletonType => null
154+
case tref: TypeRef if !tref.symbol.isClass && tref.info.exists =>
155+
convertTo(tref.info.bounds.lo)
156+
case param: TypeParamRef =>
157+
ctx.typerState.constraint.entry(param) match
158+
case TypeBounds(lo, hi) =>
159+
val hiResult = convertTo(hi)
160+
if hiResult != null then hiResult
161+
else convertTo(lo)
162+
case NoType => convertTo(param.binder.paramInfos(param.paramNum).lo)
163+
case inst => convertTo(inst)
164+
case pt: OrType =>
165+
val leftResult = convertTo(pt.tp1)
166+
if leftResult != null then leftResult
167+
else convertTo(pt.tp2)
168+
case pt =>
169+
val target = pt.typeSymbol
170+
if target == tpe.typeSymbol then this
171+
else if (target == defn.ByteClass) && isByteRange then Constant(byteValue)
172+
else if (target == defn.ShortClass) && isShortRange then Constant(shortValue)
173+
else if (target == defn.CharClass) && isCharRange then Constant(charValue)
174+
else if (target == defn.IntClass) && isIntRange then Constant(intValue)
175+
else if (target == defn.LongClass) && isLongRange then Constant(longValue)
176+
else if (target == defn.FloatClass) && isFloatRange then Constant(floatValue)
177+
else if (target == defn.DoubleClass) && isNumeric then Constant(doubleValue)
178+
else null
190179

191180
def stringValue: String = value.toString
192181

tests/pos/i24571.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@ val n3: Int = 2
44
val n4: Int | Null = 2222
55
val n5: Int | Byte = 2
66
val n6: Byte | Int = 10000
7+
val n7: 1 | Null = 1
8+
val n8: Byte | String = 2
79

810
val x: Option[Byte] = Option(2)
911
val x2: Option[Byte] = Option[Byte](2)
1012
val x3: Option[Int] = Option(2)
1113
val x4: Option[Null] = Option(null)
1214
val x5: Option[Byte | Null] = Option(2)
15+
val x6: Option[1 | Null] = Option(1)
16+
val x7: Option[Byte | String] = Option(2)
1317

1418
trait MyOption[+T]
1519

@@ -22,3 +26,4 @@ val test2: MyOption[Byte] = MyOption.applyOld(2)
2226
val test3: MyOption[Int] = MyOption(2)
2327
val test4: MyOption[Null] = MyOption(null)
2428
val test5: MyOption[Byte | Null] = MyOption(2)
29+
val test6: MyOption[Byte | String] = MyOption(2)

0 commit comments

Comments
 (0)