aboutsummaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorodersky <odersky@gmail.com>2017-03-09 10:16:51 +0100
committerGitHub <noreply@github.com>2017-03-09 10:16:51 +0100
commitbf9bdae2c2affd9a5f3e68a372c8ad3edd4ba29e (patch)
tree1beacdd84bf4b37b7472561d811931bf693289d3 /compiler
parent391aaa1d8a5880bbc64679760a5623460e9f936f (diff)
parentaa2f9078d76a21d828a06b8e324d31a502ee505c (diff)
downloaddotty-bf9bdae2c2affd9a5f3e68a372c8ad3edd4ba29e.tar.gz
dotty-bf9bdae2c2affd9a5f3e68a372c8ad3edd4ba29e.tar.bz2
dotty-bf9bdae2c2affd9a5f3e68a372c8ad3edd4ba29e.zip
Merge pull request #2065 from dotty-staging/change-implicit-conv2
Disallow subtypes of Function1 acting as implicit conversions
Diffstat (limited to 'compiler')
-rw-r--r--compiler/src/dotty/tools/dotc/core/Definitions.scala4
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Implicits.scala28
2 files changed, 27 insertions, 5 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala
index 3cab75f93..1be47c1da 100644
--- a/compiler/src/dotty/tools/dotc/core/Definitions.scala
+++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala
@@ -299,6 +299,8 @@ class Definitions {
lazy val ScalaPredefModuleRef = ctx.requiredModuleRef("scala.Predef")
def ScalaPredefModule(implicit ctx: Context) = ScalaPredefModuleRef.symbol
+ lazy val Predef_ConformsR = ScalaPredefModule.requiredClass("$less$colon$less").typeRef
+ def Predef_Conforms(implicit ctx: Context) = Predef_ConformsR.symbol
lazy val Predef_conformsR = ScalaPredefModule.requiredMethodRef("$conforms")
def Predef_conforms(implicit ctx: Context) = Predef_conformsR.symbol
lazy val Predef_classOfR = ScalaPredefModule.requiredMethodRef("classOf")
@@ -336,6 +338,8 @@ class Definitions {
def DottyPredefModule(implicit ctx: Context) = DottyPredefModuleRef.symbol
def Predef_eqAny(implicit ctx: Context) = DottyPredefModule.requiredMethod(nme.eqAny)
+ lazy val Predef_ImplicitConverterR = DottyPredefModule.requiredClass("ImplicitConverter").typeRef
+ def Predef_ImplicitConverter(implicit ctx: Context) = Predef_ImplicitConverterR.symbol
lazy val DottyArraysModuleRef = ctx.requiredModuleRef("dotty.runtime.Arrays")
def DottyArraysModule(implicit ctx: Context) = DottyArraysModuleRef.symbol
diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala
index 759cc62e9..ebbcbcc95 100644
--- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala
@@ -82,11 +82,29 @@ object Implicits {
case tpw: TermRef =>
false // can't discard overloaded refs
case tpw =>
- //if (ctx.typer.isApplicable(tp, argType :: Nil, resultType))
- // println(i"??? $tp is applicable to $this / typeSymbol = ${tpw.typeSymbol}")
- !tpw.derivesFrom(defn.FunctionClass(1)) ||
- ref.symbol == defn.Predef_conforms //
- // as an implicit conversion, Predef.$conforms is a no-op, so exclude it
+ // Only direct instances of Function1 and direct or indirect instances of <:< are eligible as views.
+ // However, Predef.$conforms is not eligible, because it is a no-op.
+ //
+ // In principle, it would be cleanest if only implicit methods qualified
+ // as implicit conversions. We could achieve that by having standard conversions like
+ // this in Predef:
+ //
+ // implicit def convertIfConforms[A, B](x: A)(implicit ev: A <:< B): B = ev(a)
+ // implicit def convertIfConverter[A, B](x: A)(implicit ev: ImplicitConverter[A, B]): B = ev(a)
+ //
+ // (Once `<:<` inherits from `ImplicitConverter` we only need the 2nd one.)
+ // But clauses like this currently slow down implicit search a lot, because
+ // they are eligible for all pairs of types, and therefore are tried too often.
+ // We emulate instead these conversions directly in the search.
+ // The reason for leaving out `Predef_conforms` is that we know it adds
+ // nothing since it only relates subtype with supertype.
+ //
+ // We keep the old behavior under -language:Scala2.
+ val isFunctionInS2 = ctx.scala2Mode && tpw.derivesFrom(defn.FunctionClass(1))
+ val isImplicitConverter = tpw.derivesFrom(defn.Predef_ImplicitConverter)
+ val isConforms =
+ tpw.derivesFrom(defn.Predef_Conforms) && ref.symbol != defn.Predef_conforms
+ !(isFunctionInS2 || isImplicitConverter || isConforms)
}
def discardForValueType(tpw: Type): Boolean = tpw match {