@@ -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
@@ -242,7 +242,7 @@ object desugar {
242
242
243
243
private def elimContextBounds (meth : DefDef , isPrimaryConstructor : Boolean )(using Context ): DefDef =
244
244
val DefDef (_, paramss, tpt, rhs) = meth
245
- val evidenceParamBuf = ListBuffer [ValDef ]()
245
+ val evidenceParamBuf = mutable. ListBuffer [ValDef ]()
246
246
247
247
var seenContextBounds : Int = 0
248
248
def desugarContextBounds (rhs : Tree ): Tree = rhs match
@@ -1445,22 +1445,101 @@ object desugar {
1445
1445
AppliedTypeTree (
1446
1446
TypeTree (defn.throwsAlias.typeRef).withSpan(op.span), tpt :: excepts :: Nil )
1447
1447
1448
+ private def checkWellFormedTupleElems (elems : List [Tree ])(using Context ): List [Tree ] =
1449
+ val seen = mutable.Set [Name ]()
1450
+ for case arg @ NamedArg (name, _) <- elems do
1451
+ if seen.contains(name) then
1452
+ report.error(em " Duplicate tuple element name " , arg.srcPos)
1453
+ seen += name
1454
+ if name.startsWith(" _" ) && name.toString.tail.toIntOption.isDefined then
1455
+ report.error(
1456
+ em " $name cannot be used as the name of a tuple element because it is a regular tuple selector " ,
1457
+ arg.srcPos)
1458
+
1459
+ elems match
1460
+ case elem :: elems1 =>
1461
+ val mismatchOpt =
1462
+ if elem.isInstanceOf [NamedArg ]
1463
+ then elems1.find(! _.isInstanceOf [NamedArg ])
1464
+ else elems1.find(_.isInstanceOf [NamedArg ])
1465
+ mismatchOpt match
1466
+ case Some (misMatch) =>
1467
+ report.error(em " Illegal combination of named and unnamed tuple elements " , misMatch.srcPos)
1468
+ elems.mapConserve(dropNamedArg)
1469
+ case None => elems
1470
+ case _ => elems
1471
+ end checkWellFormedTupleElems
1472
+
1448
1473
/** Translate tuple expressions of arity <= 22
1449
1474
*
1450
1475
* () ==> ()
1451
1476
* (t) ==> t
1452
1477
* (t1, ..., tN) ==> TupleN(t1, ..., tN)
1453
1478
*/
1454
- def smallTuple (tree : Tuple )(using Context ): Tree = {
1455
- val ts = tree.trees
1456
- val arity = ts.length
1457
- assert(arity <= Definitions .MaxTupleArity )
1458
- def tupleTypeRef = defn.TupleType (arity).nn
1459
- if (arity == 0 )
1460
- if (ctx.mode is Mode .Type ) TypeTree (defn.UnitType ) else unitLiteral
1461
- else if (ctx.mode is Mode .Type ) AppliedTypeTree (ref(tupleTypeRef), ts)
1462
- else Apply (ref(tupleTypeRef.classSymbol.companionModule.termRef), ts)
1463
- }
1479
+ def tuple (tree : Tuple , pt : Type )(using Context ): Tree =
1480
+ var elems = checkWellFormedTupleElems(tree.trees)
1481
+ if ctx.mode.is(Mode .Pattern ) then elems = adaptPatternArgs(elems, pt)
1482
+ val elemValues = elems.mapConserve(dropNamedArg)
1483
+ val tup =
1484
+ val arity = elems.length
1485
+ if arity <= Definitions .MaxTupleArity then
1486
+ def tupleTypeRef = defn.TupleType (arity).nn
1487
+ val tree1 =
1488
+ if arity == 0 then
1489
+ if ctx.mode is Mode .Type then TypeTree (defn.UnitType ) else unitLiteral
1490
+ else if ctx.mode is Mode .Type then AppliedTypeTree (ref(tupleTypeRef), elemValues)
1491
+ else Apply (ref(tupleTypeRef.classSymbol.companionModule.termRef), elemValues)
1492
+ tree1.withSpan(tree.span)
1493
+ else
1494
+ cpy.Tuple (tree)(elemValues)
1495
+ val names = elems.collect:
1496
+ case NamedArg (name, arg) => name
1497
+ if names.isEmpty || ctx.mode.is(Mode .Pattern ) then
1498
+ tup
1499
+ else
1500
+ def namesTuple = inMode(ctx.mode &~ Mode .Pattern | Mode .Type ):
1501
+ tuple(Tuple (
1502
+ names.map: name =>
1503
+ SingletonTypeTree (Literal (Constant (name.toString))).withSpan(tree.span)),
1504
+ WildcardType )
1505
+ if ctx.mode.is(Mode .Type ) then
1506
+ AppliedTypeTree (ref(defn.NamedTupleTypeRef ), namesTuple :: tup :: Nil )
1507
+ else
1508
+ TypeApply (
1509
+ Apply (Select (ref(defn.NamedTupleModule ), nme.withNames), tup),
1510
+ namesTuple :: Nil )
1511
+
1512
+ /** When desugaring a list pattern arguments `elems` adapt them and the
1513
+ * expected type `pt` to each other. This means:
1514
+ * - If `elems` are named pattern elements, rearrange them to match `pt`.
1515
+ * This requires all names in `elems` to be also present in `pt`.
1516
+ * - If `elems` are unnamed elements, and `pt` is a named tuple, drop all
1517
+ * tuple element names from `pt`.
1518
+ */
1519
+ def adaptPatternArgs (elems : List [Tree ], pt : Type )(using Context ): List [Tree ] =
1520
+
1521
+ def reorderedNamedArgs (wildcardSpan : Span ): List [untpd.Tree ] =
1522
+ var selNames = pt.namedTupleElementTypes.map(_(0 ))
1523
+ if selNames.isEmpty && pt.classSymbol.is(CaseClass ) then
1524
+ selNames = pt.classSymbol.caseAccessors.map(_.name.asTermName)
1525
+ val nameToIdx = selNames.zipWithIndex.toMap
1526
+ val reordered = Array .fill[untpd.Tree ](selNames.length):
1527
+ untpd.Ident (nme.WILDCARD ).withSpan(wildcardSpan)
1528
+ for case arg @ NamedArg (name : TermName , _) <- elems do
1529
+ nameToIdx.get(name) match
1530
+ case Some (idx) =>
1531
+ if reordered(idx).isInstanceOf [Ident ] then
1532
+ reordered(idx) = arg
1533
+ else
1534
+ report.error(em " Duplicate named pattern " , arg.srcPos)
1535
+ case _ =>
1536
+ report.error(em " No element named ` $name` is defined in selector type $pt" , arg.srcPos)
1537
+ reordered.toList
1538
+
1539
+ elems match
1540
+ case (first @ NamedArg (_, _)) :: _ => reorderedNamedArgs(first.span.startPos)
1541
+ case _ => elems
1542
+ end adaptPatternArgs
1464
1543
1465
1544
private def isTopLevelDef (stat : Tree )(using Context ): Boolean = stat match
1466
1545
case _ : ValDef | _ : PatDef | _ : DefDef | _ : Export | _ : ExtMethods => true
@@ -1977,7 +2056,7 @@ object desugar {
1977
2056
* without duplicates
1978
2057
*/
1979
2058
private def getVariables (tree : Tree , shouldAddGiven : Context ?=> Bind => Boolean )(using Context ): List [VarInfo ] = {
1980
- val buf = ListBuffer [VarInfo ]()
2059
+ val buf = mutable. ListBuffer [VarInfo ]()
1981
2060
def seenName (name : Name ) = buf exists (_._1.name == name)
1982
2061
def add (named : NameTree , t : Tree ): Unit =
1983
2062
if (! seenName(named.name) && named.name.isTermName) buf += ((named, t))
0 commit comments