aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Martres <smarter@ubuntu.com>2015-11-17 23:41:02 +0100
committerGuillaume Martres <smarter@ubuntu.com>2015-11-18 03:32:01 +0100
commit7d76151109db168d025dfc0f6501fa7694e17053 (patch)
tree2cc70c0eadab25304c03aa2d494097e60bac077a
parent945334c8affd0dc5067316447e8384f1ea7025ad (diff)
downloaddotty-7d76151109db168d025dfc0f6501fa7694e17053.tar.gz
dotty-7d76151109db168d025dfc0f6501fa7694e17053.tar.bz2
dotty-7d76151109db168d025dfc0f6501fa7694e17053.zip
Fix ambiguity errors with polymorphic implicits
Previously, `isAsSpecific(alt1, tp1, alt2, tp2)` did not handle having `tp2` be a polymorphic non-method type like `[A]Foo[A]`. Also update the documentation of `isAsSpecific` to account for this change, the new documentation is based on SLS ยง 6.26.3 but adapted to reflect the code.
-rw-r--r--src/dotty/tools/dotc/core/Types.scala5
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala29
-rw-r--r--tests/run/implicits_poly.check1
-rw-r--r--tests/run/implicits_poly.scala14
4 files changed, 43 insertions, 6 deletions
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 559839db2..db518d959 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -2266,6 +2266,11 @@ object Types {
protected def computeSignature(implicit ctx: Context) = resultSignature
+ def isPolymorphicMethodType: Boolean = resType match {
+ case _: MethodType => true
+ case _ => false
+ }
+
def instantiate(argTypes: List[Type])(implicit ctx: Context): Type =
resultType.substParams(this, argTypes)
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index 64047cc1e..c57dd7aab 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -848,11 +848,19 @@ trait Applications extends Compatibility { self: Typer =>
else (sym1 is Module) && isDerived(sym1.companionClass, sym2)
/** Is alternative `alt1` with type `tp1` as specific as alternative
- * `alt2` with type `tp2` ? This is the case if
+ * `alt2` with type `tp2` ?
*
- * 1. `tp2` is a method or poly type but `tp1` isn't, or `tp1` is nullary.
- * 2. `tp2` and `tp1` are method or poly types and `tp2` can be applied to the parameters of `tp1`.
- * 3. Neither `tp1` nor `tp2` are method or poly types and `tp1` is compatible with `tp2`.
+ * 1. A method `alt1` of type (p1: T1, ..., pn: Tn)U is as specific as `alt2`
+ * if `alt2` is applicable to arguments (p1, ..., pn) of types T1,...,Tn
+ * or if `alt1` is nullary.
+ * 2. A polymorphic member of type [a1 >: L1 <: U1, ..., an >: Ln <: Un]T is as
+ * specific as `alt2` of type `tp2` if T is as specific as `tp2` under the
+ * assumption that for i = 1,...,n each ai is an abstract type name bounded
+ * from below by Li and from above by Ui.
+ * 3. A member of any other type `tp1` is:
+ * a. always as specific as a method or a polymorphic method.
+ * b. as specific as a member of any other type `tp2` if `tp1` is compatible
+ * with `tp2`.
*/
def isAsSpecific(alt1: TermRef, tp1: Type, alt2: TermRef, tp2: Type): Boolean = ctx.traceIndented(i"isAsSpecific $tp1 $tp2", overload) { tp1 match {
case tp1: PolyType =>
@@ -870,8 +878,17 @@ trait Applications extends Compatibility { self: Typer =>
tp1.paramTypes.isEmpty && tp2.isInstanceOf[MethodOrPoly]
case _ =>
tp2 match {
- case tp2: MethodOrPoly => true
- case _ => isCompatible(tp1, tp2)
+ case tp2: MethodType => true
+ case tp2: PolyType if tp2.isPolymorphicMethodType => true
+ case tp2: PolyType =>
+ val nestedCtx = ctx.fresh.setExploreTyperState
+
+ {
+ implicit val ctx: Context = nestedCtx
+ isCompatible(tp1, constrained(tp2).resultType)
+ }
+ case _ =>
+ isCompatible(tp1, tp2)
}
}}
diff --git a/tests/run/implicits_poly.check b/tests/run/implicits_poly.check
new file mode 100644
index 000000000..0b148ee47
--- /dev/null
+++ b/tests/run/implicits_poly.check
@@ -0,0 +1 @@
+barFoo
diff --git a/tests/run/implicits_poly.scala b/tests/run/implicits_poly.scala
new file mode 100644
index 000000000..2a5d68f73
--- /dev/null
+++ b/tests/run/implicits_poly.scala
@@ -0,0 +1,14 @@
+class Foo[A](val x: String)
+class Bar[A](x: String) extends Foo[A](x)
+
+object Test {
+ implicit def anyRefFoo[A <: AnyRef]: Foo[A] = new Foo("anyRefFoo")
+ implicit def fooFoo[A]: Foo[Foo[A]] = new Foo("fooFoo")
+ implicit def barFoo[A]: Bar[Foo[A]] = new Bar("barFoo")
+
+ def getFooFoo(implicit ev: Foo[Foo[Int]]) = ev
+
+ def main(args: Array[String]): Unit = {
+ println(getFooFoo.x)
+ }
+}