diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala index c3ee7252cf7b..1345d3f012e4 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -627,6 +627,8 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => minOf(exprPurity(expr), bindings.map(statPurity)) case NamedArg(_, expr) => exprPurity(expr) + case Assign(v, rhs) => + exprPurity(v) `min` exprPurity(rhs) case _ => Impure } diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index d01fd58450c5..8350072a4158 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -888,6 +888,14 @@ object Erasure { super.typedValDef(untpd.cpy.ValDef(vdef)( tpt = untpd.TypedSplice(TypeTree(sym.info).withSpan(vdef.tpt.span))), sym) + /** Type check assignments, erasing those to erased variables. */ + override def typedAssign(tree: untpd.Assign, pt: Type)(using Context): Tree = + val untpd.Assign(lhs, rhs) = tree + if lhs.symbol.is(Flags.Erased) then + checkPureErased(rhs, isArgument = false) + EmptyTree + else super.typedAssign(tree, pt) + /** Besides normal typing, this function also compacts anonymous functions * with more than `MaxImplementedFunctionArity` parameters to use a single * parameter of type `[]Object`. diff --git a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala index fd859158b566..c55d3ecc0eec 100644 --- a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala +++ b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala @@ -522,8 +522,10 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: tree case tree: Assign => - // only transform the rhs - cpy.Assign(tree)(tree.lhs, transform(tree.rhs)) + if tree.lhs.symbol.is(Erased) then tree + else + // only transform the rhs + cpy.Assign(tree)(tree.lhs, transform(tree.rhs)) case tree: Return => // only transform the expr, because `from` is a "pointer" diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 58f38d10a2b3..895a7142a7bf 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -593,8 +593,8 @@ object Checking { end checkScala2Implicit def checkErasedOK(sym: Symbol)(using Context): Unit = - if sym.is(Method, butNot = Macro) - || sym.isOneOf(Mutable | Lazy) + if sym.is(Method, butNot = Macro | Accessor) + || sym.isOneOf(Lazy) || sym.isType then report.error(IllegalErasedDef(sym), sym.srcPos) diff --git a/tests/neg/erased-var.scala b/tests/neg/erased-var.scala index 51c9221e3bd9..e752dfbd0ce7 100644 --- a/tests/neg/erased-var.scala +++ b/tests/neg/erased-var.scala @@ -1,5 +1,9 @@ //> using options -language:experimental.erasedDefinitions -object Test { - erased var i: Int = 1 // error -} +case class Ev(i: Int) + +object A: + var ev = Ev(0) + erased val m: Unit = { // error + ev = Ev(1) + } diff --git a/tests/pos/erased-var.scala b/tests/pos/erased-var.scala new file mode 100644 index 000000000000..f03957e171cd --- /dev/null +++ b/tests/pos/erased-var.scala @@ -0,0 +1,11 @@ +//> using options -language:experimental.erasedDefinitions + +case class Ev(i: Int) + +def foo(x: Int)(erased ev: Ev): Int = x + 1 + +object A: + erased var ev = Ev(0) + ev = Ev(1) + foo(1)(ev) +