Skip to content

Commit 6713020

Browse files
committed
Refine the type of inline vals with literal rhs
1 parent 895dfe0 commit 6713020

File tree

9 files changed

+69
-10
lines changed

9 files changed

+69
-10
lines changed

compiler/src/dotty/tools/dotc/inlines/Inlines.scala

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,4 +619,32 @@ object Inlines:
619619
// the opaque type itself. An example is in pos/opaque-inline1.scala.
620620
end expand
621621
end InlineCall
622+
623+
/** An inline val is refinable if it has an explicit type that is not a
624+
* singleton type.
625+
*/
626+
def mightRefineInlineVal(mdef: untpd.ValOrDefDef, sym: Symbol)(using Context): Boolean =
627+
sym.isInlineVal && !sym.is(Final)
628+
&& !mdef.tpt.isEmpty && !mdef.tpt.isInstanceOf[untpd.SingletonTypeTree]
629+
630+
/** Refine the type of an inline val to a constant type if its right hand
631+
* side is a literal. See tests/pos/i24321.scala and tests/printing/i24321.scala.
632+
*/
633+
def refineInlineVal(mdef: untpd.ValOrDefDef, sym: Symbol, tp: Type)(using Context): Type =
634+
if !Inlines.mightRefineInlineVal(mdef, sym) then
635+
return tp
636+
637+
// Only refine if the explicit type is a primitive value types and String.
638+
// We don't include opaque types. See tests/neg/i13851b.scala.
639+
val tpSym = tp.dealiasKeepOpaques.typeSymbol
640+
if !tpSym.isPrimitiveValueClass && tpSym != defn.StringClass then
641+
return tp
642+
643+
untpd.stripBlock(mdef.rhs) match
644+
case rhs: (untpd.Literal | untpd.Number) =>
645+
ctx.typer.typedAheadExpr(rhs, tp) match
646+
case tpd.ConstantValue(c) => ConstantType(Constant(c))
647+
case _ => tp
648+
case _ => tp
649+
622650
end Inlines

compiler/src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1862,7 +1862,6 @@ class Namer { typer: Typer =>
18621862
def valOrDefDefSig(mdef: ValOrDefDef, sym: Symbol, paramss: List[List[Symbol]], paramFn: Type => Type)(using Context): Type = {
18631863

18641864
def inferredType = inferredResultType(mdef, sym, paramss, paramFn, WildcardType)
1865-
18661865
val tptProto = mdef.tpt match {
18671866
case _: untpd.DerivedTypeTree =>
18681867
WildcardType
@@ -1927,7 +1926,10 @@ class Namer { typer: Typer =>
19271926
sym.setFlag(Deferred | HasDefault)
19281927
case _ =>
19291928

1930-
val mbrTpe = paramFn(checkSimpleKinded(typedAheadType(mdef.tpt, tptProto)).tpe)
1929+
val mbrTpe0 = checkSimpleKinded(typedAheadType(mdef.tpt, tptProto)).tpe
1930+
val mbrTpe1 = Inlines.refineInlineVal(mdef, sym, mbrTpe0)
1931+
val mbrTpe = paramFn(mbrTpe1)
1932+
19311933
// Add an erased to the using clause generated from a `: Singleton` context bound
19321934
mdef.tpt match
19331935
case tpt: untpd.ContextBoundTypeTree if mbrTpe.typeSymbol == defn.SingletonClass =>

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3038,7 +3038,14 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
30383038
sym.resetFlag(Lazy)
30393039
checkErasedOK(sym)
30403040
sym.setFlag(Erased)
3041-
val tpt1 = checkSimpleKinded(typedType(tpt))
3041+
3042+
val isRefinedInlineVal =
3043+
Inlines.mightRefineInlineVal(vdef, sym)
3044+
&& sym.info.isInstanceOf[ConstantType]
3045+
3046+
val tpt0 = checkSimpleKinded(typedType(tpt))
3047+
val tpt1 = if isRefinedInlineVal then TypeTree(sym.info) else tpt0
3048+
30423049
val rhs1 = vdef.rhs match
30433050
case rhs @ Ident(nme.WILDCARD) =>
30443051
rhs.withType(tpt1.tpe)

tests/neg/i8841.check

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
-- Error: tests/neg/i8841.scala:2:20 -----------------------------------------------------------------------------------
2-
2 | inline val log1 : Boolean = false // error
3-
| ^^^^^^^
4-
| inline value must have a literal constant type
51
-- Error: tests/neg/i8841.scala:3:20 -----------------------------------------------------------------------------------
62
3 | inline val log2 = true: Boolean // error
73
| ^^^^^^^^^^^^^

tests/neg/i8841.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
object Foo {
2-
inline val log1 : Boolean = false // error
2+
inline val log1 : Boolean = false // ok
33
inline val log2 = true: Boolean // error
44
inline val log3: false = { println(); false } // error
55
}

tests/neg/inline-val.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11

22
inline val a = 1 : Int // error
3-
inline val b: Int = 1 // error
4-
inline val c = b // error
3+
inline val b: Int = 1 // ok
4+
inline val c = b // ok

tests/pos/i24321.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
object Bar:
2+
inline val MAX: Byte = 10
3+
4+
val y = Bar.MAX to Bar.MAX

tests/printing/i24321.check

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[[syntax trees at end of typer]] // tests/printing/i24321.scala
2+
package <empty> {
3+
final lazy module val i24321$package: i24321$package = new i24321$package()
4+
final module class i24321$package() extends Object() {
5+
this: i24321$package.type =>
6+
inline val BOOL_CONST: (true : Boolean) = true
7+
inline val CHAR_CONST: ('A' : Char) = 'A'
8+
inline val INT_CONST: (100000 : Int) = 100000
9+
inline val LONG_CONST: (100000L : Long) = 100000L
10+
inline val FLOAT_CONST: (3.14f : Float) = 3.14f
11+
inline val DOUBLE_CONST: (3.14159d : Double) = 3.14159d
12+
inline val STRING_CONST: ("Hello, Scala 3!" : String) = "Hello, Scala 3!"
13+
}
14+
}
15+

tests/printing/i24321.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
inline val BOOL_CONST: Boolean = true
2+
inline val CHAR_CONST: Char = 'A'
3+
inline val INT_CONST: Int = 100000
4+
inline val LONG_CONST: Long = 100000L
5+
inline val FLOAT_CONST: Float = 3.14f
6+
inline val DOUBLE_CONST: Double = 3.14159
7+
inline val STRING_CONST: String = "Hello, Scala 3!"

0 commit comments

Comments
 (0)