aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala1
-rw-r--r--src/dotty/tools/dotc/typer/ErrorReporting.scala19
-rw-r--r--src/dotty/tools/dotc/typer/Mode.scala1
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala19
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala4
-rw-r--r--test/dotc/tests.scala2
-rw-r--r--tests/neg/typers.scala10
-rw-r--r--tests/pos/typers.scala8
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 {