Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 527c8de

Browse files
Merge branch 'main' into drop-deps-cb
2 parents 68e78a7 + a120c7c commit 527c8de

Some content is hidden

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

42 files changed

+679
-109
lines changed

‎.github/workflows/stdlib.yaml‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -399,8 +399,6 @@ jobs:
399399
test-scala3-compiler-nonbootstrapped:
400400
runs-on: ubuntu-latest
401401
needs: [scala3-compiler-nonbootstrapped, tasty-core-nonbootstrapped, scala-library-nonbootstrapped]
402-
## The reference compiler generates wrong code for the non-bootstrapped stdlib, hence we cannot run tests on it at the moment
403-
if: false
404402
steps:
405403
- name: Git Checkout
406404
uses: actions/checkout@v5
@@ -413,7 +411,7 @@ jobs:
413411
cache: 'sbt'
414412
- uses: sbt/setup-sbt@v1
415413
- name: Test `scala3-compiler-nonbootstrapped`
416-
run: ./project/scripts/sbt scala3-compiler-nonbootstrapped-new/test
414+
run: ./project/scripts/sbt scala3-compiler-nonbootstrapped/test
417415

418416
test-scala3-compiler-bootstrapped:
419417
runs-on: ubuntu-latest

‎compiler/src/dotty/tools/dotc/cc/CaptureSet.scala‎

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -655,8 +655,15 @@ object CaptureSet:
655655
inline val debugVars = false
656656
inline val debugTarget = 1745
657657

658-
/** The subclass of captureset variables with given initial elements */
659-
class Var(initialOwner: Symbol = NoSymbol, initialElems: Refs = emptyRefs, underBox: Boolean = false)(using /*@constructorOnly*/ ictx: Context) extends CaptureSet:
658+
/** The subclass of captureset variables with given initial elements
659+
* @param initialOwner the initial owner. This is the real owner, except that
660+
* it can be change in HiddenSets. Used for level checking
661+
* if different from NoSymbol.
662+
* @param initialElems the initial elements
663+
* @param nestedOK relevant only if owner != NoSymbol. If true the set accepts
664+
* elements that are directly owned by owner.
665+
*/
666+
class Var(initialOwner: Symbol = NoSymbol, initialElems: Refs = emptyRefs, nestedOK: Boolean = true)(using /*@constructorOnly*/ ictx: Context) extends CaptureSet:
660667

661668
override def owner = initialOwner
662669

@@ -682,7 +689,7 @@ object CaptureSet:
682689
protected var myElems: Refs = initialElems
683690

684691
if debugVars && id == debugTarget then
685-
println(i"###INIT ELEMS of $id to $initialElems")
692+
println(i"###INIT ELEMS of $id of class $getClass in $initialOwner, $nestedOKto $initialElems")
686693
assert(false)
687694

688695
def elems: Refs = myElems
@@ -828,15 +835,16 @@ object CaptureSet:
828835

829836
def levelOK(elem: Capability)(using Context): Boolean = elem match
830837
case elem @ ResultCap(binder) =>
831-
rootLimit == null && (this.isInstanceOf[BiMapped] ||isPartOf(binder.resType))
838+
rootLimit == null && isPartOf(binder.resType)
832839
case GlobalCap =>
833840
rootLimit == null
834841
case elem: ParamRef =>
835-
this.isInstanceOf[BiMapped] ||isPartOf(elem.binder.resType)
842+
isPartOf(elem.binder.resType)
836843
case _ =>
837844
if owner.exists then
838845
val elemVis = elem.visibility
839846
!elemVis.isProperlyContainedIn(owner)
847+
|| nestedOK && elemVis.owner == owner
840848
else true
841849

842850
def addDependent(cs: CaptureSet)(using Context, VarState): Boolean =
@@ -950,6 +958,9 @@ object CaptureSet:
950958
abstract class DerivedVar(owner: Symbol, initialElems: Refs)(using @constructorOnly ctx: Context)
951959
extends Var(owner, initialElems):
952960

