Skip to content

Commit 25b2ab9

Browse files
committed
forbid given patterns in val definitions.
Suggest that they use an alias given instead.
1 parent a956774 commit 25b2ab9

File tree

6 files changed

+80
-21
lines changed

6 files changed

+80
-21
lines changed

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

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,13 +1106,24 @@ object desugar {
11061106
// - `pat` is a tuple of N variables or wildcard patterns like `(x1, x2, ..., xN)`
11071107
val tupleOptimizable = forallResults(rhs, isMatchingTuple)
11081108

1109-
val vars =
1109+
val vars0 =
11101110
if (tupleOptimizable) // include `_`
1111-
pat match {
1112-
case Tuple(pats) =>
1113-
pats.map { case id: Ident => id -> TypeTree() }
1111+
pat match
1112+
case Tuple(pats) => pats.map { case id: Ident => id -> TypeTree() }
1113+
else
1114+
getVariables(pat) // no `_`
1115+
1116+
val vars: List[VarInfo] = original match
1117+
case _: GenAlias => vars0 // allow givens in pattern aliases of a for comprehension
1118+
case _ => // assume we are in a val definition - givens are not allowed - filter them out and emit errors
1119+
vars0.filterConserve {
1120+
case (bind: Bind, tpt) if bind.mods.is(Given) =>
1121+
report.error(em"""pattern `${hl("given")} $tpt` is not allowed here,
1122+
|please bind to a variable and use an alias given.""".stripMargin, bind)
1123+
false
1124+
case _ =>
1125+
true
11141126
}
1115-
else getVariables(pat) // no `_`
11161127

11171128
val ids = for ((named, _) <- vars) yield Ident(named.name)
11181129
val caseDef = CaseDef(pat, EmptyTree, makeTuple(ids))

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import Contexts._
1515
import Names._
1616
import NameKinds.WildcardParamName
1717
import NameOps._
18-
import ast.{Positioned, Trees}
18+
import ast.{Positioned, Trees, desugar}
1919
import ast.Trees._
2020
import typer.ImportInfo
2121
import StdNames._
@@ -2703,8 +2703,9 @@ object Parsers {
27032703
case GIVEN =>
27042704
atSpan(in.offset) {
27052705
val givenMod = atSpan(in.skipToken())(Mod.Given())
2706-
val typed = Typed(Ident(nme.WILDCARD), refinedType())
2707-
Bind(nme.WILDCARD, typed).withMods(addMod(Modifiers(), givenMod))
2706+
val tpt = refinedType()
2707+
val typed = Typed(Ident(nme.WILDCARD), tpt)
2708+
Bind(desugar.inventGivenOrExtensionName(tpt), typed).withMods(addMod(Modifiers(), givenMod))
27082709
}
27092710
case _ =>
27102711
if (isLiteral) literal(inPattern = true)

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

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2006,12 +2006,7 @@ class Typer extends Namer
20062006
tpd.cpy.UnApply(body1)(fn, Nil,
20072007
typed(untpd.Bind(tree.name, untpd.TypedSplice(arg)).withSpan(tree.span), arg.tpe) :: Nil)
20082008
case _ =>
2009-
var name = tree.name
2010-
if (name == nme.WILDCARD && tree.mods.is(Given)) {
2011-
val Typed(_, tpt) = tree.body: @unchecked
2012-
name = desugar.inventGivenOrExtensionName(tpt)
2013-
}
2014-
if (name == nme.WILDCARD) body1
2009+
if (tree.name == nme.WILDCARD) body1
20152010
else {
20162011
// In `x @ Nil`, `Nil` is a _stable identifier pattern_ and will be compiled
20172012
// to an `==` test, so the type of `x` is unrelated to the type of `Nil`.
@@ -2037,11 +2032,11 @@ class Typer extends Namer
20372032
// See also #5649.
20382033
then body1.tpe
20392034
else pt & body1.tpe
2040-
val sym = newPatternBoundSymbol(name, symTp, tree.span)
2035+
val sym = newPatternBoundSymbol(tree.name, symTp, tree.span)
20412036
if (pt == defn.ImplicitScrutineeTypeRef || tree.mods.is(Given)) sym.setFlag(Given)
20422037
if (ctx.mode.is(Mode.InPatternAlternative))
20432038
report.error(i"Illegal variable ${sym.name} in pattern alternative", tree.srcPos)
2044-
assignType(cpy.Bind(tree)(name, body1), sym)
2039+
assignType(cpy.Bind(tree)(tree.name, body1), sym)
20452040
}
20462041
}
20472042
}

tests/neg/given-pattern.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ class Test {
44
import scala.collection.immutable.{TreeSet, HashSet}
55

66
def f2[T](x: Ordering[T]) = {
7-
val (given Ordering[T]) = x
8-
new TreeSet[T] // error: no implicit ordering defined for T
7+
val (given Ordering[T]) = x // error: given Ordering[T] not allowed here
8+
new TreeSet[T] // error: no implicit ordering defined for T
99
}
1010
def f3[T](x: Ordering[T]) = {
11-
val given Ordering[T] = x
12-
new TreeSet[T] // error: no implicit ordering defined for T
11+
val given Ordering[T] = x // error: given Ordering[T] not allowed here
12+
new TreeSet[T] // error: no implicit ordering defined for T
1313
}
14-
}
14+
}

