@@ -9,10 +9,10 @@ import Decorators.*
9
9
import Annotations .Annotation
10
10
import NameKinds .{UniqueName , ContextBoundParamName , ContextFunctionParamName , DefaultGetterName , WildcardParamName }
11
11
import typer .{Namer , Checking }
12
- import util .{Property , SourceFile , SourcePosition , Chars }
12
+ import util .{Property , SourceFile , SourcePosition , SrcPos , Chars }
13
13
import config .Feature .{sourceVersion , migrateTo3 , enabled }
14
14
import config .SourceVersion .*
15
- import collection .mutable . ListBuffer
15
+ import collection .mutable
16
16
import reporting .*
17
17
import annotation .constructorOnly
18
18
import printing .Formatting .hl
@@ -248,7 +248,7 @@ object desugar {
248
248
249
249
private def elimContextBounds (meth : DefDef , isPrimaryConstructor : Boolean )(using Context ): DefDef =
250
250
val DefDef (_, paramss, tpt, rhs) = meth
251
- val evidenceParamBuf = ListBuffer [ValDef ]()
251
+ val evidenceParamBuf = mutable. ListBuffer [ValDef ]()
252
252
253
253
var seenContextBounds : Int = 0
254
254
def desugarContextBounds (rhs : Tree ): Tree = rhs match
@@ -1454,22 +1454,101 @@ object desugar {
1454
1454
AppliedTypeTree (
1455
1455
TypeTree (defn.throwsAlias.typeRef).withSpan(op.span), tpt :: excepts :: Nil )
1456
1456
1457
+ private def checkWellFormedTupleElems (elems : List [Tree ])(using Context ): List [Tree ] =
1458
+ val seen = mutable.Set [Name ]()
1459
+ for case arg @ NamedArg (name, _) <- elems do
1460
+ if seen.contains(name) then
1461
+ report.error(em " Duplicate tuple element name " , arg.srcPos)
1462
+ seen += name
1463
+ if name.startsWith(" _" ) && name.toString.tail.toIntOption.isDefined then
1464
+ report.error(
1465
+ em " $name cannot be used as the name of a tuple element because it is a regular tuple selector " ,
1466
+ arg.srcPos)
1467
+
1468
+ elems match
1469
+ case elem :: elems1 =>
1470
+ val mismatchOpt =
1471
+ if elem.isInstanceOf [NamedArg ]
1472
+ then elems1.find(! _.isInstanceOf [NamedArg ])
1473
+ else elems1.find(_.isInstanceOf [NamedArg ])
1474
+ mismatchOpt match
1475
+ case Some (misMatch) =>
1476
+ report.error(em " Illegal combination of named and unnamed tuple elements " , misMatch.srcPos)
1477
+ elems.mapConserve(dropNamedArg)
1478
+ case None => elems
1479
+ case _ => elems
1480
+ end checkWellFormedTupleElems
1481
+
1457
1482
/** Translate tuple expressions of arity <= 22
1458
1483
*
1459
1484
* () ==> ()
1460
1485
* (t) ==> t
1461
1486
* (t1, ..., tN) ==> TupleN(t1, ..., tN)
1462
1487
*/
1463
- def smallTuple (tree : Tuple )(using Context ): Tree = {
1464
- val ts = tree.trees
1465
- val arity = ts.length
1466
- assert(arity <= Definitions .MaxTupleArity )
1467
- def tupleTypeRef = defn.TupleType (arity).nn
1468
- if (arity == 0 )
1469
- if (ctx.mode is Mode .Type ) TypeTree (defn.UnitType ) else unitLiteral
1470
- else if (ctx.mode is Mode .Type ) AppliedTypeTree (ref(tupleTypeRef), ts)
1471
- else Apply (ref(tupleTypeRef.classSymbol.companionModule.termRef), ts)
1472
- }
1488
+ def tuple (tree : Tuple , pt : Type )(using Context ): Tree =
1489
+ var elems = checkWellFormedTupleElems(tree.trees)
1490
+ if ctx.mode.is(Mode .Pattern ) then elems = adaptPatternArgs(elems, pt)
1491
+ val elemValues = elems.mapConserve(dropNamedArg)
1492
+ val tup =
1493
+ val arity = elems.length
1494
+ if arity <= Definitions .MaxTupleArity then
1495
+ def tupleTypeRef = defn.TupleType (arity).nn
1496
+ val tree1 =
1497
+ if arity == 0 then
1498
+ if ctx.mode is Mode .Type then TypeTree (defn.UnitType ) else unitLiteral
1499
+ else if ctx.mode is Mode .Type then AppliedTypeTree (ref(tupleTypeRef), elemValues)
1500
+ else Apply (ref(tupleTypeRef.classSymbol.companionModule.termRef), elemValues)
1501
+ tree1.withSpan(tree.span)
1502
+ else
1503
+ cpy.Tuple (tree)(elemValues)
1504
+ val names = elems.collect:
1505
+ case NamedArg (name, arg) => name
1506
+ if names.isEmpty || ctx.mode.is(Mode .Pattern ) then
1507
+ tup
1508
+ else
1509
+ def namesTuple = inMode(ctx.mode &~ Mode .Pattern | Mode .Type ):
1510
+ tuple(Tuple (
1511
+ names.map: name =>
1512
+ SingletonTypeTree (Literal (Constant (name.toString))).withSpan(tree.span)),
1513
+ WildcardType )
1514
+ if ctx.mode.is(Mode .Type ) then
1515
+ AppliedTypeTree (ref(defn.NamedTupleTypeRef ), namesTuple :: tup :: Nil )
1516
+ else
1517
+ TypeApply (
1518
+ Apply (Select (ref(defn.NamedTupleModule ), nme.withNames), tup),
1519
+ namesTuple :: Nil )
1520
+
1521
+ /** When desugaring a list pattern arguments `elems` adapt them and the
1522
+ * expected type `pt` to each other. This means:
1523
+ * - If `elems` are named pattern elements, rearrange them to match `pt`.
1524
+ * This requires all names in `elems` to be also present in `pt`.
1525
+ * - If `elems` are unnamed elements, and `pt` is a named tuple, drop all
1526
+ * tuple element names from `pt`.
1527
+ */
1528
+ def adaptPatternArgs (elems : List [Tree ], pt : Type )(using Context ): List [Tree ] =
1529
+
1530
+ def reorderedNamedArgs (wildcardSpan : Span ): List [untpd.Tree ] =
1531
+ var selNames = pt.namedTupleElementTypes.map(_(0 ))
1532
+ if selNames.isEmpty && pt.classSymbol.is(CaseClass ) then
1533
+ selNames = pt.classSymbol.caseAccessors.map(_.name.asTermName)
1534
+ val nameToIdx = selNames.zipWithIndex.toMap
1535
+ val reordered = Array .fill[untpd.Tree ](selNames.length):
1536
+ untpd.Ident (nme.WILDCARD ).withSpan(wildcardSpan)
1537
+ for case arg @ NamedArg (name : TermName , _) <- elems do
1538
+ nameToIdx.get(name) match
1539
+ case Some (idx) =>
1540
+ if reordered(idx).isInstanceOf [Ident ] then
1541
+ reordered(idx) = arg
1542
+ else
1543
+ report.error(em " Duplicate named pattern " , arg.srcPos)
1544
+ case _ =>
1545
+ report.error(em " No element named ` $name` is defined in selector type $pt" , arg.srcPos)
1546
+ reordered.toList
1547
+
1548
+ elems match
1549
+ case (first @ NamedArg (_, _)) :: _ => reorderedNamedArgs(first.span.startPos)
1550
+ case _ => elems
1551
+ end adaptPatternArgs
1473
1552
1474
1553
private def isTopLevelDef (stat : Tree )(using Context ): Boolean = stat match
1475
1554
case _ : ValDef | _ : PatDef | _ : DefDef | _ : Export | _ : ExtMethods => true
@@ -1986,7 +2065,7 @@ object desugar {
1986
2065
* without duplicates
1987
2066
*/
1988
2067
private def getVariables (tree : Tree , shouldAddGiven : Context ?=> Bind => Boolean )(using Context ): List [VarInfo ] = {
1989
- val buf = ListBuffer [VarInfo ]()
2068
+ val buf = mutable. ListBuffer [VarInfo ]()
1990
2069
def seenName (name : Name ) = buf exists (_._1.name == name)
1991
2070
def add (named : NameTree , t : Tree ): Unit =
1992
2071
if (! seenName(named.name) && named.name.isTermName) buf += ((named, t))
0 commit comments