961+
override def levelOK(elem: Capability)(using Context): Boolean =
962+
true
963+
953964
// For debugging: A trace where a set was created. Note that logically it would make more
954965
// sense to place this variable in Mapped, but that runs afoul of the initialization checker.
955966
// val stack = if debugSets && this.isInstanceOf[Mapped] then (new Throwable).getStackTrace().take(20) else null
@@ -995,6 +1006,10 @@ object CaptureSet:
9951006
(val source: Var, val bimap: BiTypeMap, initialElems: Refs)(using @constructorOnly ctx: Context)
9961007
extends DerivedVar(source.owner, initialElems):
9971008

1009+
if debugVars && id == debugTarget then
1010+
println(i"variable $id is derived from $source")
1011+
assert(false)
1012+
9981013
override def tryInclude(elem: Capability, origin: CaptureSet)(using Context, VarState): Boolean =
9991014
if origin eq source then
10001015
val mappedElem = bimap.mapCapability(elem)

‎compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ class CheckCaptures extends Recheck, SymTransformer:
430430
def capturedVars(sym: Symbol)(using Context): CaptureSet =
431431
myCapturedVars.getOrElseUpdate(sym,
432432
if sym.isTerm || !sym.owner.isStaticOwner
433-
then CaptureSet.Var(sym)
433+
then CaptureSet.Var(sym, nestedOK =false)
434434
else CaptureSet.empty)
435435

436436
// ---- Record Uses with MarkFree ----------------------------------------------------

‎compiler/src/dotty/tools/dotc/cc/Setup.scala‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,8 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
495495
def transformResultType(tpt: TypeTree, sym: Symbol)(using Context): Unit =
496496
// First step: Transform the type and record it as knownType of tpt.
497497
try
498-
transformTT(tpt, sym, boxed = false)
498+
inContext(ctx.addMode(Mode.CCPreciseOwner)):
499+
transformTT(tpt, sym, boxed = false)
499500
catch case ex: IllegalCaptureRef =>
500501
capt.println(i"fail while transforming result type $tpt of $sym")
501502
throw ex
@@ -851,7 +852,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
851852

852853
/** Add a capture set variable to `tp` if necessary. */
853854
private def addVar(tp: Type, owner: Symbol)(using Context): Type =
854-
decorate(tp, CaptureSet.Var(owner, _))
855+
decorate(tp, CaptureSet.Var(owner, _, nestedOK =!ctx.mode.is(Mode.CCPreciseOwner)))
855856

