diff options
author | Martin Odersky <odersky@gmail.com> | 2014-12-17 14:58:06 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2014-12-17 14:58:06 +0100 |
commit | 3ac70b64ebfe12dd211377aa2527a4666ec2e243 (patch) | |
tree | 806656b3e2ae1ec77b8c894de3b8cf0cd6075d45 /src/dotty/tools/dotc/typer/Typer.scala | |
parent | ecbf5f545b46d65858d27173701def9e2a4d113a (diff) | |
download | dotty-3ac70b64ebfe12dd211377aa2527a4666ec2e243.tar.gz dotty-3ac70b64ebfe12dd211377aa2527a4666ec2e243.tar.bz2 dotty-3ac70b64ebfe12dd211377aa2527a4666ec2e243.zip |
Fix returns from polymorphic methods
Return proto type was wrong; it was the type of the method
(with PolyParams if that type is polymorphic), where it should
have been the return type instantiated with the local type parameters.
We now instantiate the prototype as required.
Note the typing of return nodes is a bit more subtle than in scalac, because
dotc trees are immutable, so the tree pointed at by the context is of no help -
it does not have a return type which we could make use of.
Diffstat (limited to 'src/dotty/tools/dotc/typer/Typer.scala')
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 47 |
1 files changed, 29 insertions, 18 deletions
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 97eded7cb..5d388e7de 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -669,25 +669,36 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } def typedReturn(tree: untpd.Return)(implicit ctx: Context): Return = track("typedReturn") { - def returnProto(owner: Symbol) = - if (owner.isConstructor) defn.UnitType else owner.info.finalResultType - def enclMethInfo(cx: Context): (Tree, Type) = - if (tree.from.isEmpty) { - val owner = cx.owner - if (cx == NoContext || owner.isType) { - ctx.error("return outside method definition", tree.pos) - (EmptyTree, WildcardType) - } else if (owner.isSourceMethod) - if (owner.isCompleted) { - val from = Ident(TermRef(NoPrefix, owner.asTerm)) - val proto = returnProto(owner) - (from, proto) - } else (EmptyTree, errorType(d"$owner has return statement; needs result type", tree.pos)) - else enclMethInfo(cx.outer) + def returnProto(owner: Symbol, locals: Scope): Type = + if (owner.isConstructor) defn.UnitType + else owner.info match { + case info: PolyType => + val tparams = locals.toList.takeWhile(_ is TypeParam) + assert(info.paramNames.length == tparams.length, + i"return mismatch from $owner, tparams = $tparams, locals = ${locals.toList}%, %") + info.instantiate(tparams.map(_.typeRef)).finalResultType + case info => + info.finalResultType } - else - (tree.from.asInstanceOf[tpd.Tree], returnProto(tree.from.symbol)) - val (from, proto) = enclMethInfo(ctx) + def enclMethInfo(cx: Context): (Tree, Type) = { + val owner = cx.owner + if (cx == NoContext || owner.isType) { + ctx.error("return outside method definition", tree.pos) + (EmptyTree, WildcardType) + } + else if (owner != cx.outer.owner && owner.isSourceMethod) { + if (owner.isCompleted) { + val from = Ident(TermRef(NoPrefix, owner.asTerm)) + val proto = returnProto(owner, cx.scope) + (from, proto) + } + else (EmptyTree, errorType(d"$owner has return statement; needs result type", tree.pos)) + } + else enclMethInfo(cx.outer) + } + val (from, proto) = + if (tree.from.isEmpty) enclMethInfo(ctx) + else (tree.from.asInstanceOf[tpd.Tree], WildcardType) val expr1 = typedExpr(tree.expr orElse untpd.unitLiteral.withPos(tree.pos), proto) assignType(cpy.Return(tree)(expr1, from)) } |