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/Typer.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/Typer.scala')
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 46 |
1 files changed, 36 insertions, 10 deletions
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 944b44510..5d477193c 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -1009,15 +1009,41 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } } - def tryInsertApply(tree: Tree, pt: Type)(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) - } { - fallBack + /** 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`. + */ + 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) + if (tree1 eq tree) fallBack(failedTree, failedState) + else adapt(tree1, pt) } + /** 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) + 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)(implicit ctx: Context) = /*>|>*/ track("adapt") /*<|<*/ { /*>|>*/ ctx.traceIndented(i"adapting $tree of type ${tree.tpe} to $pt", typr, show = true) /*<|<*/ { interpolateUndetVars(tree) @@ -1087,7 +1113,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def hasEmptyParams(denot: SingleDenotation) = denot.info.paramTypess == ListOfNil pt match { case pt: FunProto => - tryInsertApply(tree, pt)((_, _) => noMatches) + tryInsertApplyOrImplicit(tree, pt)((_, _) => noMatches) case _ => if (altDenots exists (_.info.paramTypess == ListOfNil)) typed(untpd.Apply(untpd.TypedSplice(tree), Nil), pt) @@ -1113,7 +1139,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit adaptToArgs(wtp, pt.tupled) else tree - case _ => tryInsertApply(tree, pt) { + case _ => tryInsertApplyOrImplicit(tree, pt) { val more = tree match { case Apply(_, _) => " more" case _ => "" @@ -1216,7 +1242,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit case pt: FunProto => adaptToArgs(wtp, pt) case pt: PolyProto => - tryInsertApply(tree, pt) { + tryInsertApplyOrImplicit(tree, pt) { (_, _) => tree // error will be reported in typedTypeApply } case _ => |