From 8b28722f66197551fbd82da7ea12b1881c1798aa Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Tue, 9 Jul 2024 23:50:58 +0200 Subject: [PATCH] Introduce `untpd.syntheticUnitLiteral` to allow detection of explicit unit provided by user from synthetic unit introduced by compiler [Cherry-picked 8c52866c98823bb9f4030ef3ffac8cc32e1426cb][modified] --- compiler/src/dotty/tools/dotc/ast/Desugar.scala | 8 ++++---- compiler/src/dotty/tools/dotc/ast/untpd.scala | 6 +++++- compiler/src/dotty/tools/dotc/parsing/Parsers.scala | 6 +++--- compiler/src/dotty/tools/dotc/typer/Typer.scala | 2 +- compiler/src/dotty/tools/repl/ReplCompiler.scala | 2 +- 5 files changed, 14 insertions(+), 10 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 80e69c4ed8b1..6863618bacfc 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -190,7 +190,7 @@ object desugar { if isSetterNeeded(vdef) then val setterParam = makeSyntheticParameter(tpt = SetterParamTree().watching(vdef)) // The rhs gets filled in later, when field is generated and getter has parameters (see Memoize miniphase) - val setterRhs = if (vdef.rhs.isEmpty) EmptyTree else unitLiteral + val setterRhs = if (vdef.rhs.isEmpty) EmptyTree else syntheticUnitLiteral val setter = cpy.DefDef(vdef)( name = valName.setterName, paramss = (setterParam :: Nil) :: Nil, @@ -1311,7 +1311,7 @@ object desugar { def block(tree: Block)(using Context): Block = tree.expr match { case EmptyTree => cpy.Block(tree)(tree.stats, - unitLiteral.withSpan(if (tree.stats.isEmpty) tree.span else tree.span.endPos)) + syntheticUnitLiteral.withSpan(if (tree.stats.isEmpty) tree.span else tree.span.endPos)) case _ => tree } @@ -1811,7 +1811,7 @@ object desugar { case ts: Thicket => ts.trees.tail case t => Nil } map { - case Block(Nil, EmptyTree) => unitLiteral // for s"... ${} ..." + case Block(Nil, EmptyTree) => syntheticUnitLiteral // for s"... ${} ..." case Block(Nil, expr) => expr // important for interpolated string as patterns, see i1773.scala case t => t } @@ -1839,7 +1839,7 @@ object desugar { val pats1 = if (tpt.isEmpty) pats else pats map (Typed(_, tpt)) flatTree(pats1 map (makePatDef(tree, mods, _, rhs))) case ext: ExtMethods => - Block(List(ext), unitLiteral.withSpan(ext.span)) + Block(List(ext), syntheticUnitLiteral.withSpan(ext.span)) case f: FunctionWithMods if f.hasErasedParams => makeFunctionWithValDefs(f, pt) } desugared.withSpan(tree.span) diff --git a/compiler/src/dotty/tools/dotc/ast/untpd.scala b/compiler/src/dotty/tools/dotc/ast/untpd.scala index 32a09b6e0db1..4c8fea17c076 100644 --- a/compiler/src/dotty/tools/dotc/ast/untpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/untpd.scala @@ -481,7 +481,11 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { def InferredTypeTree(tpe: Type)(using Context): TypedSplice = TypedSplice(new InferredTypeTree().withTypeUnchecked(tpe)) - def unitLiteral(implicit src: SourceFile): Literal = Literal(Constant(())).withAttachment(SyntheticUnit, ()) + def unitLiteral(implicit src: SourceFile): Literal = + Literal(Constant(())) + + def syntheticUnitLiteral(implicit src: SourceFile): Literal = + unitLiteral.withAttachment(SyntheticUnit, ()) def ref(tp: NamedType)(using Context): Tree = TypedSplice(tpd.ref(tp)) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index a6521bb870b8..3bd458979754 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -2284,7 +2284,7 @@ object Parsers { in.nextToken(); val expr = subExpr() if expr.span.exists then expr - else unitLiteral // finally without an expression + else syntheticUnitLiteral // finally without an expression } else { if handler.isEmpty then @@ -3768,10 +3768,10 @@ object Parsers { val stats = selfInvocation() :: ( if (isStatSep) { in.nextToken(); blockStatSeq() } else Nil) - Block(stats, unitLiteral) + Block(stats, syntheticUnitLiteral) } } - else Block(selfInvocation() :: Nil, unitLiteral) + else Block(selfInvocation() :: Nil, syntheticUnitLiteral) /** SelfInvocation ::= this ArgumentExprs {ArgumentExprs} */ diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index d8f427ff9206..027c57d8662b 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -2009,7 +2009,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer // because we do not know the internal type params and method params. // Hence no adaptation is possible, and we assume WildcardType as prototype. (from, proto) - val expr1 = typedExpr(tree.expr orElse untpd.unitLiteral.withSpan(tree.span), proto) + val expr1 = typedExpr(tree.expr orElse untpd.syntheticUnitLiteral.withSpan(tree.span), proto) assignType(cpy.Return(tree)(expr1, from)) end typedReturn diff --git a/compiler/src/dotty/tools/repl/ReplCompiler.scala b/compiler/src/dotty/tools/repl/ReplCompiler.scala index af3fb32c3e86..5c8dcc2616b7 100644 --- a/compiler/src/dotty/tools/repl/ReplCompiler.scala +++ b/compiler/src/dotty/tools/repl/ReplCompiler.scala @@ -158,7 +158,7 @@ class ReplCompiler extends Compiler: def wrap(trees: List[untpd.Tree]): untpd.PackageDef = { import untpd.* - val valdef = ValDef("expr".toTermName, TypeTree(), Block(trees, unitLiteral).withSpan(Span(0, expr.length))) + val valdef = ValDef("expr".toTermName, TypeTree(), Block(trees, syntheticUnitLiteral).withSpan(Span(0, expr.length))) val tmpl = Template(emptyConstructor, Nil, Nil, EmptyValDef, List(valdef)) val wrapper = TypeDef("$wrapper".toTypeName, tmpl) .withMods(Modifiers(Final))