Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Insert conversions also on selections wrapped in type applications #12719

Merged
merged 2 commits into from
Jun 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
2 changes: 1 addition & 1 deletion tests/neg/i8861.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ object Test {
)
def minimalFail[M](c: Container { type A = M }): M = c.visit(
int = vi => vi.i : vi.A,
str = vs => vs.t : vs.A // error
str = vs => vs.t : vs.A // error // error
)

def main(args: Array[String]): Unit = {
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
}
}

}
13 changes: 5 additions & 8 deletions tests/neg/zipped.scala → tests/pos/zipped.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,14 @@ object Test {
xs.lazyZip(xs).lazyZip(xs)
.map( (x: Int, y: Int, z: Int) => x + y + z ) // OK

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

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

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