From 3b6266dbdd21249674e148423a4ef8d8950c70ee Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 22 Apr 2022 15:39:29 +0200 Subject: [PATCH 1/9] Disallow old uses of quoted and spliced types These have have been emitting migration warning in 3.0 and 3.1 even if the syntax was already deprecated in 3.0. These where allowed syntax found in older papers. The case `'[T]` was actually buggy but no one reported this bug so far. A good indication that this older syntax has not been used in a while. First step towards fixing #15009. --- .../tools/dotc/typer/QuotesAndSplices.scala | 43 +++++++------------ tests/neg/i15009a.check | 36 ++++++++++++++++ tests/neg/i15009a.scala | 13 ++++++ 3 files changed, 65 insertions(+), 27 deletions(-) create mode 100644 tests/neg/i15009a.check create mode 100644 tests/neg/i15009a.scala diff --git a/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala b/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala index 783c03cba812..afbb53557e79 100644 --- a/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala +++ b/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala @@ -52,11 +52,12 @@ trait QuotesAndSplices { if ctx.mode.is(Mode.Pattern) then typedQuotePattern(tree, pt, qctx).withSpan(tree.span) else if tree.quoted.isType then - val msg = em"Consider using canonical type constructor scala.quoted.Type.of[${tree.quoted}] instead" - if sourceVersion.isAtLeast(`future-migration`) then report.error(msg, tree.srcPos) - else report.warning(msg, tree.srcPos) - val typeOfTree = untpd.TypeApply(untpd.ref(defn.QuotedTypeModule_of.termRef), tree.quoted :: Nil).withSpan(tree.span) - makeInlineable(typedTypeApply(typeOfTree, pt)(using quoteContext).select(nme.apply).appliedTo(qctx).withSpan(tree.span)) + val msg = em"""Quoted types `'[..]` can only be used in patterns. + | + |Hint: To get a scala.quoted.Type[T] use scala.quoted.Type.of[T] instead. + |""".stripMargin + report.error(msg, tree.srcPos) + EmptyTree else val exprQuoteTree = untpd.Apply(untpd.ref(defn.QuotedRuntime_exprQuote.termRef), tree.quoted) makeInlineable(typedApply(exprQuoteTree, pt)(using pushQuotes(qctx)).select(nme.apply).appliedTo(qctx).withSpan(tree.span)) @@ -135,7 +136,7 @@ trait QuotesAndSplices { case arg: untpd.Ident => typedExpr(arg) case arg => - report.error("Open patttern exprected an identifier", arg.srcPos) + report.error("Open pattern expected an identifier", arg.srcPos) EmptyTree } if args.isEmpty then @@ -145,28 +146,16 @@ trait QuotesAndSplices { ref(defn.QuotedRuntimePatterns_patternHigherOrderHole).appliedToType(pt).appliedTo(typedPat, SeqLiteral(typedArgs, TypeTree(defn.AnyType))) } - /** Translate ${ t: Type[T] }` into type `t.splice` while tracking the quotation level in the context */ + /** Emit error with migration hint */ def typedTypSplice(tree: untpd.TypSplice, pt: Type)(using Context): Tree = { - record("typedTypSplice") - checkSpliceOutsideQuote(tree) - tree.expr match { - case untpd.Quote(innerType) if innerType.isType => - report.warning("Canceled quote directly inside a splice. ${ '[ XYZ ] } is equivalent to XYZ.", tree.srcPos) - case _ => - } - - if ctx.mode.is(Mode.QuotedPattern) && level == 1 then - report.error( - """`$` for quote pattern variable is not supported anymore. - |Use lower cased variable name without the `$` instead.""".stripMargin, - tree.srcPos) - ref(defn.NothingType) - else - val tree1 = typedSelect(untpd.Select(tree.expr, tpnme.Underlying), pt)(using spliceContext).withSpan(tree.span) - val msg = em"Consider using canonical type reference ${tree1.tpe} instead" - if sourceVersion.isAtLeast(`future-migration`) then report.error(msg, tree.srcPos) - else report.warning(msg, tree.srcPos) - tree1 + val msg = "Type splicing with `$` in quotes not supported anymore" + val hint = + if ctx.mode.is(Mode.QuotedPattern) && level == 1 then + "Use lower cased variable name without the `$` instead" + else + "Use a given Type[T] in a quote just write T directly" + report.error(s"$msg\n\nHint: $hint", tree.srcPos) + ref(defn.NothingType) } /** Type a pattern variable name `t` in quote pattern as `${given t$giveni: Type[t @ _]}`. diff --git a/tests/neg/i15009a.check b/tests/neg/i15009a.check new file mode 100644 index 000000000000..96398899241d --- /dev/null +++ b/tests/neg/i15009a.check @@ -0,0 +1,36 @@ +-- Error: tests/neg/i15009a.scala:3:2 ---------------------------------------------------------------------------------- +3 | '[Int] // error + | ^^^^^^ + | Quoted types `'[..]` can only be used in patterns. + | + | Hint: To get a scala.quoted.Type[T] use scala.quoted.Type.of[T] instead. +-- Error: tests/neg/i15009a.scala:4:2 ---------------------------------------------------------------------------------- +4 | '[List[${Type.of[Int]}]] // error + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | Quoted types `'[..]` can only be used in patterns. + | + | Hint: To get a scala.quoted.Type[T] use scala.quoted.Type.of[T] instead. +-- Error: tests/neg/i15009a.scala:7:16 --------------------------------------------------------------------------------- +7 | case '[List[$a]] => // error + | ^^ + | Type splicing with `$` in quotes not supported anymore + | + | Hint: Use lower cased variable name without the `$` instead +-- Error: tests/neg/i15009a.scala:10:16 -------------------------------------------------------------------------------- +10 | '{ List.empty[$int] } // error + | ^^^^ + | Type splicing with `$` in quotes not supported anymore + | + | Hint: Use a given Type[T] in a quote just write T directly +-- Error: tests/neg/i15009a.scala:11:9 --------------------------------------------------------------------------------- +11 | val t: ${int} = ??? // error + | ^^^^^^ + | Type splicing with `$` in quotes not supported anymore + | + | Hint: Use a given Type[T] in a quote just write T directly +-- [E006] Not Found Error: tests/neg/i15009a.scala:12:2 ---------------------------------------------------------------- +12 | $int // error: Not found: $int + | ^^^^ + | Not found: $int + | + | longer explanation available when compiling with `-explain` diff --git a/tests/neg/i15009a.scala b/tests/neg/i15009a.scala new file mode 100644 index 000000000000..6360b251b83e --- /dev/null +++ b/tests/neg/i15009a.scala @@ -0,0 +1,13 @@ +import scala.quoted.* +def test(using Quotes): Unit = { + '[Int] // error + '[List[${Type.of[Int]}]] // error + + Type.of[Int] match + case '[List[$a]] => // error + + val int = Type.of[Int] + '{ List.empty[$int] } // error + val t: ${int} = ??? // error + $int // error: Not found: $int +} From a72309cecbbc16049a7d5c51edfb9423f33e8055 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 22 Apr 2022 15:59:39 +0200 Subject: [PATCH 2/9] Remove error that cannot appear anymore Now that we do not support the old syntax for splicing types it is not possible to get this error. The code is buggy and fails with another error that is not worth testing. --- compiler/src/dotty/tools/dotc/ast/Desugar.scala | 2 -- .../src/dotty/tools/dotc/reporting/ErrorMessageID.scala | 8 ++++---- compiler/src/dotty/tools/dotc/reporting/messages.scala | 9 --------- tests/neg-macros/type-splice-in-val-pattern.check | 6 ------ tests/neg-macros/type-splice-in-val-pattern.scala | 7 ------- 5 files changed, 4 insertions(+), 28 deletions(-) delete mode 100644 tests/neg-macros/type-splice-in-val-pattern.check delete mode 100644 tests/neg-macros/type-splice-in-val-pattern.scala diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index faf420fcc44c..cf2c3c0e1a68 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -1911,8 +1911,6 @@ object desugar { new UntypedTreeTraverser { def traverse(tree: untpd.Tree)(using Context): Unit = tree match { case Splice(expr) => collect(expr) - case TypSplice(expr) => - report.error(TypeSpliceInValPattern(expr), tree.srcPos) case _ => traverseChildren(tree) } }.traverse(expr) diff --git a/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala index 0df893b7d6fd..c85006cc25be 100644 --- a/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala +++ b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala @@ -19,8 +19,8 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe case TypeMismatchID // errorNumber: 7 case NotAMemberID // errorNumber: 8 case EarlyDefinitionsNotSupportedID // errorNumber: 9 - case TopLevelImplicitClassID extends ErrorMessageID(isActive = false) // errorNumber: 10 - case ImplicitCaseClassID // errorNumber: 11 + case TopLevelImplicitClassID extends ErrorMessageID(isActive = false) // errorNumber: 10 + case ImplicitCaseClassID // errorNumber: 11 case ImplicitClassPrimaryConstructorArityID // errorNumber: 12 case ObjectMayNotHaveSelfTypeID // errorNumber: 13 case TupleTooLongID extends ErrorMessageID(isActive = false) // errorNumber: 14 @@ -97,7 +97,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe case FunctionTypeNeedsNonEmptyParameterListID // errorNumber: 85 case WrongNumberOfParametersID // errorNumber: 86 case DuplicatePrivateProtectedQualifierID // errorNumber: 87 - case ExpectedStartOfTopLevelDefinitionID // errorNumber: 88 + case ExpectedStartOfTopLevelDefinitionID // errorNumber: 88 case MissingReturnTypeWithReturnStatementID // errorNumber: 89 case NoReturnFromInlineableID // errorNumber: 90 case ReturnOutsideMethodDefinitionID // errorNumber: 91 @@ -164,7 +164,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe case ExtensionCanOnlyHaveDefsID // errorNumber: 152 case UnexpectedPatternForSummonFromID // errorNumber: 153 case AnonymousInstanceCannotBeEmptyID // errorNumber: 154 - case TypeSpliceInValPatternID // errorNumber: 155 + case TypeSpliceInValPatternID extends ErrorMessageID(isActive = false) // errorNumber: 155 case ModifierNotAllowedForDefinitionID // errorNumber: 156 case CannotExtendJavaEnumID // errorNumber: 157 case InvalidReferenceInImplicitNotFoundAnnotationID // errorNumber: 158 diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index 1f3ed68c90b1..f2b14ee315df 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -2447,15 +2447,6 @@ import transform.SymUtils._ |""".stripMargin } - class TypeSpliceInValPattern(expr: untpd.Tree)(using Context) - extends SyntaxMsg(TypeSpliceInValPatternID) { - def msg = "Type splices cannot be used in val patterns. Consider using `match` instead." - def explain = - em"""|Type splice: `$$${expr.show}` cannot be used in a `val` pattern. Consider rewriting the `val` pattern - |as a `match` with a corresponding `case` to replace the `val`. - |""".stripMargin - } - class ModifierNotAllowedForDefinition(flag: Flag)(using Context) extends SyntaxMsg(ModifierNotAllowedForDefinitionID) { def msg = em"Modifier ${hl(flag.flagsString)} is not allowed for this definition" diff --git a/tests/neg-macros/type-splice-in-val-pattern.check b/tests/neg-macros/type-splice-in-val-pattern.check deleted file mode 100644 index 627aa2d5755d..000000000000 --- a/tests/neg-macros/type-splice-in-val-pattern.check +++ /dev/null @@ -1,6 +0,0 @@ --- [E155] Syntax Error: tests/neg-macros/type-splice-in-val-pattern.scala:5:14 ----------------------------------------- -5 | val '[ *:[$t] ] = ??? // error - | ^^ - | Type splices cannot be used in val patterns. Consider using `match` instead. - | - | longer explanation available when compiling with `-explain` diff --git a/tests/neg-macros/type-splice-in-val-pattern.scala b/tests/neg-macros/type-splice-in-val-pattern.scala deleted file mode 100644 index 7e5e95cb7785..000000000000 --- a/tests/neg-macros/type-splice-in-val-pattern.scala +++ /dev/null @@ -1,7 +0,0 @@ -import scala.quoted.* -object Foo { - def f(using q: Quotes) = { - val t: Type[Int] = ??? - val '[ *:[$t] ] = ??? // error - } -} \ No newline at end of file From f95f0c7ef6a2ec876945def1ce32a98b054acadd Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 22 Apr 2022 17:03:40 +0200 Subject: [PATCH 3/9] Move type quote and splice error to parser --- .../dotty/tools/dotc/parsing/Parsers.scala | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index c78e4cd8fb2f..1f1759deda9d 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1572,13 +1572,17 @@ object Parsers { /** The block in a quote or splice */ def stagedBlock() = inBraces(block(simplify = true)) - /** SimpleExpr ::= spliceId | ‘$’ ‘{’ Block ‘}’) unless inside quoted pattern - * SimpleType ::= spliceId | ‘$’ ‘{’ Block ‘}’) unless inside quoted pattern + /** ExprSplice ::= ‘$’ spliceId if inside quoted block + * | ‘$’ ‘{’ Block ‘}’) unless inside quoted pattern + * | ‘$’ ‘{’ Pattern ‘}’) when inside quoted pattern * - * SimpleExpr ::= spliceId | ‘$’ ‘{’ Pattern ‘}’) when inside quoted pattern - * SimpleType ::= spliceId | ‘$’ ‘{’ Pattern ‘}’) when inside quoted pattern + * // Deprecated syntax + * TypeSplice ::= ‘$’ spliceId if inside quoted type + * | ‘$’ ‘{’ Block ‘}’) unless inside quoted pattern + * | ‘$’ ‘{’ Pattern ‘}’) when inside quoted pattern */ def splice(isType: Boolean): Tree = + val start = in.offset atSpan(in.offset) { val expr = if (in.name.length == 1) { @@ -1591,7 +1595,16 @@ object Parsers { in.nextToken() id } - if (isType) TypSplice(expr) else Splice(expr) + if isType then + val msg = "Type splicing with `$` in quotes not supported anymore" + val inPattern = (staged & StageKind.QuotedPattern) != 0 + val hint = + if inPattern then "Use lower cased variable name without the `$` instead" + else "Use a given Type[T] in a quote just write T directly" + syntaxError(s"$msg\n\nHint: $hint", Span(start, in.lastOffset)) + Ident(nme.ERROR.toTypeName) + else + Splice(expr) } /** SimpleType ::= SimpleLiteral @@ -1635,7 +1648,7 @@ object Parsers { * | Singleton `.' type * | ‘(’ ArgTypes ‘)’ * | Refinement - * | ‘$’ ‘{’ Block ‘}’ + * | TypeSplice * | SimpleType1 TypeArgs * | SimpleType1 `#' id */ @@ -2237,7 +2250,7 @@ object Parsers { /** SimpleExpr ::= ‘new’ ConstrApp {`with` ConstrApp} [TemplateBody] * | ‘new’ TemplateBody * | BlockExpr - * | ‘$’ ‘{’ Block ‘}’ + * | ExprSplice * | Quoted * | quoteId * | SimpleExpr1 [`_`] From 435c8ff92bb924b596ccd91cab364b160783ed2e Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 22 Apr 2022 17:06:39 +0200 Subject: [PATCH 4/9] Remove unnecessary untpd.TypSplice --- compiler/src/dotty/tools/dotc/ast/untpd.scala | 9 --------- .../dotty/tools/dotc/printing/RefinedPrinter.scala | 2 -- .../dotty/tools/dotc/typer/QuotesAndSplices.scala | 14 -------------- compiler/src/dotty/tools/dotc/typer/Typer.scala | 1 - 4 files changed, 26 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/untpd.scala b/compiler/src/dotty/tools/dotc/ast/untpd.scala index 2decfd3c0479..a769df537f1a 100644 --- a/compiler/src/dotty/tools/dotc/ast/untpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/untpd.scala @@ -110,7 +110,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { case class Splice(expr: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree { def isInBraces: Boolean = span.end != expr.span.end } - case class TypSplice(expr: Tree)(implicit @constructorOnly src: SourceFile) extends TypTree case class ForYield(enums: List[Tree], expr: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree case class ForDo(enums: List[Tree], body: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree case class GenFrom(pat: Tree, expr: Tree, checkMode: GenCheckMode)(implicit @constructorOnly src: SourceFile) extends Tree @@ -613,10 +612,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { case tree: Splice if expr eq tree.expr => tree case _ => finalize(tree, untpd.Splice(expr)(tree.source)) } - def TypSplice(tree: Tree)(expr: Tree)(using Context): Tree = tree match { - case tree: TypSplice if expr eq tree.expr => tree - case _ => finalize(tree, untpd.TypSplice(expr)(tree.source)) - } def ForYield(tree: Tree)(enums: List[Tree], expr: Tree)(using Context): TermTree = tree match { case tree: ForYield if (enums eq tree.enums) && (expr eq tree.expr) => tree case _ => finalize(tree, untpd.ForYield(enums, expr)(tree.source)) @@ -695,8 +690,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { cpy.Quote(tree)(transform(t)) case Splice(expr) => cpy.Splice(tree)(transform(expr)) - case TypSplice(expr) => - cpy.TypSplice(tree)(transform(expr)) case ForYield(enums, expr) => cpy.ForYield(tree)(transform(enums), transform(expr)) case ForDo(enums, body) => @@ -754,8 +747,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { this(x, t) case Splice(expr) => this(x, expr) - case TypSplice(expr) => - this(x, expr) case ForYield(enums, expr) => this(this(x, enums), expr) case ForDo(enums, body) => diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 8bdf1d4822ce..5e89fa9c6e6b 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -691,8 +691,6 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { keywordStr("'{") ~ toTextGlobal(dropBlock(tree)) ~ keywordStr("}") case Splice(tree) => keywordStr("${") ~ toTextGlobal(dropBlock(tree)) ~ keywordStr("}") - case TypSplice(tree) => - keywordStr("${") ~ toTextGlobal(dropBlock(tree)) ~ keywordStr("}") case Thicket(trees) => "Thicket {" ~~ toTextGlobal(trees, "\n") ~~ "}" case MacroTree(call) => diff --git a/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala b/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala index afbb53557e79..d260d530994d 100644 --- a/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala +++ b/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala @@ -38,8 +38,6 @@ trait QuotesAndSplices { tree.quoted match { case untpd.Splice(innerExpr) if tree.isTerm && !ctx.mode.is(Mode.Pattern) => report.warning("Canceled splice directly inside a quote. '{ ${ XYZ } } is equivalent to XYZ.", tree.srcPos) - case untpd.TypSplice(innerType) if tree.isType => - report.warning("Canceled splice directly inside a quote. '[ ${ XYZ } ] is equivalent to XYZ.", tree.srcPos) case _ => } val qctx = inferImplicitArg(defn.QuotesClass.typeRef, tree.span) @@ -146,18 +144,6 @@ trait QuotesAndSplices { ref(defn.QuotedRuntimePatterns_patternHigherOrderHole).appliedToType(pt).appliedTo(typedPat, SeqLiteral(typedArgs, TypeTree(defn.AnyType))) } - /** Emit error with migration hint */ - def typedTypSplice(tree: untpd.TypSplice, pt: Type)(using Context): Tree = { - val msg = "Type splicing with `$` in quotes not supported anymore" - val hint = - if ctx.mode.is(Mode.QuotedPattern) && level == 1 then - "Use lower cased variable name without the `$` instead" - else - "Use a given Type[T] in a quote just write T directly" - report.error(s"$msg\n\nHint: $hint", tree.srcPos) - ref(defn.NothingType) - } - /** Type a pattern variable name `t` in quote pattern as `${given t$giveni: Type[t @ _]}`. * The resulting pattern is the split in `splitQuotePattern`. */ diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 34eb2b7df41f..eb0b92358db8 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -2898,7 +2898,6 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer case untpd.EmptyTree => tpd.EmptyTree case tree: untpd.Quote => typedQuote(tree, pt) case tree: untpd.Splice => typedSplice(tree, pt) - case tree: untpd.TypSplice => typedTypSplice(tree, pt) case tree: untpd.MacroTree => report.error("Unexpected macro", tree.srcPos); tpd.nullLiteral // ill-formed code may reach here case tree: untpd.Hole => typedHole(tree, pt) case _ => typedUnadapted(desugar(tree), pt, locked) From 055f66bc61ad6236b7ebb73398ea1495533ec87c Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 22 Apr 2022 17:20:32 +0200 Subject: [PATCH 5/9] Fix syntax documentation --- compiler/src/dotty/tools/dotc/parsing/Parsers.scala | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 1f1759deda9d..8bde73bf65a0 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1572,14 +1572,14 @@ object Parsers { /** The block in a quote or splice */ def stagedBlock() = inBraces(block(simplify = true)) - /** ExprSplice ::= ‘$’ spliceId if inside quoted block - * | ‘$’ ‘{’ Block ‘}’) unless inside quoted pattern - * | ‘$’ ‘{’ Pattern ‘}’) when inside quoted pattern + /** ExprSplice ::= ‘$’ id if inside quoted block + * | ‘$’ ‘{’ Block ‘}’ unless inside quoted pattern + * | ‘$’ ‘{’ Pattern ‘}’ when inside quoted pattern * * // Deprecated syntax - * TypeSplice ::= ‘$’ spliceId if inside quoted type - * | ‘$’ ‘{’ Block ‘}’) unless inside quoted pattern - * | ‘$’ ‘{’ Pattern ‘}’) when inside quoted pattern + * TypeSplice ::= ‘$’ id if inside quoted type + * | ‘$’ ‘{’ Block ‘}’ unless inside quoted type pattern + * | ‘$’ ‘{’ Pattern ‘}’ when inside quoted type pattern */ def splice(isType: Boolean): Tree = val start = in.offset From bf600bcc38eb16d0b0d435e2e99e610e7b0a08dc Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 22 Apr 2022 17:22:22 +0200 Subject: [PATCH 6/9] Remove unnecessary special casing of splice idents --- compiler/src/dotty/tools/dotc/parsing/Parsers.scala | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 8bde73bf65a0..c83c7e6f2a92 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -452,8 +452,6 @@ object Parsers { makeParameter(nme.ERROR, tree, mods) case Typed(id @ Ident(name), tpt) => makeParameter(name.asTermName, tpt, mods, isBackquoted = isBackquoted(id)).withSpan(tree.span) - case Typed(Splice(Ident(name)), tpt) => - makeParameter(("$" + name).toTermName, tpt, mods).withSpan(tree.span) case _ => syntaxError(s"not a legal $expected", tree.span) makeParameter(nme.ERROR, tree, mods) From 5d6901fbf316614d05575f06e59a26fc597bafd6 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 22 Apr 2022 17:28:33 +0200 Subject: [PATCH 7/9] Fix typo --- .../dotty/tools/dotc/parsing/Parsers.scala | 2 +- tests/neg/i15009a.check | 24 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index c83c7e6f2a92..963aa407ac00 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1598,7 +1598,7 @@ object Parsers { val inPattern = (staged & StageKind.QuotedPattern) != 0 val hint = if inPattern then "Use lower cased variable name without the `$` instead" - else "Use a given Type[T] in a quote just write T directly" + else "To use a given Type[T] in a quote just write T directly" syntaxError(s"$msg\n\nHint: $hint", Span(start, in.lastOffset)) Ident(nme.ERROR.toTypeName) else diff --git a/tests/neg/i15009a.check b/tests/neg/i15009a.check index 96398899241d..4bdca5318d38 100644 --- a/tests/neg/i15009a.check +++ b/tests/neg/i15009a.check @@ -1,15 +1,9 @@ --- Error: tests/neg/i15009a.scala:3:2 ---------------------------------------------------------------------------------- -3 | '[Int] // error - | ^^^^^^ - | Quoted types `'[..]` can only be used in patterns. - | - | Hint: To get a scala.quoted.Type[T] use scala.quoted.Type.of[T] instead. --- Error: tests/neg/i15009a.scala:4:2 ---------------------------------------------------------------------------------- +-- Error: tests/neg/i15009a.scala:4:9 ---------------------------------------------------------------------------------- 4 | '[List[${Type.of[Int]}]] // error - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | Quoted types `'[..]` can only be used in patterns. + | ^^^^^^^^^^^^^^^ + | Type splicing with `$` in quotes not supported anymore | - | Hint: To get a scala.quoted.Type[T] use scala.quoted.Type.of[T] instead. + | Hint: To use a given Type[T] in a quote just write T directly -- Error: tests/neg/i15009a.scala:7:16 --------------------------------------------------------------------------------- 7 | case '[List[$a]] => // error | ^^ @@ -21,13 +15,19 @@ | ^^^^ | Type splicing with `$` in quotes not supported anymore | - | Hint: Use a given Type[T] in a quote just write T directly + | Hint: To use a given Type[T] in a quote just write T directly -- Error: tests/neg/i15009a.scala:11:9 --------------------------------------------------------------------------------- 11 | val t: ${int} = ??? // error | ^^^^^^ | Type splicing with `$` in quotes not supported anymore | - | Hint: Use a given Type[T] in a quote just write T directly + | Hint: To use a given Type[T] in a quote just write T directly +-- Error: tests/neg/i15009a.scala:3:2 ---------------------------------------------------------------------------------- +3 | '[Int] // error + | ^^^^^^ + | Quoted types `'[..]` can only be used in patterns. + | + | Hint: To get a scala.quoted.Type[T] use scala.quoted.Type.of[T] instead. -- [E006] Not Found Error: tests/neg/i15009a.scala:12:2 ---------------------------------------------------------------- 12 | $int // error: Not found: $int | ^^^^ From 920c97f5ce10c5e855eb6739e7bdc7020bf8a87d Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 25 Apr 2022 10:27:35 +0200 Subject: [PATCH 8/9] Simplify grammar --- .../dotty/tools/dotc/parsing/Parsers.scala | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 963aa407ac00..004c5838f5d6 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1570,14 +1570,12 @@ object Parsers { /** The block in a quote or splice */ def stagedBlock() = inBraces(block(simplify = true)) - /** ExprSplice ::= ‘$’ id if inside quoted block - * | ‘$’ ‘{’ Block ‘}’ unless inside quoted pattern - * | ‘$’ ‘{’ Pattern ‘}’ when inside quoted pattern - * - * // Deprecated syntax - * TypeSplice ::= ‘$’ id if inside quoted type - * | ‘$’ ‘{’ Block ‘}’ unless inside quoted type pattern - * | ‘$’ ‘{’ Pattern ‘}’ when inside quoted type pattern + /** Splice ::= ‘$’ id if inside quoted block + * | ‘$’ ‘{’ Block ‘}’ unless inside quoted pattern + * | ‘$’ ‘{’ Pattern ‘}’ when inside quoted pattern + * | ‘$’ id if inside quoted type // Deprecated syntax + * | ‘$’ ‘{’ Block ‘}’ unless inside quoted type pattern // Deprecated syntax + * | ‘$’ ‘{’ Pattern ‘}’ when inside quoted type pattern // Deprecated syntax */ def splice(isType: Boolean): Tree = val start = in.offset @@ -1608,7 +1606,7 @@ object Parsers { /** SimpleType ::= SimpleLiteral * | ‘?’ SubtypeBounds * | SimpleType1 - * | SimpeType ‘(’ Singletons ‘)’ -- under language.experimental.dependent, checked in Typer + * | SimpleType ‘(’ Singletons ‘)’ -- under language.experimental.dependent, checked in Typer * Singletons ::= Singleton {‘,’ Singleton} */ def simpleType(): Tree = @@ -1646,7 +1644,7 @@ object Parsers { * | Singleton `.' type * | ‘(’ ArgTypes ‘)’ * | Refinement - * | TypeSplice + * | Splice * | SimpleType1 TypeArgs * | SimpleType1 `#' id */ @@ -2248,7 +2246,7 @@ object Parsers { /** SimpleExpr ::= ‘new’ ConstrApp {`with` ConstrApp} [TemplateBody] * | ‘new’ TemplateBody * | BlockExpr - * | ExprSplice + * | Splice * | Quoted * | quoteId * | SimpleExpr1 [`_`] From 930627431c9e5482e4e871ffd12d9de42010446d Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 25 Apr 2022 18:02:27 +0200 Subject: [PATCH 9/9] Update syntax.md --- .../src/dotty/tools/dotc/parsing/Parsers.scala | 16 ++++++++-------- docs/_docs/internals/syntax.md | 17 +++++++++++------ 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 004c5838f5d6..3b7d11d16fd0 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1570,12 +1570,12 @@ object Parsers { /** The block in a quote or splice */ def stagedBlock() = inBraces(block(simplify = true)) - /** Splice ::= ‘$’ id if inside quoted block - * | ‘$’ ‘{’ Block ‘}’ unless inside quoted pattern - * | ‘$’ ‘{’ Pattern ‘}’ when inside quoted pattern - * | ‘$’ id if inside quoted type // Deprecated syntax - * | ‘$’ ‘{’ Block ‘}’ unless inside quoted type pattern // Deprecated syntax - * | ‘$’ ‘{’ Pattern ‘}’ when inside quoted type pattern // Deprecated syntax + /** ExprSplice ::= ‘$’ spliceId -- if inside quoted block + * | ‘$’ ‘{’ Block ‘}’ -- unless inside quoted pattern + * | ‘$’ ‘{’ Pattern ‘}’ -- when inside quoted pattern + * TypeSplice ::= ‘$’ spliceId -- if inside quoted type + * | ‘$’ ‘{’ Block ‘}’ -- unless inside quoted type pattern + * | ‘$’ ‘{’ Pattern ‘}’ -- when inside quoted type pattern */ def splice(isType: Boolean): Tree = val start = in.offset @@ -1644,7 +1644,7 @@ object Parsers { * | Singleton `.' type * | ‘(’ ArgTypes ‘)’ * | Refinement - * | Splice + * | TypeSplice -- deprecated syntax (since 3.0.0) * | SimpleType1 TypeArgs * | SimpleType1 `#' id */ @@ -2246,7 +2246,7 @@ object Parsers { /** SimpleExpr ::= ‘new’ ConstrApp {`with` ConstrApp} [TemplateBody] * | ‘new’ TemplateBody * | BlockExpr - * | Splice + * | ExprSplice * | Quoted * | quoteId * | SimpleExpr1 [`_`] diff --git a/docs/_docs/internals/syntax.md b/docs/_docs/internals/syntax.md index cae2ebae7af2..55b098e91849 100644 --- a/docs/_docs/internals/syntax.md +++ b/docs/_docs/internals/syntax.md @@ -27,7 +27,7 @@ upper ::= ‘A’ | … | ‘Z’ | ‘\$’ | ‘_’ “… and U lower ::= ‘a’ | … | ‘z’ “… and Unicode category Ll” letter ::= upper | lower “… and Unicode categories Lo, Lt, Lm, Nl” digit ::= ‘0’ | … | ‘9’ -paren ::= ‘(’ | ‘)’ | ‘[’ | ‘]’ | ‘{’ | ‘}’ | ‘'(’ | ‘'[’ | ‘'{’ +paren ::= ‘(’ | ‘)’ | ‘[’ | ‘]’ | ‘{’ | ‘}’ delim ::= ‘`’ | ‘'’ | ‘"’ | ‘.’ | ‘;’ | ‘,’ opchar ::= ‘!’ | ‘#’ | ‘%’ | ‘&’ | ‘*’ | ‘+’ | ‘-’ | ‘/’ | ‘:’ | ‘<’ | ‘=’ | ‘>’ | ‘?’ | ‘@’ | ‘\’ | ‘^’ | ‘|’ | ‘~’ @@ -45,6 +45,7 @@ id ::= plainid | ‘`’ { charNoBackQuoteOrNewline | UnicodeEscape | charEscapeSeq } ‘`’ idrest ::= {letter | digit} [‘_’ op] quoteId ::= ‘'’ alphaid +spliceId ::= ‘$’ alphaid ; integerLiteral ::= (decimalNumeral | hexNumeral) [‘L’ | ‘l’] decimalNumeral ::= ‘0’ | nonZeroDigit [{digit | ‘_’} digit] @@ -183,8 +184,7 @@ SimpleType1 ::= id | Singleton ‘.’ ‘type’ SingletonTypeTree(p) | ‘(’ Types ‘)’ Tuple(ts) | Refinement RefinedTypeTree(EmptyTree, refinement) - | ‘$’ ‘{’ Block ‘}’ -- unless inside quoted pattern - | ‘$’ ‘{’ Pattern ‘}’ -- only inside quoted pattern + | TypeSplice -- deprecated syntax | SimpleType1 TypeArgs AppliedTypeTree(t, args) | SimpleType1 ‘#’ id Select(t, name) Singleton ::= SimpleRef @@ -243,8 +243,7 @@ SimpleExpr ::= SimpleRef | Literal | ‘_’ | BlockExpr - | ‘$’ ‘{’ Block ‘}’ -- unless inside quoted pattern - | ‘$’ ‘{’ Pattern ‘}’ -- only inside quoted pattern + | ExprSplice | Quoted | quoteId -- only inside splices | ‘new’ ConstrApp {‘with’ ConstrApp} [TemplateBody] New(constr | templ) @@ -259,8 +258,14 @@ SimpleExpr ::= SimpleRef | SimpleExpr ‘_’ PostfixOp(expr, _) (to be dropped) | XmlExpr -- to be dropped IndentedExpr ::= indent CaseClauses | Block outdent -Quoted ::= ‘'’ ‘{’ Block ‘}’ +Quoted ::= ‘'’ ‘{’ Block ‘}’ | ‘'’ ‘[’ Type ‘]’ +ExprSplice ::= spliceId -- if inside quoted block + | ‘$’ ‘{’ Block ‘}’ -- unless inside quoted pattern + | ‘$’ ‘{’ Pattern ‘}’ -- when inside quoted pattern +TypeSplice ::= spliceId -- if inside quoted type -- deprecated syntax + | ‘$’ ‘{’ Block ‘}’ -- unless inside quoted type pattern -- deprecated syntax + | ‘$’ ‘{’ Pattern ‘}’ -- when inside quoted type pattern -- deprecated syntax ExprsInParens ::= ExprInParens {‘,’ ExprInParens} ExprInParens ::= PostfixExpr ‘:’ Type -- normal Expr allows only RefinedType here | Expr