diff --git a/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala b/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala index 63e1959412e7..b6144b677801 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala @@ -479,10 +479,16 @@ object Semantic: RefSet(refs1 ++ diff) /** Conservatively approximate the value with `Cold` or `Hot` */ - def widenArg: Value = + def widenArg: Contextual[Value] = a match - case _: Ref | _: Fun => Cold - case RefSet(refs) => refs.map(_.widenArg).join + case _: Ref | _: Fun => + val errors = Reporter.stopEarly { a.promote("Argument cannot be promoted to hot") } + if errors.isEmpty then Hot + else Cold + + case RefSet(refs) => + refs.map(_.widenArg).join + case _ => a @@ -491,7 +497,7 @@ object Semantic: if values.isEmpty then Hot else values.reduce { (v1, v2) => v1.join(v2) } - def widenArgs: List[Value] = values.map(_.widenArg).toList + def widenArgs: Contextual[List[Value]] = values.map(_.widenArg).toList extension (ref: Ref) @@ -738,12 +744,13 @@ object Semantic: if ctor.hasSource then val cls = ctor.owner.enclosingClass.asClass val ddef = ctor.defTree.asInstanceOf[DefDef] - given Env = Env(ddef, args.map(_.value).widenArgs) + val env2 = Env(ddef, args.map(_.value).widenArgs) if ctor.isPrimaryConstructor then + given Env = env2 val tpl = cls.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template] extendTrace(cls.defTree) { init(tpl, ref, cls) } else - addParamsAsFields(env, ref, ddef) + addParamsAsFields(env2, ref, ddef) val initCall = ddef.rhs match case Block(call :: _, _) => call case call => call @@ -756,13 +763,14 @@ object Semantic: if ctor.hasSource then val cls = ctor.owner.enclosingClass.asClass val ddef = ctor.defTree.asInstanceOf[DefDef] - given Env = Env(ddef, args.map(_.value).widenArgs) + val env2 = Env(ddef, args.map(_.value).widenArgs) if ctor.isPrimaryConstructor then + given Env = env2 val tpl = cls.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template] extendTrace(cls.defTree) { eval(tpl, ref, cls, cacheResult = true) } ref else - addParamsAsFields(env, ref, ddef) + addParamsAsFields(env2, ref, ddef) extendTrace(ddef) { eval(ddef.rhs, ref, cls, cacheResult = true) } else if ref.canIgnoreMethodCall(ctor) then Hot diff --git a/tests/init/neg/promote-warm.scala b/tests/init/neg/promote-warm.scala new file mode 100644 index 000000000000..c9f9268f1fbd --- /dev/null +++ b/tests/init/neg/promote-warm.scala @@ -0,0 +1,12 @@ +class PromoteWarm: + class A: + def foo() = PromoteWarm.this.foo() + + class B(a: A): + a.foo() + + val a = new A + val b = new B(a) // error + val n = 10 + + def foo() = println(n) diff --git a/tests/init/pos/promote-warm.scala b/tests/init/pos/promote-warm.scala new file mode 100644 index 000000000000..16131ec5263f --- /dev/null +++ b/tests/init/pos/promote-warm.scala @@ -0,0 +1,12 @@ +class PromoteWarm: + class A: + def foo() = PromoteWarm.this.foo() + + class B(a: A): + a.foo() + + val n = 10 + val a = new A + val b = new B(a) + + def foo() = println(n)