Skip to content

Commit a82af21

Browse files
authored
Merge pull request #12719 from dotty-staging/fix-12708
Insert conversions also on selections wrapped in type applications
2 parents dd3f2fb + 03f88ef commit a82af21

File tree

4 files changed

+49
-14
lines changed

4 files changed

+49
-14
lines changed

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3045,12 +3045,12 @@ class Typer extends Namer
30453045
}
30463046
}
30473047

3048-
/** If this tree is a select node `qual.name` that does not conform to `pt`,
3049-
* try to insert an implicit conversion `c` around `qual` so that
3050-
* `c(qual).name` conforms to `pt`.
3048+
/** If this tree is a select node `qual.name` (possibly applied to type variables)
3049+
* that does not conform to `pt`, try to insert an implicit conversion `c` around
3050+
* `qual` so that `c(qual).name` conforms to `pt`.
30513051
*/
30523052
def tryInsertImplicitOnQualifier(tree: Tree, pt: Type, locked: TypeVars)(using Context): Option[Tree] = trace(i"try insert impl on qualifier $tree $pt") {
3053-
tree match {
3053+
tree match
30543054
case tree @ Select(qual, name) if name != nme.CONSTRUCTOR =>
30553055
val selProto = SelectionProto(name, pt, NoViewsAllowed, privateOK = false)
30563056
if selProto.isMatchedBy(qual.tpe) then None
@@ -3061,8 +3061,9 @@ class Typer extends Namer
30613061
else Some(adapt(tree1, pt, locked))
30623062
} { (_, _) => None
30633063
}
3064+
case TypeApply(fn, args) if args.forall(_.isInstanceOf[TypeVarBinder[_]]) =>
3065+
tryInsertImplicitOnQualifier(fn, pt, locked)
30643066
case _ => None
3065-
}
30663067
}
30673068

30683069
/** Given a selection `qual.name`, try to convert to an extension method

tests/neg/i8861.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ object Test {
2020
)
2121
def minimalFail[M](c: Container { type A = M }): M = c.visit(
2222
int = vi => vi.i : vi.A,
23-
str = vs => vs.t : vs.A // error
23+
str = vs => vs.t : vs.A // error // error
2424
)
2525

2626
def main(args: Array[String]): Unit = {

tests/pos/i12708.scala

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import language.implicitConversions
2+
3+
trait AdditiveSemigroup[A]
4+
5+
final class AdditiveSemigroupOps[A](lhs: A)(implicit as: AdditiveSemigroup[A]) {
6+
def +(rhs: A): A = ???
7+
def ^(rhs: A): A = ???
8+
}
9+
10+
trait AdditiveSemigroupSyntax {
11+
implicit def additiveSemigroupOps[A: AdditiveSemigroup](a: A): AdditiveSemigroupOps[A] =
12+
new AdditiveSemigroupOps(a)
13+
}
14+
15+
object syntax {
16+
object additiveSemigroup extends AdditiveSemigroupSyntax
17+
}
18+
19+
object App {
20+
21+
def main(args: Array[String]): Unit = {
22+
import syntax.additiveSemigroup._
23+
24+
implicit def IntAlgebra[A]: AdditiveSemigroup[Map[Int, A]] = ???
25+
26+
def res[A]: Map[Int, A] = {
27+
val a: Map[Int, A] = Map.empty
28+
val b: Map[Int, A] = Map.empty
29+
// Calls the operator on AdditiveSemigroupOps
30+
a ^ b
31+
// Calls the operator + on AdditiveSemigroupOps only in Scala 2
32+
// In Scala 3 tries to call `+` on Map
33+
a + b
34+
}
35+
}
36+
37+
}

tests/neg/zipped.scala renamed to tests/pos/zipped.scala

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,14 @@ object Test {
2222
xs.lazyZip(xs).lazyZip(xs)
2323
.map( (x: Int, y: Int, z: Int) => x + y + z ) // OK
2424

25-
// 4. The single parameter map does not work.
25+
// 4. The single parameter map works through an inserted conversion
2626
xs.lazyZip(xs).lazyZip(xs)
27-
.map( (x: (Int, Int, Int)) => x match { case (x, y, z) => x + y + z }) // error
27+
.map( (x: (Int, Int, Int)) => x match { case (x, y, z) => x + y + z }) // now also OK
2828

29-
// 5. If we leave out the parameter type, we get a "Wrong number of parameters" error instead
29+
// 5. If we leave out the parameter type, it now works as well.
3030
xs.lazyZip(xs).lazyZip(xs)
31-
.map( x => x match { case (x, y, z) => x + y + z }) // error
31+
.map( x => x match { case (x, y, z) => x + y + z }) // now also OK
3232

33-
// This means that the following works in Dotty in normal mode, since a `withFilter`
34-
// is inserted. But it does no work under -strict. And it will not work in Scala 3.1.
35-
// The reason is that without -strict, the code below is mapped to (1), but with -strict
36-
// it is mapped to (5).
33+
// This means that the following works in Dotty 3.0 as well as 3.x
3734
for ((x, y, z) <- xs.lazyZip(xs).lazyZip(xs)) yield x + y + z
3835
}

0 commit comments

Comments
 (0)