Skip to content

Commit 55c2002

Browse files
Refactor some tuple methods (#19032)
- Move from Definitions to TypeUtils - Unify TypeUtils.tupleElementTypes and Definitions.tupleTypes. They do the same thing. I'd like to move more things out of Definitions and into TypeUtils and SymUtils. Then I'd like to move these files to the core package, and make their operations accessible automatically by having the companion objects of Types and Symbols inherit from them. This is a first step into that direction.
2 parents 00e9e6b + 125321e commit 55c2002

File tree

105 files changed

+144
-206
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

105 files changed

+144
-206
lines changed

Diff for: compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala

-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import dotty.tools.dotc.core.Types.*
1919
import dotty.tools.dotc.core.StdNames.{nme, str}
2020
import dotty.tools.dotc.core.Symbols.*
2121
import dotty.tools.dotc.transform.Erasure
22-
import dotty.tools.dotc.transform.SymUtils.*
2322
import dotty.tools.dotc.util.Spans.*
2423
import dotty.tools.dotc.core.Contexts.*
2524
import dotty.tools.dotc.core.Phases.*

Diff for: compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import dotty.tools.dotc.core.Types.*
2020
import dotty.tools.dotc.core.Contexts.*
2121
import dotty.tools.dotc.util.Spans.*
2222
import dotty.tools.dotc.report
23-
import dotty.tools.dotc.transform.SymUtils.*
23+
2424

2525
/*
2626
*

Diff for: compiler/src/dotty/tools/backend/jvm/BTypesFromSymbols.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import dotty.tools.dotc.core.Contexts.*
1212
import dotty.tools.dotc.core.Phases.*
1313
import dotty.tools.dotc.core.Symbols.*
1414
import dotty.tools.dotc.core.Phases.Phase
15-
import dotty.tools.dotc.transform.SymUtils.*
15+
1616
import dotty.tools.dotc.core.StdNames
1717
import dotty.tools.dotc.core.Phases
1818

Diff for: compiler/src/dotty/tools/backend/jvm/CodeGen.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import dotty.tools.dotc.core.Phases.Phase
99

1010
import scala.collection.mutable
1111
import scala.jdk.CollectionConverters.*
12-
import dotty.tools.dotc.transform.SymUtils.*
12+
1313
import dotty.tools.dotc.interfaces
1414
import dotty.tools.dotc.report
1515

Diff for: compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import scala.language.unsafeNulls
44

55
import dotty.tools.dotc.ast.tpd
66
import dotty.tools.dotc.core.Flags.*
7-
import dotty.tools.dotc.transform.SymUtils.*
7+
88
import java.io.{File => _}
99

1010
import scala.reflect.ClassTag

Diff for: compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import StdNames.*
2121
import TypeErasure.ErasedValueType
2222

2323
import dotty.tools.dotc.transform.{Erasure, ValueClasses}
24-
import dotty.tools.dotc.transform.SymUtils.*
24+
2525
import dotty.tools.dotc.util.SourcePosition
2626
import dotty.tools.dotc.report
2727

Diff for: compiler/src/dotty/tools/dotc/CompilationUnit.scala

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import ast.{tpd, untpd}
1212
import tpd.{Tree, TreeTraverser}
1313
import ast.Trees.{Import, Ident}
1414
import typer.Nullables
15-
import transform.SymUtils.*
1615
import core.Decorators.*
1716
import config.{SourceVersion, Feature}
1817
import StdNames.nme

Diff for: compiler/src/dotty/tools/dotc/ast/Desugar.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ package ast
55
import core.*
66
import util.Spans.*, Types.*, Contexts.*, Constants.*, Names.*, NameOps.*, Flags.*
77
import Symbols.*, StdNames.*, Trees.*, ContextOps.*
8-
import Decorators.*, transform.SymUtils.*
8+
import Decorators.*
99
import Annotations.Annotation
1010
import NameKinds.{UniqueName, ContextBoundParamName, ContextFunctionParamName, DefaultGetterName, WildcardParamName}
1111
import typer.{Namer, Checking}

Diff for: compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import Flags.*, Trees.*, Types.*, Contexts.*
77
import Names.*, StdNames.*, NameOps.*, Symbols.*
88
import typer.ConstFold
99
import reporting.trace
10-
import dotty.tools.dotc.transform.SymUtils.*
10+
1111
import Decorators.*
1212
import Constants.Constant
1313
import scala.collection.mutable

Diff for: compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import core.*
66
import Types.*, Contexts.*, Flags.*
77
import Symbols.*, Annotations.*, Trees.*, Symbols.*, Constants.Constant
88
import Decorators.*
9-
import dotty.tools.dotc.transform.SymUtils.*
9+
1010

1111
/** A map that applies three functions and a substitution together to a tree and
1212
* makes sure they are coordinated so that the result is well-typed. The functions are

Diff for: compiler/src/dotty/tools/dotc/ast/tpd.scala

-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ package ast
44

55
import dotty.tools.dotc.transform.{ExplicitOuter, Erasure}
66
import typer.ProtoTypes
7-
import transform.SymUtils.*
8-
import transform.TypeUtils.*
97
import core.*
108
import Scopes.newScope
119
import util.Spans.*, Types.*, Contexts.*, Constants.*, Names.*, Flags.*, NameOps.*

Diff for: compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala

-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import typer.Checking.{checkBounds, checkAppliedTypesIn}
1515
import typer.ErrorReporting.{Addenda, err}
1616
import typer.ProtoTypes.{AnySelectionProto, LhsProto}
1717
import util.{SimpleIdentitySet, EqHashMap, EqHashSet, SrcPos, Property}
18-
import transform.SymUtils.*
1918
import transform.{Recheck, PreRecheck, CapturedVars}
2019
import Recheck.*
2120
import scala.collection.mutable

Diff for: compiler/src/dotty/tools/dotc/config/JavaPlatform.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import classpath.AggregateClassPath
77
import core.*
88
import Symbols.*, Types.*, Contexts.*, StdNames.*
99
import Flags.*
10-
import transform.ExplicitOuter, transform.SymUtils.*
10+
import transform.ExplicitOuter
1111

1212
class JavaPlatform extends Platform {
1313

Diff for: compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import Flags.*
1010
import config.Config
1111
import config.Printers.typr
1212
import typer.ProtoTypes.{newTypeVar, representedParamRef}
13-
import transform.TypeUtils.isTransparent
1413
import UnificationDirection.*
1514
import NameKinds.AvoidNameKind
1615
import util.SimpleIdentitySet

Diff for: compiler/src/dotty/tools/dotc/core/Definitions.scala

-20
Original file line numberDiff line numberDiff line change
@@ -1749,26 +1749,6 @@ class Definitions {
17491749
else TypeOps.nestedPairs(elems)
17501750
}
17511751

1752-
def tupleTypes(tp: Type, bound: Int = Int.MaxValue)(using Context): Option[List[Type]] = {
1753-
@tailrec def rec(tp: Type, acc: List[Type], bound: Int): Option[List[Type]] = tp.normalized.dealias match {
1754-
case _ if bound < 0 => Some(acc.reverse)
1755-
case tp: AppliedType if PairClass == tp.classSymbol => rec(tp.args(1), tp.args.head :: acc, bound - 1)
1756-
case tp: AppliedType if isTupleNType(tp) => Some(acc.reverse ::: tp.args)
1757-
case tp: TermRef if tp.symbol == defn.EmptyTupleModule => Some(acc.reverse)
1758-
case _ => None
1759-
}
1760-
rec(tp.stripTypeVar, Nil, bound)
1761-
}
1762-
1763-
def isSmallGenericTuple(tp: Type)(using Context): Boolean =
1764-
if tp.derivesFrom(defn.PairClass) && !defn.isTupleNType(tp.widenDealias) then
1765-
// If this is a generic tuple we need to cast it to make the TupleN/ members accessible.
1766-
// This works only for generic tuples of known size up to 22.
1767-
defn.tupleTypes(tp.widenTermRefExpr) match
1768-
case Some(elems) if elems.length <= Definitions.MaxTupleArity => true
1769-
case _ => false
1770-
else false
1771-
17721752
def isProductSubType(tp: Type)(using Context): Boolean = tp.derivesFrom(ProductClass)
17731753

17741754
/** Is `tp` (an alias) of either a scala.FunctionN or a scala.ContextFunctionN

Diff for: compiler/src/dotty/tools/dotc/core/SymDenotations.scala

-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import scala.util.control.NonFatal
2323
import config.Config
2424
import reporting.*
2525
import collection.mutable
26-
import transform.TypeUtils.*
2726
import cc.{CapturingType, derivedCapturingType}
2827

2928
import scala.annotation.internal.sharable

Diff for: compiler/src/dotty/tools/dotc/transform/SymUtils.scala renamed to compiler/src/dotty/tools/dotc/core/SymUtils.scala

+12-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
package dotty.tools.dotc
2-
package transform
2+
package core
33

44
import core.*
55
import Types.*
@@ -11,18 +11,18 @@ import NameOps.*
1111
import StdNames.*
1212
import NameKinds.*
1313
import Flags.*
14-
import ValueClasses.isDerivedValueClass
1514
import Decorators.*
1615
import Constants.Constant
1716
import Annotations.Annotation
1817
import Phases.*
1918
import ast.tpd.Literal
19+
import transform.Mixin
2020

2121
import dotty.tools.dotc.transform.sjs.JSSymUtils.sjsNeedsField
2222

2323
import scala.annotation.tailrec
2424

25-
object SymUtils:
25+
class SymUtils:
2626

2727
extension (self: Symbol)
2828

@@ -79,6 +79,14 @@ object SymUtils:
7979
self.is(Enum, butNot = Case) &&
8080
self.info.parents.exists(p => p.typeSymbol == defn.JavaEnumClass)
8181

82+
def isDerivedValueClass(using Context): Boolean = self.isClass && {
83+
val d = self.denot
84+
!d.isRefinementClass &&
85+
d.isValueClass &&
86+
(d.initial.symbol ne defn.AnyValClass) && // Compare the initial symbol because AnyVal does not exist after erasure
87+
!d.isPrimitiveValueClass
88+
}
89+
8290
/** Is this a case class for which a product mirror is generated?
8391
* Excluded are value classes, abstract classes and case classes with more than one
8492
* parameter section.
@@ -100,7 +108,7 @@ object SymUtils:
100108
if (!self.is(CaseClass)) "it is not a case class"
101109
else if (self.is(Abstract)) "it is an abstract class"
102110
else if (self.primaryConstructor.info.paramInfoss.length != 1) "it takes more than one parameter list"
103-
else if (isDerivedValueClass(self)) "it is a value class"
111+
else if self.isDerivedValueClass then "it is a value class"
104112
else if (!(companionMirror || canAccessCtor)) s"the constructor of $self is inaccessible from the calling scope."
105113
else ""
106114
end whyNotGenericProduct

Diff for: compiler/src/dotty/tools/dotc/core/Symbols.scala

+1-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import util.Spans.*
1818
import DenotTransformers.*
1919
import StdNames.*
2020
import NameOps.*
21-
import transform.SymUtils.*
2221
import NameKinds.LazyImplicitName
2322
import ast.tpd
2423
import tpd.{Tree, TreeProvider, TreeOps}
@@ -36,7 +35,7 @@ import dotty.tools.dotc.classpath.FileUtils.isScalaBinary
3635
import scala.compiletime.uninitialized
3736
import dotty.tools.tasty.TastyVersion
3837

39-
object Symbols {
38+
object Symbols extends SymUtils {
4039

4140
implicit def eqSymbol: CanEqual[Symbol, Symbol] = CanEqual.derived
4241

Diff for: compiler/src/dotty/tools/dotc/core/TypeApplications.scala

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import Names.*
1212
import StdNames.nme
1313
import Flags.{Module, Provisional}
1414
import dotty.tools.dotc.config.Config
15-
import dotty.tools.dotc.transform.TypeUtils.isErasedValueType
1615

1716
object TypeApplications {
1817

Diff for: compiler/src/dotty/tools/dotc/core/TypeComparer.scala

-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ import TypeErasure.{erasedLub, erasedGlb}
1616
import TypeApplications.*
1717
import Variances.{Variance, variancesConform}
1818
import Constants.Constant
19-
import transform.TypeUtils.*
20-
import transform.SymUtils.*
2119
import scala.util.control.NonFatal
2220
import typer.ProtoTypes.constrained
2321
import typer.Applications.productSelectorTypes

Diff for: compiler/src/dotty/tools/dotc/core/TypeErasure.scala

+5-7
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import TypeOps.makePackageObjPrefixExplicit
99
import backend.sjs.JSDefinitions
1010
import transform.ExplicitOuter.*
1111
import transform.ValueClasses.*
12-
import transform.TypeUtils.*
1312
import transform.ContextFunctionResults.*
1413
import unpickleScala2.Scala2Erasure
1514
import Decorators.*
@@ -72,7 +71,7 @@ end SourceLanguage
7271
object TypeErasure {
7372

7473
private def erasureDependsOnArgs(sym: Symbol)(using Context) =
75-
sym == defn.ArrayClass || sym == defn.PairClass || isDerivedValueClass(sym)
74+
sym == defn.ArrayClass || sym == defn.PairClass || sym.isDerivedValueClass
7675

7776
/** The arity of this tuple type, which can be made up of EmptyTuple, TupleX and `*:` pairs.
7877
*
@@ -126,7 +125,7 @@ object TypeErasure {
126125
case tp: TypeRef =>
127126
val sym = tp.symbol
128127
sym.isClass &&
129-
(!erasureDependsOnArgs(sym) || isDerivedValueClass(sym)) &&
128+
(!erasureDependsOnArgs(sym) || sym.isDerivedValueClass) &&
130129
!defn.specialErasure.contains(sym) &&
131130
!defn.isSyntheticFunctionClass(sym)
132131
case _: TermRef =>
@@ -404,7 +403,6 @@ object TypeErasure {
404403
tp1 // After erasure, T | Nothing is just T and C | Null is just C, if C is a reference type.
405404
else tp1 match {
406405
case JavaArrayType(elem1) =>
407-
import dotty.tools.dotc.transform.TypeUtils.*
408406
tp2 match {
409407
case JavaArrayType(elem2) =>
410408
if (elem1.isPrimitiveValueType || elem2.isPrimitiveValueType)
@@ -632,15 +630,15 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
632630
case tp: TypeRef =>
633631
val sym = tp.symbol
634632
if !sym.isClass then this(checkedSuperType(tp))
635-
else if semiEraseVCs && isDerivedValueClass(sym) then eraseDerivedValueClass(tp)
633+
else if semiEraseVCs && sym.isDerivedValueClass then eraseDerivedValueClass(tp)
636634
else if defn.isSyntheticFunctionClass(sym) then defn.functionTypeErasure(sym)
637635
else eraseNormalClassRef(tp)
638636
case tp: AppliedType =>
639637
val tycon = tp.tycon
640638
if (tycon.isRef(defn.ArrayClass)) eraseArray(tp)
641639
else if (tycon.isRef(defn.PairClass)) erasePair(tp)
642640
else if (tp.isRepeatedParam) apply(tp.translateFromRepeated(toArray = sourceLanguage.isJava))
643-
else if (semiEraseVCs && isDerivedValueClass(tycon.classSymbol)) eraseDerivedValueClass(tp)
641+
else if (semiEraseVCs && tycon.classSymbol.isDerivedValueClass) eraseDerivedValueClass(tp)
644642
else this(checkedSuperType(tp))
645643
case tp: TermRef =>
646644
this(underlyingOfTermRef(tp))
@@ -900,7 +898,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
900898
if (!info.exists) assert(false, i"undefined: $tp with symbol $sym")
901899
return sigName(info)
902900
}
903-
if (semiEraseVCs && isDerivedValueClass(sym)) {
901+
if (semiEraseVCs && sym.isDerivedValueClass) {
904902
val erasedVCRef = eraseDerivedValueClass(tp)
905903
if (erasedVCRef.exists) return sigName(erasedVCRef)
906904
}

Diff for: compiler/src/dotty/tools/dotc/core/TypeOps.scala

-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import ast.tpd.*
1313
import reporting.trace
1414
import config.Printers.typr
1515
import config.Feature
16-
import transform.SymUtils.*
1716
import typer.ProtoTypes.*
1817
import typer.ForceDegree
1918
import typer.Inferencing.*

Diff for: compiler/src/dotty/tools/dotc/transform/TypeUtils.scala renamed to compiler/src/dotty/tools/dotc/core/TypeUtils.scala

+41-19
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
package dotty.tools
22
package dotc
3-
package transform
3+
package core
44

5-
import core.*
65
import TypeErasure.ErasedValueType
76
import Types.*, Contexts.*, Symbols.*, Flags.*, Decorators.*
87
import Names.Name
98

10-
object TypeUtils {
9+
class TypeUtils {
1110
/** A decorator that provides methods on types
1211
* that are needed in the transformer pipeline.
1312
*/
@@ -45,22 +44,45 @@ object TypeUtils {
4544
case ps => ps.reduceLeft(AndType(_, _))
4645
}
4746

48-
/** The element types of this tuple type, which can be made up of EmptyTuple, TupleX and `*:` pairs */
49-
def tupleElementTypes(using Context): Option[List[Type]] = self.dealias match {
50-
case AppliedType(tycon, hd :: tl :: Nil) if tycon.isRef(defn.PairClass) =>
51-
tl.tupleElementTypes.map(hd :: _)
52-
case self: SingletonType =>
53-
if self.termSymbol == defn.EmptyTupleModule then Some(Nil) else None
54-
case AndType(tp1, tp2) =>
55-
// We assume that we have the following property:
56-
// (T1, T2, ..., Tn) & (U1, U2, ..., Un) = (T1 & U1, T2 & U2, ..., Tn & Un)
57-
tp1.tupleElementTypes.zip(tp2.tupleElementTypes).map { case (t1, t2) => t1.intersect(t2) }
58-
case OrType(tp1, tp2) =>
59-
None // We can't combine the type of two tuples
60-
case _ =>
61-
if defn.isTupleClass(self.typeSymbol) then Some(self.dealias.argInfos)
62-
else None
63-
}
47+
/** The element types of this tuple type, which can be made up of EmptyTuple, TupleX and `*:` pairs
48+
*/
49+
def tupleElementTypes(using Context): Option[List[Type]] =
50+
tupleElementTypesUpTo(Int.MaxValue)
51+
52+
/** The element types of this tuple type, which can be made up of EmptyTuple, TupleX and `*:` pairs
53+
* @param bound The maximum number of elements that needs generating minus 1
54+
* The generation will stop once more than bound elems have been generated
55+
* @param normalize If true, normalize and dealias at each step.
56+
* If false, never normalize and dealias only to find *:
57+
* and EmptyTuple types. This is useful for printing.
58+
*/
59+
def tupleElementTypesUpTo(bound: Int, normalize: Boolean = true)(using Context): Option[List[Type]] =
60+
def recur(tp: Type, bound: Int): Option[List[Type]] =
61+
if bound < 0 then Some(Nil)
62+
else (if normalize then tp.normalized else tp).dealias match
63+
case AppliedType(tycon, hd :: tl :: Nil) if tycon.isRef(defn.PairClass) =>
64+
recur(tl, bound - 1).map(hd :: _)
65+
case tp: AppliedType if defn.isTupleNType(tp) && normalize =>
66+
Some(tp.args) // if normalize is set, use the dealiased tuple
67+
// otherwise rely on the default case below to print unaliased tuples.
68+
case tp: SingletonType =>
69+
if tp.termSymbol == defn.EmptyTupleModule then Some(Nil) else None
70+
case _ =>
71+
if defn.isTupleClass(tp.typeSymbol) && !normalize then Some(tp.dealias.argInfos)
72+
else None
73+
recur(self.stripTypeVar, bound)
74+
75+
/** Is this a generic tuple that would fit into the range 1..22,
76+
* but is not already an instance of one of Tuple1..22?
77+
* In this case we need to cast it to make the TupleN/ members accessible.
78+
* This works only for generic tuples of known size up to 22.
79+
*/
80+
def isSmallGenericTuple(using Context): Boolean =
81+
self.derivesFrom(defn.PairClass)
82+
&& !defn.isTupleNType(self.widenDealias)
83+
&& self.widenTermRefExpr.tupleElementTypesUpTo(Definitions.MaxTupleArity).match
84+
case Some(elems) if elems.length <= Definitions.MaxTupleArity => true
85+
case _ => false
6486

6587
/** The `*:` equivalent of an instance of a Tuple class */
6688
def toNestedPairs(using Context): Type =

0 commit comments

Comments
 (0)