Skip to content

Commit 74f8e80

Browse files
committed
Fixes to isPureExpr
- erasedValue[<ConstantType>] is now considered to be pure - calls of synthetic case class apply are considered pure if the case class is NoInits - Companions of Scala-2 classes Tuple and Some are assumed to be NoInits
1 parent 4e16a13 commit 74f8e80

File tree

5 files changed

+21
-6
lines changed

5 files changed

+21
-6
lines changed

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -590,9 +590,13 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
590590
case New(_) | Closure(_, _, _) =>
591591
Pure
592592
case TypeApply(fn, _) =>
593+
val sym = fn.symbol
593594
if tree.tpe.isInstanceOf[MethodOrPoly] then exprPurity(fn)
594-
else if fn.symbol == defn.QuotedTypeModule_of || fn.symbol == defn.Predef_classOf then Pure
595-
else if fn.symbol == defn.Compiletime_erasedValue && tree.tpe.dealias.isInstanceOf[ConstantType] then Pure
595+
else if sym == defn.QuotedTypeModule_of
596+
|| sym == defn.Predef_classOf
597+
|| sym == defn.Compiletime_erasedValue && tree.tpe.dealias.isInstanceOf[ConstantType]
598+
|| defn.capsErasedValueMethods.contains(sym)
599+
then Pure
596600
else Impure
597601
case Apply(fn, args) =>
598602
val factorPurity = minOf(exprPurity(fn), args.map(exprPurity))
@@ -636,6 +640,15 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
636640

637641
def isPureBinding(tree: Tree)(using Context): Boolean = statPurity(tree) >= Pure
638642

643+
def isPureSyntheticCaseApply(sym: Symbol)(using Context): Boolean =
644+
sym.isAllOf(SyntheticMethod)
645+
&& sym.name == nme.apply
646+
&& sym.owner.is(Module)
647+
&& {
648+
val cls = sym.owner.companionClass
649+
cls.is(Case) && cls.isNoInitsRealClass
650+
}
651+
639652
/** Is the application `tree` with function part `fn` known to be pure?
640653
* Function value and arguments can still be impure.
641654
*/
@@ -647,6 +660,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
647660

648661
tree.tpe.isInstanceOf[ConstantType] && tree.symbol != NoSymbol && isKnownPureOp(tree.symbol) // A constant expression with pure arguments is pure.
649662
|| fn.symbol.isStableMember && fn.symbol.isConstructor // constructors of no-inits classes are stable
663+
|| isPureSyntheticCaseApply(fn.symbol)
650664

651665
/** The purity level of this reference.
652666
* @return

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2006,7 +2006,9 @@ class Definitions {
20062006

20072007
/** A allowlist of Scala-2 classes that are known to be pure */
20082008
def isAssuredNoInits(sym: Symbol): Boolean =
2009-
(sym `eq` SomeClass) || isTupleClass(sym)
2009+
(sym `eq` SomeClass)
2010+
|| isTupleClass(sym)
2011+
|| sym.is(Module) && isAssuredNoInits(sym.companionClass)
20102012

20112013
/** If `cls` is Tuple1..Tuple22, add the corresponding *: type as last parent to `parents` */
20122014
def adjustForTuple(cls: ClassSymbol, tparams: List[TypeSymbol], parents: List[Type]): List[Type] = {

compiler/src/dotty/tools/dotc/util/DiffUtil.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ object DiffUtil {
103103
case Deleted(str) => deleted(str)
104104
}.mkString
105105

106-
(expectedDiff, actualDiff)
107106
val pad = " " * 0.max(expectedSize - expected.length)
108107

109108
expectedDiff + pad + " | " + actualDiff

library/src/scala/CanThrow.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ erased class CanThrow[-E <: Exception] extends caps.SharedCapability
1212

1313
@experimental
1414
object unsafeExceptions:
15-
given canThrowAny: CanThrow[Exception] = compiletime.erasedValue
15+
inline given canThrowAny: CanThrow[Exception] = compiletime.erasedValue
1616

tests/init/warn/inner30.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class Scanners {
88

99
class Scanner {
1010
def foo() =
11-
Conc(Run('a', 3), Run('b', 4))
11+
Conc(Run('a', 3), Run('b', 4)) // warn
1212
new LookAheadScanner
1313

1414
class LookAheadScanner() extends Scanner

0 commit comments

Comments
 (0)