Skip to content

Commit 3ac70b6

Browse files
committed
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.
1 parent ecbf5f5 commit 3ac70b6

File tree

1 file changed

+29
-18
lines changed

1 file changed

+29
-18
lines changed

src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -669,25 +669,36 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
669669
}
670670

671671
def typedReturn(tree: untpd.Return)(implicit ctx: Context): Return = track("typedReturn") {
672-
def returnProto(owner: Symbol) =
673-
if (owner.isConstructor) defn.UnitType else owner.info.finalResultType
674-
def enclMethInfo(cx: Context): (Tree, Type) =
675-
if (tree.from.isEmpty) {
676-
val owner = cx.owner
677-
if (cx == NoContext || owner.isType) {
678-
ctx.error("return outside method definition", tree.pos)
679-
(EmptyTree, WildcardType)
680-
} else if (owner.isSourceMethod)
681-
if (owner.isCompleted) {
682-
val from = Ident(TermRef(NoPrefix, owner.asTerm))
683-
val proto = returnProto(owner)
684-
(from, proto)
685-
} else (EmptyTree, errorType(d"$owner has return statement; needs result type", tree.pos))
686-
else enclMethInfo(cx.outer)
672+
def returnProto(owner: Symbol, locals: Scope): Type =
673+
if (owner.isConstructor) defn.UnitType
674+
else owner.info match {
675+
case info: PolyType =>
676+
val tparams = locals.toList.takeWhile(_ is TypeParam)
677+
assert(info.paramNames.length == tparams.length,
678+
i"return mismatch from $owner, tparams = $tparams, locals = ${locals.toList}%, %")
679+
info.instantiate(tparams.map(_.typeRef)).finalResultType
680+
case info =>
681+
info.finalResultType
687682
}
688-
else
689-
(tree.from.asInstanceOf[tpd.Tree], returnProto(tree.from.symbol))
690-
val (from, proto) = enclMethInfo(ctx)
683+
def enclMethInfo(cx: Context): (Tree, Type) = {
684+
val owner = cx.owner
685+
if (cx == NoContext || owner.isType) {
686+
ctx.error("return outside method definition", tree.pos)
687+
(EmptyTree, WildcardType)
688+
}
689+
else if (owner != cx.outer.owner && owner.isSourceMethod) {
690+
if (owner.isCompleted) {
691+
val from = Ident(TermRef(NoPrefix, owner.asTerm))
692+
val proto = returnProto(owner, cx.scope)
693+
(from, proto)
694+
}
695+
else (EmptyTree, errorType(d"$owner has return statement; needs result type", tree.pos))
696+
}
697+
else enclMethInfo(cx.outer)
698+
}
699+
val (from, proto) =
700+
if (tree.from.isEmpty) enclMethInfo(ctx)
701+
else (tree.from.asInstanceOf[tpd.Tree], WildcardType)
691702
val expr1 = typedExpr(tree.expr orElse untpd.unitLiteral.withPos(tree.pos), proto)
692703
assignType(cpy.Return(tree)(expr1, from))
693704
}

0 commit comments

Comments
 (0)