@@ -73,6 +73,9 @@ object Parsers {
73
73
enum ParseKind :
74
74
case Expr , Type , Pattern
75
75
76
+ enum IntoOK :
77
+ case Yes , No , Nested
78
+
76
79
type StageKind = Int
77
80
object StageKind {
78
81
val None = 0
@@ -1484,7 +1487,7 @@ object Parsers {
1484
1487
/** Same as [[typ ]], but if this results in a wildcard it emits a syntax error and
1485
1488
* returns a tree for type `Any` instead.
1486
1489
*/
1487
- def toplevelTyp (): Tree = rejectWildcardType(typ())
1490
+ def toplevelTyp (intoOK : IntoOK = IntoOK . No ): Tree = rejectWildcardType(typ(intoOK ))
1488
1491
1489
1492
private def getFunction (tree : Tree ): Option [Function ] = tree match {
1490
1493
case Parens (tree1) => getFunction(tree1)
@@ -1535,12 +1538,21 @@ object Parsers {
1535
1538
* | `(' [ FunArgType {`,' FunArgType } ] `)'
1536
1539
* | '(' [ TypedFunParam {',' TypedFunParam } ')'
1537
1540
* MatchType ::= InfixType `match` <<< TypeCaseClauses >>>
1541
+ * IntoType ::= [‘into’] IntoTargetType
1542
+ * | ‘( IntoType ‘)’
1543
+ * IntoTargetType ::= Type
1544
+ * | FunTypeArgs (‘=>’ | ‘?=>’) IntoType
1538
1545
*/
1539
- def typ (): Tree =
1546
+ def typ (intoOK : IntoOK = IntoOK . No ): Tree =
1540
1547
val start = in.offset
1541
1548
var imods = Modifiers ()
1542
1549
val erasedArgs : ListBuffer [Boolean ] = ListBuffer ()
1543
1550
1551
+ def nestedIntoOK (token : Int ) =
1552
+ if token == TLARROW then IntoOK .No
1553
+ else if intoOK == IntoOK .Nested then IntoOK .Yes
1554
+ else intoOK
1555
+
1544
1556
def functionRest (params : List [Tree ]): Tree =
1545
1557
val paramSpan = Span (start, in.lastOffset)
1546
1558
atSpan(start, in.offset) {
@@ -1569,8 +1581,9 @@ object Parsers {
1569
1581
else
1570
1582
accept(ARROW )
1571
1583
1584
+ def resType () = typ(nestedIntoOK(token))
1572
1585
val resultType =
1573
- if isPure then capturesAndResult(typ ) else typ ()
1586
+ if isPure then capturesAndResult(resType ) else resType ()
1574
1587
if token == TLARROW then
1575
1588
for case ValDef (_, tpt, _) <- params do
1576
1589
if isByNameType(tpt) then
@@ -1605,6 +1618,12 @@ object Parsers {
1605
1618
syntaxError(ErasedTypesCanOnlyBeFunctionTypes (), implicitKwPos(start))
1606
1619
t
1607
1620
1621
+ def isIntoPrefix : Boolean =
1622
+ intoOK == IntoOK .Yes
1623
+ && in.isIdent(nme.into)
1624
+ && in.featureEnabled(Feature .into)
1625
+ && canStartTypeTokens.contains(in.lookahead.token)
1626
+
1608
1627
var isValParamList = false
1609
1628
if in.token == LPAREN then
1610
1629
in.nextToken()
@@ -1635,17 +1654,36 @@ object Parsers {
1635
1654
funArgType()
1636
1655
commaSeparatedRest(t, funArg)
1637
1656
accept(RPAREN )
1657
+
1658
+ val intoAllowed =
1659
+ intoOK == IntoOK .Yes
1660
+ && args.lengthCompare(1 ) == 0
1661
+ && (! canFollowSimpleTypeTokens.contains(in.token) || followingIsVararg())
1662
+ val byNameAllowed = in.isArrow || isPureArrow
1663
+
1664
+ def sanitize (arg : Tree ): Tree = arg match
1665
+ case ByNameTypeTree (t) if ! byNameAllowed =>
1666
+ syntaxError(ByNameParameterNotSupported (t), t.span)
1667
+ t
1668
+ case PrefixOp (id @ Ident (tpnme.into), t) if ! intoAllowed =>
1669
+ syntaxError(em " no `into` modifier allowed here " , id.span)
1670
+ t
1671
+ case Parens (t) =>
1672
+ cpy.Parens (arg)(sanitize(t))
1673
+ case arg : FunctionWithMods =>
1674
+ val body1 = sanitize(arg.body)
1675
+ if body1 eq arg.body then arg
1676
+ else FunctionWithMods (arg.args, body1, arg.mods, arg.erasedParams).withSpan(arg.span)
1677
+ case Function (args, res) if ! intoAllowed =>
1678
+ cpy.Function (arg)(args, sanitize(res))
1679
+ case arg =>
1680
+ arg
1681
+
1682
+ val args1 = args.mapConserve(sanitize)
1638
1683
if isValParamList || in.isArrow || isPureArrow then
1639
1684
functionRest(args)
1640
1685
else
1641
- val args1 = args.mapConserve: t =>
1642
- if isByNameType(t) then
1643
- syntaxError(ByNameParameterNotSupported (t), t.span)
1644
- stripByNameType(t)
1645
- else
1646
- t
1647
- val tuple = atSpan(start):
1648
- makeTupleOrParens(args1)
1686
+ val tuple = atSpan(start)(makeTupleOrParens(args1))
1649
1687
typeRest :
1650
1688
infixTypeRest :
1651
1689
refinedTypeRest :
@@ -1660,7 +1698,7 @@ object Parsers {
1660
1698
LambdaTypeTree (tparams, toplevelTyp())
1661
1699
else if in.token == ARROW || isPureArrow(nme.PUREARROW ) then
1662
1700
val arrowOffset = in.skipToken()
1663
- val body = toplevelTyp()
1701
+ val body = toplevelTyp(nestedIntoOK(in.token) )
1664
1702
atSpan(start, arrowOffset):
1665
1703
getFunction(body) match
1666
1704
case Some (f) =>
@@ -1673,6 +1711,8 @@ object Parsers {
1673
1711
typ()
1674
1712
else if in.token == INDENT then
1675
1713
enclosed(INDENT , typ())
1714
+ else if isIntoPrefix then
1715
+ PrefixOp (typeIdent(), typ(IntoOK .Nested ))
1676
1716
else
1677
1717
typeRest(infixType())
1678
1718
end typ
@@ -2047,18 +2087,13 @@ object Parsers {
2047
2087
else
2048
2088
core()
2049
2089
2050
- private def maybeInto (tp : () => Tree ) =
2051
- if in.isIdent(nme.into)
2052
- && in.featureEnabled(Feature .into)
2053
- && canStartTypeTokens.contains(in.lookahead.token)
2054
- then atSpan(in.skipToken()) { Into (tp()) }
2055
- else tp()
2056
-
2057
2090
/** FunArgType ::= Type
2058
2091
* | `=>' Type
2059
2092
* | `->' [CaptureSet] Type
2060
2093
*/
2061
- val funArgType : () => Tree = () => paramTypeOf(typ)
2094
+ val funArgType : () => Tree =
2095
+ () => paramTypeOf(() => typ(IntoOK .Yes ))
2096
+ // We allow intoOK and filter out afterwards in typ()
2062
2097
2063
2098
/** ParamType ::= ParamValueType
2064
2099
* | `=>' ParamValueType
@@ -2067,15 +2102,21 @@ object Parsers {
2067
2102
def paramType (): Tree = paramTypeOf(paramValueType)
2068
2103
2069
2104
/** ParamValueType ::= Type [`*']
2105
+ * | IntoType
2106
+ * | ‘(’ IntoType ‘)’ `*'
2070
2107
*/
2071
- def paramValueType (): Tree = {
2072
- val t = maybeInto(toplevelTyp)
2073
- if (isIdent(nme.raw.STAR )) {
2108
+ def paramValueType (): Tree =
2109
+ val t = toplevelTyp(IntoOK .Yes )
2110
+ if isIdent(nme.raw.STAR ) then
2111
+ if ! t.isInstanceOf [Parens ] && isInto(t) then
2112
+ syntaxError(
2113
+ em """ `*` cannot directly follow `into` parameter
2114
+ |the `into` parameter needs to be put in parentheses """ ,
2115
+ in.offset)
2074
2116
in.nextToken()
2075
- atSpan(startOffset(t)) { PostfixOp (t, Ident (tpnme.raw. STAR )) }
2076
- }
2117
+ atSpan(startOffset(t)):
2118
+ PostfixOp (t, Ident (tpnme.raw. STAR ))
2077
2119
else t
2078
- }
2079
2120
2080
2121
/** TypeArgs ::= `[' Type {`,' Type} `]'
2081
2122
* NamedTypeArgs ::= `[' NamedTypeArg {`,' NamedTypeArg} `]'
@@ -3315,7 +3356,7 @@ object Parsers {
3315
3356
/** ContextTypes ::= FunArgType {‘,’ FunArgType}
3316
3357
*/
3317
3358
def contextTypes (paramOwner : ParamOwner , numLeadParams : Int , impliedMods : Modifiers ): List [ValDef ] =
3318
- val tps = commaSeparated(() => paramTypeOf(toplevelTyp))
3359
+ val tps = commaSeparated(() => paramTypeOf(() => toplevelTyp() ))
3319
3360
var counter = numLeadParams
3320
3361
def nextIdx = { counter += 1 ; counter }
3321
3362
val paramFlags = if paramOwner.isClass then LocalParamAccessor else Param
0 commit comments