856857
/** A map that adds <fluid> capture sets at all contra- and invariant positions
857858
* in a type where a capture set would be needed. This is used to make types

‎compiler/src/dotty/tools/dotc/config/Feature.scala‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ object Feature:
3737
val modularity = experimental("modularity")
3838
val quotedPatternsWithPolymorphicFunctions = experimental("quotedPatternsWithPolymorphicFunctions")
3939
val packageObjectValues = experimental("packageObjectValues")
40+
val multiSpreads = experimental("multiSpreads")
4041
val subCases = experimental("subCases")
4142

4243
def experimentalAutoEnableFeatures(using Context): List[TermName] =

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,11 @@ class Definitions {
468468
@tu lazy val throwMethod: TermSymbol = enterMethod(OpsPackageClass, nme.THROWkw,
469469
MethodType(List(ThrowableType), NothingType))
470470

471+
@tu lazy val spreadMethod = enterMethod(OpsPackageClass, nme.spread,
472+
PolyType(TypeBounds.empty :: Nil)(
473+
tl => MethodType(AnyType :: Nil, tl.paramRefs(0))
474+
))
475+
471476
@tu lazy val NothingClass: ClassSymbol = enterCompleteClassSymbol(
472477
ScalaPackageClass, tpnme.Nothing, AbstractFinal, List(AnyType))
473478
def NothingType: TypeRef = NothingClass.typeRef
@@ -519,6 +524,8 @@ class Definitions {
519524
@tu lazy val newGenericArrayMethod: TermSymbol = DottyArraysModule.requiredMethod("newGenericArray")
520525
@tu lazy val newArrayMethod: TermSymbol = DottyArraysModule.requiredMethod("newArray")
521526

527+
@tu lazy val VarArgsBuilderModule: Symbol = requiredModule("scala.runtime.VarArgsBuilder")
528+
522529
def getWrapVarargsArrayModule: Symbol = ScalaRuntimeModule
523530

524531
// The set of all wrap{X, Ref}Array methods, where X is a value type
@@ -563,11 +570,12 @@ class Definitions {
563570
@tu lazy val Seq_apply : Symbol = SeqClass.requiredMethod(nme.apply)
564571
@tu lazy val Seq_head : Symbol = SeqClass.requiredMethod(nme.head)
565572
@tu lazy val Seq_drop : Symbol = SeqClass.requiredMethod(nme.drop)
573+
@tu lazy val Seq_dropRight : Symbol = SeqClass.requiredMethod(nme.dropRight)
574+
@tu lazy val Seq_takeRight : Symbol = SeqClass.requiredMethod(nme.takeRight)
566575
@tu lazy val Seq_lengthCompare: Symbol = SeqClass.requiredMethod(nme.lengthCompare, List(IntType))
567576
@tu lazy val Seq_length : Symbol = SeqClass.requiredMethod(nme.length)
568577
@tu lazy val Seq_toSeq : Symbol = SeqClass.requiredMethod(nme.toSeq)
569578

570-
571579
@tu lazy val StringOps: Symbol = requiredClass("scala.collection.StringOps")
572580
@tu lazy val StringOps_format: Symbol = StringOps.requiredMethod(nme.format)
573581

@@ -2234,7 +2242,7 @@ class Definitions {
22342242

22352243
/** Lists core methods that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */
22362244
@tu lazy val syntheticCoreMethods: List[TermSymbol] =
2237-
AnyMethods ++ ObjectMethods ++ List(String_+, throwMethod)
2245+
AnyMethods ++ ObjectMethods ++ List(String_+, throwMethod, spreadMethod)
22382246

22392247
@tu lazy val reservedScalaClassNames: Set[Name] = syntheticScalaClasses.map(_.name).toSet
22402248

