Skip to content

Commit

Permalink
Insert conversions also on selections wrapped in type applications
Browse files Browse the repository at this point in the history
In i12708.scala, the problematic function was a selection `qual.m[tvs]` that was already
applied to type variables. In that case we need to backtrack, forget the type variables
and try to insert a conversion or extension method on `qual`.

Fixes scala#12708
  • Loading branch information
odersky committed Jun 5, 2021
1 parent 06df92b commit 14ffb35
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 5 deletions.
11 changes: 6 additions & 5 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3045,12 +3045,12 @@ class Typer extends Namer
}
}

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

/** Given a selection `qual.name`, try to convert to an extension method
Expand Down
37 changes: 37 additions & 0 deletions tests/pos/i12708.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import language.implicitConversions

trait AdditiveSemigroup[A]

final class AdditiveSemigroupOps[A](lhs: A)(implicit as: AdditiveSemigroup[A]) {
def +(rhs: A): A = ???
def ^(rhs: A): A = ???
}

trait AdditiveSemigroupSyntax {
implicit def additiveSemigroupOps[A: AdditiveSemigroup](a: A): AdditiveSemigroupOps[A] =
new AdditiveSemigroupOps(a)
}

object syntax {
object additiveSemigroup extends AdditiveSemigroupSyntax
}

object App {

def main(args: Array[String]): Unit = {
import syntax.additiveSemigroup._

implicit def IntAlgebra[A]: AdditiveSemigroup[Map[Int, A]] = ???

def res[A]: Map[Int, A] = {
val a: Map[Int, A] = Map.empty
val b: Map[Int, A] = Map.empty
// Calls the operator on AdditiveSemigroupOps
a ^ b
// Calls the operator + on AdditiveSemigroupOps only in Scala 2
// In Scala 3 tries to call `+` on Map
a + b
}
}

}

0 comments on commit 14ffb35

Please sign in to comment.