Skip to content

Commit 8daf2b7

Browse files
committed
Avoid creating cyclic types when reporting errors in selectionType
The previous code was a great demonstration of the perils of mixing mutable variables with delayed evaluation. Also, make lazy vals in Message @ThreadUnsafe. This means that any recursion (like the one we encountered before the fix) manifests itself in stackoverflows instead of deadlocks. Fixes #12220
1 parent e2ea418 commit 8daf2b7

File tree

3 files changed

+13
-8
lines changed

3 files changed

+13
-8
lines changed

compiler/src/dotty/tools/dotc/reporting/Message.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package dotty.tools
22
package dotc
33
package reporting
4-
4+
import scala.annotation.threadUnsafe
55
import util.SourcePosition
66

77
object Message {
@@ -85,10 +85,10 @@ abstract class Message(val errorId: ErrorMessageID) { self =>
8585
def rawMessage = message
8686

8787
/** The message to report. <nonsensical> tags are filtered out */
88-
lazy val message: String = dropNonSensical(msg + msgSuffix)
88+
@threadUnsafe lazy val message: String = dropNonSensical(msg + msgSuffix)
8989

9090
/** The explanation to report. <nonsensical> tags are filtered out */
91-
lazy val explanation: String = dropNonSensical(explain)
91+
@threadUnsafe lazy val explanation: String = dropNonSensical(explain)
9292

9393
/** A message is non-sensical if it contains references to <nonsensical>
9494
* tags. Such tags are inserted by the error diagnostic framework if a

compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,13 @@ trait TypeAssigner {
118118
/** The type of the selection `tree`, where `qual1` is the typed qualifier part. */
119119
def selectionType(tree: untpd.RefTree, qual1: Tree)(using Context): Type =
120120
var qualType = qual1.tpe.widenIfUnstable
121-
if !qualType.hasSimpleKind && tree.name != nme.CONSTRUCTOR then
122-
// constructors are selected on typeconstructor, type arguments are passed afterwards
123-
qualType = errorType(em"$qualType takes type parameters", qual1.srcPos)
124-
else if !qualType.isInstanceOf[TermType] then
125-
qualType = errorType(em"$qualType is illegal as a selection prefix", qual1.srcPos)
121+
if !qualType.isError then
122+
val prevQual = qualType
123+
if !qualType.hasSimpleKind && tree.name != nme.CONSTRUCTOR then
124+
// constructors are selected on typeconstructor, type arguments are passed afterwards
125+
qualType = errorType(em"$prevQual takes type parameters", qual1.srcPos)
126+
else if !qualType.isInstanceOf[TermType] then
127+
qualType = errorType(em"$prevQual is illegal as a selection prefix", qual1.srcPos)
126128

127129
def arrayElemType = qual1.tpe.widen match
128130
case JavaArrayType(elemtp) => elemtp

tests/neg/i12220.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
val a: List[Any] = List(List(1,2), List(3,4))
2+
val _ = for(b <- a ; c <- b.asInstanceOf[List]) { println(c) } // error
3+

0 commit comments

Comments
 (0)