diff --git a/compiler/src/dotty/tools/dotc/transform/init/Objects.scala b/compiler/src/dotty/tools/dotc/transform/init/Objects.scala index 474ec4de7962..1aa6f0ff4298 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Objects.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Objects.scala @@ -144,6 +144,8 @@ class Objects(using Context @constructorOnly): def isObjectRef: Boolean = this.isInstanceOf[ObjectRef] + def asObjectRef: ObjectRef = this.asInstanceOf[ObjectRef] + def valValue(sym: Symbol)(using Heap.MutableData): Value = Heap.readVal(this, sym) def varValue(sym: Symbol)(using Heap.MutableData): Value = Heap.readVal(this, sym) @@ -178,6 +180,12 @@ class Objects(using Context @constructorOnly): /** A reference to a static object */ case class ObjectRef private (klass: ClassSymbol)(using Trace) extends Ref: + var afterSuperCall = false + + def isAfterSuperCall = afterSuperCall + + def setAfterSuperCall(): Unit = afterSuperCall = true + def owner = klass def show(using Context) = "ObjectRef(" + klass.show + ")" @@ -1058,6 +1066,9 @@ class Objects(using Context @constructorOnly): else if target.equals(defn.Predef_classOf) then // Predef.classOf is a stub method in tasty and is replaced in backend UnknownValue + else if ref.isInstanceOf[ObjectRef] && !ref.asObjectRef.isAfterSuperCall then + report.warning("Calling " + target + " of object " + ref.klass + " before the super constructor of the object finishes! " + Trace.show, Trace.position) + Bottom else if target.hasSource then val cls = target.owner.enclosingClass.asClass val ddef = target.defTree.asInstanceOf[DefDef] @@ -1449,7 +1460,9 @@ class Objects(using Context @constructorOnly): if classSym.hasSource then State.checkObjectAccess(classSym) else - ObjectRef(classSym) + val obj = ObjectRef(classSym) + obj.setAfterSuperCall() + obj } @@ -2112,6 +2125,10 @@ class Objects(using Context @constructorOnly): tasks.foreach(task => task()) end if + if thisV.isInstanceOf[ObjectRef] && klass == thisV.klass then + thisV.asObjectRef.setAfterSuperCall() + end if + // class body tpl.body.foreach { case vdef : ValDef if !vdef.symbol.is(Flags.Lazy) && !vdef.rhs.isEmpty => diff --git a/tests/init-global/pos/multiple-by-name.scala b/tests/init-global/pos/multiple-by-name.scala index 5697c7c1bc52..1cc0df80e670 100644 --- a/tests/init-global/pos/multiple-by-name.scala +++ b/tests/init-global/pos/multiple-by-name.scala @@ -18,10 +18,3 @@ object O { val c = foo2(new Y) val d = foo3(new Y) } - -/** - * Pass arg to by-name parameter: create a Fun where body is the argument expression - * Read value of by-name parameter: call 'apply' on every possible Fun value of the by-name parameter - * Solution: Add special EnvRefs for by-name params; - * differentiate these EnvRefs by the arg tree passed to the by-name param - */ \ No newline at end of file diff --git a/tests/init-global/warn/call-before-super.scala b/tests/init-global/warn/call-before-super.scala new file mode 100644 index 000000000000..89a24099fe5b --- /dev/null +++ b/tests/init-global/warn/call-before-super.scala @@ -0,0 +1,7 @@ +class C(i: Int = 42, j: Int = 27) + +object X extends C(j = X.foo()): // warn + def foo() = 5 + +@main def test = println: + X diff --git a/tests/init-global/warn/call-before-super2.scala b/tests/init-global/warn/call-before-super2.scala new file mode 100644 index 000000000000..1fe6c95aafea --- /dev/null +++ b/tests/init-global/warn/call-before-super2.scala @@ -0,0 +1,10 @@ +class C(j: Int) + +object A: + def foo = X.k // warn + +object X extends C(A.foo): + def k = 5 + +@main def test = println: + X \ No newline at end of file diff --git a/tests/init-global/warn/call-before-super3.scala b/tests/init-global/warn/call-before-super3.scala new file mode 100644 index 000000000000..dab1cb9248ff --- /dev/null +++ b/tests/init-global/warn/call-before-super3.scala @@ -0,0 +1,9 @@ +class C(i: Int = 42, j: Int = 27) { + val f = X.foo() // warn +} + +object X extends C(j = 5): + def foo() = 5 + +@main def test = println: + X \ No newline at end of file diff --git a/tests/init-global/warn/global-cycle7.check b/tests/init-global/warn/global-cycle7.check index 366857885769..19865b479284 100644 --- a/tests/init-global/warn/global-cycle7.check +++ b/tests/init-global/warn/global-cycle7.check @@ -18,3 +18,13 @@ | │ ^ | └── val m: Int = A.n // warn [ global-cycle7.scala:6 ] | ^^^ +-- Warning: /Users/enzexing/IdeaProjects/dotty-staging/dotty/tests/init-global/warn/global-cycle7.scala:12:66 +12 | val tokenString, debugString: Array[String] = new Array[String](maxToken + 1) + | ^^^^^^^^ + |Calling method maxToken of object module class JavaTokens$ before the super constructor of the object finishes! Calling trace: + |├── object JavaTokens extends TokensCommon { [ global-cycle7.scala:15 ] + |│ ^ + |├── abstract class TokensCommon { [ global-cycle7.scala:9 ] + |│ ^ + |└── val tokenString, debugString: Array[String] = new Array[String](maxToken + 1) [ global-cycle7.scala:12 ] + | ^^^^^^^^ diff --git a/tests/init-global/warn/global-cycle7.scala b/tests/init-global/warn/global-cycle7.scala index 30b74ceb95c4..f7690b029ef9 100644 --- a/tests/init-global/warn/global-cycle7.scala +++ b/tests/init-global/warn/global-cycle7.scala @@ -9,7 +9,7 @@ object B { abstract class TokensCommon { def maxToken: Int - val tokenString, debugString: Array[String] = new Array[String](maxToken + 1) + val tokenString, debugString: Array[String] = new Array[String](maxToken + 1) // warn } object JavaTokens extends TokensCommon {