Skip to content

Commit 6c1198e

Browse files
authored
Merge branch 'scala:main' into init-global-warning
2 parents 0cecb11 + 57db77a commit 6c1198e

File tree

676 files changed

+96412
-507
lines changed

Some content is hidden

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

676 files changed

+96412
-507
lines changed

.github/CODEOWNERS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Any changes to the Scala 3 Standard Library must be approve
2+
# by one of the officers responsible of maintaining it
3+
/library/ @scala/stdlib-officers
4+
/library-aux/ @scala/stdlib-officers
5+
/library-js/ @scala/stdlib-officers

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

Lines changed: 73 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1450,6 +1450,27 @@ object desugar {
14501450
sel
14511451
end match
14521452

1453+
case class TuplePatternInfo(arity: Int, varNum: Int, wildcardNum: Int)
1454+
object TuplePatternInfo:
1455+
def apply(pat: Tree)(using Context): TuplePatternInfo = pat match
1456+
case Tuple(pats) =>
1457+
var arity = 0
1458+
var varNum = 0
1459+
var wildcardNum = 0
1460+
pats.foreach: p =>
1461+
arity += 1
1462+
p match
1463+
case id: Ident if !isBackquoted(id) =>
1464+
if id.name.isVarPattern then
1465+
varNum += 1
1466+
if id.name == nme.WILDCARD then
1467+
wildcardNum += 1
1468+
case _ =>
1469+
TuplePatternInfo(arity, varNum, wildcardNum)
1470+
case _ =>
1471+
TuplePatternInfo(-1, -1, -1)
1472+
end TuplePatternInfo
1473+
14531474
/** If `pat` is a variable pattern,
14541475
*
14551476
* val/var/lazy val p = e
@@ -1483,30 +1504,47 @@ object desugar {
14831504
|please bind to an identifier and use an alias given.""", bind)
14841505
false
14851506

1486-
def isTuplePattern(arity: Int): Boolean = pat match {
1487-
case Tuple(pats) if pats.size == arity =>
1488-
pats.forall(isVarPattern)
1489-
case _ => false
1490-
}
1491-
1492-
val isMatchingTuple: Tree => Boolean = {
1493-
case Tuple(es) => isTuplePattern(es.length) && !hasNamedArg(es)
1494-
case _ => false
1495-
}
1507+
val tuplePatternInfo = TuplePatternInfo(pat)
1508+
1509+
// When desugaring a PatDef in general, we use pattern matching on the rhs
1510+
// and collect the variable values in a tuple, then outside the match,
1511+
// we destructure the tuple to get the individual variables.
1512+
// We can achieve two kinds of tuple optimizations if the pattern is a tuple
1513+
// of simple variables or wildcards:
1514+
// 1. Full optimization:
1515+
// If the rhs is known to produce a literal tuple of the same arity,
1516+
// we can directly fetch the values from the tuple.
1517+
// For example: `val (x, y) = if ... then (1, "a") else (2, "b")` becomes
1518+
// `val $1$ = if ...; val x = $1$._1; val y = $1$._2`.
1519+
// 2. Partial optimization:
1520+
// If the rhs can be typed as a tuple and matched with correct arity, we can
1521+
// return the tuple itself in the case if there are no more than one variable
1522+
// in the pattern, or return the the value if there is only one variable.
1523+
1524+
val fullTupleOptimizable =
1525+
val isMatchingTuple: Tree => Boolean = {
1526+
case Tuple(es) => tuplePatternInfo.varNum == es.length && !hasNamedArg(es)
1527+
case _ => false
1528+
}
1529+
tuplePatternInfo.arity > 0
1530+
&& tuplePatternInfo.arity == tuplePatternInfo.varNum
1531+
&& forallResults(rhs, isMatchingTuple)
14961532

1497-
// We can only optimize `val pat = if (...) e1 else e2` if:
1498-
// - `e1` and `e2` are both tuples of arity N
1499-
// - `pat` is a tuple of N variables or wildcard patterns like `(x1, x2, ..., xN)`
1500-
val tupleOptimizable = forallResults(rhs, isMatchingTuple)
1533+
val partialTupleOptimizable =
1534+
tuplePatternInfo.arity > 0
1535+
&& tuplePatternInfo.arity == tuplePatternInfo.varNum
1536+
// We exclude the case where there is only one variable,
1537+
// because it should be handled by `makeTuple` directly.
1538+
&& tuplePatternInfo.wildcardNum < tuplePatternInfo.arity - 1
15011539

15021540
val inAliasGenerator = original match
15031541
case _: GenAlias => true
15041542
case _ => false
15051543

1506-
val vars =
1507-
if (tupleOptimizable) // include `_`
1544+
val vars: List[VarInfo] =
1545+
if fullTupleOptimizable || partialTupleOptimizable then // include `_`
15081546
pat match
1509-
case Tuple(pats) => pats.map { case id: Ident => id -> TypeTree() }
1547+
case Tuple(pats) => pats.map { case id: Ident => (id, TypeTree()) }
15101548
else
15111549
getVariables(
15121550
tree = pat,
@@ -1517,12 +1555,27 @@ object desugar {
15171555
errorOnGivenBinding
15181556
) // no `_`
15191557

1520-
val ids = for ((named, _) <- vars) yield Ident(named.name)
1558+
val ids = for ((named, tpt) <- vars) yield Ident(named.name)
1559+
15211560
val matchExpr =
1522-
if (tupleOptimizable) rhs
1561+
if fullTupleOptimizable then rhs
15231562
else
1524-
val caseDef = CaseDef(pat, EmptyTree, makeTuple(ids).withAttachment(ForArtifact, ()))
1563+
val caseDef =
1564+
if partialTupleOptimizable then
1565+
val tmpTuple = UniqueName.fresh()
1566+
// Replace all variables with wildcards in the pattern
1567+
val pat1 = pat match
1568+
case Tuple(pats) =>
1569+
val wildcardPats = pats.map(p => Ident(nme.WILDCARD).withSpan(p.span))
1570+
Tuple(wildcardPats).withSpan(pat.span)
1571+
CaseDef(
1572+
Bind(tmpTuple, pat1),
1573+
EmptyTree,
1574+
Ident(tmpTuple).withAttachment(ForArtifact, ())
1575+
)
1576+
else CaseDef(pat, EmptyTree, makeTuple(ids).withAttachment(ForArtifact, ()))
15251577
Match(makeSelector(rhs, MatchCheck.IrrefutablePatDef), caseDef :: Nil)
1578+
15261579
vars match {
15271580
case Nil if !mods.is(Lazy) =>
15281581
matchExpr

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -350,14 +350,16 @@ trait TreeInfo[T <: Untyped] { self: Trees.Instance[T] =>
350350
}
351351

352352
/** Checks whether predicate `p` is true for all result parts of this expression,
353-
* where we zoom into Ifs, Matches, and Blocks.
353+
* where we zoom into Ifs, Matches, Tries, and Blocks.
354354
*/
355-
def forallResults(tree: Tree, p: Tree => Boolean): Boolean = tree match {
355+
def forallResults(tree: Tree, p: Tree => Boolean): Boolean = tree match
356356
case If(_, thenp, elsep) => forallResults(thenp, p) && forallResults(elsep, p)
357-
case Match(_, cases) => cases forall (c => forallResults(c.body, p))
357+
case Match(_, cases) => cases.forall(c => forallResults(c.body, p))
358+
case Try(_, cases, finalizer) =>
359+
cases.forall(c => forallResults(c.body, p))
360+
&& (finalizer.isEmpty || forallResults(finalizer, p))
358361
case Block(_, expr) => forallResults(expr, p)
359362
case _ => p(tree)
360-
}
361363

362364
/** The tree stripped of the possibly nested applications (term and type).
363365
* The original tree if it's not an application.

compiler/src/dotty/tools/dotc/config/MigrationVersion.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ enum MigrationVersion(val warnFrom: SourceVersion, val errorFrom: SourceVersion)
3131
case ImportRename extends MigrationVersion(future, future)
3232
case ParameterEnclosedByParenthesis extends MigrationVersion(future, future)
3333
case XmlLiteral extends MigrationVersion(future, future)
34-
case GivenSyntax extends MigrationVersion(future, never)
34+
case GivenSyntax extends MigrationVersion(future, future)
3535
case ImplicitParamsWithoutUsing extends MigrationVersion(`3.7`, future)
3636
case Scala2Implicits extends MigrationVersion(future, future)
3737

compiler/src/dotty/tools/dotc/config/SourceVersion.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import Feature.isPreviewEnabled
88
import util.Property
99

1010
enum SourceVersion:
11-
case `3.0-migration`, `3.0`
11+
case `3.0-migration`, `3.0`
1212
case `3.1-migration`, `3.1`
1313
case `3.2-migration`, `3.2`
1414
case `3.3-migration`, `3.3`
@@ -44,8 +44,10 @@ enum SourceVersion:
4444
def enablesNamedTuples = isAtLeast(`3.7`)
4545
def enablesBetterFors(using Context) = isAtLeast(`3.7`) && isPreviewEnabled
4646

47+
def requiresNewSyntax = isAtLeast(future)
48+
4749
object SourceVersion extends Property.Key[SourceVersion]:
48-
50+
4951
/* The default source version used by the built compiler */
5052
val defaultSourceVersion = `3.7`
5153

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ class CheckRealizable(using Context) {
196196
}
197197
}
198198
if sourceVersion.isAtLeast(future) then
199-
// check fields only from version 3.x.
199+
// check fields only from version 3.future.
200200
// Reason: An embedded field could well be nullable, which means it
201201
// should not be part of a path and need not be checked; but we cannot recognize
202202
// this situation until we have a typesystem that tracks nullability.

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

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,25 @@ import util.Spans.Span
1414
/** Operations that are shared between Namer and TreeUnpickler */
1515
object NamerOps:
1616