‎compiler/src/dotty/tools/dotc/core/Mode.scala‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,15 @@ object Mode {
141141
*/
142142
val InPackageClauseName: Mode = newMode(19, "InPackageClauseName")
143143

144+
/** When creating capset Vars in cc.Setup, mark the variable to be in
145+
* the result type of the context's owner, so that nested vals cannot
146+
* be included in it.
147+
* Reuses the value of InPackageClauseName to save Mode bits.
148+
* This is OK since InPackageClauseName is only set and tested during Typer,
149+
* and CCPreciseOwner only has an effect during phase CheckCaptures.
150+
*/
151+
val CCPreciseOwner = InPackageClauseName
152+
144153
/** We are in the IDE */
145154
val Interactive: Mode = newMode(20, "Interactive")
146155

‎compiler/src/dotty/tools/dotc/core/StdNames.scala‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,7 @@ object StdNames {
470470
val doubleHash: N = "doubleHash"
471471
val dotty: N = "dotty"
472472
val drop: N = "drop"
473+
val dropRight: N = "dropRight"
473474
val dynamics: N = "dynamics"
474475
val elem: N = "elem"
475476
val elems: N = "elems"
@@ -619,6 +620,7 @@ object StdNames {
619620
val setSymbol: N = "setSymbol"
620621
val setType: N = "setType"
621622
val setTypeSignature: N = "setTypeSignature"
623+
val spread: N = "spread"
622624
val standardInterpolator: N = "standardInterpolator"
623625
val staticClass : N = "staticClass"
624626
val staticModule : N = "staticModule"
@@ -801,6 +803,7 @@ object StdNames {
801803
val takeModulo: N = "takeModulo"
802804
val takeNot: N = "takeNot"
803805
val takeOr: N = "takeOr"
806+
val takeRight: N = "takeRight"
804807
val takeXor: N = "takeXor"
805808
val testEqual: N = "testEqual"
806809
val testGreaterOrEqualThan: N = "testGreaterOrEqualThan"

‎compiler/src/dotty/tools/dotc/parsing/Parsers.scala‎

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,17 +1056,22 @@ object Parsers {
10561056
}
10571057

10581058
/** Is current ident a `*`, and is it followed by a `)`, `, )`, `,EOF`? The latter two are not
1059-
syntactically valid, but we need to include them here for error recovery. */
1059+
syntactically valid, but we need to include them here for error recovery.
1060+
Under experimental.multiSpreads we allow `*`` followed by `,` unconditionally.
1061+
*/
10601062
def followingIsVararg(): Boolean =
10611063
in.isIdent(nme.raw.STAR) && {
10621064
val lookahead = in.LookaheadScanner()
10631065
lookahead.nextToken()
10641066
lookahead.token == RPAREN
10651067
|| lookahead.token == COMMA
1066-
&& {
1067-
lookahead.nextToken()
1068-
lookahead.token == RPAREN || lookahead.token == EOF
1069-
}
1068+
&& (
1069+
in.featureEnabled(Feature.multiSpreads)
1070+
|| {
1071+
lookahead.nextToken()
1072+
lookahead.token == RPAREN || lookahead.token == EOF
1073+
}
1074+
)
10701075
}
10711076

10721077
/** When encountering a `:`, is that in the binding of a lambda?
@@ -3347,7 +3352,9 @@ object Parsers {
33473352
if (in.token == RPAREN) Nil else patterns(location)
33483353

33493354
/** ArgumentPatterns ::= ‘(’ [Patterns] ‘)’
3350-
* | ‘(’ [Patterns ‘,’] PatVar ‘*’ ‘)’
3355+
* | ‘(’ [Patterns ‘,’] PatVar ‘*’ [‘,’ Patterns] ‘)’
3356+
*
3357+
* -- It is checked in Typer that there are no repeated PatVar arguments.
33513358
*/
33523359
def argumentPatterns(): List[Tree] =
33533360
inParensWithCommas(patternsOpt(Location.InPatternArgs))

‎compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala‎

Lines changed: 61 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,8 @@ object PatternMatcher {
198198
case object NonNullTest extends Test // scrutinee ne null
199199
case object GuardTest extends Test // scrutinee
200200

201+
val noLengthTest = LengthTest(0, exact = false)
202+
201203
// ------- Generating plans from trees ------------------------
202204

203205
/** A set of variabes that are known to be not null */
@@ -291,38 +293,67 @@ object PatternMatcher {
291293
/** Plan for matching the sequence in `seqSym` against sequence elements `args`.
292294
* If `exact` is true, the sequence is not permitted to have any elements following `args`.
293295
*/
294-
def matchElemsPlan(seqSym: Symbol, args: List[Tree], exact: Boolean, onSuccess: Plan) = {
295-
val selectors = args.indices.toList.map(idx =>
296-
ref(seqSym).select(defn.Seq_apply.matchingMember(seqSym.info)).appliedTo(Literal(Constant(idx))))
297-
TestPlan(LengthTest(args.length, exact), seqSym, seqSym.span,
298-
matchArgsPlan(selectors, args, onSuccess))
299-
}
296+
def matchElemsPlan(seqSym: Symbol, args: List[Tree], lengthTest: LengthTest, onSuccess: Plan) =
297+
val selectors = args.indices.toList.map: idx =>
298+
ref(seqSym).select(defn.Seq_apply.matchingMember(seqSym.info)).appliedTo(Literal(Constant(idx)))
299+
if lengthTest.len == 0 && lengthTest.exact == false then // redundant test
300+
matchArgsPlan(selectors, args, onSuccess)
301+
else
302+
TestPlan(lengthTest, seqSym, seqSym.span,
303+
matchArgsPlan(selectors, args, onSuccess))
300304

301305
/** Plan for matching the sequence in `getResult` against sequence elements
302-
* and a possible last varargs argument `args`.
306+
* `args`. Sequence elements may contain a varargs argument.
307+
* Example:
308+
*
309+
* lst match case Seq(1, xs*, 2, 3) => ...
310+
*
311+
* generates code which is equivalent to:
312+
*
313+
* if lst != null then
314+
* if lst.lengthCompare >= 3 then
315+
* if lst(0) == 1 then
316+
* val x1 = lst.drop(1)
317+
* val xs = x1.dropRight(2)
318+
* val x2 = lst.takeRight(2)
319+
* if x2(0) == 2 && x2(1) == 3 then
320+
* return[matchResult] ...
303321
*/
304-
def unapplySeqPlan(getResult: Symbol, args: List[Tree]): Plan = args.lastOption match {
305-
case Some(VarArgPattern(arg)) =>
306-
val matchRemaining =
307-
if (args.length == 1) {
308-
val toSeq = ref(getResult)
309-
.select(defn.Seq_toSeq.matchingMember(getResult.info))
310-
letAbstract(toSeq) { toSeqResult =>
311-
patternPlan(toSeqResult, arg, onSuccess)
312-
}
313-
}
314-
else {
315-
val dropped = ref(getResult)
316-
.select(defn.Seq_drop.matchingMember(getResult.info))
317-
.appliedTo(Literal(Constant(args.length - 1)))
318-
letAbstract(dropped) { droppedResult =>
319-
patternPlan(droppedResult, arg, onSuccess)
320-
}
321-
}
322-
matchElemsPlan(getResult, args.init, exact = false, matchRemaining)
323-
case _ =>
324-
matchElemsPlan(getResult, args, exact = true, onSuccess)
325-
}
322+
def unapplySeqPlan(getResult: Symbol, args: List[Tree]): Plan =
323+
val (leading, varargAndRest) = args.span:
324+
case VarArgPattern(_) => false
325+
case _ => true
326+
varargAndRest match
327+
case VarArgPattern(arg) :: trailing =>
328+
val remaining =
329+
if leading.isEmpty then
330+
ref(getResult)
331+
.select(defn.Seq_toSeq.matchingMember(getResult.info))
332+
else
333+
ref(getResult)
334+
.select(defn.Seq_drop.matchingMember(getResult.info))
335+
.appliedTo(Literal(Constant(leading.length)))
336+
val matchRemaining =
337+
letAbstract(remaining): remainingResult =>
338+
if trailing.isEmpty then
339+
patternPlan(remainingResult, arg, onSuccess)
340+
else
341+
val seq = ref(remainingResult)
342+
.select(defn.Seq_dropRight.matchingMember(remainingResult.info))
343+
.appliedTo(Literal(Constant(trailing.length)))
344+
letAbstract(seq): seqResult =>
345+
val rest = ref(remainingResult)
346+
.select(defn.Seq_takeRight.matchingMember(remainingResult.info))
347+
.appliedTo(Literal(Constant(trailing.length)))
348+
val matchTrailing =
349+
letAbstract(rest): trailingResult =>
350+
matchElemsPlan(trailingResult, trailing, noLengthTest, onSuccess)
351+
patternPlan(seqResult, arg, matchTrailing)
352+
matchElemsPlan(getResult, leading,
353+
LengthTest(leading.length + trailing.length, exact = false),
354+
matchRemaining)
355+
case _ =>
356+
matchElemsPlan(getResult, args, LengthTest(args.length, exact = true), onSuccess)
326357

327358
/** Plan for matching the sequence in `getResult`
328359
*
@@ -491,7 +522,7 @@ object PatternMatcher {
491522
case WildcardPattern() | This(_) =>
492523
onSuccess
493524
case SeqLiteral(pats, _) =>
494-
matchElemsPlan(scrutinee, pats, exact = true, onSuccess)
525+
matchElemsPlan(scrutinee, pats, LengthTest(pats.length, exact = true), onSuccess)
495526
case _ =>
496527
TestPlan(EqualTest(tree), scrutinee, tree.span, onSuccess)
497528
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /