From a24a37087564ee1a9f7b054d75d8e3fe5c37f10b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 12 Aug 2020 19:31:53 +0200 Subject: [PATCH] Fix #9464: Fix computation of expected type in a return We need to substitute type as well as term parameters in the expected type of a return to handle dependent methods correctly. --- .../src/dotty/tools/dotc/typer/Typer.scala | 20 +++++++++++-------- tests/pos/i9464.scala | 6 ++++++ 2 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 tests/pos/i9464.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index ded36b9fdaac..b1ffb7c40aa1 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1473,17 +1473,21 @@ class Typer extends Namer instantiateCFT(appType.instantiate(paramss.head.map(_.termRef)), paramss.tail) else pt - def returnProto(owner: Symbol, locals: Scope): Type = + def returnProto(owner: Symbol): Type = if (owner.isConstructor) defn.UnitType else - val rt = owner.info match + // We need to get the return type of the enclosing function, with all parameters replaced + // by the local type and value parameters. It would be nice if we could look up that + // type simply in the tpt field of the enclosing function. But the tree argument in + // a context is an untyped tree, so we cannot extract its type. + def instantiateRT(info: Type, psymss: List[List[Symbol]]): Type = 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 + instantiateRT(info.instantiate(psymss.head.map(_.typeRef)), psymss.tail) + case info: MethodType => + instantiateRT(info.instantiate(psymss.head.map(_.termRef)), psymss.tail) case info => - info.finalResultType + info.widenExpr + val rt = instantiateRT(owner.info, owner.paramSymss) def iftParamss = ctx.owner.ownersIterator .filter(_.is(Method, butNot = Accessor)) .takeWhile(_.isAnonymousFunction) @@ -1505,7 +1509,7 @@ class Typer extends Namer (EmptyTree, errorType(MissingReturnTypeWithReturnStatement(owner), tree.sourcePos)) else { val from = Ident(TermRef(NoPrefix, owner.asTerm)) - val proto = returnProto(owner, cx.scope) + val proto = returnProto(owner) (from, proto) } else enclMethInfo(cx.outer) diff --git a/tests/pos/i9464.scala b/tests/pos/i9464.scala new file mode 100644 index 000000000000..56cef7aedff8 --- /dev/null +++ b/tests/pos/i9464.scala @@ -0,0 +1,6 @@ +trait T: + type X + def x: X + +def test1(t: T): t.X = t.x +def test2(t: T): t.X = return t.x