aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/typer/Typer.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-12-17 14:58:06 +0100
committerMartin Odersky <odersky@gmail.com>2014-12-17 14:58:06 +0100
commit3ac70b64ebfe12dd211377aa2527a4666ec2e243 (patch)
tree806656b3e2ae1ec77b8c894de3b8cf0cd6075d45 /src/dotty/tools/dotc/typer/Typer.scala
parentecbf5f545b46d65858d27173701def9e2a4d113a (diff)
downloaddotty-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.scala47
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))
}