diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 11e16c6aabd9..14584820ee3e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -888,9 +888,12 @@ trait Checking { // final vals can be marked inline even if they're not pure, see Typer#patchFinalVals val purityLevel = if (sym.is(Final)) Idempotent else Pure tpt.tpe.widenTermRefExpr.dealias match - case tp: ConstantType if exprPurity(tree) >= purityLevel => // ok + case tp: ConstantType => + if !(exprPurity(tree) >= purityLevel) then + ctx.error(em"inline value must be pure", tree.sourcePos) case _ => - ctx.error(em"type of inline must be a known value", tree.sourcePos) + val pos = if tpt.span.isZeroExtent then tree.sourcePos else tpt.sourcePos + ctx.error(em"inline value must have a literal constant type", pos) } /** A hook to exclude selected symbols from double declaration check */ diff --git a/docs/docs/reference/metaprogramming/inline.md b/docs/docs/reference/metaprogramming/inline.md index e6edeb7261cb..5e79fabfd2bf 100644 --- a/docs/docs/reference/metaprogramming/inline.md +++ b/docs/docs/reference/metaprogramming/inline.md @@ -228,6 +228,25 @@ constant expressions in the sense defined by the [SLS ยง including _platform-specific_ extensions such as constant folding of pure numeric computations. +An inline value must have a literal type such as `1` or `true`. +```scala +inline val four = 4 +// equivalent to +inline val four: 4 = 4 +``` + +It is also possible to have inline vals of types that do not have a syntax, such as `Short(4)`. + +```scala +trait InlineConstants { + inline val myShort: Short +} + +object Constants extends InlineConstants { + inline val myShort/*: Short(4)*/ = 4 +} +``` + ## Transparent Inline Methods Inline methods can additionally be declared `transparent`. diff --git a/tests/neg/i8841.check b/tests/neg/i8841.check new file mode 100644 index 000000000000..d5b79c6bc88b --- /dev/null +++ b/tests/neg/i8841.check @@ -0,0 +1,12 @@ +-- Error: tests/neg/i8841.scala:2:20 ----------------------------------------------------------------------------------- +2 | inline val log1 : Boolean = false // error + | ^^^^^^^ + | inline value must have a literal constant type +-- Error: tests/neg/i8841.scala:3:20 ----------------------------------------------------------------------------------- +3 | inline val log2 = true: Boolean // error + | ^^^^^^^^^^^^^ + | inline value must have a literal constant type +-- Error: tests/neg/i8841.scala:4:28 ----------------------------------------------------------------------------------- +4 | inline val log3: false = { println(); false } // error + | ^^^^^^^^^^^^^^^^^^^^ + | inline value must be pure diff --git a/tests/neg/i8841.scala b/tests/neg/i8841.scala new file mode 100644 index 000000000000..ebe39bb7991e --- /dev/null +++ b/tests/neg/i8841.scala @@ -0,0 +1,5 @@ +object Foo { + inline val log1 : Boolean = false // error + inline val log2 = true: Boolean // error + inline val log3: false = { println(); false } // error +} diff --git a/tests/pos/inline-vals.scala b/tests/pos/inline-vals.scala new file mode 100644 index 000000000000..b6d9cc44bdb0 --- /dev/null +++ b/tests/pos/inline-vals.scala @@ -0,0 +1,23 @@ +trait InlineConstants { + inline val myInlinedBoolean: Boolean + inline val myInlinedByte: Byte + inline val myInlinedShort: Short + inline val myInlinedInt: Int + inline val myInlinedLong: Long + inline val myInlinedFloat: Float + inline val myInlinedDouble: Double + inline val myInlinedChar: Char + inline val myInlinedString: String +} + +object Constants extends InlineConstants { + inline val myInlinedBoolean = true + inline val myInlinedByte = 1 + inline val myInlinedShort = 2 + inline val myInlinedInt = 3 + inline val myInlinedLong = 4 + inline val myInlinedFloat = 5 + inline val myInlinedDouble = 6 + inline val myInlinedChar = 'a' + inline val myInlinedString = "abc" +}