summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@typesafe.com>2016-05-13 15:07:06 +0200
committerLukas Rytz <lukas.rytz@typesafe.com>2016-05-13 15:07:06 +0200
commit554af4da73f812bf275d58589da4374fbbfa92a8 (patch)
treeb11fa0cf08c136dc991eca5e7734f935a815af88
parenta33b0853452a625ac93eada7d5f265ed09f8e362 (diff)
parent6379b70d952cf0eea96d205e14a291b441f9cd45 (diff)
downloadscala-554af4da73f812bf275d58589da4374fbbfa92a8.tar.gz
scala-554af4da73f812bf275d58589da4374fbbfa92a8.tar.bz2
scala-554af4da73f812bf275d58589da4374fbbfa92a8.zip
Merge pull request #5146 from som-snytt/issue/9045-msg
SI-9045 Error on recursive ctor
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala5
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala65
-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, 52 insertions, 39 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 8f5c4b9f6d..329ce8c23b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -2992,43 +2992,36 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
def includesTargetPos(tree: Tree) =
tree.pos.isRange && context.unit.exists && (tree.pos includes context.unit.targetPos)
val localTarget = stats exists includesTargetPos
- def typedStat(stat: Tree): Tree = {
- if (context.owner.isRefinementClass && !treeInfo.isDeclarationOrTypeDef(stat))
- OnlyDeclarationsError(stat)
- else
- stat match {
- case imp @ Import(_, _) =>
- imp.symbol.initialize
- if (!imp.symbol.isError) {
- context = context.make(imp)
- typedImport(imp)
- } else EmptyTree
- case _ =>
- if (localTarget && !includesTargetPos(stat)) {
- // skip typechecking of statements in a sequence where some other statement includes
- // the targetposition
- stat
- } else {
- 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 (!isPastTyper && treeInfo.isPureExprForWarningPurposes(result)) context.warning(stat.pos,
- "a pure expression does nothing in statement position; " +
- "you may be omitting necessary parentheses"
- )
- result
- }
+ def typedStat(stat: Tree): Tree = stat match {
+ case s if context.owner.isRefinementClass && !treeInfo.isDeclarationOrTypeDef(s) => OnlyDeclarationsError(s)
+ case imp @ Import(_, _) =>
+ imp.symbol.initialize
+ if (!imp.symbol.isError) {
+ context = context.make(imp)
+ typedImport(imp)
+ } else EmptyTree
+ // 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))
+ // 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)) {
+ 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"
+ )
+ result
}
/* 'accessor' and 'accessed' are so similar it becomes very difficult to
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)
+}