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