Skip to content

Commit 69e1338

Browse files
authored
Support implicit arguments before extractor method (#18671)
Currently the global object initialization checker crashes when encountering implicit arguments in extractor methods that are before scrutinee. This PR fixes the issue and adds tests with implicit arguments before scrutinee for `unapply` and `unapplySeq` respectively.
2 parents 3ea7f7a + 6c34ce4 commit 69e1338

9 files changed

+114
-3
lines changed

compiler/src/dotty/tools/dotc/transform/init/Objects.scala

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,9 +1305,14 @@ object Objects:
13051305
case select: Select =>
13061306
eval(select.qualifier, thisV, klass)
13071307

1308-
val implicitValues = evalArgs(implicits.map(Arg.apply), thisV, klass)
1309-
// TODO: implicit values may appear before and/or after the scrutinee parameter.
1310-
val unapplyRes = call(receiver, funRef.symbol, TraceValue(scrutinee, summon[Trace]) :: implicitValues, funRef.prefix, superType = NoType, needResolve = true)
1308+
def implicitArgsBeforeScrutinee(fun: Tree): Contextual[List[ArgInfo]] = fun match
1309+
case Apply(f, implicitArgs) =>
1310+
implicitArgsBeforeScrutinee(f) ++ evalArgs(implicitArgs.map(Arg.apply), thisV, klass)
1311+
case _ => List()
1312+
1313+
val implicitArgsAfterScrutinee = evalArgs(implicits.map(Arg.apply), thisV, klass)
1314+
val args = implicitArgsBeforeScrutinee(fun) ++ (TraceValue(scrutinee, summon[Trace]) :: implicitArgsAfterScrutinee)
1315+
val unapplyRes = call(receiver, funRef.symbol, args, funRef.prefix, superType = NoType, needResolve = true)
13111316

13121317
if fun.symbol.name == nme.unapplySeq then
13131318
var resultTp = unapplyResTp
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
object Bar {
2+
class Foo {
3+
def m1(i: Int) = i+1
4+
def m2(i: Int) = i+2
5+
}
6+
def unapply(using f1: Foo)(i: Int): Option[Int] =
7+
if i == 0 then Some(f1.m1(i)) else Some(f1.m2(i))
8+
9+
given Foo = new Foo
10+
val i1: Int = 0
11+
val i2: Int = i2 match // error
12+
case Bar(i) => i
13+
case _ => 0
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
object Bar {
2+
class Foo {
3+
def m1(i: Int) = i+1
4+
def m2(i: Int) = i+2
5+
}
6+
def unapply(using f1: Foo)(i: Int): Option[Int] =
7+
if i == 0 then Some(f1.m1(i1)) else Some(f1.m2(i2)) // error
8+
9+
given Foo = new Foo
10+
val i1: Int = 0
11+
val i2: Int = i1 match
12+
case Bar(i) => i
13+
case _ => 0
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
object Bar {
2+
class Foo {
3+
def m1(i: Int) = i + i1
4+
def m2(i: Int) = i + i2 // error
5+
}
6+
def unapply(using f1: Foo)(i: Int): Option[Int] =
7+
if i == 0 then Some(f1.m1(i)) else Some(f1.m2(i))
8+
9+
given Foo = new Foo
10+
val i1: Int = 0
11+
val i2: Int = i1 match
12+
case Bar(i) => i
13+
case _ => 0
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
object Bar {
2+
class Foo {
3+
def m1(seq: Seq[Int]) = 1 +: seq
4+
def m2(seq: Seq[Int]) = 2 +: seq
5+
}
6+
def unapplySeq(using f1: Foo)(seqi: Seq[Int]): Option[Seq[Int]] =
7+
if seqi(0) == 0 then Some(f1.m1(seqi)) else Some(f1.m2(seqi))
8+
9+
given Foo = new Foo
10+
val i1: Int = 0
11+
val i2: Int = Seq(i2) match // error
12+
case Bar(i) => i
13+
case _ => 0
14+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
object Bar {
2+
class Foo
3+
def unapplySeq(using f1: Foo)(using f2: Foo)(seqi: Seq[Int])(using Foo): Option[Seq[Int]] =
4+
Some(i1 +: seqi) // error
5+
given Foo = new Foo
6+
val i1: Int = Seq(0) match {
7+
case Bar(i) => i
8+
case _ => 0
9+
}
10+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
object Bar {
2+
class Foo {
3+
def m(seq: Seq[Int]) = i1 +: seq // error
4+
}
5+
def unapplySeq(using f1: Foo)(seqi: Seq[Int])(using Foo): Option[Seq[Int]] =
6+
Some(f1.m(seqi))
7+
given Foo = new Foo
8+
val i1: Int = Seq(0) match {
9+
case Bar(i, _) => i
10+
case _ => 0
11+
}
12+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
object Bar {
2+
class Foo {
3+
def m1(i: Int) = i + i1
4+
def m2(i: Int) = i + 2
5+
}
6+
def unapply(using f1: Foo)(using f2: Foo)(i: Int)(using f3: Foo): Option[Int] =
7+
if i == 0 then Some(f1.m1(i1) + f3.m1(i1)) else Some(f2.m2(i) + f3.m2(i))
8+
9+
given Foo = new Foo
10+
val i1: Int = 0
11+
val i2: Int = i1 match
12+
case Bar(i) => i
13+
case _ => 0
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
object Bar {
2+
class Foo {
3+
def m1(seq: Seq[Int]) = 0 +: seq
4+
def m2(seq: Seq[Int]) = i1 +: seq
5+
}
6+
def unapplySeq(using f1: Foo)(using f2: Foo)(seqi: Seq[Int])(using f3: Foo): Option[Seq[Int]] =
7+
if seqi(0) == 0 then Some(f1.m1(seqi)) else Some(f2.m2(seqi))
8+
9+
given Foo = new Foo
10+
val i1: Int = 0
11+
val i2: Int = Seq(i1) match
12+
case Bar(i) => i
13+
case _ => 0
14+
}

0 commit comments

Comments
 (0)