diff options
-rw-r--r-- | src/dotty/tools/dotc/core/SymDenotations.scala | 1 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/ErrorReporting.scala | 19 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Mode.scala | 1 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Namer.scala | 19 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 4 | ||||
-rw-r--r-- | test/dotc/tests.scala | 2 | ||||
-rw-r--r-- | tests/neg/typers.scala | 10 | ||||
-rw-r--r-- | tests/pos/typers.scala | 8 |
8 files changed, 61 insertions, 3 deletions
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index ccf4f83e7..0fd8f1acb 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -692,6 +692,7 @@ object SymDenotations { else if (isClass) "class" else if (isType) "type" else if (this is Module) "module" + else if (this is Method) "method" else "val" s"$kindString $name" } diff --git a/src/dotty/tools/dotc/typer/ErrorReporting.scala b/src/dotty/tools/dotc/typer/ErrorReporting.scala index 9b6188fe6..372d12f82 100644 --- a/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -24,6 +24,25 @@ object ErrorReporting { ErrorType } + def cyclicErrorMsg(ex: CyclicReference)(implicit ctx: Context) = { + val cycleSym = ex.denot.symbol + def errorMsg(msg: String, cx: Context): String = + if (cx.mode is Mode.InferringReturnType) { + cx.tree match { + case tree: Trees.ValOrDefDef[_] => + val treeSym = ctx.symOfContextTree(tree) + if (treeSym.exists && treeSym.name == cycleSym.name && treeSym.owner == cycleSym.owner) { + val result = if (cycleSym.isSourceMethod) " result" else "" + i"overloaded or recursive $cycleSym needs$result type" + } + else errorMsg(msg, cx.outer) + case _ => + errorMsg(msg, cx.outer) + } + } else msg + errorMsg(ex.getMessage, ctx) + } + class Errors(implicit ctx: Context) { def expectedTypeStr(tp: Type): String = tp match { diff --git a/src/dotty/tools/dotc/typer/Mode.scala b/src/dotty/tools/dotc/typer/Mode.scala index 8b8b74b84..b11d4dc7d 100644 --- a/src/dotty/tools/dotc/typer/Mode.scala +++ b/src/dotty/tools/dotc/typer/Mode.scala @@ -29,6 +29,7 @@ object Mode { val Type = newMode(1, "Type") val ImplicitsEnabled = newMode(2, "ImplicitsEnabled") + val InferringReturnType = newMode(3, "InferencingReturnType") val PatternOrType = Pattern | Type }
\ No newline at end of file diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala index e054aaa3a..3e39c3926 100644 --- a/src/dotty/tools/dotc/typer/Namer.scala +++ b/src/dotty/tools/dotc/typer/Namer.scala @@ -47,6 +47,22 @@ trait NamerContextOps { this: Context => def effectiveScope: Scope = if (owner != null && owner.isClass) owner.asClass.decls else scope + + /** The symbol (stored in some typer's symTree) of an enclosing context definition */ + def symOfContextTree(tree: untpd.Tree) = { + def go(ctx: Context): Symbol = { + val typer = ctx.typer + if (typer == null) NoSymbol + else typer.symOfTree get tree match { + case Some(sym) => sym + case None => + var cx = ctx.outer + while (cx.typer eq typer) cx = cx.outer + go(cx) + } + } + go(this) + } } /** This class creates symbols from definitions and imports and gives them @@ -416,7 +432,8 @@ class Namer { typer: Typer => } // println(s"final inherited for $sym: ${inherited.toString}") !!! // println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}") - def rhsType = adapt(typedAheadExpr(mdef.rhs), WildcardType).tpe.widen + val rhsCtx = ctx.fresh addMode Mode.InferringReturnType + def rhsType = adapt(typedAheadExpr(mdef.rhs)(rhsCtx), WildcardType).tpe.widen def lhsType = fullyDefinedType(rhsType, "right-hand side", mdef.pos) inherited orElse lhsType } diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 20f9aeb19..6b6252638 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -831,8 +831,9 @@ class Typer extends Namer with Applications with Implicits { typedTree remove xtree match { case Some(ttree) => ttree case none => - val sym = symOfTree.remove(xtree).getOrElse(NoSymbol) + val sym = symOfTree.getOrElse(xtree, NoSymbol) sym.ensureCompleted() + symOfTree.remove(xtree) def localContext = ctx.fresh.withOwner(sym).withTree(xtree) def typedNamed(tree: untpd.NameTree): Tree = tree match { @@ -900,6 +901,7 @@ class Typer extends Namer with Applications with Implicits { def typed(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = ctx.traceIndented (s"typing ${tree.show}", show = true) { try adapt(typedUnadapted(tree, pt), pt) catch { + case ex: CyclicReference => errorTree(tree, cyclicErrorMsg(ex)) case ex: FatalTypeError => errorTree(tree, ex.getMessage) } } diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index 0d7d84457..02b2e6ca2 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -34,5 +34,5 @@ class tests extends CompilerTest { @Test def neg_typedapply() = compileFile(negDir, "typedapply", xerrors = 4) @Test def neg_typedidents() = compileFile(negDir, "typedidents", xerrors = 2) @Test def neg_assignments() = compileFile(negDir, "assignments", xerrors = 3) - @Test def neg_typers() = compileFile(negDir, "typers", xerrors = 7) + @Test def neg_typers() = compileFile(negDir, "typers", xerrors = 10) }
\ No newline at end of file diff --git a/tests/neg/typers.scala b/tests/neg/typers.scala index a8e008373..d25a8911e 100644 --- a/tests/neg/typers.scala +++ b/tests/neg/typers.scala @@ -25,6 +25,16 @@ object typers { return 4 } + object cyclic { + def factorial(acc: Int, n: Int) = + if (n == 0) acc + else factorial(acc * n, n - 1) + + def foo(x: Int) = x + def foo() = foo(1) + + } + object tries { val x = try { diff --git a/tests/pos/typers.scala b/tests/pos/typers.scala index 900baef75..66c10f4b0 100644 --- a/tests/pos/typers.scala +++ b/tests/pos/typers.scala @@ -1,3 +1,5 @@ +import annotation.tailrec + object typers { class List[+T] { @@ -43,6 +45,12 @@ object typers { } class C { + + @tailrec def factorial(acc: Int, n: Int): Int = + if (n == 0) acc + else factorial(acc * n, n - 1) + + println(factorial(1, 10)) } class Refinements { |