summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSom Snytt <som.snytt@gmail.com>2016-05-04 12:44:40 -0700
committerSom Snytt <som.snytt@gmail.com>2016-05-04 16:00:11 -0700
commit6379b70d952cf0eea96d205e14a291b441f9cd45 (patch)
tree5f26e590ef4a8dbd30519b8cf368b277a3c2bff8
parentf952a812340db7bc11f45b45f46e4b8ce7d6fb49 (diff)
downloadscala-6379b70d952cf0eea96d205e14a291b441f9cd45.tar.gz
scala-6379b70d952cf0eea96d205e14a291b441f9cd45.tar.bz2
scala-6379b70d952cf0eea96d205e14a291b441f9cd45.zip
SI-9045 Error on recursive ctor
If the constructor invokes itself, say so.
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala5
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala17
-rw-r--r--test/files/neg/constrs.check2
-rw-r--r--test/files/neg/t4460a.check2
-rw-r--r--test/files/neg/t4460b.check2
-rw-r--r--test/files/neg/t9045.check7
-rw-r--r--test/files/neg/t9045.scala8
7 files changed, 32 insertions, 11 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index ccdff5c9a1..e190b57017 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -469,6 +469,11 @@ trait ContextErrors {
setError(tree)
}
+ def ConstructorRecursesError(tree: Tree) = {
+ issueNormalTypeError(tree, "constructor invokes itself")
+ setError(tree)
+ }
+
def OnlyDeclarationsError(tree: Tree) = {
issueNormalTypeError(tree, "only declarations allowed here")
setError(tree)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 65c6e09fd3..329ce8c23b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -3003,22 +3003,23 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
// skip typechecking of statements in a sequence where some other statement includes the targetposition
case s if localTarget && !includesTargetPos(s) => s
case _ =>
- val localTyper = if (inBlock || (stat.isDef && !stat.isInstanceOf[LabelDef])) {
- this
- } else newTyper(context.make(stat, exprOwner))
+ val localTyper = if (inBlock || (stat.isDef && !stat.isInstanceOf[LabelDef])) this
+ else newTyper(context.make(stat, exprOwner))
// XXX this creates a spurious dead code warning if an exception is thrown
// in a constructor, even if it is the only thing in the constructor.
val result = checkDead(localTyper.typedByValueExpr(stat))
if (treeInfo.isSelfOrSuperConstrCall(result)) {
context.inConstructorSuffix = true
- if (treeInfo.isSelfConstrCall(result) && result.symbol.pos.pointOrElse(0) >= exprOwner.enclMethod.pos.pointOrElse(0))
- ConstructorsOrderError(stat)
+ if (treeInfo.isSelfConstrCall(result)) {
+ if (result.symbol == exprOwner.enclMethod)
+ ConstructorRecursesError(stat)
+ else if (result.symbol.pos.pointOrElse(0) >= exprOwner.enclMethod.pos.pointOrElse(0))
+ ConstructorsOrderError(stat)
+ }
}
-
if (!isPastTyper && treeInfo.isPureExprForWarningPurposes(result)) context.warning(stat.pos,
- "a pure expression does nothing in statement position; " +
- "you may be omitting necessary parentheses"
+ "a pure expression does nothing in statement position; you may be omitting necessary parentheses"
)
result
}
diff --git a/test/files/neg/constrs.check b/test/files/neg/constrs.check
index 4f4a12bc13..8a5bd97ae3 100644
--- a/test/files/neg/constrs.check
+++ b/test/files/neg/constrs.check
@@ -7,7 +7,7 @@ constrs.scala:6: error: value u is not a member of object test
constrs.scala:10: error: called constructor's definition must precede calling constructor's definition
def this() = this("abc")
^
-constrs.scala:12: error: called constructor's definition must precede calling constructor's definition
+constrs.scala:12: error: constructor invokes itself
def this(x: Boolean) = this(x)
^
constrs.scala:16: error: type mismatch;
diff --git a/test/files/neg/t4460a.check b/test/files/neg/t4460a.check
index b711e7acb1..7a7618a114 100644
--- a/test/files/neg/t4460a.check
+++ b/test/files/neg/t4460a.check
@@ -1,4 +1,4 @@
-t4460a.scala:6: error: called constructor's definition must precede calling constructor's definition
+t4460a.scala:6: error: constructor invokes itself
def this() = this() // was binding to Predef.<init> !!
^
one error found
diff --git a/test/files/neg/t4460b.check b/test/files/neg/t4460b.check
index f0e703fd10..9a621dbd5c 100644
--- a/test/files/neg/t4460b.check
+++ b/test/files/neg/t4460b.check
@@ -1,4 +1,4 @@
-t4460b.scala:7: error: called constructor's definition must precede calling constructor's definition
+t4460b.scala:7: error: constructor invokes itself
def this() = this() // was binding to Predef.<init> !!
^
one error found
diff --git a/test/files/neg/t9045.check b/test/files/neg/t9045.check
new file mode 100644
index 0000000000..07d0e2dd74
--- /dev/null
+++ b/test/files/neg/t9045.check
@@ -0,0 +1,7 @@
+t9045.scala:3: error: constructor invokes itself
+ def this(axes: Array[Int]) = this(axes)
+ ^
+t9045.scala:6: error: called constructor's definition must precede calling constructor's definition
+ def this(d: Double) = this(d.toLong)
+ ^
+two errors found
diff --git a/test/files/neg/t9045.scala b/test/files/neg/t9045.scala
new file mode 100644
index 0000000000..e6710ab324
--- /dev/null
+++ b/test/files/neg/t9045.scala
@@ -0,0 +1,8 @@
+
+case class AffineImageShape(axes: Seq[Int]) {
+ def this(axes: Array[Int]) = this(axes)
+}
+class X(i: Int) {
+ def this(d: Double) = this(d.toLong)
+ def this(n: Long) = this(n.toInt)
+}