From 2783476e16625d34eccc6870be0f54f419eb4eff Mon Sep 17 00:00:00 2001 From: EnzeXing Date: Wed, 20 Mar 2024 22:57:09 -0400 Subject: [PATCH 1/3] Added second trace and enabled positions for tasty files --- compiler/src/dotty/tools/dotc/Compiler.scala | 2 + .../tools/dotc/transform/init/Objects.scala | 38 +++++++++++-------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/Compiler.scala b/compiler/src/dotty/tools/dotc/Compiler.scala index 290df761d117..3abd46ebe8eb 100644 --- a/compiler/src/dotty/tools/dotc/Compiler.scala +++ b/compiler/src/dotty/tools/dotc/Compiler.scala @@ -167,6 +167,8 @@ class Compiler { val rctx = if ctx.settings.Xsemanticdb.value then ctx.addMode(Mode.ReadPositions) + else if ctx.settings.YcheckInitGlobal.value then + ctx.addMode(Mode.ReadPositions) else ctx new Run(this, rctx) diff --git a/compiler/src/dotty/tools/dotc/transform/init/Objects.scala b/compiler/src/dotty/tools/dotc/transform/init/Objects.scala index 4b56a7c81ca4..02c76faa0c4a 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Objects.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Objects.scala @@ -197,7 +197,7 @@ class Objects: * * @param owner The static object whose initialization creates the array. */ - case class OfArray(owner: ClassSymbol, regions: Regions.Data)(using @constructorOnly ctx: Context) extends ValueElement: + case class OfArray(owner: ClassSymbol, regions: Regions.Data)(using @constructorOnly ctx: Context, @constructorOnly trace: Trace) extends ValueElement: val klass: ClassSymbol = defn.ArrayClass val addr: Heap.Addr = Heap.arrayAddr(regions, owner) def show(using Context) = "OfArray(owner = " + owner.show + ")" @@ -455,9 +455,11 @@ class Objects: abstract class Addr: /** The static object which owns the mutable slot */ def owner: ClassSymbol + def getTrace: Trace = Trace.empty /** The address for mutable fields of objects. */ - private case class FieldAddr(regions: Regions.Data, field: Symbol, owner: ClassSymbol) extends Addr + private case class FieldAddr(regions: Regions.Data, field: Symbol, owner: ClassSymbol)(trace: Trace) extends Addr: + override def getTrace: Trace = trace /** The address for mutable local variables . */ private case class LocalVarAddr(regions: Regions.Data, sym: Symbol, owner: ClassSymbol) extends Addr @@ -497,11 +499,11 @@ class Objects: def localVarAddr(regions: Regions.Data, sym: Symbol, owner: ClassSymbol): Addr = LocalVarAddr(regions, sym, owner) - def fieldVarAddr(regions: Regions.Data, sym: Symbol, owner: ClassSymbol): Addr = - FieldAddr(regions, sym, owner) + def fieldVarAddr(regions: Regions.Data, sym: Symbol, owner: ClassSymbol)(using Trace): Addr = + FieldAddr(regions, sym, owner)(summon[Trace]) - def arrayAddr(regions: Regions.Data, owner: ClassSymbol)(using Context): Addr = - FieldAddr(regions, defn.ArrayClass, owner) + def arrayAddr(regions: Regions.Data, owner: ClassSymbol)(using Trace, Context): Addr = + FieldAddr(regions, defn.ArrayClass, owner)(summon[Trace]) def getHeapData()(using mutable: MutableData): Data = mutable.heap @@ -654,12 +656,12 @@ class Objects: if arr.addr.owner == State.currentObject then Heap.read(arr.addr) else - errorReadOtherStaticObject(State.currentObject, arr.addr.owner) + errorReadOtherStaticObject(State.currentObject, arr.addr) Bottom else if target == defn.Array_update then assert(args.size == 2, "Incorrect number of arguments for Array update, found = " + args.size) if arr.addr.owner != State.currentObject then - errorMutateOtherStaticObject(State.currentObject, arr.addr.owner) + errorMutateOtherStaticObject(State.currentObject, arr.addr) else Heap.writeJoin(arr.addr, args.tail.head.value) Bottom @@ -810,7 +812,7 @@ class Objects: if addr.owner == State.currentObject then Heap.read(addr) else - errorReadOtherStaticObject(State.currentObject, addr.owner) + errorReadOtherStaticObject(State.currentObject, addr) Bottom else if ref.isObjectRef && ref.klass.hasSource then report.warning("Access uninitialized field " + field.show + ". " + Trace.show, Trace.position) @@ -879,7 +881,7 @@ class Objects: if ref.hasVar(field) then val addr = ref.varAddr(field) if addr.owner != State.currentObject then - errorMutateOtherStaticObject(State.currentObject, addr.owner) + errorMutateOtherStaticObject(State.currentObject, addr) else Heap.writeJoin(addr, rhs) else @@ -968,7 +970,7 @@ class Objects: if addr.owner == State.currentObject then Heap.read(addr) else - errorReadOtherStaticObject(State.currentObject, addr.owner) + errorReadOtherStaticObject(State.currentObject, addr) Bottom end if case _ => @@ -1020,7 +1022,7 @@ class Objects: Env.getVar(sym) match case Some(addr) => if addr.owner != State.currentObject then - errorMutateOtherStaticObject(State.currentObject, addr.owner) + errorMutateOtherStaticObject(State.currentObject, addr) else Heap.writeJoin(addr, value) case _ => @@ -1758,19 +1760,23 @@ class Objects: else evalType(tref.prefix, thisV, klass, elideObjectAccess = cls.isStatic) val mutateErrorSet: mutable.Set[(ClassSymbol, ClassSymbol)] = mutable.Set.empty - def errorMutateOtherStaticObject(currentObj: ClassSymbol, otherObj: ClassSymbol)(using Trace, Context) = + def errorMutateOtherStaticObject(currentObj: ClassSymbol, addr: Heap.Addr)(using Trace, Context) = + val otherObj = addr.owner if mutateErrorSet.add((currentObj, otherObj)) then val msg = s"Mutating ${otherObj.show} during initialization of ${currentObj.show}.\n" + - "Mutating other static objects during the initialization of one static object is forbidden. " + Trace.show + "Mutating other static objects during the initialization of one static object is forbidden. " + Trace.show + + "The mutable state is created through: " + Trace.show(using addr.getTrace) report.warning(msg, Trace.position) val readErrorSet: mutable.Set[(ClassSymbol, ClassSymbol)] = mutable.Set.empty - def errorReadOtherStaticObject(currentObj: ClassSymbol, otherObj: ClassSymbol)(using Trace, Context) = + def errorReadOtherStaticObject(currentObj: ClassSymbol, addr: Heap.Addr)(using Trace, Context) = + val otherObj = addr.owner if readErrorSet.add((currentObj, otherObj)) then val msg = "Reading mutable state of " + otherObj.show + " during initialization of " + currentObj.show + ".\n" + - "Reading mutable state of other static objects is forbidden as it breaks initialization-time irrelevance. " + Trace.show + "Reading mutable state of other static objects is forbidden as it breaks initialization-time irrelevance. " + Trace.show + + "The mutable state is created through: " + Trace.show(using addr.getTrace) report.warning(msg, Trace.position) From db0cdb10c6a3a521bf174a756a6c61941efbb998 Mon Sep 17 00:00:00 2001 From: EnzeXing Date: Wed, 20 Mar 2024 22:58:31 -0400 Subject: [PATCH 2/3] Update check files --- tests/init-global/warn/TypeCast.check | 10 ++++++++++ tests/init-global/warn/TypeCast.scala | 18 ++++++++++++++++++ tests/init-global/warn/global-cycle5.check | 3 +++ .../init-global/warn/global-irrelevance1.check | 3 +++ .../init-global/warn/global-irrelevance2.check | 3 +++ .../init-global/warn/global-irrelevance3.check | 1 + .../init-global/warn/global-irrelevance4.check | 1 + .../init-global/warn/global-irrelevance5.check | 5 +++++ .../init-global/warn/global-irrelevance6.check | 5 +++++ .../init-global/warn/global-irrelevance7.check | 5 +++++ tests/init-global/warn/mutable-array.check | 7 +++++++ tests/init-global/warn/mutable-read1.check | 7 +++++++ tests/init-global/warn/mutable-read2.check | 7 +++++++ tests/init-global/warn/mutable-read3.check | 7 +++++++ tests/init-global/warn/mutable-read4.check | 7 +++++++ tests/init-global/warn/mutable-read5.check | 3 +++ tests/init-global/warn/mutable-read6.check | 7 +++++++ tests/init-global/warn/mutable-read7.check | 3 +++ tests/init-global/warn/mutable-read8.check | 3 +++ tests/init-global/warn/patmat-unapplySeq.check | 5 +++++ .../init-global/warn/patmat-unapplySeq2.check | 5 +++++ 21 files changed, 115 insertions(+) create mode 100644 tests/init-global/warn/TypeCast.check create mode 100644 tests/init-global/warn/TypeCast.scala diff --git a/tests/init-global/warn/TypeCast.check b/tests/init-global/warn/TypeCast.check new file mode 100644 index 000000000000..3308727463e8 --- /dev/null +++ b/tests/init-global/warn/TypeCast.check @@ -0,0 +1,10 @@ +-- Warning: tests/init-global/warn/TypeCast.scala:7:17 ----------------------------------------------------------------- +7 | def g(): Int = f // warn + | ^ + | Access uninitialized field value f. Calling trace: + | ├── object B { [ TypeCast.scala:5 ] + | │ ^ + | ├── val f: Int = g() [ TypeCast.scala:6 ] + | │ ^^^ + | └── def g(): Int = f // warn [ TypeCast.scala:7 ] + | ^ diff --git a/tests/init-global/warn/TypeCast.scala b/tests/init-global/warn/TypeCast.scala new file mode 100644 index 000000000000..ae389bb4e55c --- /dev/null +++ b/tests/init-global/warn/TypeCast.scala @@ -0,0 +1,18 @@ +object A { + val f: Int = 10 + def m() = f +} +object B { + val f: Int = g() + def g(): Int = f // warn +} +object C { + val a: A.type | B.type = if ??? then A else B + def cast[T](a: Any): T = a.asInstanceOf[T] + val c: A.type = cast[A.type](a) // abstraction for c is {A, B} + val d = c.f // treat as c.asInstanceOf[owner of f].f + val e = c.m() // treat as c.asInstanceOf[owner of f].m() + val c2: B.type = cast[B.type](a) + val g = c2.f // no error here +} + diff --git a/tests/init-global/warn/global-cycle5.check b/tests/init-global/warn/global-cycle5.check index 072a80e4530f..99ddb7c4e944 100644 --- a/tests/init-global/warn/global-cycle5.check +++ b/tests/init-global/warn/global-cycle5.check @@ -7,3 +7,6 @@ |│ ^ |└── val b: Int = A.a.foo() // warn [ global-cycle5.scala:10 ] | ^^^ + |The mutable state is created through: Calling trace: + |└── object A { [ global-cycle5.scala:5 ] + | ^ diff --git a/tests/init-global/warn/global-irrelevance1.check b/tests/init-global/warn/global-irrelevance1.check index 447ba6b6b29a..18f866ddf5b3 100644 --- a/tests/init-global/warn/global-irrelevance1.check +++ b/tests/init-global/warn/global-irrelevance1.check @@ -7,3 +7,6 @@ |│ ^ |└── var y = A.x * 2 // warn [ global-irrelevance1.scala:5 ] | ^^^ + |The mutable state is created through: Calling trace: + |└── object A: [ global-irrelevance1.scala:1 ] + | ^ diff --git a/tests/init-global/warn/global-irrelevance2.check b/tests/init-global/warn/global-irrelevance2.check index 156b34fa6aa5..e8fa5219df9d 100644 --- a/tests/init-global/warn/global-irrelevance2.check +++ b/tests/init-global/warn/global-irrelevance2.check @@ -11,3 +11,6 @@ | │ ^ | └── A.x = b * 2 // warn [ global-irrelevance2.scala:5 ] | ^^^^^^^^^^^^ + | The mutable state is created through: Calling trace: + | └── object A: [ global-irrelevance2.scala:1 ] + | ^ diff --git a/tests/init-global/warn/global-irrelevance3.check b/tests/init-global/warn/global-irrelevance3.check index dba945224f97..17abf8ffb038 100644 --- a/tests/init-global/warn/global-irrelevance3.check +++ b/tests/init-global/warn/global-irrelevance3.check @@ -9,3 +9,4 @@ |│ ^^^^^^^ |└── (() => x) // warn [ global-irrelevance3.scala:9 ] | ^ + |The mutable state is created through: diff --git a/tests/init-global/warn/global-irrelevance4.check b/tests/init-global/warn/global-irrelevance4.check index 7253e5b39688..a15e852f03a4 100644 --- a/tests/init-global/warn/global-irrelevance4.check +++ b/tests/init-global/warn/global-irrelevance4.check @@ -9,3 +9,4 @@ | │ ^^^^^^^^^ | └── (y => x = y), // warn [ global-irrelevance4.scala:8 ] | ^^^^^^^^^^ + | The mutable state is created through: diff --git a/tests/init-global/warn/global-irrelevance5.check b/tests/init-global/warn/global-irrelevance5.check index c3581e0b9bbc..8cbc8ec57656 100644 --- a/tests/init-global/warn/global-irrelevance5.check +++ b/tests/init-global/warn/global-irrelevance5.check @@ -7,3 +7,8 @@ |│ ^ |└── var y = A.array(0) * 2 // warn [ global-irrelevance5.scala:6 ] | ^^^^^^^^^^ + |The mutable state is created through: Calling trace: + |├── object A: [ global-irrelevance5.scala:1 ] + |│ ^ + |└── val array: Array[Int] = new Array(1) [ global-irrelevance5.scala:2 ] + | ^^^^^^^^^^^^ diff --git a/tests/init-global/warn/global-irrelevance6.check b/tests/init-global/warn/global-irrelevance6.check index 3e447a915ba3..e4561d5447b3 100644 --- a/tests/init-global/warn/global-irrelevance6.check +++ b/tests/init-global/warn/global-irrelevance6.check @@ -7,3 +7,8 @@ |│ ^ |└── var y = A.array(0).foo() * 2 // warn [ global-irrelevance6.scala:9 ] | ^^^^^^^^^^ + |The mutable state is created through: Calling trace: + |├── object A: [ global-irrelevance6.scala:4 ] + |│ ^ + |└── val array: Array[Box] = new Array(1) [ global-irrelevance6.scala:5 ] + | ^^^^^^^^^^^^ diff --git a/tests/init-global/warn/global-irrelevance7.check b/tests/init-global/warn/global-irrelevance7.check index c5f0da1a204b..ae7f9d3b1b6d 100644 --- a/tests/init-global/warn/global-irrelevance7.check +++ b/tests/init-global/warn/global-irrelevance7.check @@ -7,3 +7,8 @@ |│ ^ |└── var y = A.array(0).foo() * 2 // warn [ global-irrelevance7.scala:10 ] | ^^^^^^^^^^ + |The mutable state is created through: Calling trace: + |├── object A: [ global-irrelevance7.scala:4 ] + |│ ^ + |└── val array: Array[Box] = new Array(1) [ global-irrelevance7.scala:5 ] + | ^^^^^^^^^^^^ diff --git a/tests/init-global/warn/mutable-array.check b/tests/init-global/warn/mutable-array.check index fb96b33c85a9..994c221d7c6f 100644 --- a/tests/init-global/warn/mutable-array.check +++ b/tests/init-global/warn/mutable-array.check @@ -7,3 +7,10 @@ |│ ^ |└── val x: Int = box.value // warn [ mutable-array.scala:8 ] | ^^^^^^^^^ + |The mutable state is created through: Calling trace: + |├── object A: [ mutable-array.scala:1 ] + |│ ^ + |├── val box: Box = new Box(0) [ mutable-array.scala:3 ] + |│ ^^^^^^^^^^ + |└── class Box(var value: Int) [ mutable-array.scala:2 ] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/init-global/warn/mutable-read1.check b/tests/init-global/warn/mutable-read1.check index e141ced0c70d..48ec12cb9d0b 100644 --- a/tests/init-global/warn/mutable-read1.check +++ b/tests/init-global/warn/mutable-read1.check @@ -7,3 +7,10 @@ |│ ^ |└── val n: Int = boxA.value // warn [ mutable-read1.scala:10 ] | ^^^^^^^^^^ + |The mutable state is created through: Calling trace: + |├── object A: [ mutable-read1.scala:3 ] + |│ ^ + |├── val box: Box = new Box(4) [ mutable-read1.scala:4 ] + |│ ^^^^^^^^^^ + |└── class Box(var value: Int) [ mutable-read1.scala:1 ] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/init-global/warn/mutable-read2.check b/tests/init-global/warn/mutable-read2.check index 906a82ec09a5..320f7b151c9c 100644 --- a/tests/init-global/warn/mutable-read2.check +++ b/tests/init-global/warn/mutable-read2.check @@ -7,3 +7,10 @@ |│ ^ |└── val b: Int = box.value // warn [ mutable-read2.scala:10 ] | ^^^^^^^^^ + |The mutable state is created through: Calling trace: + |├── object A: [ mutable-read2.scala:1 ] + |│ ^ + |├── val box: Box = new Box(0) [ mutable-read2.scala:5 ] + |│ ^^^^^^^^^^ + |└── class Box(var value: Int) { [ mutable-read2.scala:2 ] + | ^ diff --git a/tests/init-global/warn/mutable-read3.check b/tests/init-global/warn/mutable-read3.check index 754196794a1f..cabf8c6350e8 100644 --- a/tests/init-global/warn/mutable-read3.check +++ b/tests/init-global/warn/mutable-read3.check @@ -7,3 +7,10 @@ |│ ^ |└── val x: Int = box.value // warn [ mutable-read3.scala:9 ] | ^^^^^^^^^ + |The mutable state is created through: Calling trace: + |├── object A: [ mutable-read3.scala:1 ] + |│ ^ + |├── val box: Box = new Box(0) [ mutable-read3.scala:3 ] + |│ ^^^^^^^^^^ + |└── class Box(var value: Int) [ mutable-read3.scala:2 ] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/init-global/warn/mutable-read4.check b/tests/init-global/warn/mutable-read4.check index 0ccb8e61549d..d80f946c3b94 100644 --- a/tests/init-global/warn/mutable-read4.check +++ b/tests/init-global/warn/mutable-read4.check @@ -7,3 +7,10 @@ |│ ^ |└── val n: Int = boxA.value // warn [ mutable-read4.scala:10 ] | ^^^^^^^^^^ + |The mutable state is created through: Calling trace: + |├── object A: [ mutable-read4.scala:3 ] + |│ ^ + |├── val box: Box = new Box(4) [ mutable-read4.scala:4 ] + |│ ^^^^^^^^^^ + |└── class Box(var value: Int) [ mutable-read4.scala:1 ] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/init-global/warn/mutable-read5.check b/tests/init-global/warn/mutable-read5.check index ffbf1c71fc2c..6a869df062eb 100644 --- a/tests/init-global/warn/mutable-read5.check +++ b/tests/init-global/warn/mutable-read5.check @@ -9,3 +9,6 @@ |│ ^^^^^^^^^^^^^^^^^^^^ |└── def name(s: String): Name = Name(0, chrs.length) // warn [ mutable-read5.scala:4 ] | ^^^^ + |The mutable state is created through: Calling trace: + |└── object Names: [ mutable-read5.scala:1 ] + | ^ diff --git a/tests/init-global/warn/mutable-read6.check b/tests/init-global/warn/mutable-read6.check index 92d2f58c3ecc..8e36d5372042 100644 --- a/tests/init-global/warn/mutable-read6.check +++ b/tests/init-global/warn/mutable-read6.check @@ -9,3 +9,10 @@ |│ ^^^^^^^^^^^^^^^^ |└── final def source: SourceFile = _source // warn [ mutable-read6.scala:7 ] | ^^^^^^^ + |The mutable state is created through: Calling trace: + |├── object Contexts: [ mutable-read6.scala:3 ] + |│ ^ + |├── val NoContext: Context = new Context [ mutable-read6.scala:4 ] + |│ ^^^^^^^^^^^ + |└── class Context: [ mutable-read6.scala:5 ] + | ^ diff --git a/tests/init-global/warn/mutable-read7.check b/tests/init-global/warn/mutable-read7.check index 244ed1519cdf..7f8adb182dd3 100644 --- a/tests/init-global/warn/mutable-read7.check +++ b/tests/init-global/warn/mutable-read7.check @@ -13,3 +13,6 @@ |│ ^ |└── if (Positioned.debug) { // warn [ mutable-read7.scala:7 ] | ^^^^^^^^^^^^^^^^ + |The mutable state is created through: Calling trace: + |└── object Positioned: [ mutable-read7.scala:1 ] + | ^ diff --git a/tests/init-global/warn/mutable-read8.check b/tests/init-global/warn/mutable-read8.check index 4527a2e5e5d8..545507d901fc 100644 --- a/tests/init-global/warn/mutable-read8.check +++ b/tests/init-global/warn/mutable-read8.check @@ -11,3 +11,6 @@ |│ ^ |└── if (Stats.monitored) println("record stats") // warn [ mutable-read8.scala:6 ] | ^^^^^^^^^^^^^^^ + |The mutable state is created through: Calling trace: + |└── object Stats { [ mutable-read8.scala:1 ] + | ^ diff --git a/tests/init-global/warn/patmat-unapplySeq.check b/tests/init-global/warn/patmat-unapplySeq.check index e46de1d60910..666bbe2131be 100644 --- a/tests/init-global/warn/patmat-unapplySeq.check +++ b/tests/init-global/warn/patmat-unapplySeq.check @@ -9,3 +9,8 @@ |│ ^^^^ |└── def apply(i: Int): Box = array(i) // warn [ patmat-unapplySeq.scala:8 ] | ^^^^^^^^ + |The mutable state is created through: Calling trace: + |├── object A: [ patmat-unapplySeq.scala:1 ] + |│ ^ + |└── val array: Array[Box] = new Array(1) [ patmat-unapplySeq.scala:4 ] + | ^^^^^^^^^^^^ diff --git a/tests/init-global/warn/patmat-unapplySeq2.check b/tests/init-global/warn/patmat-unapplySeq2.check index 5b5c89122f67..0a3cb645b0d6 100644 --- a/tests/init-global/warn/patmat-unapplySeq2.check +++ b/tests/init-global/warn/patmat-unapplySeq2.check @@ -9,3 +9,8 @@ |│ ^^^^^ |└── def apply(i: Int): Box = array(i) // warn [ patmat-unapplySeq2.scala:8 ] | ^^^^^^^^ + |The mutable state is created through: Calling trace: + |├── object A: [ patmat-unapplySeq2.scala:1 ] + |│ ^ + |└── val array: Array[Box] = new Array(1) [ patmat-unapplySeq2.scala:4 ] + | ^^^^^^^^^^^^ From fd6aaf7e5fa1cb064c196b92838048ee95cba6d5 Mon Sep 17 00:00:00 2001 From: EnzeXing Date: Sun, 24 Mar 2024 23:27:21 -0400 Subject: [PATCH 3/3] Only showing traces with >1 entries --- .../src/dotty/tools/dotc/transform/init/Objects.scala | 11 +++++++++-- tests/init-global/warn/global-cycle5.check | 3 --- tests/init-global/warn/global-irrelevance1.check | 3 --- tests/init-global/warn/global-irrelevance2.check | 3 --- tests/init-global/warn/global-irrelevance3.check | 1 - tests/init-global/warn/global-irrelevance4.check | 1 - tests/init-global/warn/global-irrelevance5.check | 2 +- tests/init-global/warn/global-irrelevance6.check | 2 +- tests/init-global/warn/global-irrelevance7.check | 2 +- tests/init-global/warn/mutable-array.check | 2 +- tests/init-global/warn/mutable-read1.check | 2 +- tests/init-global/warn/mutable-read2.check | 2 +- tests/init-global/warn/mutable-read3.check | 2 +- tests/init-global/warn/mutable-read4.check | 2 +- tests/init-global/warn/mutable-read5.check | 3 --- tests/init-global/warn/mutable-read6.check | 2 +- tests/init-global/warn/mutable-read7.check | 3 --- tests/init-global/warn/mutable-read8.check | 3 --- tests/init-global/warn/patmat-unapplySeq.check | 2 +- tests/init-global/warn/patmat-unapplySeq2.check | 2 +- 20 files changed, 20 insertions(+), 33 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/init/Objects.scala b/compiler/src/dotty/tools/dotc/transform/init/Objects.scala index 02c76faa0c4a..9812c32f2955 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Objects.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Objects.scala @@ -1759,24 +1759,31 @@ class Objects: if cls.isAllOf(Flags.JavaInterface) then Bottom else evalType(tref.prefix, thisV, klass, elideObjectAccess = cls.isStatic) + def printTraceWhenMultiple(trace: Trace)(using Context): String = + if trace.toVector.size > 1 then + Trace.buildStacktrace(trace, "The mutable state is created through: " + System.lineSeparator()) + else "" + val mutateErrorSet: mutable.Set[(ClassSymbol, ClassSymbol)] = mutable.Set.empty def errorMutateOtherStaticObject(currentObj: ClassSymbol, addr: Heap.Addr)(using Trace, Context) = val otherObj = addr.owner + val addr_trace = addr.getTrace if mutateErrorSet.add((currentObj, otherObj)) then val msg = s"Mutating ${otherObj.show} during initialization of ${currentObj.show}.\n" + "Mutating other static objects during the initialization of one static object is forbidden. " + Trace.show + - "The mutable state is created through: " + Trace.show(using addr.getTrace) + printTraceWhenMultiple(addr_trace) report.warning(msg, Trace.position) val readErrorSet: mutable.Set[(ClassSymbol, ClassSymbol)] = mutable.Set.empty def errorReadOtherStaticObject(currentObj: ClassSymbol, addr: Heap.Addr)(using Trace, Context) = val otherObj = addr.owner + val addr_trace = addr.getTrace if readErrorSet.add((currentObj, otherObj)) then val msg = "Reading mutable state of " + otherObj.show + " during initialization of " + currentObj.show + ".\n" + "Reading mutable state of other static objects is forbidden as it breaks initialization-time irrelevance. " + Trace.show + - "The mutable state is created through: " + Trace.show(using addr.getTrace) + printTraceWhenMultiple(addr_trace) report.warning(msg, Trace.position) diff --git a/tests/init-global/warn/global-cycle5.check b/tests/init-global/warn/global-cycle5.check index 99ddb7c4e944..072a80e4530f 100644 --- a/tests/init-global/warn/global-cycle5.check +++ b/tests/init-global/warn/global-cycle5.check @@ -7,6 +7,3 @@ |│ ^ |└── val b: Int = A.a.foo() // warn [ global-cycle5.scala:10 ] | ^^^ - |The mutable state is created through: Calling trace: - |└── object A { [ global-cycle5.scala:5 ] - | ^ diff --git a/tests/init-global/warn/global-irrelevance1.check b/tests/init-global/warn/global-irrelevance1.check index 18f866ddf5b3..447ba6b6b29a 100644 --- a/tests/init-global/warn/global-irrelevance1.check +++ b/tests/init-global/warn/global-irrelevance1.check @@ -7,6 +7,3 @@ |│ ^ |└── var y = A.x * 2 // warn [ global-irrelevance1.scala:5 ] | ^^^ - |The mutable state is created through: Calling trace: - |└── object A: [ global-irrelevance1.scala:1 ] - | ^ diff --git a/tests/init-global/warn/global-irrelevance2.check b/tests/init-global/warn/global-irrelevance2.check index e8fa5219df9d..156b34fa6aa5 100644 --- a/tests/init-global/warn/global-irrelevance2.check +++ b/tests/init-global/warn/global-irrelevance2.check @@ -11,6 +11,3 @@ | │ ^ | └── A.x = b * 2 // warn [ global-irrelevance2.scala:5 ] | ^^^^^^^^^^^^ - | The mutable state is created through: Calling trace: - | └── object A: [ global-irrelevance2.scala:1 ] - | ^ diff --git a/tests/init-global/warn/global-irrelevance3.check b/tests/init-global/warn/global-irrelevance3.check index 17abf8ffb038..dba945224f97 100644 --- a/tests/init-global/warn/global-irrelevance3.check +++ b/tests/init-global/warn/global-irrelevance3.check @@ -9,4 +9,3 @@ |│ ^^^^^^^ |└── (() => x) // warn [ global-irrelevance3.scala:9 ] | ^ - |The mutable state is created through: diff --git a/tests/init-global/warn/global-irrelevance4.check b/tests/init-global/warn/global-irrelevance4.check index a15e852f03a4..7253e5b39688 100644 --- a/tests/init-global/warn/global-irrelevance4.check +++ b/tests/init-global/warn/global-irrelevance4.check @@ -9,4 +9,3 @@ | │ ^^^^^^^^^ | └── (y => x = y), // warn [ global-irrelevance4.scala:8 ] | ^^^^^^^^^^ - | The mutable state is created through: diff --git a/tests/init-global/warn/global-irrelevance5.check b/tests/init-global/warn/global-irrelevance5.check index 8cbc8ec57656..b9bb2392da4d 100644 --- a/tests/init-global/warn/global-irrelevance5.check +++ b/tests/init-global/warn/global-irrelevance5.check @@ -7,7 +7,7 @@ |│ ^ |└── var y = A.array(0) * 2 // warn [ global-irrelevance5.scala:6 ] | ^^^^^^^^^^ - |The mutable state is created through: Calling trace: + |The mutable state is created through: |├── object A: [ global-irrelevance5.scala:1 ] |│ ^ |└── val array: Array[Int] = new Array(1) [ global-irrelevance5.scala:2 ] diff --git a/tests/init-global/warn/global-irrelevance6.check b/tests/init-global/warn/global-irrelevance6.check index e4561d5447b3..2e2af367eadd 100644 --- a/tests/init-global/warn/global-irrelevance6.check +++ b/tests/init-global/warn/global-irrelevance6.check @@ -7,7 +7,7 @@ |│ ^ |└── var y = A.array(0).foo() * 2 // warn [ global-irrelevance6.scala:9 ] | ^^^^^^^^^^ - |The mutable state is created through: Calling trace: + |The mutable state is created through: |├── object A: [ global-irrelevance6.scala:4 ] |│ ^ |└── val array: Array[Box] = new Array(1) [ global-irrelevance6.scala:5 ] diff --git a/tests/init-global/warn/global-irrelevance7.check b/tests/init-global/warn/global-irrelevance7.check index ae7f9d3b1b6d..e6a43cc37d80 100644 --- a/tests/init-global/warn/global-irrelevance7.check +++ b/tests/init-global/warn/global-irrelevance7.check @@ -7,7 +7,7 @@ |│ ^ |└── var y = A.array(0).foo() * 2 // warn [ global-irrelevance7.scala:10 ] | ^^^^^^^^^^ - |The mutable state is created through: Calling trace: + |The mutable state is created through: |├── object A: [ global-irrelevance7.scala:4 ] |│ ^ |└── val array: Array[Box] = new Array(1) [ global-irrelevance7.scala:5 ] diff --git a/tests/init-global/warn/mutable-array.check b/tests/init-global/warn/mutable-array.check index 994c221d7c6f..7618f3470433 100644 --- a/tests/init-global/warn/mutable-array.check +++ b/tests/init-global/warn/mutable-array.check @@ -7,7 +7,7 @@ |│ ^ |└── val x: Int = box.value // warn [ mutable-array.scala:8 ] | ^^^^^^^^^ - |The mutable state is created through: Calling trace: + |The mutable state is created through: |├── object A: [ mutable-array.scala:1 ] |│ ^ |├── val box: Box = new Box(0) [ mutable-array.scala:3 ] diff --git a/tests/init-global/warn/mutable-read1.check b/tests/init-global/warn/mutable-read1.check index 48ec12cb9d0b..4862b4399de4 100644 --- a/tests/init-global/warn/mutable-read1.check +++ b/tests/init-global/warn/mutable-read1.check @@ -7,7 +7,7 @@ |│ ^ |└── val n: Int = boxA.value // warn [ mutable-read1.scala:10 ] | ^^^^^^^^^^ - |The mutable state is created through: Calling trace: + |The mutable state is created through: |├── object A: [ mutable-read1.scala:3 ] |│ ^ |├── val box: Box = new Box(4) [ mutable-read1.scala:4 ] diff --git a/tests/init-global/warn/mutable-read2.check b/tests/init-global/warn/mutable-read2.check index 320f7b151c9c..7339e76672ef 100644 --- a/tests/init-global/warn/mutable-read2.check +++ b/tests/init-global/warn/mutable-read2.check @@ -7,7 +7,7 @@ |│ ^ |└── val b: Int = box.value // warn [ mutable-read2.scala:10 ] | ^^^^^^^^^ - |The mutable state is created through: Calling trace: + |The mutable state is created through: |├── object A: [ mutable-read2.scala:1 ] |│ ^ |├── val box: Box = new Box(0) [ mutable-read2.scala:5 ] diff --git a/tests/init-global/warn/mutable-read3.check b/tests/init-global/warn/mutable-read3.check index cabf8c6350e8..ecaaac65994b 100644 --- a/tests/init-global/warn/mutable-read3.check +++ b/tests/init-global/warn/mutable-read3.check @@ -7,7 +7,7 @@ |│ ^ |└── val x: Int = box.value // warn [ mutable-read3.scala:9 ] | ^^^^^^^^^ - |The mutable state is created through: Calling trace: + |The mutable state is created through: |├── object A: [ mutable-read3.scala:1 ] |│ ^ |├── val box: Box = new Box(0) [ mutable-read3.scala:3 ] diff --git a/tests/init-global/warn/mutable-read4.check b/tests/init-global/warn/mutable-read4.check index d80f946c3b94..e66fd8235a61 100644 --- a/tests/init-global/warn/mutable-read4.check +++ b/tests/init-global/warn/mutable-read4.check @@ -7,7 +7,7 @@ |│ ^ |└── val n: Int = boxA.value // warn [ mutable-read4.scala:10 ] | ^^^^^^^^^^ - |The mutable state is created through: Calling trace: + |The mutable state is created through: |├── object A: [ mutable-read4.scala:3 ] |│ ^ |├── val box: Box = new Box(4) [ mutable-read4.scala:4 ] diff --git a/tests/init-global/warn/mutable-read5.check b/tests/init-global/warn/mutable-read5.check index 6a869df062eb..ffbf1c71fc2c 100644 --- a/tests/init-global/warn/mutable-read5.check +++ b/tests/init-global/warn/mutable-read5.check @@ -9,6 +9,3 @@ |│ ^^^^^^^^^^^^^^^^^^^^ |└── def name(s: String): Name = Name(0, chrs.length) // warn [ mutable-read5.scala:4 ] | ^^^^ - |The mutable state is created through: Calling trace: - |└── object Names: [ mutable-read5.scala:1 ] - | ^ diff --git a/tests/init-global/warn/mutable-read6.check b/tests/init-global/warn/mutable-read6.check index 8e36d5372042..7a4798456acb 100644 --- a/tests/init-global/warn/mutable-read6.check +++ b/tests/init-global/warn/mutable-read6.check @@ -9,7 +9,7 @@ |│ ^^^^^^^^^^^^^^^^ |└── final def source: SourceFile = _source // warn [ mutable-read6.scala:7 ] | ^^^^^^^ - |The mutable state is created through: Calling trace: + |The mutable state is created through: |├── object Contexts: [ mutable-read6.scala:3 ] |│ ^ |├── val NoContext: Context = new Context [ mutable-read6.scala:4 ] diff --git a/tests/init-global/warn/mutable-read7.check b/tests/init-global/warn/mutable-read7.check index 7f8adb182dd3..244ed1519cdf 100644 --- a/tests/init-global/warn/mutable-read7.check +++ b/tests/init-global/warn/mutable-read7.check @@ -13,6 +13,3 @@ |│ ^ |└── if (Positioned.debug) { // warn [ mutable-read7.scala:7 ] | ^^^^^^^^^^^^^^^^ - |The mutable state is created through: Calling trace: - |└── object Positioned: [ mutable-read7.scala:1 ] - | ^ diff --git a/tests/init-global/warn/mutable-read8.check b/tests/init-global/warn/mutable-read8.check index 545507d901fc..4527a2e5e5d8 100644 --- a/tests/init-global/warn/mutable-read8.check +++ b/tests/init-global/warn/mutable-read8.check @@ -11,6 +11,3 @@ |│ ^ |└── if (Stats.monitored) println("record stats") // warn [ mutable-read8.scala:6 ] | ^^^^^^^^^^^^^^^ - |The mutable state is created through: Calling trace: - |└── object Stats { [ mutable-read8.scala:1 ] - | ^ diff --git a/tests/init-global/warn/patmat-unapplySeq.check b/tests/init-global/warn/patmat-unapplySeq.check index 666bbe2131be..15d0fc7abefc 100644 --- a/tests/init-global/warn/patmat-unapplySeq.check +++ b/tests/init-global/warn/patmat-unapplySeq.check @@ -9,7 +9,7 @@ |│ ^^^^ |└── def apply(i: Int): Box = array(i) // warn [ patmat-unapplySeq.scala:8 ] | ^^^^^^^^ - |The mutable state is created through: Calling trace: + |The mutable state is created through: |├── object A: [ patmat-unapplySeq.scala:1 ] |│ ^ |└── val array: Array[Box] = new Array(1) [ patmat-unapplySeq.scala:4 ] diff --git a/tests/init-global/warn/patmat-unapplySeq2.check b/tests/init-global/warn/patmat-unapplySeq2.check index 0a3cb645b0d6..7570f850a6ce 100644 --- a/tests/init-global/warn/patmat-unapplySeq2.check +++ b/tests/init-global/warn/patmat-unapplySeq2.check @@ -9,7 +9,7 @@ |│ ^^^^^ |└── def apply(i: Int): Box = array(i) // warn [ patmat-unapplySeq2.scala:8 ] | ^^^^^^^^ - |The mutable state is created through: Calling trace: + |The mutable state is created through: |├── object A: [ patmat-unapplySeq2.scala:1 ] |│ ^ |└── val array: Array[Box] = new Array(1) [ patmat-unapplySeq2.scala:4 ]