aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala13
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala64
-rwxr-xr-xtests/pos/t2504.scala (renamed from tests/untried/pos/t2504.scala)1
-rw-r--r--tests/pos/test.scala6
-rw-r--r--tests/untried/pos/t2500.scala6
-rw-r--r--tests/untried/pos/t252.scala17
-rwxr-xr-xtests/untried/pos/t2545.scala10
-rw-r--r--tests/untried/pos/t2569/Child.scala9
-rw-r--r--tests/untried/pos/t2569/Parent.java13
-rw-r--r--tests/untried/pos/t2591.scala15
10 files changed, 54 insertions, 100 deletions
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index a4c26080d..023063585 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -125,9 +125,16 @@ trait Applications extends Compatibility { self: Typer =>
protected def init() = methType match {
case methType: MethodType =>
// apply the result type constraint, unless method type is dependent
- if (!methType.isDependent)
+ if (!methType.isDependent) {
+ val savedConstraint = ctx.typerState.constraint
if (!constrainResult(methType.resultType, resultType))
- fail(err.typeMismatchStr(methType.resultType, resultType))
+ if (ctx.typerState.isCommittable)
+ // defer the problem until after the application;
+ // it might be healed by an implicit conversion
+ assert(ctx.typerState.constraint eq savedConstraint)
+ else
+ fail(err.typeMismatchStr(methType.resultType, resultType))
+ }
// match all arguments with corresponding formal parameters
matchArgs(orderedArgs, methType.paramTypes, 0)
case _ =>
@@ -454,7 +461,7 @@ trait Applications extends Compatibility { self: Typer =>
val result = app.result
ConstFold(result)
} { (failedVal, failedState) =>
- val fun2 = tryInsertImplicit(fun1, proto)
+ val fun2 = tryInsertImplicits(fun1, proto)
if (fun1 eq fun2) {
failedState.commit()
failedVal
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 050fcbc76..3698c648c 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -1009,40 +1009,62 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
}
- /** Try to insert `.apply` so that the result conforms to prototype `pt`.
- * If that fails try to insert an implicit conversion around the qualifier
- * part of `tree`. If either result conforms to `pt`, adapt it, else
- * continue with `fallBack`.
+ private def noResultProto(pt: Type) = pt match {
+ case pt: FunProto => pt.derivedFunProto(pt.args, WildcardType, pt.typer) // drop result type, because views are disabled
+ case _ => pt
+ }
+
+ /** Add apply node or implicit conversions. Three strategies are tried, and the first
+ * that is succesful is picked. If none of the strategies are succesful, continues with
+ * `fallBack`.
+ *
+ * 1st strategy: Try to insert `.apply` so that the result conforms to prototype `pt`.
+ * 2nd strategy: If the expected type is a FunProto with a non-wildcard resulttype,
+ * try to match against the FunProto with wildcard resulttype (this allows for an additional
+ * implicit conversion on the result).
+ * 3rd stratgey: If tree is a select `qual.name`, try to insert an implicit conversion
+ * around the qualifier part `qual` so that the result conforms to the expected type
+ * with wildcard result type.
*/
def tryInsertApplyOrImplicit(tree: Tree, pt: ProtoType)(fallBack: (Tree, TyperState) => Tree)(implicit ctx: Context): Tree =
tryEither { implicit ctx =>
val sel = typedSelect(untpd.Select(untpd.TypedSplice(tree), nme.apply), pt)
if (sel.tpe.isError) sel else adapt(sel, pt)
} { (failedTree, failedState) =>
- val tree1 = tryInsertImplicit(tree, pt)
+ val tree1 = tryInsertImplicits(tree, pt)
if (tree1 eq tree) fallBack(failedTree, failedState)
- else adapt(tree1, pt)
+ else adapt(tree1, noResultProto(pt))
}
+ def tryInsertImplicits(tree: Tree, pt: ProtoType)(implicit ctx: Context): Tree = {
+ val normalizedProto = noResultProto(pt)
+ if (normalizedProto eq pt) tryInsertImplicitOnQualifier(tree, pt)
+ else tryEither { implicit ctx =>
+ val tree1 = adaptInterpolated(tree, normalizedProto, EmptyTree)
+ if (tree1 eq tree) ctx.error("no progress")
+ tree1
+ } { (_, _) =>
+ tryInsertImplicitOnQualifier(tree, normalizedProto)
+ }
+ }
+
/** If this tree is a select node `qual.name`, try to insert an implicit conversion
* `c` around `qual` so that `c(qual).name` conforms to `pt`. If that fails
* return `tree` itself.
*/
- def tryInsertImplicit(tree: Tree, pt: ProtoType)(implicit ctx: Context): Tree = ctx.traceIndented(i"try ins impl $tree $pt") { tree match {
- case Select(qual, name) =>
- val normalizedProto = pt match {
- case pt: FunProto => pt.derivedFunProto(pt.args, WildcardType, pt.typer) // drop result type, because views are disabled
- case _ => pt
- }
- val qualProto = SelectionProto(name, normalizedProto, NoViewsAllowed)
- tryEither { implicit ctx =>
- val qual1 = adaptInterpolated(qual, qualProto, EmptyTree)
- if ((qual eq qual1) || ctx.reporter.hasErrors) tree
- else typedSelect(cpy.Select(tree, untpd.TypedSplice(qual1), name), pt)
- } { (_, _) => tree
- }
- case _ => tree
- }}
+ def tryInsertImplicitOnQualifier(tree: Tree, pt: Type)(implicit ctx: Context): Tree = ctx.traceIndented(i"try insert impl on qualifier $tree $pt") {
+ tree match {
+ case Select(qual, name) =>
+ val qualProto = SelectionProto(name, pt, NoViewsAllowed)
+ tryEither { implicit ctx =>
+ val qual1 = adaptInterpolated(qual, qualProto, EmptyTree)
+ if ((qual eq qual1) || ctx.reporter.hasErrors) tree
+ else typedSelect(cpy.Select(tree, untpd.TypedSplice(qual1), name), pt)
+ } { (_, _) => tree
+ }
+ case _ => tree
+ }
+ }
def adapt(tree: Tree, pt: Type, original: untpd.Tree = untpd.EmptyTree)(implicit ctx: Context) = /*>|>*/ track("adapt") /*<|<*/ {
/*>|>*/ ctx.traceIndented(i"adapting $tree of type ${tree.tpe} to $pt", typr, show = true) /*<|<*/ {
diff --git a/tests/untried/pos/t2504.scala b/tests/pos/t2504.scala
index 67f822685..72117174c 100755
--- a/tests/untried/pos/t2504.scala
+++ b/tests/pos/t2504.scala
@@ -1,4 +1,5 @@
object Test {
+ val zs = Array("abc")
val ys: Iterable[_] = Array("abc")
val xs = Array("abc")
xs sameElements Array("abc")
diff --git a/tests/pos/test.scala b/tests/pos/test.scala
deleted file mode 100644
index 71fa1b1d9..000000000
--- a/tests/pos/test.scala
+++ /dev/null
@@ -1,6 +0,0 @@
-object test {
-
- val m = new java.util.HashMap[String, String]
- m.size
-
-} \ No newline at end of file
diff --git a/tests/untried/pos/t2500.scala b/tests/untried/pos/t2500.scala
deleted file mode 100644
index d0ff99a93..000000000
--- a/tests/untried/pos/t2500.scala
+++ /dev/null
@@ -1,6 +0,0 @@
-object Test {
- import scala.collection._
- ((Map(1 -> "a", 2 -> "b"): collection.Map[Int, String]) map identity[(Int, String)]) : scala.collection.Map[Int,String]
- ((SortedMap(1 -> "a", 2 -> "b"): collection.SortedMap[Int, String]) map identity[(Int, String)]): scala.collection.SortedMap[Int,String]
- ((SortedSet(1, 2): collection.SortedSet[Int]) map identity[Int]): scala.collection.SortedSet[Int]
-}
diff --git a/tests/untried/pos/t252.scala b/tests/untried/pos/t252.scala
deleted file mode 100644
index d51b5511e..000000000
--- a/tests/untried/pos/t252.scala
+++ /dev/null
@@ -1,17 +0,0 @@
-abstract class Module {}
-
-abstract class T {
- type moduleType <: Module
- val module: moduleType
-}
-
-abstract class Base {
- type mType = Module
- type tType = T { type moduleType <: mType }
-}
-
-abstract class Derived extends Base {
- def f(inputs: List[tType]): Unit = {
- for (t <- inputs; m = t.module) { }
- }
-}
diff --git a/tests/untried/pos/t2545.scala b/tests/untried/pos/t2545.scala
deleted file mode 100755
index 6ad994223..000000000
--- a/tests/untried/pos/t2545.scala
+++ /dev/null
@@ -1,10 +0,0 @@
-trait Frog[T] {
- def hello: T
- def size: Int
- }
-
- trait OnlyWithFrogs {
- self: Frog[_] =>
-
- def sizeStr = size.toString
- }
diff --git a/tests/untried/pos/t2569/Child.scala b/tests/untried/pos/t2569/Child.scala
deleted file mode 100644
index 64f4dc172..000000000
--- a/tests/untried/pos/t2569/Child.scala
+++ /dev/null
@@ -1,9 +0,0 @@
-package varargs
-
- class Child extends Parent {
-
- override def concatenate(strings: String*): String =
- strings map("\"" + _ + "\"") mkString("(", ", ", ")")
-
- }
-
diff --git a/tests/untried/pos/t2569/Parent.java b/tests/untried/pos/t2569/Parent.java
deleted file mode 100644
index 89421becb..000000000
--- a/tests/untried/pos/t2569/Parent.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package varargs;
-
- public class Parent {
-
- public String concatenate(String... strings) {
- StringBuilder builder = new StringBuilder();
- for (String s : strings) {
- builder.append(s);
- }
- return builder.toString();
- }
-
- }
diff --git a/tests/untried/pos/t2591.scala b/tests/untried/pos/t2591.scala
deleted file mode 100644
index 47ae551bf..000000000
--- a/tests/untried/pos/t2591.scala
+++ /dev/null
@@ -1,15 +0,0 @@
-class A
-class B
-
-object Implicits {
- implicit def imp(x: A): Int = 41
- implicit def imp(x: B): Int = 41
-}
-
-object Test {
- // should cause imp to be in scope so that the next expression type checks
- // `import Implicits._` works
- import Implicits.imp
-
- (new A) : Int
-}