diff options
author | Martin Odersky <odersky@gmail.com> | 2016-08-21 11:18:42 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2016-08-21 15:19:27 +0200 |
commit | 704f4d745e2b71b30e44533d38936cdb43813acf (patch) | |
tree | 0426d2f410348c673f04af2bb9febfd1bedf7f8c /src/dotty/tools/dotc/typer/Applications.scala | |
parent | 1b2fc1f016f837ca51c7627d359ed88e24692df6 (diff) | |
download | dotty-704f4d745e2b71b30e44533d38936cdb43813acf.tar.gz dotty-704f4d745e2b71b30e44533d38936cdb43813acf.tar.bz2 dotty-704f4d745e2b71b30e44533d38936cdb43813acf.zip |
Make sure arguments are evaluated in the correct typer state.
There's a tricky interaction with caching of typed arguments in FunProto types
and backtracking using different typer states. We might end up with a typed
argument that is evaluated in one typer state and that is used in another. The
problem is that the argument typing might have inserted type variables (maybe
by adding polymorphic implicit views) that are not registered in the typer
state in which the application is finally typed. In that case we will see
an "orphan poly parameter" in pickling.
The fix is to discard argument types is their typerstate is not committed
to the one in which the application is finally typed. To apply the fix we
need to track
- for typer states: whether or not it was committed, and what its parent is.
- for function prototypes: the typer state in which an argument with cached type
was evaluated.
Test case is t1756.scala, which produced an "orphan poly parameter CI" before.
Diffstat (limited to 'src/dotty/tools/dotc/typer/Applications.scala')
-rw-r--r-- | src/dotty/tools/dotc/typer/Applications.scala | 59 |
1 files changed, 33 insertions, 26 deletions
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index efd12cb5e..3916f935f 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -541,18 +541,6 @@ trait Applications extends Compatibility { self: Typer with Dynamic => def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = { - /** Try same application with an implicit inserted around the qualifier of the function - * part. Return an optional value to indicate success. - */ - def tryWithImplicitOnQualifier(fun1: Tree, proto: FunProto)(implicit ctx: Context): Option[Tree] = - tryInsertImplicitOnQualifier(fun1, proto) flatMap { fun2 => - tryEither { implicit ctx => - Some(typedApply( - cpy.Apply(tree)(untpd.TypedSplice(fun2), proto.typedArgs map untpd.TypedSplice), - pt)): Option[Tree] - } { (_, _) => None } - } - def realApply(implicit ctx: Context): Tree = track("realApply") { val originalProto = new FunProto(tree.args, IgnoredProto(pt), this)(argCtx(tree)) val fun1 = typedExpr(tree.fun, originalProto) @@ -574,6 +562,32 @@ trait Applications extends Compatibility { self: Typer with Dynamic => if (!constrainResult(fun1.tpe.widen, proto.derivedFunProto(resultType = pt))) typr.println(i"result failure for $tree with type ${fun1.tpe.widen}, expected = $pt") + /** Type application where arguments come from prototype, and no implicits are inserted */ + def simpleApply(fun1: Tree, proto: FunProto)(implicit ctx: Context): Tree = + methPart(fun1).tpe match { + case funRef: TermRef => + val app = + if (proto.allArgTypesAreCurrent()) + new ApplyToTyped(tree, fun1, funRef, proto.typedArgs, pt) + else + new ApplyToUntyped(tree, fun1, funRef, proto, pt)(argCtx(tree)) + convertNewGenericArray(ConstFold(app.result)) + case _ => + handleUnexpectedFunType(tree, fun1) + } + + /** Try same application with an implicit inserted around the qualifier of the function + * part. Return an optional value to indicate success. + */ + def tryWithImplicitOnQualifier(fun1: Tree, proto: FunProto)(implicit ctx: Context): Option[Tree] = + tryInsertImplicitOnQualifier(fun1, proto) flatMap { fun2 => + tryEither { + implicit ctx => Some(simpleApply(fun2, proto)): Option[Tree] + } { + (_, _) => None + } + } + fun1.tpe match { case ErrorType => tree.withType(ErrorType) case TryDynamicCallType => @@ -583,23 +597,16 @@ trait Applications extends Compatibility { self: Typer with Dynamic => case _ => handleUnexpectedFunType(tree, fun1) } - case _ => methPart(fun1).tpe match { - case funRef: TermRef => - tryEither { implicit ctx => - val app = - if (proto.argsAreTyped) new ApplyToTyped(tree, fun1, funRef, proto.typedArgs, pt) - else new ApplyToUntyped(tree, fun1, funRef, proto, pt)(argCtx(tree)) - val result = app.result - convertNewGenericArray(ConstFold(result)) - } { (failedVal, failedState) => + case _ => + tryEither { + implicit ctx => simpleApply(fun1, proto) + } { + (failedVal, failedState) => def fail = { failedState.commit(); failedVal } tryWithImplicitOnQualifier(fun1, originalProto).getOrElse( if (proto eq originalProto) fail else tryWithImplicitOnQualifier(fun1, proto).getOrElse(fail)) - } - case _ => - handleUnexpectedFunType(tree, fun1) - } + } } } @@ -611,7 +618,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => * * { val xs = es; e' = e' + args } */ - def typedOpAssign: Tree = track("typedOpAssign") { + def typedOpAssign: Tree = track("typedOpAssign") { val Apply(Select(lhs, name), rhss) = tree val lhs1 = typedExpr(lhs) val liftedDefs = new mutable.ListBuffer[Tree] |