Skip to content

Commit c1f0a56

Browse files
authored
fix #11897: error on given pattern in val def (#12631)
fix #11897: error on given pattern in val def
2 parents 6287ff2 + f26026a commit c1f0a56

File tree

5 files changed

+143
-14
lines changed

5 files changed

+143
-14
lines changed

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

+34-9
Original file line numberDiff line numberDiff line change
@@ -1093,6 +1093,16 @@ object desugar {
10931093
case IdPattern(named, tpt) =>
10941094
derivedValDef(original, named, tpt, rhs, mods)
10951095
case _ =>
1096+
1097+
def filterWildcardGivenBinding(givenPat: Bind): Boolean =
1098+
givenPat.name != nme.WILDCARD
1099+
1100+
def errorOnGivenBinding(bind: Bind)(using Context): Boolean =
1101+
report.error(
1102+
em"""${hl("given")} patterns are not allowed in a ${hl("val")} definition,
1103+
|please bind to an identifier and use an alias given.""".stripMargin, bind)
1104+
false
1105+
10961106
def isTuplePattern(arity: Int): Boolean = pat match {
10971107
case Tuple(pats) if pats.size == arity =>
10981108
pats.forall(isVarPattern)
@@ -1108,13 +1118,23 @@ object desugar {
11081118
// - `pat` is a tuple of N variables or wildcard patterns like `(x1, x2, ..., xN)`
11091119
val tupleOptimizable = forallResults(rhs, isMatchingTuple)
11101120

1121+
val inAliasGenerator = original match
1122+
case _: GenAlias => true
1123+
case _ => false
1124+
11111125
val vars =
11121126
if (tupleOptimizable) // include `_`
1113-
pat match {
1114-
case Tuple(pats) =>
1115-
pats.map { case id: Ident => id -> TypeTree() }
1116-
}
1117-
else getVariables(pat) // no `_`
1127+
pat match
1128+
case Tuple(pats) => pats.map { case id: Ident => id -> TypeTree() }
1129+
else
1130+
getVariables(
1131+
tree = pat,
1132+
shouldAddGiven =
1133+
if inAliasGenerator then
1134+
filterWildcardGivenBinding
1135+
else
1136+
errorOnGivenBinding
1137+
) // no `_`
11181138

11191139
val ids = for ((named, _) <- vars) yield Ident(named.name)
11201140
val caseDef = CaseDef(pat, EmptyTree, makeTuple(ids))
@@ -1800,16 +1820,21 @@ object desugar {
18001820
/** Returns list of all pattern variables, possibly with their types,
18011821
* without duplicates
18021822
*/
1803-
private def getVariables(tree: Tree)(using Context): List[VarInfo] = {
1823+
private def getVariables(tree: Tree, shouldAddGiven: Context ?=> Bind => Boolean)(using Context): List[VarInfo] = {
18041824
val buf = ListBuffer[VarInfo]()
18051825
def seenName(name: Name) = buf exists (_._1.name == name)
18061826
def add(named: NameTree, t: Tree): Unit =
18071827
if (!seenName(named.name) && named.name.isTermName) buf += ((named, t))
18081828
def collect(tree: Tree): Unit = tree match {
1809-
case Bind(nme.WILDCARD, tree1) =>
1829+
case tree @ Bind(nme.WILDCARD, tree1) =>
1830+
if tree.mods.is(Given) then
1831+
val Typed(_, tpt) = tree1: @unchecked
1832+
if shouldAddGiven(tree) then
1833+
add(tree, tpt)
18101834
collect(tree1)
18111835
case tree @ Bind(_, Typed(tree1, tpt)) =>
1812-
add(tree, tpt)
1836+
if !(tree.mods.is(Given) && !shouldAddGiven(tree)) then
1837+
add(tree, tpt)
18131838
collect(tree1)
18141839
case tree @ Bind(_, tree1) =>
18151840
add(tree, TypeTree())
@@ -1827,7 +1852,7 @@ object desugar {
18271852
case SeqLiteral(elems, _) =>
18281853
elems foreach collect
18291854
case Alternative(trees) =>
1830-
for (tree <- trees; (vble, _) <- getVariables(tree))
1855+
for (tree <- trees; (vble, _) <- getVariables(tree, shouldAddGiven))
18311856
report.error(IllegalVariableInPatternAlternative(), vble.srcPos)
18321857
case Annotated(arg, _) =>
18331858
collect(arg)

tests/neg/given-pattern.scala

+5-5
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

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
-- Error: tests/neg/i11897.scala:11:10 ---------------------------------------------------------------------------------
2+
11 | val (x, given A) = (1, A(23)) // error
3+
| ^^^^^^^
4+
| given patterns are not allowed in a val definition,
5+
| please bind to an identifier and use an alias given.
6+
-- Error: tests/neg/i11897.scala:12:10 ---------------------------------------------------------------------------------
7+
12 | val (_, given B) = (true, B(false)) // error
8+
| ^^^^^^^
9+
| given patterns are not allowed in a val definition,
10+
| please bind to an identifier and use an alias given.
11+
-- Error: tests/neg/i11897.scala:13:8 ----------------------------------------------------------------------------------
12+
13 | val D(given C) = D(C("c")) // error
13+
| ^^^^^^^
14+
| given patterns are not allowed in a val definition,
15+
| please bind to an identifier and use an alias given.
16+
-- Error: tests/neg/i11897.scala:14:11 ---------------------------------------------------------------------------------
17+
14 | val F(y, given E) = F(47, E(93)) // error
18+
| ^^^^^^^
19+
| given patterns are not allowed in a val definition,
20+
| please bind to an identifier and use an alias given.
21+
-- Error: tests/neg/i11897.scala:15:11 ---------------------------------------------------------------------------------
22+
15 | val H(z, q @ given G) = H(47, G(101)) // error
23+
| ^^^^^^^^^^^
24+
| given patterns are not allowed in a val definition,
25+
| please bind to an identifier and use an alias given.
26+
-- Error: tests/neg/i11897.scala:16:18 ---------------------------------------------------------------------------------
27+
16 | assert(summon[A] == A(23)) // error
28+
| ^
29+
| no implicit argument of type A was found for parameter x of method summon in object Predef
30+
-- Error: tests/neg/i11897.scala:17:18 ---------------------------------------------------------------------------------
31+
17 | assert(summon[B] == B(false)) // error
32+
| ^
33+
| no implicit argument of type B was found for parameter x of method summon in object Predef
34+
-- Error: tests/neg/i11897.scala:18:18 ---------------------------------------------------------------------------------
35+
18 | assert(summon[C] == C("c")) // error
36+
| ^
37+
| no implicit argument of type C was found for parameter x of method summon in object Predef
38+
-- Error: tests/neg/i11897.scala:19:18 ---------------------------------------------------------------------------------
39+
19 | assert(summon[E] == E(93)) // error
40+
| ^
41+
| no implicit argument of type E was found for parameter x of method summon in object Predef
42+
-- Error: tests/neg/i11897.scala:20:18 ---------------------------------------------------------------------------------
43+
20 | assert(summon[G] == G(101)) // error
44+
| ^
45+
| no implicit argument of type G was found for parameter x of method summon in object Predef

tests/neg/i11897.scala

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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+
case class G(i: Int)
8+
case class H(i: Int, e: G)
9+
10+
def Test =
11+
val (x, given A) = (1, A(23)) // error
12+
val (_, given B) = (true, B(false)) // error
13+
val D(given C) = D(C("c")) // error
14+
val F(y, given E) = F(47, E(93)) // error
15+
val H(z, q @ given G) = H(47, G(101)) // error
16+
assert(summon[A] == A(23)) // error
17+
assert(summon[B] == B(false)) // error
18+
assert(summon[C] == C("c")) // error
19+
assert(summon[E] == E(93)) // error
20+
assert(summon[G] == G(101)) // error

tests/run/i10178.scala

+39
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,42 @@
33
x <- Option(23)
44
given Int = x
55
do assert(summon[Int] == 23)
6+
7+
for
8+
y <- Option("ok")
9+
q @ given String = y
10+
do assert(summon[String] == "ok")
11+
12+
for
13+
z <- Option("key" -> true)
14+
(q @ given String, u @ given Boolean) = z
15+
do
16+
assert(summon[String] == "key")
17+
assert(summon[Boolean] == true)
18+
19+
for
20+
w <- Option("no" -> false)
21+
(given String, given Boolean) = w
22+
do
23+
assert(summon[String] == "no")
24+
assert(summon[Boolean] == false)
25+
26+
for
27+
given Int <- Option(23)
28+
do assert(summon[Int] == 23)
29+
30+
for
31+
q @ given String <- Option("ok")
32+
do assert(summon[String] == "ok")
33+
34+
for
35+
(q @ given String, u @ given Boolean) <- Option("key" -> true)
36+
do
37+
assert(summon[String] == "key")
38+
assert(summon[Boolean] == true)
39+
40+
for
41+
(given String, given Boolean) <- Option("no" -> false)
42+
do
43+
assert(summon[String] == "no")
44+
assert(summon[Boolean] == false)

0 commit comments

Comments
 (0)