tests/neg/i11897.check

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
-- Error: tests/neg/i11897.scala:9:10 ----------------------------------------------------------------------------------
2+
9 | val (x, given A) = (1, A(23)) // error
3+
| ^^^^^^^
4+
| pattern `given A` is not allowed here,
5+
| please bind to a variable and use an alias given.
6+
-- Error: tests/neg/i11897.scala:10:10 ---------------------------------------------------------------------------------
7+
10 | val (_, given B) = (true, B(false)) // error
8+
| ^^^^^^^
9+
| pattern `given B` is not allowed here,
10+
| please bind to a variable and use an alias given.
11+
-- Error: tests/neg/i11897.scala:11:8 ----------------------------------------------------------------------------------
12+
11 | val D(given C) = D(C("c")) // error
13+
| ^^^^^^^
14+
| pattern `given C` is not allowed here,
15+
| please bind to a variable and use an alias given.
16+
-- Error: tests/neg/i11897.scala:12:11 ---------------------------------------------------------------------------------
17+
12 | val F(y, given E) = F(47, E(93)) // error
18+
| ^^^^^^^
19+
| pattern `given E` is not allowed here,
20+
| please bind to a variable and use an alias given.
21+
-- Error: tests/neg/i11897.scala:13:18 ---------------------------------------------------------------------------------
22+
13 | assert(summon[A] == A(23)) // error
23+
| ^
24+
| no implicit argument of type A was found for parameter x of method summon in object Predef
25+
-- Error: tests/neg/i11897.scala:14:18 ---------------------------------------------------------------------------------
26+
14 | assert(summon[B] == B(false)) // error
27+
| ^
28+
| no implicit argument of type B was found for parameter x of method summon in object Predef
29+
-- Error: tests/neg/i11897.scala:15:18 ---------------------------------------------------------------------------------
30+
15 | assert(summon[C] == C("c")) // error
31+
| ^
32+
| no implicit argument of type C was found for parameter x of method summon in object Predef
33+
-- Error: tests/neg/i11897.scala:16:18 ---------------------------------------------------------------------------------
34+
16 | assert(summon[E] == E(93)) // error
35+
| ^
36+
| no implicit argument of type E was found for parameter x of method summon in object Predef

tests/neg/i11897.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
case class A(i: Int)
2+
case class B(b: Boolean)
3+
case class C(s: String)
4+
case class D(c: C)
5+
case class E(i: Int)
6+
case class F(i: Int, e: E)
7+
8+
def Test =
9+
val (x, given A) = (1, A(23)) // error
10+
val (_, given B) = (true, B(false)) // error
11+
val D(given C) = D(C("c")) // error
12+
val F(y, given E) = F(47, E(93)) // error
13+
assert(summon[A] == A(23)) // error
14+
assert(summon[B] == B(false)) // error
15+
assert(summon[C] == C("c")) // error
16+
assert(summon[E] == E(93)) // error

0 commit comments

Comments
 (0)