diff options
author | Martin Odersky <odersky@gmail.com> | 2014-05-07 14:50:56 +0200 |
---|---|---|
committer | Samuel Gruetter <samuel.gruetter@epfl.ch> | 2014-05-20 13:38:48 +0200 |
commit | c2d5246bdb33d60d3eaff62a539d01368124d859 (patch) | |
tree | 8042d19558c350597655d5bb1dfee4ffa25e02d6 /src/dotty/tools/dotc/typer/Applications.scala | |
parent | 2d3c79f7cf3e79b592c7e479d262e8d3f9b04959 (diff) | |
download | dotty-c2d5246bdb33d60d3eaff62a539d01368124d859.tar.gz dotty-c2d5246bdb33d60d3eaff62a539d01368124d859.tar.bz2 dotty-c2d5246bdb33d60d3eaff62a539d01368124d859.zip |
More systematic treatment of prototypes.
There's a delicate balance about how much of a prototype should be passed down the
tree when typechecking. Passing little can cause ambiguity errors (both in overloading
and in implicit search). Passing too much can cause spurious errors because implicit conversions
"down the road" that apply to some tree continaing the result might not be considered.
Symptoms of the problems wree that we could not handle the tests included in this commit before.
The new scheme is as follows: we always keep all available information in a prototype, but hide nested
prototypes behined a `IgnoredProto` wall. These trees will not be considered for conformity checking.
When type checking hits an ambiguity, it tries again with a prototype that's one level deeper (has fewer
Ignore links) than the previous one. This continues until there are no more Ignore links to unwrap.
We also generalize the scheme for wrapping qualifiers of select nodes from realApply to all instances where
we compare against a FunProto.
Finally, there are some fixes that avoid assertion violations that were provoked by the new typechecking scheme.
Diffstat (limited to 'src/dotty/tools/dotc/typer/Applications.scala')
-rw-r--r-- | src/dotty/tools/dotc/typer/Applications.scala | 44 |
1 files changed, 17 insertions, 27 deletions
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index 0f47336fc..92acb7939 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -434,7 +434,7 @@ trait Applications extends Compatibility { self: Typer => def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = { def realApply(implicit ctx: Context): Tree = track("realApply") { - var proto = new FunProto(tree.args, pt, this) + var proto = new FunProto(tree.args, ignoreIfProto(pt), this) val fun1 = typedExpr(tree.fun, proto) // Warning: The following line is dirty and fragile. We record that auto-tupling was demanded as @@ -453,30 +453,13 @@ trait Applications extends Compatibility { self: Typer => else new ApplyToUntyped(tree, fun1, funRef, proto, pt) val result = app.result ConstFold(result) - } { (failedVal, failedState) => fun1 match { - case Select(qual, name) => - // try with prototype `[].name(args)`, this might succeed by inserting an - // implicit conversion around []. (an example is Int + BigInt). - tryEither { implicit ctx => - val simpleFunProto = new FunProto(tree.args, WildcardType, this) // drop result type, because views are disabled - val selProto = SelectionProto(name, simpleFunProto, NoViewsAllowed) - val qual1 = adaptInterpolated(qual, selProto) - if (qual eq qual1) ctx.error("no progress") - if (ctx.reporter.hasErrors) qual1 - else - typedApply( - cpy.Apply(tree, - cpy.Select(fun1, untpd.TypedSplice(qual1), name), - proto.typedArgs map untpd.TypedSplice), - pt) - } { (_, _) => - failedState.commit() - failedVal - } - case _ => - failedState.commit() - failedVal - } + } { (failedVal, failedState) => + val fun2 = tryInsertImplicit(fun1, proto) + if (fun1 eq fun2) { + failedState.commit() + failedVal + } else typedApply( + cpy.Apply(tree, untpd.TypedSplice(fun2), proto.typedArgs map untpd.TypedSplice), pt) } case _ => fun1.tpe match { @@ -771,7 +754,7 @@ trait Applications extends Compatibility { self: Typer => def isAsSpecific(alt1: TermRef, tp1: Type, alt2: TermRef, tp2: Type): Boolean = ctx.traceIndented(i"isAsSpecific $tp1 $tp2", overload) { tp1 match { case tp1: PolyType => def bounds(tparamRefs: List[TypeRef]) = tp1.paramBounds map (_.substParams(tp1, tparamRefs)) - val tparams = ctx.newTypeParams(alt1.symbol.owner, tp1.paramNames, EmptyFlags, bounds) + val tparams = ctx.newTypeParams(alt1.symbol, tp1.paramNames, EmptyFlags, bounds) isAsSpecific(alt1, tp1.instantiate(tparams map (_.typeRef)), alt2, tp2) case tp1: MethodType => def repeatedToSingle(tp: Type) = if (tp.isRepeatedParam) tp.argTypesHi.head else tp @@ -927,7 +910,14 @@ trait Applications extends Compatibility { self: Typer => alts filter (normalizedCompatible(_, pt)) } if (isDetermined(candidates)) candidates - else narrowMostSpecific(candidates) + else narrowMostSpecific(candidates) match { + case result @ (alt1 :: alt2 :: _) => + val deepPt = pt.deepenProto + if (deepPt ne pt) resolveOverloaded(alts, deepPt, targs) + else result + case result => + result + } } } |