From 260183f12ff7e31221cd24a6084713d41af4ab63 Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Thu, 7 Jan 2021 12:31:39 +0100 Subject: [PATCH 1/9] Fix #10994: align typed pattern syntax to Scala 2 In Scala 2, a typed pattern `p: T` restricts that `p` can only be a pattern variable. In Dotty, #6919 allows `p` to be any pattern, in order to support pattern matching on generic number literals. This PR aligns the syntax with Scala 2 by stipulating that in a typed pattern `p: T`, either - `p` is a pattern variable, or - `p` is a number literal --- compiler/src/dotty/tools/dotc/parsing/Parsers.scala | 6 ++++-- docs/_docs/internals/syntax.md | 4 +++- tests/neg/i10994.scala | 2 ++ 3 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 tests/neg/i10994.scala diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 309dd8a20aba..2dd5d162364a 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -2809,11 +2809,13 @@ object Parsers { if (isIdent(nme.raw.BAR)) { in.nextToken(); pattern1(location) :: patternAlts(location) } else Nil - /** Pattern1 ::= Pattern2 [Ascription] + /** Pattern1 ::= PatVar Ascription + * | SimpleLiteral Ascription + * | Pattern2 */ def pattern1(location: Location = Location.InPattern): Tree = val p = pattern2() - if in.isColon then + if (isVarPattern(p) || p.isInstanceOf[Number]) && in.isColon then in.nextToken() ascription(p, location) else p diff --git a/docs/_docs/internals/syntax.md b/docs/_docs/internals/syntax.md index bae8e6d3ec8d..236079539655 100644 --- a/docs/_docs/internals/syntax.md +++ b/docs/_docs/internals/syntax.md @@ -318,7 +318,9 @@ TypeCaseClauses ::= TypeCaseClause { TypeCaseClause } TypeCaseClause ::= ‘case’ (InfixType | ‘_’) ‘=>’ Type [semi] Pattern ::= Pattern1 { ‘|’ Pattern1 } Alternative(pats) -Pattern1 ::= Pattern2 [‘:’ RefinedType] Bind(name, Typed(Ident(wildcard), tpe)) +Pattern1 ::= PatVar ‘:’ RefinedType Bind(name, Typed(Ident(wildcard), tpe)) + | SimpleLiteral ‘:’ RefinedType Bind(name, Typed(Ident(wildcard), tpe)) + | Pattern2 Pattern2 ::= [id ‘@’] InfixPattern [‘*’] Bind(name, pat) InfixPattern ::= SimplePattern { id [nl] SimplePattern } InfixOp(pat, op, pat) SimplePattern ::= PatVar Ident(wildcard) diff --git a/tests/neg/i10994.scala b/tests/neg/i10994.scala new file mode 100644 index 000000000000..ce5cb2cf3df9 --- /dev/null +++ b/tests/neg/i10994.scala @@ -0,0 +1,2 @@ +def foo = true match + case (b: Boolean): Boolean => () // error From 50e3a77030bc80d6cf4fe0a66d4be52a94db6561 Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Thu, 7 Jan 2021 12:55:59 +0100 Subject: [PATCH 2/9] Fix bootstrapping --- .../src/dotty/tools/dotc/core/Types.scala | 29 ++++++++++++++++--- .../src/dotty/tools/dotc/typer/Typer.scala | 8 +++-- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index f60bba88dde2..7ac562750ae2 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1287,7 +1287,7 @@ object Types { * then the top-level union isn't widened. This is needed so that type inference can infer nullable types. */ def widenUnion(using Context): Type = widen match - case tp @ OrNull(tp1): OrType => + case tp @ OrNull(tp1) => // Don't widen `T|Null`, since otherwise we wouldn't be able to infer nullable unions. val tp1Widen = tp1.widenUnionWithoutNull if (tp1Widen.isRef(defn.AnyClass)) tp1Widen @@ -3497,10 +3497,31 @@ object Types { */ object OrNull { def apply(tp: Type)(using Context) = - if tp.isNullType then tp else OrType(tp, defn.NullType, soft = false) + OrType(tp, defn.NullType, soft = false) + def unapply(tp: OrType)(using Context): Option[Type] = + if (ctx.explicitNulls) { + val tp1 = tp.stripNull() + if tp1 ne tp then Some(tp1) else None + } + else None + } + + /** An extractor object to pattern match against a Java-nullable union. + * e.g. + * + * (tp: Type) match + * case OrUncheckedNull(tp1) => // tp had the form `tp1 | UncheckedNull` + * case _ => // tp was not a Java-nullable union + */ + object OrUncheckedNull { + def apply(tp: Type)(using Context) = + OrType(tp, defn.UncheckedNullAliasType, soft = false) def unapply(tp: Type)(using Context): Option[Type] = - val tp1 = tp.stripNull - if tp1 ne tp then Some(tp1) else None + if (ctx.explicitNulls) { + val tp1 = tp.stripUncheckedNull + if tp1 ne tp then Some(tp1) else None + } + else None } // ----- ExprType and LambdaTypes ----------------------------------- diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 6a1e6e0b671f..9d8274dfb21c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -476,13 +476,17 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer * (x: T | Null) => x.$asInstanceOf$[x.type & T] */ def toNotNullTermRef(tree: Tree, pt: Type)(using Context): Tree = tree.tpe match - case ref @ OrNull(tpnn) : TermRef + case ref: TermRef if pt != AssignProto && // Ensure it is not the lhs of Assign ctx.notNullInfos.impliesNotNull(ref) && // If a reference is in the context, it is already trackable at the point we add it. // Hence, we don't use isTracked in the next line, because checking use out of order is enough. !ref.usedOutOfOrder => - tree.cast(AndType(ref, tpnn)) + ref.widenDealias match + case OrNull(tpnn) => + tree.cast(AndType(ref, tpnn)) + case _ => + tree case _ => tree From 8275f324f6e90d862ce00b107d0b825e67b058da Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Thu, 7 Jan 2021 16:20:47 +0100 Subject: [PATCH 3/9] Fix tests --- tests/pos/patmat.scala | 7 +------ tests/semanticdb/expect/ValPattern.expect.scala | 2 +- tests/semanticdb/expect/ValPattern.scala | 2 +- tests/semanticdb/metac.expect | 6 ++---- 4 files changed, 5 insertions(+), 12 deletions(-) diff --git a/tests/pos/patmat.scala b/tests/pos/patmat.scala index 035464437671..707475e7051d 100644 --- a/tests/pos/patmat.scala +++ b/tests/pos/patmat.scala @@ -16,7 +16,7 @@ object Test { } (xs.length, xs) match { - case (0, Nil: List[Int]) => println("1") + case (0, Nil) => println("1") case (_, Nil) => println("2") case (0, _) => println("3") case (x, y) => println("4") @@ -46,9 +46,4 @@ object Test { case Some(s) => println(s) case None => println("nothing") } - - type IntPair = (Int, Int) - ??? match { - case (x, y): IntPair => x * y - } } diff --git a/tests/semanticdb/expect/ValPattern.expect.scala b/tests/semanticdb/expect/ValPattern.expect.scala index 8eac1dc87d87..8c1215655c7c 100644 --- a/tests/semanticdb/expect/ValPattern.expect.scala +++ b/tests/semanticdb/expect/ValPattern.expect.scala @@ -6,7 +6,7 @@ class ValPattern/*<-example::ValPattern#*/ { val Some/*->scala::Some.*/(number1/*<-example::ValPattern#number1.*/) = Some/*->scala::Some.*/(1) - val List/*->scala::package.List.*/(Some/*->scala::Some.*/(q1/*<-example::ValPattern#q1.*/), None/*->scala::None.*/: None/*->scala::None.*/.type, None/*->scala::None.*/) = ???/*->scala::Predef.`???`().*/ + val List/*->scala::package.List.*/(Some/*->scala::Some.*/(q1/*<-example::ValPattern#q1.*/), None/*->scala::None.*/) = ???/*->scala::Predef.`???`().*/ var (leftVar/*<-example::ValPattern#leftVar().*/, rightVar/*<-example::ValPattern#rightVar().*/) = (1, 2) var Some/*->scala::Some.*/(number1Var/*<-example::ValPattern#number1Var().*/) = diff --git a/tests/semanticdb/expect/ValPattern.scala b/tests/semanticdb/expect/ValPattern.scala index b4e4ea3363c1..9d8923f0a45c 100644 --- a/tests/semanticdb/expect/ValPattern.scala +++ b/tests/semanticdb/expect/ValPattern.scala @@ -6,7 +6,7 @@ class ValPattern { val Some(number1) = Some(1) - val List(Some(q1), None: None.type, None) = ??? + val List(Some(q1), None) = ??? var (leftVar, rightVar) = (1, 2) var Some(number1Var) = diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index 4f7d6692eee7..2cd3a20851e7 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -3493,7 +3493,7 @@ Uri => ValPattern.scala Text => empty Language => Scala Symbols => 22 entries -Occurrences => 46 entries +Occurrences => 44 entries Synthetics => 11 entries Symbols: @@ -3532,9 +3532,7 @@ Occurrences: [8:11..8:15): Some -> scala/Some. [8:16..8:18): q1 <- example/ValPattern#q1. [8:21..8:25): None -> scala/None. -[8:27..8:31): None -> scala/None. -[8:38..8:42): None -> scala/None. -[8:46..8:49): ??? -> scala/Predef.`???`(). +[8:29..8:32): ??? -> scala/Predef.`???`(). [10:7..10:14): leftVar <- example/ValPattern#leftVar(). [10:16..10:24): rightVar <- example/ValPattern#rightVar(). [11:6..11:10): Some -> scala/Some. From 7cff9dd239b142f8586bfac1cb946e6e3248251c Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Thu, 7 Jan 2021 18:29:17 +0100 Subject: [PATCH 4/9] Fix NonNull test The test case `tests/explicit-nulls/neg/strip.scala` specify that null unions inside intersection types should work. After changing the scrutinee type of the extractor `OrNull` it is no longer the case. Changing the scrutinee type is still justified because it agrees with the name as well as the usage in `Types.scala`. In contrast, in `Typer.scala`, the logic is more clear without using `OrNull`. --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 9d8274dfb21c..1e6dbf10c6e0 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -477,15 +477,17 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer */ def toNotNullTermRef(tree: Tree, pt: Type)(using Context): Tree = tree.tpe match case ref: TermRef - if pt != AssignProto && // Ensure it is not the lhs of Assign + if ctx.explicitNulls && + pt != AssignProto && // Ensure it is not the lhs of Assign ctx.notNullInfos.impliesNotNull(ref) && // If a reference is in the context, it is already trackable at the point we add it. // Hence, we don't use isTracked in the next line, because checking use out of order is enough. !ref.usedOutOfOrder => - ref.widenDealias match - case OrNull(tpnn) => - tree.cast(AndType(ref, tpnn)) - case _ => + val tp1 = ref.widenDealias + val tp2 = tp1.stripNull() + if tp1 ne tp2 then + tree.cast(AndType(ref, tp2)) + else tree case _ => tree From ddcecd154375a7f7131d10492592cc1b4a34dd28 Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Fri, 8 Jan 2021 15:28:29 +0100 Subject: [PATCH 5/9] Update docs/docs/internals/syntax.md Co-authored-by: Jamie Thompson --- docs/_docs/internals/syntax.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_docs/internals/syntax.md b/docs/_docs/internals/syntax.md index 236079539655..76b393cb9408 100644 --- a/docs/_docs/internals/syntax.md +++ b/docs/_docs/internals/syntax.md @@ -319,7 +319,7 @@ TypeCaseClause ::= ‘case’ (InfixType | ‘_’) ‘=>’ Type [semi] Pattern ::= Pattern1 { ‘|’ Pattern1 } Alternative(pats) Pattern1 ::= PatVar ‘:’ RefinedType Bind(name, Typed(Ident(wildcard), tpe)) - | SimpleLiteral ‘:’ RefinedType Bind(name, Typed(Ident(wildcard), tpe)) + | SimpleLiteral ‘:’ RefinedType Typed(pat, tpe) | Pattern2 Pattern2 ::= [id ‘@’] InfixPattern [‘*’] Bind(name, pat) InfixPattern ::= SimplePattern { id [nl] SimplePattern } InfixOp(pat, op, pat) From 0bce5e591eb1f1a0ccbf636e25a5870deea132ef Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Fri, 7 Oct 2022 10:22:51 +0100 Subject: [PATCH 6/9] Fix tests --- .../src/dotty/tools/dotc/core/Types.scala | 40 +++++-------------- .../src/dotty/tools/dotc/typer/Typer.scala | 12 ++---- tests/neg/t5702-neg-bad-and-wild.check | 6 +-- tests/pos-macros/i11211.scala | 2 +- tests/pos-special/fatal-warnings/i10994.scala | 2 - 5 files changed, 19 insertions(+), 43 deletions(-) delete mode 100644 tests/pos-special/fatal-warnings/i10994.scala diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 7ac562750ae2..2b2a5fad79da 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1287,11 +1287,14 @@ object Types { * then the top-level union isn't widened. This is needed so that type inference can infer nullable types. */ def widenUnion(using Context): Type = widen match - case tp @ OrNull(tp1) => - // Don't widen `T|Null`, since otherwise we wouldn't be able to infer nullable unions. - val tp1Widen = tp1.widenUnionWithoutNull - if (tp1Widen.isRef(defn.AnyClass)) tp1Widen - else tp.derivedOrType(tp1Widen, defn.NullType) + case tp: OrType => tp match + case OrNull(tp1) => + // Don't widen `T|Null`, since otherwise we wouldn't be able to infer nullable unions. + val tp1Widen = tp1.widenUnionWithoutNull + if (tp1Widen.isRef(defn.AnyClass)) tp1Widen + else tp.derivedOrType(tp1Widen, defn.NullType) + case _ => + tp.widenUnionWithoutNull case tp => tp.widenUnionWithoutNull @@ -3497,31 +3500,10 @@ object Types { */ object OrNull { def apply(tp: Type)(using Context) = - OrType(tp, defn.NullType, soft = false) - def unapply(tp: OrType)(using Context): Option[Type] = - if (ctx.explicitNulls) { - val tp1 = tp.stripNull() - if tp1 ne tp then Some(tp1) else None - } - else None - } - - /** An extractor object to pattern match against a Java-nullable union. - * e.g. - * - * (tp: Type) match - * case OrUncheckedNull(tp1) => // tp had the form `tp1 | UncheckedNull` - * case _ => // tp was not a Java-nullable union - */ - object OrUncheckedNull { - def apply(tp: Type)(using Context) = - OrType(tp, defn.UncheckedNullAliasType, soft = false) + if tp.isNullType then tp else OrType(tp, defn.NullType, soft = false) def unapply(tp: Type)(using Context): Option[Type] = - if (ctx.explicitNulls) { - val tp1 = tp.stripUncheckedNull - if tp1 ne tp then Some(tp1) else None - } - else None + val tp1 = tp.stripNull + if tp1 ne tp then Some(tp1) else None } // ----- ExprType and LambdaTypes ----------------------------------- diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 1e6dbf10c6e0..1072c87e6db4 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -477,18 +477,14 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer */ def toNotNullTermRef(tree: Tree, pt: Type)(using Context): Tree = tree.tpe match case ref: TermRef - if ctx.explicitNulls && - pt != AssignProto && // Ensure it is not the lhs of Assign + if pt != AssignProto && // Ensure it is not the lhs of Assign ctx.notNullInfos.impliesNotNull(ref) && // If a reference is in the context, it is already trackable at the point we add it. // Hence, we don't use isTracked in the next line, because checking use out of order is enough. !ref.usedOutOfOrder => - val tp1 = ref.widenDealias - val tp2 = tp1.stripNull() - if tp1 ne tp2 then - tree.cast(AndType(ref, tp2)) - else - tree + ref match + case OrNull(tpnn) => tree.cast(AndType(ref, tpnn)) + case _ => tree case _ => tree diff --git a/tests/neg/t5702-neg-bad-and-wild.check b/tests/neg/t5702-neg-bad-and-wild.check index f6d761a6726f..731195411069 100644 --- a/tests/neg/t5702-neg-bad-and-wild.check +++ b/tests/neg/t5702-neg-bad-and-wild.check @@ -10,10 +10,10 @@ | pattern expected | | longer explanation available when compiling with `-explain` --- [E040] Syntax Error: tests/neg/t5702-neg-bad-and-wild.scala:13:23 --------------------------------------------------- +-- [E040] Syntax Error: tests/neg/t5702-neg-bad-and-wild.scala:13:22 --------------------------------------------------- 13 | case List(1, _*3:) => // error // error - | ^ - | an identifier expected, but ')' found + | ^ + | ')' expected, but ':' found -- [E032] Syntax Error: tests/neg/t5702-neg-bad-and-wild.scala:15:18 --------------------------------------------------- 15 | case List(x*, 1) => // error: pattern expected | ^ diff --git a/tests/pos-macros/i11211.scala b/tests/pos-macros/i11211.scala index 2650fa754193..154d8df174e7 100644 --- a/tests/pos-macros/i11211.scala +++ b/tests/pos-macros/i11211.scala @@ -12,7 +12,7 @@ def takeOptionImpl2[T](using Quotes, Type[T]): Unit = '{ def takeOptionImpl[T](o: Expr[Option[T]], default: Expr[T])(using Quotes, Type[T]): Expr[T] = '{ $o match { case Some(t1) => t1 - case None: Option[T] => $default + case None => $default } } diff --git a/tests/pos-special/fatal-warnings/i10994.scala b/tests/pos-special/fatal-warnings/i10994.scala deleted file mode 100644 index 99ae647466b1..000000000000 --- a/tests/pos-special/fatal-warnings/i10994.scala +++ /dev/null @@ -1,2 +0,0 @@ -def foo = true match - case (b: Boolean): Boolean => () From 4baaa50de135ec17fb7f5859170080f3ca384840 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Fri, 7 Oct 2022 10:50:13 +0100 Subject: [PATCH 7/9] Add latest test case --- tests/neg/i15893.scala | 61 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 tests/neg/i15893.scala diff --git a/tests/neg/i15893.scala b/tests/neg/i15893.scala new file mode 100644 index 000000000000..997c51179099 --- /dev/null +++ b/tests/neg/i15893.scala @@ -0,0 +1,61 @@ +sealed trait NatT +case class Zero() extends NatT +case class Succ[+N <: NatT](n: N) extends NatT + +type Mod2[N <: NatT] <: NatT = N match + case Zero => Zero + case Succ[Zero] => Succ[Zero] + case Succ[Succ[predPredN]] => Mod2[predPredN] + +def mod2(n: NatT): NatT = n match + case Zero() => Zero() + case Succ(Zero()) => Succ(Zero()) + case Succ(Succ(predPredN)) => mod2(predPredN) + +inline def inlineMod2(inline n: NatT): NatT = inline n match + case Zero() => Zero() + case Succ(Zero()) => Succ(Zero()) + case Succ(Succ(predPredN)) => inlineMod2(predPredN) + +transparent inline def transparentInlineMod2(inline n: NatT): NatT = inline n match + case Zero() => Zero() + case Succ(Zero()) => Succ(Zero()) + case Succ(Succ(predPredN)) => transparentInlineMod2(predPredN) + +def dependentlyTypedMod2[N <: NatT](n: N): Mod2[N] = n match // exhaustivity warning; unexpected + case Zero(): Zero => Zero() // error + case Succ(Zero()): Succ[Zero] => Succ(Zero()) // error + case Succ(Succ(predPredN)): Succ[Succ[_]] => dependentlyTypedMod2(predPredN) // error + +inline def inlineDependentlyTypedMod2[N <: NatT](inline n: N): Mod2[N] = inline n match + case Zero(): Zero => Zero() // error + case Succ(Zero()): Succ[Zero] => Succ(Zero()) // error + case Succ(Succ(predPredN)): Succ[Succ[_]] => inlineDependentlyTypedMod2(predPredN) // error + +transparent inline def transparentInlineDependentlyTypedMod2[N <: NatT](inline n: N): Mod2[N] = inline n match + case Zero(): Zero => Zero() // error + case Succ(Zero()): Succ[Zero] => Succ(Zero()) // error + case Succ(Succ(predPredN)): Succ[Succ[_]] => transparentInlineDependentlyTypedMod2(predPredN) // error + +def foo(n: NatT): NatT = mod2(n) match + case Succ(Zero()) => Zero() + case _ => n + +inline def inlineFoo(inline n: NatT): NatT = inline inlineMod2(n) match + case Succ(Zero()) => Zero() + case _ => n + +inline def transparentInlineFoo(inline n: NatT): NatT = inline transparentInlineMod2(n) match + case Succ(Zero()) => Zero() + case _ => n + +@main def main(): Unit = + println(mod2(Succ(Succ(Succ(Zero()))))) // prints Succ(Zero()), as expected + println(foo(Succ(Succ(Succ(Zero()))))) // prints Zero(), as expected + println(inlineMod2(Succ(Succ(Succ(Zero()))))) // prints Succ(Zero()), as expected + println(inlineFoo(Succ(Succ(Succ(Zero()))))) // prints Succ(Succ(Succ(Zero()))); unexpected + println(transparentInlineMod2(Succ(Succ(Succ(Zero()))))) // prints Succ(Zero()), as expected + println(transparentInlineFoo(Succ(Succ(Succ(Zero()))))) // prints Zero(), as expected + println(dependentlyTypedMod2(Succ(Succ(Succ(Zero()))))) // runtime error; unexpected +// println(inlineDependentlyTypedMod2(Succ(Succ(Succ(Zero()))))) // doesn't compile; unexpected +// println(transparentInlineDependentlyTypedMod2(Succ(Succ(Succ(Zero()))))) // doesn't compile; unexpected From 2c459cdce8b14896ee80e653b88b26f267f5f3b0 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Mon, 17 Oct 2022 11:10:16 +0200 Subject: [PATCH 8/9] Only allow _numeric_ literals in typed patterns --- compiler/src/dotty/tools/dotc/parsing/Parsers.scala | 3 ++- docs/_docs/internals/syntax.md | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 2dd5d162364a..6a862d076a2e 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -2810,7 +2810,8 @@ object Parsers { else Nil /** Pattern1 ::= PatVar Ascription - * | SimpleLiteral Ascription + * | [‘-’] integerLiteral Ascription + * | [‘-’] floatingPointLiteral Ascription * | Pattern2 */ def pattern1(location: Location = Location.InPattern): Tree = diff --git a/docs/_docs/internals/syntax.md b/docs/_docs/internals/syntax.md index 76b393cb9408..7fce82cbebbc 100644 --- a/docs/_docs/internals/syntax.md +++ b/docs/_docs/internals/syntax.md @@ -319,7 +319,8 @@ TypeCaseClause ::= ‘case’ (InfixType | ‘_’) ‘=>’ Type [semi] Pattern ::= Pattern1 { ‘|’ Pattern1 } Alternative(pats) Pattern1 ::= PatVar ‘:’ RefinedType Bind(name, Typed(Ident(wildcard), tpe)) - | SimpleLiteral ‘:’ RefinedType Typed(pat, tpe) + | [‘-’] integerLiteral ‘:’ RefinedType Typed(pat, tpe) + | [‘-’] floatingPointLiteral ‘:’ RefinedType Typed(pat, tpe) | Pattern2 Pattern2 ::= [id ‘@’] InfixPattern [‘*’] Bind(name, pat) InfixPattern ::= SimplePattern { id [nl] SimplePattern } InfixOp(pat, op, pat) From 27ba2e1d16b762e954fd73103ce63f4fb747a668 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Sat, 5 Nov 2022 10:04:06 +0000 Subject: [PATCH 9/9] Copy changes from internal/syntax to reference/syntax --- docs/_docs/reference/syntax.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/_docs/reference/syntax.md b/docs/_docs/reference/syntax.md index e11629c8eaf9..53d54e29634e 100644 --- a/docs/_docs/reference/syntax.md +++ b/docs/_docs/reference/syntax.md @@ -306,7 +306,10 @@ TypeCaseClauses ::= TypeCaseClause { TypeCaseClause } TypeCaseClause ::= ‘case’ (InfixType | ‘_’) ‘=>’ Type [semi] Pattern ::= Pattern1 { ‘|’ Pattern1 } -Pattern1 ::= Pattern2 [‘:’ RefinedType] +Pattern1 ::= PatVar ‘:’ RefinedType + | [‘-’] integerLiteral ‘:’ RefinedType + | [‘-’] floatingPointLiteral ‘:’ RefinedType + | Pattern2 Pattern2 ::= [id ‘@’] InfixPattern [‘*’] InfixPattern ::= SimplePattern { id [nl] SimplePattern } SimplePattern ::= PatVar