Skip to content

Commit 478b527

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 ace6578 commit 478b527

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
@@ -588,9 +588,13 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
588588
case New(_) | Closure(_, _, _) =>
589589
Pure
590590
case TypeApply(fn, _) =>
591+
val sym = fn.symbol
591592
if tree.tpe.isInstanceOf[MethodOrPoly] then exprPurity(fn)
592-
else if fn.symbol == defn.QuotedTypeModule_of || fn.symbol == defn.Predef_classOf then Pure
593-
else if fn.symbol == defn.Compiletime_erasedValue && tree.tpe.dealias.isInstanceOf[ConstantType] then Pure
593+
else if sym == defn.QuotedTypeModule_of
594+
|| sym == defn.Predef_classOf
595+
|| sym == defn.Compiletime_erasedValue && tree.tpe.dealias.isInstanceOf[ConstantType]
596+
|| defn.capsErasedValueMethods.contains(sym)
597+
then Pure
594598
else Impure
595599
case Apply(fn, args) =>
596600
val factorPurity = minOf(exprPurity(fn), args.map(exprPurity))
@@ -634,6 +638,15 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
634638

635639
def isPureBinding(tree: Tree)(using Context): Boolean = statPurity(tree) >= Pure
636640

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

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

649663
/** The purity level of this reference.
650664
* @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)