diff --git a/compiler/src/dotty/tools/dotc/transform/init/Objects.scala b/compiler/src/dotty/tools/dotc/transform/init/Objects.scala index 3d01b6a93b08..db0066401621 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Objects.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Objects.scala @@ -1298,9 +1298,14 @@ object Objects: case select: Select => eval(select.qualifier, thisV, klass) - val implicitValues = evalArgs(implicits.map(Arg.apply), thisV, klass) - // TODO: implicit values may appear before and/or after the scrutinee parameter. - val unapplyRes = call(receiver, funRef.symbol, TraceValue(scrutinee, summon[Trace]) :: implicitValues, funRef.prefix, superType = NoType, needResolve = true) + def implicitArgsBeforeScrutinee(fun: Tree): Contextual[List[ArgInfo]] = fun match + case Apply(f, implicitArgs) => + implicitArgsBeforeScrutinee(f) ++ evalArgs(implicitArgs.map(Arg.apply), thisV, klass) + case _ => List() + + val implicitArgsAfterScrutinee = evalArgs(implicits.map(Arg.apply), thisV, klass) + val args = implicitArgsBeforeScrutinee(fun) ++ (TraceValue(scrutinee, summon[Trace]) :: implicitArgsAfterScrutinee) + val unapplyRes = call(receiver, funRef.symbol, args, funRef.prefix, superType = NoType, needResolve = true) if fun.symbol.name == nme.unapplySeq then var resultTp = unapplyResTp diff --git a/tests/init-global/neg/unapply-implicit-arg.scala b/tests/init-global/neg/unapply-implicit-arg.scala new file mode 100644 index 000000000000..bf41fbbf9412 --- /dev/null +++ b/tests/init-global/neg/unapply-implicit-arg.scala @@ -0,0 +1,14 @@ +object Bar { + class Foo { + def m1(i: Int) = i+1 + def m2(i: Int) = i+2 + } + def unapply(using f1: Foo)(i: Int): Option[Int] = + if i == 0 then Some(f1.m1(i)) else Some(f1.m2(i)) + + given Foo = new Foo + val i1: Int = 0 + val i2: Int = i2 match // error + case Bar(i) => i + case _ => 0 +} \ No newline at end of file diff --git a/tests/init-global/neg/unapply-implicit-arg2.scala b/tests/init-global/neg/unapply-implicit-arg2.scala new file mode 100644 index 000000000000..c0a16faac377 --- /dev/null +++ b/tests/init-global/neg/unapply-implicit-arg2.scala @@ -0,0 +1,14 @@ +object Bar { + class Foo { + def m1(i: Int) = i+1 + def m2(i: Int) = i+2 + } + def unapply(using f1: Foo)(i: Int): Option[Int] = + if i == 0 then Some(f1.m1(i1)) else Some(f1.m2(i2)) // error + + given Foo = new Foo + val i1: Int = 0 + val i2: Int = i1 match + case Bar(i) => i + case _ => 0 +} diff --git a/tests/init-global/neg/unapply-implicit-arg3.scala b/tests/init-global/neg/unapply-implicit-arg3.scala new file mode 100644 index 000000000000..efa348f6cfdb --- /dev/null +++ b/tests/init-global/neg/unapply-implicit-arg3.scala @@ -0,0 +1,14 @@ +object Bar { + class Foo { + def m1(i: Int) = i + i1 + def m2(i: Int) = i + i2 // error + } + def unapply(using f1: Foo)(i: Int): Option[Int] = + if i == 0 then Some(f1.m1(i)) else Some(f1.m2(i)) + + given Foo = new Foo + val i1: Int = 0 + val i2: Int = i1 match + case Bar(i) => i + case _ => 0 +} diff --git a/tests/init-global/neg/unapplySeq-implicit-arg.scala b/tests/init-global/neg/unapplySeq-implicit-arg.scala new file mode 100644 index 000000000000..e58635a3090f --- /dev/null +++ b/tests/init-global/neg/unapplySeq-implicit-arg.scala @@ -0,0 +1,14 @@ +object Bar { + class Foo { + def m1(seq: Seq[Int]) = 1 +: seq + def m2(seq: Seq[Int]) = 2 +: seq + } + def unapplySeq(using f1: Foo)(seqi: Seq[Int]): Option[Seq[Int]] = + if seqi(0) == 0 then Some(f1.m1(seqi)) else Some(f1.m2(seqi)) + + given Foo = new Foo + val i1: Int = 0 + val i2: Int = Seq(i2) match // error + case Bar(i) => i + case _ => 0 +} diff --git a/tests/init-global/neg/unapplySeq-implicit-arg2.scala b/tests/init-global/neg/unapplySeq-implicit-arg2.scala new file mode 100644 index 000000000000..35f5105b84d2 --- /dev/null +++ b/tests/init-global/neg/unapplySeq-implicit-arg2.scala @@ -0,0 +1,10 @@ +object Bar { + class Foo + def unapplySeq(using f1: Foo)(using f2: Foo)(seqi: Seq[Int])(using Foo): Option[Seq[Int]] = + Some(i1 +: seqi) // error + given Foo = new Foo + val i1: Int = Seq(0) match { + case Bar(i) => i + case _ => 0 + } +} diff --git a/tests/init-global/neg/unapplySeq-implicit-arg3.scala b/tests/init-global/neg/unapplySeq-implicit-arg3.scala new file mode 100644 index 000000000000..2b5cdd327e57 --- /dev/null +++ b/tests/init-global/neg/unapplySeq-implicit-arg3.scala @@ -0,0 +1,12 @@ +object Bar { + class Foo { + def m(seq: Seq[Int]) = i1 +: seq // error + } + def unapplySeq(using f1: Foo)(seqi: Seq[Int])(using Foo): Option[Seq[Int]] = + Some(f1.m(seqi)) + given Foo = new Foo + val i1: Int = Seq(0) match { + case Bar(i, _) => i + case _ => 0 + } +} diff --git a/tests/init-global/pos/unapply-implicit-arg-pos.scala b/tests/init-global/pos/unapply-implicit-arg-pos.scala new file mode 100644 index 000000000000..5573a2210160 --- /dev/null +++ b/tests/init-global/pos/unapply-implicit-arg-pos.scala @@ -0,0 +1,14 @@ +object Bar { + class Foo { + def m1(i: Int) = i + i1 + def m2(i: Int) = i + 2 + } + def unapply(using f1: Foo)(using f2: Foo)(i: Int)(using f3: Foo): Option[Int] = + if i == 0 then Some(f1.m1(i1) + f3.m1(i1)) else Some(f2.m2(i) + f3.m2(i)) + + given Foo = new Foo + val i1: Int = 0 + val i2: Int = i1 match + case Bar(i) => i + case _ => 0 +} \ No newline at end of file diff --git a/tests/init-global/pos/unapplySeq-implicit-arg-pos.scala b/tests/init-global/pos/unapplySeq-implicit-arg-pos.scala new file mode 100644 index 000000000000..08e69d4ff3bc --- /dev/null +++ b/tests/init-global/pos/unapplySeq-implicit-arg-pos.scala @@ -0,0 +1,14 @@ +object Bar { + class Foo { + def m1(seq: Seq[Int]) = 0 +: seq + def m2(seq: Seq[Int]) = i1 +: seq + } + def unapplySeq(using f1: Foo)(using f2: Foo)(seqi: Seq[Int])(using f3: Foo): Option[Seq[Int]] = + if seqi(0) == 0 then Some(f1.m1(seqi)) else Some(f2.m2(seqi)) + + given Foo = new Foo + val i1: Int = 0 + val i2: Int = Seq(i1) match + case Bar(i) => i + case _ => 0 +}