Skip to content

Commit 87aa777

Browse files
committed
Allow paper syntax to parse capturing types
# Conflicts: # compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala # compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala # compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala # tests/pos-custom-args/captures/boxmap.scala # tests/pos-custom-args/captures/cc-expand.scala
1 parent 2070751 commit 87aa777

File tree

10 files changed

+76
-9
lines changed

10 files changed

+76
-9
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,7 @@ class Definitions {
476476
@tu lazy val Predef_identity : Symbol = ScalaPredefModule.requiredMethod(nme.identity)
477477
@tu lazy val Predef_undefined: Symbol = ScalaPredefModule.requiredMethod(nme.???)
478478
@tu lazy val Predef_retainsType: Symbol = ScalaPredefModule.requiredType(tpnme.retains)
479+
@tu lazy val Predef_capturing: Symbol = ScalaPredefModule.requiredType(tpnme.CAPTURING)
479480
@tu lazy val ScalaPredefModuleClass: ClassSymbol = ScalaPredefModule.moduleClass.asClass
480481

481482
@tu lazy val SubTypeClass: ClassSymbol = requiredClass("scala.<:<")

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ object StdNames {
119119
val BITMAP_TRANSIENT: N = s"${BITMAP_PREFIX}trans$$" // initialization bitmap for transient lazy vals
120120
val BITMAP_CHECKINIT: N = s"${BITMAP_PREFIX}init$$" // initialization bitmap for checkinit values
121121
val BITMAP_CHECKINIT_TRANSIENT: N = s"${BITMAP_PREFIX}inittrans$$" // initialization bitmap for transient checkinit values
122+
val CAPTURING = "|>"
122123
val DEFAULT_GETTER: N = str.DEFAULT_GETTER
123124
val DEFAULT_GETTER_INIT: N = "$lessinit$greater"
124125
val DO_WHILE_PREFIX: N = "doWhile$"

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,8 @@ class TreeUnpickler(reader: TastyReader,
361361
val args = until(end)(readType())
362362
tycon match
363363
case tycon: TypeRef if tycon.symbol == defn.Predef_retainsType =>
364-
CapturingType(args(0), CaptureSet.fromRetainsTypeArg(args(1)))
364+
if ctx.settings.Ycc.value then CapturingType(args(0), CaptureSet.fromRetainsTypeArg(args(1)))
365+
else args(0)
365366
case _ =>
366367
tycon.appliedTo(args)
367368
case TYPEBOUNDS =>

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

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,24 @@ object Parsers {
890890
}
891891
}
892892

893+
def followingIsCaptureSet(): Boolean =
894+
val lookahead = in.LookaheadScanner()
895+
def recur(): Boolean =
896+
lookahead.isIdent && {
897+
lookahead.nextToken()
898+
if lookahead.token == COMMA then
899+
lookahead.nextToken()
900+
recur()
901+
else
902+
lookahead.token == RBRACE && {
903+
lookahead.nextToken()
904+
canStartInfixTypeTokens.contains(lookahead.token)
905+
|| lookahead.token == LBRACKET
906+
}
907+
}
908+
lookahead.nextToken()
909+
recur()
910+
893911
/* --------- OPERAND/OPERATOR STACK --------------------------------------- */
894912

895913
var opStack: List[OpInfo] = Nil
@@ -1329,17 +1347,27 @@ object Parsers {
13291347
case _ => false
13301348
}
13311349

1350+
def captureRef(): Tree =
1351+
atSpan(in.offset) {
1352+
val name = ident()
1353+
if name.isVarPattern then SingletonTypeTree(Ident(name))
1354+
else Ident(name.toTypeName)
1355+
}
1356+
13321357
/** Type ::= FunType
13331358
* | HkTypeParamClause ‘=>>’ Type
13341359
* | FunParamClause ‘=>>’ Type
13351360
* | MatchType
13361361
* | InfixType
1362+
* | CaptureSet Type
13371363
* FunType ::= (MonoFunType | PolyFunType)
13381364
* MonoFunType ::= FunTypeArgs (‘=>’ | ‘?=>’) Type
13391365
* PolyFunType ::= HKTypeParamClause '=>' Type
13401366
* FunTypeArgs ::= InfixType
13411367
* | `(' [ [ ‘[using]’ ‘['erased'] FunArgType {`,' FunArgType } ] `)'
13421368
* | '(' [ ‘[using]’ ‘['erased'] TypedFunParam {',' TypedFunParam } ')'
1369+
* CaptureSet ::= `{` CaptureRef {`,` CaptureRef} `}`
1370+
* CaptureRef ::= Ident
13431371
*/
13441372
def typ(): Tree = {
13451373
val start = in.offset
@@ -1445,6 +1473,11 @@ object Parsers {
14451473
}
14461474
else { accept(TLARROW); typ() }
14471475
}
1476+
else if in.token == LBRACE && followingIsCaptureSet() then
1477+
val refs = inBraces { commaSeparated(captureRef) }
1478+
val t = typ()
1479+
val captured = refs.reduce(InfixOp(_, Ident(tpnme.raw.BAR), _))
1480+
AppliedTypeTree(TypeTree(defn.Predef_capturing.typeRef), captured :: t :: Nil)
14481481
else if (in.token == INDENT) enclosed(INDENT, typ())
14491482
else infixType()
14501483

@@ -1513,7 +1546,7 @@ object Parsers {
15131546
def infixType(): Tree = infixTypeRest(refinedType())
15141547

15151548
def infixTypeRest(t: Tree): Tree =
1516-
infixOps(t, canStartTypeTokens, refinedTypeFn, Location.ElseWhere,
1549+
infixOps(t, canStartInfixTypeTokens, refinedTypeFn, Location.ElseWhere,
15171550
isType = true,
15181551
isOperator = !followingIsVararg())
15191552

@@ -3154,7 +3187,7 @@ object Parsers {
31543187
ImportSelector(
31553188
atSpan(in.skipToken()) { Ident(nme.EMPTY) },
31563189
bound =
3157-
if canStartTypeTokens.contains(in.token) then rejectWildcardType(infixType())
3190+
if canStartInfixTypeTokens.contains(in.token) then rejectWildcardType(infixType())
31583191
else EmptyTree)
31593192

31603193
/** id [‘as’ (id | ‘_’) */

compiler/src/dotty/tools/dotc/parsing/Tokens.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,8 @@ object Tokens extends TokensCommon {
230230

231231
final val canStartExprTokens2: TokenSet = canStartExprTokens3 | BitSet(DO)
232232

233-
final val canStartTypeTokens: TokenSet = literalTokens | identifierTokens | BitSet(
234-
THIS, SUPER, USCORE, LPAREN, AT)
233+
final val canStartInfixTypeTokens: TokenSet = literalTokens | identifierTokens | BitSet(
234+
THIS, SUPER, USCORE, LPAREN, LBRACE, AT)
235235

236236
final val templateIntroTokens: TokenSet = BitSet(CLASS, TRAIT, OBJECT, ENUM, CASECLASS, CASEOBJECT)
237237

compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,9 +191,9 @@ class PlainPrinter(_ctx: Context) extends Printer {
191191
case CapturingType(parent, refs) =>
192192
if refs.isConst then
193193
if Config.printCaptureSetsAsPrefix then
194-
changePrec(GlobalPrec)("{" ~ toTextCaptureRef(ref) ~ "} " ~ toText(parent))
194+
changePrec(GlobalPrec)("{" ~ Text(refs.elems.toList.map(toTextCaptureRef), ", ") ~ "} " ~ toText(parent))
195195
else
196-
changePrec(InfixPrec)(toText(parent) ~ " retains " ~ toTextCaptureRef(ref))
196+
changePrec(InfixPrec)(toText(parent) ~ " retains " ~ toText(refs.toRetainsTypeArg))
197197
else
198198
s"$refs " ~ toText(parent) // ^^^ improve
199199
case tp: PreviousErrorType if ctx.settings.XprintTypes.value =>
@@ -283,7 +283,7 @@ class PlainPrinter(_ctx: Context) extends Printer {
283283

284284
/** If -uniqid is set, the unique id of symbol, after a # */
285285
protected def idString(sym: Symbol): String =
286-
if (showUniqueIds || Printer.debugPrintUnique) "#" + sym.id else ""
286+
if showUniqueIds then "#" + sym.id else ""
287287

288288
def nameString(sym: Symbol): String =
289289
simpleNameString(sym) + idString(sym) // + "<" + (if (sym.exists) sym.owner else "") + ">"
@@ -323,7 +323,7 @@ class PlainPrinter(_ctx: Context) extends Printer {
323323
case tp @ ConstantType(value) =>
324324
toText(value)
325325
case pref: TermParamRef =>
326-
nameString(pref.binder.paramNames(pref.paramNum))
326+
nameString(pref.binder.paramNames(pref.paramNum)) ~ lambdaHash(pref.binder)
327327
case tp: RecThis =>
328328
val idx = openRecs.reverse.indexOf(tp.binder)
329329
if (idx >= 0) selfRecName(idx + 1)

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,10 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
532532
changePrec(OrTypePrec) { toText(args(0)) ~ " | " ~ atPrec(OrTypePrec + 1) { toText(args(1)) } }
533533
else if (tpt.symbol == defn.andType && args.length == 2)
534534
changePrec(AndTypePrec) { toText(args(0)) ~ " & " ~ atPrec(AndTypePrec + 1) { toText(args(1)) } }
535+
else if tpt.symbol == defn.Predef_retainsType && args.length == 2 then
536+
changePrec(InfixPrec) { toText(args(0)) ~ " retains " ~ toText(args(1)) }
537+
else if tpt.symbol == defn.Predef_capturing && args.length == 2 then
538+
changePrec(GlobalPrec) { "{" ~ toText(args(0)) ~ "}" ~ toText(args(1)) }
535539
else if defn.isFunctionClass(tpt.symbol)
536540
&& tpt.isInstanceOf[TypeTree] && tree.hasType && !printDebug
537541
then changePrec(GlobalPrec) { toText(tree.typeOpt) }

compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,10 @@ trait TypeAssigner {
218218
if ctx.settings.Ycc.value
219219
then CapturingType(args(0), include(CaptureSet.empty, args(1)))
220220
else args(0)
221+
else if constr == defn.Predef_capturing then
222+
if ctx.settings.Ycc.value
223+
then CapturingType(args(1), include(CaptureSet.empty, args(0)))
224+
else args(1)
221225
else tp
222226
case _ => tp
223227
end processAppliedType

library/src/scala/runtime/stdLibPatches/Predef.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,6 @@ object Predef:
5151
/** type `A` with capture set `B` */
5252
infix type retains[A, B]
5353

54+
/** An alternative notation for capturing types. TODO: needed? Or maybe mangle the name? */
55+
infix type |> [A, B]
5456
end Predef
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
object Test:
2+
3+
class A
4+
class B
5+
class C
6+
class CTC
7+
type CT = CTC retains *
8+
9+
def test(ct: CT, dt: CT) =
10+
11+
def x0: A => {ct} B = ???
12+
13+
def x1: A => B retains ct.type = ???
14+
def x2: A => B => C retains ct.type = ???
15+
def x3: A => () => B => C retains ct.type = ???
16+
17+
def x4: (x: A retains ct.type) => B => C = ???
18+
19+
def x5: A => (x: B retains ct.type) => () => C retains dt.type = ???
20+
def x6: A => (x: B retains ct.type) => (() => C retains dt.type) retains x.type | dt.type = ???
21+
def x7: A => (x: B retains ct.type) => (() => C retains dt.type) retains x.type = ???

0 commit comments

Comments
 (0)