From a7eb17400c241e4e0414b1cb0438512472ec5f3e Mon Sep 17 00:00:00 2001 From: EnzeXing Date: Wed, 25 Jun 2025 23:49:16 -0400 Subject: [PATCH 1/2] Fix errors when compiling bootstrapped dotty --- .../tools/dotc/transform/init/Objects.scala | 27 +++++++------------ tests/init-global/pos/enum.scala | 17 ++++++++++++ 2 files changed, 27 insertions(+), 17 deletions(-) create mode 100644 tests/init-global/pos/enum.scala diff --git a/compiler/src/dotty/tools/dotc/transform/init/Objects.scala b/compiler/src/dotty/tools/dotc/transform/init/Objects.scala index 70bb52f3ead3..52c53e6bf781 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Objects.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Objects.scala @@ -151,12 +151,12 @@ class Objects(using Context @constructorOnly): def hasVar(sym: Symbol)(using Heap.MutableData): Boolean = Heap.containsVal(this, sym) def initVal(field: Symbol, value: Value)(using Context, Heap.MutableData) = log("Initialize " + field.show + " = " + value + " for " + this, printer) { - assert(!field.is(Flags.Mutable), "Field is mutable: " + field.show) + assert(field.is(Flags.Param) || !field.is(Flags.Mutable), "Field is mutable: " + field.show) Heap.writeJoinVal(this, field, value) } def initVar(field: Symbol, value: Value)(using Context, Heap.MutableData) = log("Initialize " + field.show + " = " + value + " for " + this, printer) { - assert(field.is(Flags.Mutable), "Field is not mutable: " + field.show) + assert(field.is(Flags.Mutable, butNot = Flags.Param), "Field is not mutable: " + field.show) Heap.writeJoinVal(this, field, value) } @@ -421,12 +421,12 @@ class Objects(using Context @constructorOnly): def hasVar(sym: Symbol)(using EnvMap.EnvMapMutableData): Boolean = EnvMap.containsVal(this, sym) def initVal(field: Symbol, value: Value)(using Context, EnvMap.EnvMapMutableData) = log("Initialize " + field.show + " = " + value + " for " + this, printer) { - assert(!field.is(Flags.Mutable), "Field is mutable: " + field.show) + assert(field.is(Flags.Param) || !field.is(Flags.Mutable), "Field is mutable: " + field.show) EnvMap.writeJoinVal(this, field, value) } def initVar(field: Symbol, value: Value)(using Context, EnvMap.EnvMapMutableData) = log("Initialize " + field.show + " = " + value + " for " + this, printer) { - assert(field.is(Flags.Mutable), "Field is not mutable: " + field.show) + assert(field.is(Flags.Mutable, butNot = Flags.Param), "Field is not mutable: " + field.show) EnvMap.writeJoinVal(this, field, value) } @@ -527,12 +527,12 @@ class Objects(using Context @constructorOnly): _of(Map.empty, byNameParam, thisV, outerEnv) def setLocalVal(x: Symbol, value: Value)(using scope: Scope, ctx: Context, heap: Heap.MutableData, envMap: EnvMap.EnvMapMutableData): Unit = - assert(!x.isOneOf(Flags.Param | Flags.Mutable), "Only local immutable variable allowed") + assert(x.is(Flags.Param) || !x.is(Flags.Mutable), "Only local immutable variable allowed") scope match case env: EnvRef => env.initVal(x, value) case ref: Ref => - ref.initVal(x, value) // TODO: This is possible for match statement in class body. Report warning? + ref.initVal(x, value) // This is possible for match statement in class body. def setLocalVar(x: Symbol, value: Value)(using scope: Scope, ctx: Context, heap: Heap.MutableData, envMap: EnvMap.EnvMapMutableData): Unit = assert(x.is(Flags.Mutable, butNot = Flags.Param), "Only local mutable variable allowed") @@ -540,7 +540,7 @@ class Objects(using Context @constructorOnly): case env: EnvRef => env.initVar(x, value) case ref: Ref => - ref.initVar(x, value) // TODO: This is possible for match statement in class body. Report warning? + ref.initVar(x, value) // This is possible for match statement in class body. /** * Resolve the environment by searching for a given symbol. @@ -986,15 +986,7 @@ class Objects(using Context @constructorOnly): // Assume such method is pure. Check return type, only try to analyze body if return type is not safe val target = resolve(v.typeSymbol.asClass, meth) val targetType = target.denot.info - assert(targetType.isInstanceOf[ExprType] || targetType.isInstanceOf[MethodType], - "Unexpected type! Receiver = " + v.show + ", meth = " + target + ", type = " + targetType) - val returnType = - if targetType.isInstanceOf[ExprType] then - // corresponds to parameterless method like `def meth: ExprType[T]` - // See pos/toDouble.scala - targetType.asInstanceOf[ExprType].resType - else - targetType.asInstanceOf[MethodType].resType + val returnType = targetType.finalResultType val typeSymbol = SafeValue.getSafeTypeSymbol(returnType) if typeSymbol.isDefined then // since method is pure and return type is safe, no need to analyze method body @@ -1326,7 +1318,8 @@ class Objects(using Context @constructorOnly): report.warning("[Internal error] top-level class should have `Package` as outer, class = " + klass.show + ", outer = " + outer.show + ", " + Trace.show, Trace.position) (Bottom, Env.NoEnv) else - val outerCls = klass.owner.enclosingClass.asClass + // enclosingClass is specially handled for java static terms, so use `lexicallyEnclosingClass` here + val outerCls = klass.owner.lexicallyEnclosingClass.asClass // When `klass` is directly nested in `outerCls`, `outerCls`.enclosingMethod returns its primary constructor if klass.owner.enclosingMethod == outerCls.primaryConstructor then (outer, Env.NoEnv) diff --git a/tests/init-global/pos/enum.scala b/tests/init-global/pos/enum.scala new file mode 100644 index 000000000000..40687c8f9cf6 --- /dev/null +++ b/tests/init-global/pos/enum.scala @@ -0,0 +1,17 @@ +enum FileExtension(val toLowerCase: String): + case Tasty extends FileExtension("tasty") + case Betasty extends FileExtension("betasty") + case Class extends FileExtension("class") + case Jar extends FileExtension("jar") + case Scala extends FileExtension("scala") + case ScalaScript extends FileExtension("sc") + case Java extends FileExtension("java") + case Zip extends FileExtension("zip") + case Inc extends FileExtension("inc") + case Empty extends FileExtension("") + + /** Fallback extension */ + case External(override val toLowerCase: String) extends FileExtension(toLowerCase) + +object O: + val a = FileExtension.Empty \ No newline at end of file From 13440a712a738559d612da42c6e9a706184a2998 Mon Sep 17 00:00:00 2001 From: EnzeXing Date: Tue, 1 Jul 2025 23:30:59 -0400 Subject: [PATCH 2/2] Address comments --- .../src/dotty/tools/dotc/transform/init/Objects.scala | 11 ++++++----- .../src/dotty/tools/dotc/transform/init/Util.scala | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/init/Objects.scala b/compiler/src/dotty/tools/dotc/transform/init/Objects.scala index 52c53e6bf781..dfa685f8aaa9 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Objects.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Objects.scala @@ -151,12 +151,12 @@ class Objects(using Context @constructorOnly): def hasVar(sym: Symbol)(using Heap.MutableData): Boolean = Heap.containsVal(this, sym) def initVal(field: Symbol, value: Value)(using Context, Heap.MutableData) = log("Initialize " + field.show + " = " + value + " for " + this, printer) { - assert(field.is(Flags.Param) || !field.is(Flags.Mutable), "Field is mutable: " + field.show) + assert(!field.is(Flags.Mutable), "Field is mutable: " + field.show) Heap.writeJoinVal(this, field, value) } def initVar(field: Symbol, value: Value)(using Context, Heap.MutableData) = log("Initialize " + field.show + " = " + value + " for " + this, printer) { - assert(field.is(Flags.Mutable, butNot = Flags.Param), "Field is not mutable: " + field.show) + assert(field.is(Flags.Mutable), "Field is not mutable: " + field.show) Heap.writeJoinVal(this, field, value) } @@ -421,12 +421,12 @@ class Objects(using Context @constructorOnly): def hasVar(sym: Symbol)(using EnvMap.EnvMapMutableData): Boolean = EnvMap.containsVal(this, sym) def initVal(field: Symbol, value: Value)(using Context, EnvMap.EnvMapMutableData) = log("Initialize " + field.show + " = " + value + " for " + this, printer) { - assert(field.is(Flags.Param) || !field.is(Flags.Mutable), "Field is mutable: " + field.show) + assert(!field.is(Flags.Mutable), "Field is mutable: " + field.show) EnvMap.writeJoinVal(this, field, value) } def initVar(field: Symbol, value: Value)(using Context, EnvMap.EnvMapMutableData) = log("Initialize " + field.show + " = " + value + " for " + this, printer) { - assert(field.is(Flags.Mutable, butNot = Flags.Param), "Field is not mutable: " + field.show) + assert(field.is(Flags.Mutable), "Field is not mutable: " + field.show) EnvMap.writeJoinVal(this, field, value) } @@ -527,7 +527,7 @@ class Objects(using Context @constructorOnly): _of(Map.empty, byNameParam, thisV, outerEnv) def setLocalVal(x: Symbol, value: Value)(using scope: Scope, ctx: Context, heap: Heap.MutableData, envMap: EnvMap.EnvMapMutableData): Unit = - assert(x.is(Flags.Param) || !x.is(Flags.Mutable), "Only local immutable variable allowed") + assert(!x.isOneOf(Flags.Param | Flags.Mutable), "Only local immutable variable allowed") scope match case env: EnvRef => env.initVal(x, value) @@ -1806,6 +1806,7 @@ class Objects(using Context @constructorOnly): val toSeqResTp = resultTp.memberInfo(selectors.last).finalResultType evalSeqPatterns(toSeqRes, toSeqResTp, elemTp, seqPats) end if + // TODO: refactor the code of product sequence match, avoid passing NoType to parameter elemTp in evalSeqPatterns else // distribute unapply to patterns diff --git a/compiler/src/dotty/tools/dotc/transform/init/Util.scala b/compiler/src/dotty/tools/dotc/transform/init/Util.scala index 3280c289f926..9a1c38bcac36 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Util.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Util.scala @@ -17,7 +17,7 @@ import Trace.* object Util: /** Exception used for errors encountered when reading TASTy. */ case class TastyTreeException(msg: String) extends RuntimeException(msg) - + /** Utility definition used for better error-reporting of argument errors */ case class TraceValue[T](value: T, trace: Trace) @@ -96,7 +96,7 @@ object Util: else sym.matchingMember(cls.appliedRef) extension (sym: Symbol) - def hasSource(using Context): Boolean = !sym.defTree.isEmpty + def hasSource(using Context): Boolean = !sym.is(Flags.JavaDefined) && !sym.defTree.isEmpty def isStaticObject(using Context) = sym.is(Flags.Module, butNot = Flags.Package) && sym.isStatic