Compiler version
3.8.2, same outcome on latest main.
Minimized code
import language.experimental.erasedDefinitions
object Foo:
private erased val evidence: Boolean = true
inline def foo = Bar.bar(evidence)
object Bar:
def bar(erased x: Boolean) = println("Hello World")
def main =
Foo.foo
Output
-- Error: tests/pos/inline-private-erased-must-propagate.scala:13:23 -----------
13 | private erased val evidence: Boolean = true
| ^
| value evidence is declared as `erased`, but is in fact used
-- [E217] Type Error: tests/pos/inline-private-erased-must-propagate.scala:20:8
20 | Foo.foo
| ^^^^^^^
| argument to an erased parameter fails to be a pure expression
|----------------------------------------------------------------------------
|Inline stack trace
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|This location contains code that was inlined from inline-private-erased-must-propagate.scala:14
14 | inline def foo = Bar.bar(evidence)
| ^^^^^^^^
----------------------------------------------------------------------------
Expectation
Should compile. Compare to the following which does compile:
import language.experimental.erasedDefinitions
object Foo:
erased val evidence: Boolean = true
inline def foo = Bar.bar(evidence)
object Bar:
def bar(erased x: Boolean) = println("Hello World")
def main =
Foo.foo
(only difference is that we remove private; the uses of evidence stay the same)
Looking at -Vprint:erasure:
package <empty> {
@experimental(
"Added by top level \u001b[33mimport \u001b[0mlanguage.experimental.erasedDefinitions"
) final lazy module val Foo: Foo = new Foo()
@SourceFile("tests/pos/inline-private-erased-must-propagate.scala")
@experimental(
"Added by top level \u001b[33mimport \u001b[0mlanguage.experimental.erasedDefinitions"
) final module class Foo() extends Object() {
private def writeReplace(): Object =
new scala.runtime.ModuleSerializationProxy(classOf[Foo])
final def inline$evidence(): Boolean = Foo.evidence
}
@experimental(
"Added by top level \u001b[33mimport \u001b[0mlanguage.experimental.erasedDefinitions"
) final lazy module val Bar: Bar = new Bar()
@SourceFile("tests/pos/inline-private-erased-must-propagate.scala")
@experimental(
"Added by top level \u001b[33mimport \u001b[0mlanguage.experimental.erasedDefinitions"
) final module class Bar() extends Object() {
private def writeReplace(): Object =
new scala.runtime.ModuleSerializationProxy(classOf[Bar])
def bar(): Unit = println("Hello World")
}
@experimental(
"Added by top level \u001b[33mimport \u001b[0mlanguage.experimental.erasedDefinitions"
) final lazy module val inline-private-erased-must-propagate$package:
inline-private-erased-must-propagate$package =
new inline-private-erased-must-propagate$package()
@SourceFile("tests/pos/inline-private-erased-must-propagate.scala") final
module class inline-private-erased-must-propagate$package() extends Object()
{
private def writeReplace(): Object =
new scala.runtime.ModuleSerializationProxy(
classOf[inline-private-erased-must-propagate$package])
@experimental(
"Added by top level \u001b[33mimport \u001b[0mlanguage.experimental.erasedDefinitions"
) def main(): Unit = Bar.bar()
}
}
We can see that the only use site is in the inline accessor proxy which is itself unused.
Fix
We should copy the erased flag onto the inline accessor proxy if it accesses a property which is erased, so that:
- If someone uses the inline access proxy in a non-erased context the first error is still thrown ("declared as erased but still used").
- If the inline access proxy is not referred to (except in an erased context, like in this example), the code is allowed to pass.
The second error is a result of the same problem, because the check runs in a pre-erasure context where we are passing the inline$evidence parameter as for x. Making the accessor proxy erased will also get rid of this error because x is erased and we are allowed to pass erased vals as erased parameters (they are treated as pure) and so the code will compile, which is what we want.
Ran into this while working on my specialized traits work (#26156), as we generate the Specialized evidences as erased.
Compiler version
3.8.2, same outcome on latest main.
Minimized code
Output
Expectation
Should compile. Compare to the following which does compile:
(only difference is that we remove
private; the uses ofevidencestay the same)Looking at
-Vprint:erasure:We can see that the only use site is in the inline accessor proxy which is itself unused.
Fix
We should copy the erased flag onto the inline accessor proxy if it accesses a property which is erased, so that:
The second error is a result of the same problem, because the check runs in a pre-erasure context where we are passing the
inline$evidenceparameter as forx. Making the accessor proxy erased will also get rid of this error becausexis erased and we are allowed to pass erased vals as erased parameters (they are treated as pure) and so the code will compile, which is what we want.Ran into this while working on my specialized traits work (#26156), as we generate the Specialized evidences as erased.