Skip to content

Commit 598403f

Browse files
Backport "Don't emit line number for synthetic unit value" to LTS (#20723)
Backports #18717 to the LTS branch. PR submitted by the release tooling. [skip ci]
2 parents 61994a0 + 240b1ae commit 598403f

16 files changed

+60
-40
lines changed

compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala

+22-23
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,24 @@ package backend
33
package jvm
44

55
import scala.language.unsafeNulls
6-
76
import scala.annotation.tailrec
8-
9-
import scala.collection.{ mutable, immutable }
10-
7+
import scala.collection.{immutable, mutable}
118
import scala.tools.asm
129
import dotty.tools.dotc.ast.tpd
1310
import dotty.tools.dotc.ast.TreeTypeMap
1411
import dotty.tools.dotc.CompilationUnit
15-
import dotty.tools.dotc.core.Decorators._
16-
import dotty.tools.dotc.core.Flags._
17-
import dotty.tools.dotc.core.StdNames._
18-
import dotty.tools.dotc.core.NameKinds._
12+
import dotty.tools.dotc.ast.Trees.SyntheticUnit
13+
import dotty.tools.dotc.core.Decorators.*
14+
import dotty.tools.dotc.core.Flags.*
15+
import dotty.tools.dotc.core.StdNames.*
16+
import dotty.tools.dotc.core.NameKinds.*
1917
import dotty.tools.dotc.core.Names.TermName
20-
import dotty.tools.dotc.core.Symbols._
21-
import dotty.tools.dotc.core.Types._
22-
import dotty.tools.dotc.core.Contexts._
23-
import dotty.tools.dotc.util.Spans._
18+
import dotty.tools.dotc.core.Symbols.*
19+
import dotty.tools.dotc.core.Types.*
20+
import dotty.tools.dotc.core.Contexts.*
21+
import dotty.tools.dotc.util.Spans.*
2422
import dotty.tools.dotc.report
25-
import dotty.tools.dotc.transform.SymUtils._
23+
import dotty.tools.dotc.transform.SymUtils.*
2624

2725
/*
2826
*
@@ -624,16 +622,17 @@ trait BCodeSkelBuilder extends BCodeHelpers {
624622
case _ => a
625623
}
626624

627-
if (!emitLines || !tree.span.exists) return;
628-
val nr = ctx.source.offsetToLine(tree.span.point) + 1
629-
if (nr != lastEmittedLineNr) {
630-
lastEmittedLineNr = nr
631-
getNonLabelNode(lastInsn) match {
632-
case lnn: asm.tree.LineNumberNode =>
633-
// overwrite previous landmark as no instructions have been emitted for it
634-
lnn.line = nr
635-
case _ =>
636-
mnode.visitLineNumber(nr, currProgramPoint())
625+
if (emitLines && tree.span.exists && !tree.hasAttachment(SyntheticUnit)) {
626+
val nr = ctx.source.offsetToLine(tree.span.point) + 1
627+
if (nr != lastEmittedLineNr) {
628+
lastEmittedLineNr = nr
629+
getNonLabelNode(lastInsn) match {
630+
case lnn: asm.tree.LineNumberNode =>
631+
// overwrite previous landmark as no instructions have been emitted for it
632+
lnn.line = nr
633+
case _ =>
634+
mnode.visitLineNumber(nr, currProgramPoint())
635+
}
637636
}
638637
}
639638
}

compiler/src/dotty/tools/dotc/ast/Desugar.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -1809,7 +1809,7 @@ object desugar {
18091809
case ts: Thicket => ts.trees.tail
18101810
case t => Nil
18111811
} map {
1812-
case Block(Nil, EmptyTree) => Literal(Constant(())) // for s"... ${} ..."
1812+
case Block(Nil, EmptyTree) => unitLiteral // for s"... ${} ..."
18131813
case Block(Nil, expr) => expr // important for interpolated string as patterns, see i1773.scala
18141814
case t => t
18151815
}
@@ -1837,7 +1837,7 @@ object desugar {
18371837
val pats1 = if (tpt.isEmpty) pats else pats map (Typed(_, tpt))
18381838
flatTree(pats1 map (makePatDef(tree, mods, _, rhs)))
18391839
case ext: ExtMethods =>
1840-
Block(List(ext), Literal(Constant(())).withSpan(ext.span))
1840+
Block(List(ext), unitLiteral.withSpan(ext.span))
18411841
case f: FunctionWithMods if f.hasErasedParams => makeFunctionWithValDefs(f, pt)
18421842
}
18431843
desugared.withSpan(tree.span)

compiler/src/dotty/tools/dotc/ast/Trees.scala

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ object Trees {
3131

3232
/** Property key for backquoted identifiers and definitions */
3333
val Backquoted: Property.StickyKey[Unit] = Property.StickyKey()
34+
35+
val SyntheticUnit: Property.StickyKey[Unit] = Property.StickyKey()
3436

3537
/** Trees take a parameter indicating what the type of their `tpe` field
3638
* is. Two choices: `Type` or `Untyped`.

compiler/src/dotty/tools/dotc/ast/tpd.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
6464
ta.assignType(untpd.Literal(const))
6565

6666
def unitLiteral(using Context): Literal =
67-
Literal(Constant(()))
67+
Literal(Constant(())).withAttachment(SyntheticUnit, ())
6868

6969
def nullLiteral(using Context): Literal =
7070
Literal(Constant(null))

compiler/src/dotty/tools/dotc/ast/untpd.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
479479
def InferredTypeTree(tpe: Type)(using Context): TypedSplice =
480480
TypedSplice(new InferredTypeTree().withTypeUnchecked(tpe))
481481

482-
def unitLiteral(implicit src: SourceFile): Literal = Literal(Constant(()))
482+
def unitLiteral(implicit src: SourceFile): Literal = Literal(Constant(())).withAttachment(SyntheticUnit, ())
483483

484484
def ref(tp: NamedType)(using Context): Tree =
485485
TypedSplice(tpd.ref(tp))

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -793,7 +793,7 @@ class Inliner(val call: tpd.Tree)(using Context):
793793
typed(tree.cond, defn.BooleanType)(using condCtx) match {
794794
case cond1 @ ConstantValue(b: Boolean) =>
795795
val selected0 = if (b) tree.thenp else tree.elsep
796-
val selected = if (selected0.isEmpty) tpd.Literal(Constant(())) else typed(selected0, pt)
796+
val selected = if (selected0.isEmpty) tpd.unitLiteral else typed(selected0, pt)
797797
if (isIdempotentExpr(cond1)) selected
798798
else Block(cond1 :: Nil, selected)
799799
case cond1 =>

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ object Inlines:
408408
arg match
409409
case ConstantValue(_) | Inlined(_, Nil, Typed(ConstantValue(_), _)) => // ok
410410
case _ => report.error(em"expected a constant value but found: $arg", arg.srcPos)
411-
return Literal(Constant(())).withSpan(call.span)
411+
return unitLiteral.withSpan(call.span)
412412
else if inlinedMethod == defn.Compiletime_codeOf then
413413
return Intrinsics.codeOf(arg, call.srcPos)
414414
case _ =>

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

+4-4
Original file line numberDiff line numberDiff line change
@@ -2180,7 +2180,7 @@ object Parsers {
21802180
case _ =>
21812181
}
21822182
patch(source, cond.span.endPos, "}) ()")
2183-
WhileDo(Block(body, cond), Literal(Constant(())))
2183+
WhileDo(Block(body, cond), unitLiteral)
21842184
}
21852185
case TRY =>
21862186
val tryOffset = in.offset
@@ -2210,7 +2210,7 @@ object Parsers {
22102210
in.nextToken();
22112211
val expr = subExpr()
22122212
if expr.span.exists then expr
2213-
else Literal(Constant(())) // finally without an expression
2213+
else unitLiteral // finally without an expression
22142214
}
22152215
else {
22162216
if handler.isEmpty then
@@ -3701,10 +3701,10 @@ object Parsers {
37013701
val stats = selfInvocation() :: (
37023702
if (isStatSep) { in.nextToken(); blockStatSeq() }
37033703
else Nil)
3704-
Block(stats, Literal(Constant(())))
3704+
Block(stats, unitLiteral)
37053705
}
37063706
}
3707-
else Block(selfInvocation() :: Nil, Literal(Constant(())))
3707+
else Block(selfInvocation() :: Nil, unitLiteral)
37083708

37093709
/** SelfInvocation ::= this ArgumentExprs {ArgumentExprs}
37103710
*/

compiler/src/dotty/tools/dotc/transform/DropBreaks.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ class DropBreaks extends MiniPhase:
122122
case id: Ident =>
123123
val arg = (args: @unchecked) match
124124
case arg :: Nil => arg
125-
case Nil => Literal(Constant(())).withSpan(tree.span)
125+
case Nil => unitLiteral.withSpan(tree.span)
126126
Some((id.symbol, arg))
127127
case _ => None
128128
case _ => None

compiler/src/dotty/tools/dotc/transform/Erasure.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ object Erasure {
317317
cast(tree1, pt)
318318
case _ =>
319319
val cls = pt.classSymbol
320-
if (cls eq defn.UnitClass) constant(tree, Literal(Constant(())))
320+
if (cls eq defn.UnitClass) constant(tree, unitLiteral)
321321
else {
322322
assert(cls ne defn.ArrayClass)
323323
ref(unboxMethod(cls.asClass)).appliedTo(tree)

compiler/src/dotty/tools/dotc/transform/Memoize.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ class Memoize extends MiniPhase with IdentityDenotTransformer { thisPhase =>
173173
myState.classesThatNeedReleaseFence += sym.owner
174174
val initializer =
175175
if isErasableBottomField(field, tree.termParamss.head.head.tpt.tpe.classSymbol)
176-
then Literal(Constant(()))
176+
then unitLiteral
177177
else Assign(ref(field), adaptToField(field, ref(tree.termParamss.head.head.symbol)))
178178
val setterDef = cpy.DefDef(tree)(rhs = transformFollowingDeep(initializer)(using ctx.withOwner(sym)))
179179
sym.keepAnnotationsCarrying(thisPhase, Set(defn.SetterMetaAnnot))

compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -947,7 +947,7 @@ object PatternMatcher {
947947
case LabeledPlan(label, expr) =>
948948
Labeled(label, emit(expr))
949949
case ReturnPlan(label) =>
950-
Return(Literal(Constant(())), ref(label))
950+
Return(unitLiteral, ref(label))
951951
case plan: SeqPlan =>
952952
def default = seq(emit(plan.head) :: Nil, emit(plan.tail))
953953
def maybeEmitSwitch(scrutinee: Tree): Tree = {

compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ object TypeTestsCasts {
285285
Typed(expr, tree.args.head) // Replace cast by type ascription (which does not generate any bytecode)
286286
else if (testCls eq defn.BoxedUnitClass)
287287
// as a special case, casting to Unit always successfully returns Unit
288-
Block(expr :: Nil, Literal(Constant(()))).withSpan(expr.span)
288+
Block(expr :: Nil, unitLiteral).withSpan(expr.span)
289289
else if (foundClsSymPrimitive)
290290
if (testCls.isPrimitiveValueClass) primitiveConversion(expr, testCls)
291291
else derivedTree(box(expr), defn.Any_asInstanceOf, testType)

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1547,7 +1547,7 @@ class RefChecks extends MiniPhase { thisPhase =>
15471547
private def transformIf(tree: If): Tree = {
15481548
val If(cond, thenpart, elsepart) = tree
15491549
def unitIfEmpty(t: Tree): Tree =
1550-
if (t == EmptyTree) Literal(Constant(())).setPos(tree.pos).setType(UnitTpe) else t
1550+
if (t == EmptyTree) unitLiteral.setPos(tree.pos).setType(UnitTpe) else t
15511551
15521552
cond.tpe match {
15531553
case ConstantType(value) =>

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -4117,7 +4117,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
41174117
if (!ctx.isAfterTyper && !tree.isInstanceOf[Inlined] && ctx.settings.WvalueDiscard.value && !isThisTypeResult(tree)) {
41184118
report.warning(ValueDiscarding(tree.tpe), tree.srcPos)
41194119
}
4120-
return tpd.Block(tree1 :: Nil, Literal(Constant(())))
4120+
return tpd.Block(tree1 :: Nil, unitLiteral)
41214121
}
41224122

41234123
// convert function literal to SAM closure

compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala

+19
Original file line numberDiff line numberDiff line change
@@ -1682,6 +1682,25 @@ class DottyBytecodeTests extends DottyBytecodeTest {
16821682
assertSameCode(instructions, expected)
16831683
}
16841684
}
1685+
1686+
@Test def i18320(): Unit = {
1687+
val c1 =
1688+
"""class C {
1689+
| def m: Unit = {
1690+
| val x = 1
1691+
| }
1692+
|}
1693+
|""".stripMargin
1694+
checkBCode(c1) {dir =>
1695+
val clsIn = dir.lookupName("C.class", directory = false).input
1696+
val clsNode = loadClassNode(clsIn, skipDebugInfo = false)
1697+
val method = getMethod(clsNode, "m")
1698+
val instructions = instructionsFromMethod(method).filter(_.isInstanceOf[LineNumber])
1699+
val expected = List(LineNumber(3, Label(0)))
1700+
assertSameCode(instructions, expected)
1701+
1702+
}
1703+
}
16851704
}
16861705

16871706
object invocationReceiversTestCode {

0 commit comments

Comments
 (0)