17+
/** A completer supporting cleanup actions.
18+
* Needed to break the loop between completion of class and companion object.
19+
* If we try to complete the class first, and completion needs the companion
20+
* object (for instance for processing an import) then the companion object
21+
* completion would consult the companion class info for constructor that
22+
* need a constructor proxy in the object. This can lead to a cyclic reference.
23+
* We break the cycle by delaying adding constructor proxies to be a cleanuo
24+
* action instead.
25+
*/
26+
trait CompleterWithCleanup extends LazyType:
27+
private var cleanupActions: List[() => Unit] = Nil
28+
def addCleanupAction(op: () => Unit): Unit =
29+
cleanupActions = op :: cleanupActions
30+
def cleanup(): Unit =
31+
if cleanupActions.nonEmpty then
32+
cleanupActions.reverse.foreach(_())
33+
cleanupActions = Nil
34+
end CompleterWithCleanup
35+
1736
/** The type of the constructed instance is returned
1837
*
1938
* @param ctor the constructor
@@ -164,8 +183,14 @@ object NamerOps:
164183
ApplyProxyCompleter(constr),
165184
cls.privateWithin,
166185
constr.coord)
167-
for dcl <- cls.info.decls do
186+
def doAdd() = for dcl <- cls.info.decls do
168187
if dcl.isConstructor then scope.enter(proxy(dcl))
188+
cls.infoOrCompleter match
189+
case completer: CompleterWithCleanup if cls.is(Touched) =>
190+
// Taking the info would lead to a cyclic reference here - delay instead until cleanup of `cls`
191+
completer.addCleanupAction(doAdd)
192+
case _ =>
193+
doAdd()
169194
scope
170195
end addConstructorApplies
171196

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
410410
compareErasedValueType
411411
case ConstantType(v2) =>
412412
tp1 match {
413-
case ConstantType(v1) => v1.value == v2.value && recur(v1.tpe, v2.tpe)
413+
case ConstantType(v1) => v1 == v2 && recur(v1.tpe, v2.tpe)
414414
case _ => secondTry
415415
}
416416
case tp2: AnyConstantType =>

0 commit comments

Comments
 (0)