diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala index b9780aca0968..d2d0b38644d1 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -577,21 +577,28 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => // blocks returning a class literal alone, even if they're idempotent. tree1 case ConstantType(value) => - if (isIdempotentExpr(tree1)) Literal(value).withSpan(tree.span) - else { - def keepPrefix(pre: Tree) = + def dropOp(t: Tree): Tree = t match + case Select(pre, _) if t.tpe.isInstanceOf[ConstantType] => + // it's a primitive unary operator + pre + case Apply(TypeApply(Select(pre, nme.getClass_), _), Nil) => + pre + case _ => + tree1 + + val countsAsPure = + if dropOp(tree1).symbol.isInlineVal + then isIdempotentExpr(tree1) + else isPureExpr(tree1) + + if countsAsPure then Literal(value).withSpan(tree.span) + else + val pre = dropOp(tree1) + if pre eq tree1 then tree1 + else + // it's a primitive unary operator or getClass call; + // Simplify `pre.op` to `{ pre; v }` where `v` is the value of `pre.op` Block(pre :: Nil, Literal(value)).withSpan(tree.span) - - tree1 match { - case Select(pre, _) if tree1.tpe.isInstanceOf[ConstantType] => - // it's a primitive unary operator; Simplify `pre.op` to `{ pre; v }` where `v` is the value of `pre.op` - keepPrefix(pre) - case Apply(TypeApply(Select(pre, nme.getClass_), _), Nil) => - keepPrefix(pre) - case _ => - tree1 - } - } case _ => tree1 } } diff --git a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala index 33e476829970..c7f9c762e440 100644 --- a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala @@ -110,6 +110,11 @@ object SymUtils: self.isCoDefinedGiven(res.typeSymbol) self.isAllOf(Given | Method) && isCodefined(self.info) + // TODO Scala 3.x: only check for inline vals (no final ones) + def isInlineVal(using Context) = + self.isOneOf(FinalOrInline, butNot = Mutable) + && (!self.is(Method) || self.is(Accessor)) + def useCompanionAsSumMirror(using Context): Boolean = def companionExtendsSum(using Context): Boolean = self.linkedClass.isSubClass(defn.Mirror_SumClass) diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 232018bc7cd0..241d9a7a094e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -1694,11 +1694,6 @@ class Namer { typer: Typer => case _ => approxTp - // println(s"final inherited for $sym: ${inherited.toString}") !!! - // println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}") - // TODO Scala 3.1: only check for inline vals (no final ones) - def isInlineVal = sym.isOneOf(FinalOrInline, butNot = Method | Mutable) - var rhsCtx = ctx.fresh.addMode(Mode.InferringReturnType) if sym.isInlineMethod then rhsCtx = rhsCtx.addMode(Mode.InlineableBody) if sym.is(ExtensionMethod) then rhsCtx = rhsCtx.addMode(Mode.InExtensionMethod) @@ -1732,7 +1727,7 @@ class Namer { typer: Typer => // don't strip @uncheckedVariance annot for default getters TypeOps.simplify(tp.widenTermRefExpr, if defaultTp.exists then TypeOps.SimplifyKeepUnchecked() else null) match - case ctp: ConstantType if isInlineVal => ctp + case ctp: ConstantType if sym.isInlineVal => ctp case tp => TypeComparer.widenInferred(tp, pt) // Replace aliases to Unit by Unit itself. If we leave the alias in @@ -1743,7 +1738,7 @@ class Namer { typer: Typer => def lhsType = fullyDefinedType(cookedRhsType, "right-hand side", mdef.span) //if (sym.name.toString == "y") println(i"rhs = $rhsType, cooked = $cookedRhsType") if (inherited.exists) - if (isInlineVal) lhsType else inherited + if sym.isInlineVal then lhsType else inherited else { if (sym.is(Implicit)) mdef match { diff --git a/tests/pos/java-annot/S.scala b/tests/pos/java-annot/S.scala index 68fdeea2710f..945a50753577 100644 --- a/tests/pos/java-annot/S.scala +++ b/tests/pos/java-annot/S.scala @@ -1,5 +1,5 @@ object C { - val cs: "cs" = "cs" + final val cs: "cs" = "cs" } object S { diff --git a/tests/run/i2266.check b/tests/run/i2266.check new file mode 100644 index 000000000000..c09dc6b79c42 --- /dev/null +++ b/tests/run/i2266.check @@ -0,0 +1,3 @@ +X +true +1 diff --git a/tests/run/i2266.scala b/tests/run/i2266.scala new file mode 100644 index 000000000000..1b21036b289e --- /dev/null +++ b/tests/run/i2266.scala @@ -0,0 +1,13 @@ +object Test extends App { + lazy val x: true = { println("X"); true } + println(x) + + object Inner { + println("Y") // not printed + inline val y = 1 + } + println(Inner.y) + + inline val MV = Int.MaxValue +} +