aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/typer/Typer.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-05-09 18:55:10 +0200
committerSamuel Gruetter <samuel.gruetter@epfl.ch>2014-05-20 13:38:49 +0200
commit394b645dd2d44ff68597527c6c690c73653f1bcb (patch)
tree22e72a22f891c002d5fef946361d223d6f6fc1a4 /src/dotty/tools/dotc/typer/Typer.scala
parent67e5130e63b10631106490cbc1cec5adcd5273e6 (diff)
downloaddotty-394b645dd2d44ff68597527c6c690c73653f1bcb.tar.gz
dotty-394b645dd2d44ff68597527c6c690c73653f1bcb.tar.bz2
dotty-394b645dd2d44ff68597527c6c690c73653f1bcb.zip
Fix of pos/t2429
This was a hard nut to crack. The problem exemplified by t2429 is that in a situation like val x: T = foo(...) where `foo` needs implicit parameters the expected result type `T` is propagated into the typechecking of foo(...) and consequently also into the implicit parameter search. This is often necessary, for instance to instantiate type parameters. But it can lead to overconstrained searches if in fact the right expansion is val x: T = viewToT(foo(...)(implicit params)) where `viewToT` is some implicit conversion. The fix handles that case by re-hecking the application foo(...) with an empty result type, if the implicit parameter search fails. But the re-checking is very subtle as is explained in the comment to `TyperState#tryWithFallback`.
Diffstat (limited to 'src/dotty/tools/dotc/typer/Typer.scala')
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala53
1 files changed, 30 insertions, 23 deletions
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 5d477193c..050fcbc76 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -954,7 +954,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def typed(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = /*>|>*/ ctx.traceIndented (i"typing $tree", typr, show = true) /*<|<*/ {
if (!tree.isEmpty && ctx.typerState.isGlobalCommittable) assert(tree.pos.exists, i"position not set for $tree")
- try adapt(typedUnadapted(tree, pt), pt)
+ try adapt(typedUnadapted(tree, pt), pt, tree)
catch {
case ex: CyclicReference => errorTree(tree, cyclicErrorMsg(ex))
case ex: FatalTypeError => errorTree(tree, ex.getMessage)
@@ -1036,7 +1036,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
val qualProto = SelectionProto(name, normalizedProto, NoViewsAllowed)
tryEither { implicit ctx =>
- val qual1 = adaptInterpolated(qual, qualProto)
+ 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
@@ -1044,11 +1044,11 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
case _ => tree
}}
- def adapt(tree: Tree, pt: Type)(implicit ctx: Context) = /*>|>*/ track("adapt") /*<|<*/ {
+ 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) /*<|<*/ {
interpolateUndetVars(tree)
tree overwriteType tree.tpe.simplified
- adaptInterpolated(tree, pt)
+ adaptInterpolated(tree, pt, original)
}
}
@@ -1090,7 +1090,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
* (14) When in mode EXPRmode, apply a view
* If all this fails, error
*/
- def adaptInterpolated(tree: Tree, pt: Type)(implicit ctx: Context): Tree = {
+ def adaptInterpolated(tree: Tree, pt: Type, original: untpd.Tree)(implicit ctx: Context): Tree = {
assert(pt.exists)
@@ -1104,7 +1104,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def expectedStr = err.expectedTypeStr(pt)
resolveOverloaded(alts, pt) match {
case alt :: Nil =>
- adapt(tree.withType(alt), pt)
+ adapt(tree.withType(alt), pt, original)
case Nil =>
def noMatches =
errorTree(tree,
@@ -1150,24 +1150,31 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def adaptNoArgs(wtp: Type): Tree = wtp match {
case wtp: ExprType =>
- adaptInterpolated(tree.withType(wtp.resultType), pt)
+ adaptInterpolated(tree.withType(wtp.resultType), pt, original)
case wtp: ImplicitMethodType if constrainResult(wtp, pt) =>
- def implicitArgError(msg: => String): Tree = {
- ctx.error(msg, tree.pos.endPos)
- EmptyTree
- }
- val args = (wtp.paramNames, wtp.paramTypes).zipped map { (pname, formal) =>
- def where = d"parameter $pname of $methodStr"
- inferImplicit(formal, EmptyTree, tree.pos.endPos) match {
- case SearchSuccess(arg, _, _) =>
- adapt(arg, formal)
- case ambi: AmbiguousImplicits =>
- implicitArgError(s"ambiguous implicits: ${ambi.explanation} of $where")
- case failure: SearchFailure =>
- implicitArgError(d"no implicit argument of type $formal found for $where" + failure.postscript)
+ def addImplicitArgs = {
+ def implicitArgError(msg: => String): Tree = {
+ ctx.error(msg, tree.pos.endPos)
+ EmptyTree
+ }
+ val args = (wtp.paramNames, wtp.paramTypes).zipped map { (pname, formal) =>
+ def where = d"parameter $pname of $methodStr"
+ inferImplicit(formal, EmptyTree, tree.pos.endPos) match {
+ case SearchSuccess(arg, _, _) =>
+ adapt(arg, formal)
+ case ambi: AmbiguousImplicits =>
+ implicitArgError(s"ambiguous implicits: ${ambi.explanation} of $where")
+ case failure: SearchFailure =>
+ implicitArgError(d"no implicit argument of type $formal found for $where" + failure.postscript)
+ }
}
+ adapt(tpd.Apply(tree, args), pt)
}
- adapt(tpd.Apply(tree, args), pt)
+ if ((pt eq WildcardType) || original.isEmpty) addImplicitArgs
+ else
+ ctx.typerState.tryWithFallback(addImplicitArgs) {
+ adapt(typed(original, WildcardType), pt, EmptyTree)
+ }
case wtp: MethodType if !pt.isInstanceOf[SingletonType] =>
val arity =
if (defn.isFunctionType(pt)) defn.functionArity(pt)
@@ -1176,7 +1183,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
if (arity >= 0 && !tree.symbol.isConstructor)
typed(etaExpand(tree, wtp, arity), pt)
else if (wtp.paramTypes.isEmpty)
- adaptInterpolated(tpd.Apply(tree, Nil), pt)
+ adaptInterpolated(tpd.Apply(tree, Nil), pt, EmptyTree)
else
errorTree(tree,
d"""missing arguments for $methodStr
@@ -1235,7 +1242,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
if (pt.isInstanceOf[PolyProto]) tree
else {
val (_, tvars) = constrained(poly, tree)
- adaptInterpolated(tree appliedToTypes tvars, pt)
+ adaptInterpolated(tree appliedToTypes tvars, pt, original)
}
case wtp =>
pt match {