Skip to content

Commit 55dc64a

Browse files
authored
Merge pull request #13022 from dotty-staging/more-abbrevs
Make CapturingTypes take sets instead of single references
2 parents 2d22ac2 + b4b5bfd commit 55dc64a

File tree

18 files changed

+134
-113
lines changed

18 files changed

+134
-113
lines changed

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ case class CaptureSet(elems: CaptureSet.Refs) extends Showable:
4040
def <:< (that: CaptureSet)(using Context): Boolean =
4141
elems.isEmpty || elems.forall(that.accountsFor)
4242

43+
def map(f: CaptureRef => CaptureRef)(using Context): CaptureSet =
44+
(empty /: elems)((cs, ref) => cs + f(ref))
45+
4346
def flatMap(f: CaptureRef => CaptureSet)(using Context): CaptureSet =
4447
(empty /: elems)((cs, ref) => cs ++ f(ref))
4548

@@ -53,6 +56,14 @@ case class CaptureSet(elems: CaptureSet.Refs) extends Showable:
5356
((NoType: Type) /: elems) ((tp, ref) =>
5457
if tp.exists then OrType(tp, ref, soft = false) else ref)
5558

59+
override def hashCode: Int = (0 /: elems) ((x, ref) => x + ref.hashCode)
60+
61+
override def equals(other: Any) = other match
62+
case that: CaptureSet =>
63+
this.elems.size == that.elems.size && this.elems.forall(that.elems.contains)
64+
case _ =>
65+
false
66+
5667
override def toString = elems.toString
5768

5869
override def toText(printer: Printer): Text =
@@ -66,6 +77,8 @@ object CaptureSet:
6677
/** Used as a recursion brake */
6778
@sharable private[core] val Pending = CaptureSet(SimpleIdentitySet.empty)
6879

80+
def universal(using Context) = defn.captureRootType.typeRef.singletonCaptureSet
81+
6982
def apply(elems: CaptureRef*)(using Context): CaptureSet =
7083
if elems.isEmpty then empty
7184
else CaptureSet(SimpleIdentitySet(elems.map(_.normalizedRef)*))
@@ -93,8 +106,8 @@ object CaptureSet:
93106
def recur(tp: Type): CaptureSet = tp match
94107
case tp: CaptureRef =>
95108
tp.captureSet
96-
case CapturingType(parent, ref) =>
97-
recur(parent) + ref
109+
case CapturingType(parent, refs) =>
110+
recur(parent) ++ refs
98111
case AppliedType(tycon, args) =>
99112
val cs = recur(tycon)
100113
tycon.typeParams match

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ class Definitions {
264264
*/
265265
@tu lazy val AnyClass: ClassSymbol = completeClass(enterCompleteClassSymbol(ScalaPackageClass, tpnme.Any, Abstract, Nil), ensureCtor = false)
266266
def AnyType: TypeRef = AnyClass.typeRef
267-
@tu lazy val TopType: Type = CapturingType(AnyType, captureRootType.typeRef)
267+
@tu lazy val TopType: Type = CapturingType(AnyType, captureRootType.typeRef.singletonCaptureSet)
268268
@tu lazy val MatchableClass: ClassSymbol = completeClass(enterCompleteClassSymbol(ScalaPackageClass, tpnme.Matchable, Trait, AnyType :: Nil), ensureCtor = false)
269269
def MatchableType: TypeRef = MatchableClass.typeRef
270270
@tu lazy val AnyValClass: ClassSymbol =

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
331331
if parent1 ne tp.parent then tp.derivedAnnotatedType(parent1, tp.annot) else tp
332332
case tp: CapturingType =>
333333
val parent1 = recur(tp.parent, fromBelow)
334-
if parent1 ne tp.parent then tp.derivedCapturingType(parent1, tp.ref) else tp
334+
if parent1 ne tp.parent then tp.derivedCapturingType(parent1, tp.refs) else tp
335335
case _ =>
336336
val tp1 = tp.dealiasKeepAnnots
337337
if tp1 ne tp then

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2151,7 +2151,7 @@ object SymDenotations {
21512151
recur(TypeComparer.bounds(tp).hi)
21522152

21532153
case tp: CapturingType =>
2154-
tp.derivedCapturingType(recur(tp.parent), tp.ref)
2154+
tp.derivedCapturingType(recur(tp.parent), tp.refs)
21552155

21562156
case tp: TypeProxy =>
21572157
def computeTypeProxy = {

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
490490
// under -Ycheck. Test case is i7965.scala.
491491

492492
case tp1: CapturingType =>
493-
if tp2.captureSet.accountsFor(tp1.ref) then recur(tp1.parent, tp2)
493+
if tp1.refs <:< tp2.captureSet then recur(tp1.parent, tp2)
494494
else thirdTry
495495
case tp1: MatchType =>
496496
val reduced = tp1.reduced
@@ -818,7 +818,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
818818
// ---------------------------
819819
// E |- x: {x} T
820820
//
821-
CapturingType(tp2, defn.captureRootType.typeRef)
821+
CapturingType(tp2, CaptureSet.universal)
822822
case _ => tp2
823823
isSubType(tp1.underlying.widenExpr, tp2n, approx.addLow)
824824
}
@@ -2361,8 +2361,11 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
23612361
tp1.underlying & tp2
23622362
case tp1: AnnotatedType if !tp1.isRefining =>
23632363
tp1.underlying & tp2
2364-
case tp1: CapturingType if !tp2.captureSet.accountsFor(tp1.ref) =>
2365-
tp1.parent & tp2
2364+
case tp1: CapturingType =>
2365+
val parent1 = tp1.parent & tp2
2366+
if tp2.captureSet <:< tp1.refs then parent1
2367+
else if parent1.exists then tp1.derivedCapturingType(parent1, tp1.refs)
2368+
else NoType
23662369
case _ =>
23672370
NoType
23682371
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ object TypeOps:
169169
val normed = tp.tryNormalize
170170
if (normed.exists) normed else mapOver
171171
case tp: CapturingType
172-
if !ctx.mode.is(Mode.Type) && tp.parent.captureSet.accountsFor(tp.ref) =>
172+
if !ctx.mode.is(Mode.Type) && tp.refs <:< tp.parent.captureSet =>
173173
simplify(tp.parent, theMap)
174174
case tp: MethodicType =>
175175
tp // See documentation of `Types#simplified`
@@ -271,7 +271,7 @@ object TypeOps:
271271
case tp1: RecType =>
272272
return tp1.rebind(approximateOr(tp1.parent, tp2))
273273
case tp1: CapturingType =>
274-
return tp1.derivedCapturingType(approximateOr(tp1.parent, tp2), tp1.ref)
274+
return tp1.derivedCapturingType(approximateOr(tp1.parent, tp2), tp1.refs)
275275
case err: ErrorType =>
276276
return err
277277
case _ =>
@@ -280,7 +280,7 @@ object TypeOps:
280280
case tp2: RecType =>
281281
return tp2.rebind(approximateOr(tp1, tp2.parent))
282282
case tp2: CapturingType =>
283-
return tp2.derivedCapturingType(approximateOr(tp1, tp2.parent), tp2.ref)
283+
return tp2.derivedCapturingType(approximateOr(tp1, tp2.parent), tp2.refs)
284284
case err: ErrorType =>
285285
return err
286286
case _ =>

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

Lines changed: 37 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ object Types {
373373
case tp: AndOrType => tp.tp1.unusableForInference || tp.tp2.unusableForInference
374374
case tp: LambdaType => tp.resultType.unusableForInference || tp.paramInfos.exists(_.unusableForInference)
375375
case WildcardType(optBounds) => optBounds.unusableForInference
376-
case CapturingType(parent, ref) => parent.unusableForInference || ref.unusableForInference
376+
case CapturingType(parent, ref) => parent.unusableForInference
377377
case _: ErrorType => true
378378
case _ => false
379379

@@ -1385,7 +1385,7 @@ object Types {
13851385
val tp1 = tp.parent.dealias1(keep)
13861386
if keep(tp) then tp.derivedAnnotatedType(tp1, tp.annot) else tp1
13871387
case tp: CapturingType =>
1388-
tp.derivedCapturingType(tp.parent.dealias1(keep), tp.ref)
1388+
tp.derivedCapturingType(tp.parent.dealias1(keep), tp.refs)
13891389
case tp: LazyRef =>
13901390
tp.ref.dealias1(keep)
13911391
case _ => this
@@ -1838,10 +1838,12 @@ object Types {
18381838
}
18391839

18401840
def capturing(ref: CaptureRef)(using Context): Type =
1841-
if captureSet.accountsFor(ref) then this else CapturingType(this, ref)
1841+
if captureSet.accountsFor(ref) then this
1842+
else CapturingType(this, ref.singletonCaptureSet)
18421843

18431844
def capturing(cs: CaptureSet)(using Context): Type =
1844-
(this /: cs.elems)(_.capturing(_))
1845+
val cs1 = cs -- captureSet
1846+
if cs1.isEmpty then this else CapturingType(this, cs)
18451847

18461848
/** The set of distinct symbols referred to by this type, after all aliases are expanded */
18471849
def coveringSet(using Context): Set[Symbol] =
@@ -3620,9 +3622,10 @@ object Types {
36203622
case tp: TermParamRef if tp.binder eq thisLambdaType => TrueDeps
36213623
case tp: CapturingType =>
36223624
val status1 = compute(status, tp.parent, theAcc)
3623-
tp.ref.stripTypeVar match
3624-
case tp: TermParamRef if tp.binder eq thisLambdaType => combine(status1, CaptureDeps)
3625-
case _ => status1
3625+
(status1 /: tp.refs.elems)((s, ref) => ref.stripTypeVar match
3626+
case tp: TermParamRef if tp.binder eq thisLambdaType => combine(s, CaptureDeps)
3627+
case _ => s
3628+
)
36263629
case _: ThisType | _: BoundType | NoPrefix => status
36273630
case _ =>
36283631
(if theAcc != null then theAcc else DepAcc()).foldOver(status, tp)
@@ -5162,39 +5165,38 @@ object Types {
51625165
unique(CachedAnnotatedType(parent, annot))
51635166
end AnnotatedType
51645167

5165-
abstract case class CapturingType(parent: Type, ref: CaptureRef) extends AnnotOrCaptType:
5168+
abstract case class CapturingType(parent: Type, refs: CaptureSet) extends AnnotOrCaptType:
51665169
override def underlying(using Context): Type = parent
51675170

5168-
def derivedCapturingType(parent: Type, ref: CaptureRef)(using Context): CapturingType =
5169-
if (parent eq this.parent) && (ref eq this.ref) then this
5170-
else CapturingType(parent, ref)
5171-
5172-
def derivedCapturing(parent: Type, capt: Type)(using Context): Type =
5173-
if (parent eq this.parent) && (capt eq this.ref) then this
5174-
else parent.capturing(capt.captureSet)
5171+
def derivedCapturingType(parent: Type, refs: CaptureSet)(using Context): CapturingType =
5172+
if (parent eq this.parent) && (refs eq this.refs) then this
5173+
else CapturingType(parent, refs)
51755174

51765175
// equals comes from case class; no matching override is needed
51775176

51785177
override def computeHash(bs: Binders): Int =
5179-
doHash(bs, parent, ref)
5178+
doHash(bs, refs, parent)
51805179
override def hashIsStable: Boolean =
5181-
parent.hashIsStable && ref.hashIsStable
5180+
parent.hashIsStable && refs.elems.forall(_.hashIsStable)
51825181

51835182
override def eql(that: Type): Boolean = that match
5184-
case that: CapturingType => (parent eq that.parent) && (ref eq that.ref)
5183+
case that: CapturingType => (parent eq that.parent) && refs.equals(that.refs)
51855184
case _ => false
51865185

51875186
override def iso(that: Any, bs: BinderPairs): Boolean = that match
5188-
case that: CapturingType => parent.equals(that.parent, bs) && ref.equals(that.ref, bs)
5187+
case that: CapturingType => parent.equals(that.parent, bs) && refs.equals(that.refs)
51895188
case _ => false
51905189

5191-
class CachedCapturingType(parent: Type, ref: CaptureRef) extends CapturingType(parent, ref)
5190+
class CachedCapturingType(parent: Type, refs: CaptureSet) extends CapturingType(parent, refs)
51925191

51935192
object CapturingType:
5194-
def apply(parent: Type, ref: CaptureRef)(using Context): CapturingType =
5195-
unique(CachedCapturingType(parent, ref.normalizedRef))
5196-
def checked(parent: Type, ref: Type)(using Context): CapturingType = ref match
5197-
case ref: CaptureRef => apply(parent, ref)
5193+
def apply(parent: Type, refs: CaptureSet)(using Context): CapturingType =
5194+
unique(CachedCapturingType(parent, refs.map(_.normalizedRef)))
5195+
def checked(parent: Type, tps: Type*)(using Context): CapturingType =
5196+
val refs: Seq[CaptureRef] = tps map {
5197+
case ref: CaptureRef => ref
5198+
}
5199+
apply(parent, CaptureSet(refs*))
51985200
end CapturingType
51995201

52005202
// Special type objects and classes -----------------------------------------------------
@@ -5458,8 +5460,8 @@ object Types {
54585460
tp.derivedMatchType(bound, scrutinee, cases)
54595461
protected def derivedAnnotatedType(tp: AnnotatedType, underlying: Type, annot: Annotation): Type =
54605462
tp.derivedAnnotatedType(underlying, annot)
5461-
protected def derivedCapturing(tp: CapturingType, parent: Type, capt: Type): Type =
5462-
tp.derivedCapturing(parent, capt)
5463+
protected def derivedCapturingType(tp: CapturingType, parent: Type, cs: CaptureSet): Type =
5464+
tp.derivedCapturingType(parent, cs)
54635465
protected def derivedWildcardType(tp: WildcardType, bounds: Type): Type =
54645466
tp.derivedWildcardType(bounds)
54655467
protected def derivedSkolemType(tp: SkolemType, info: Type): Type =
@@ -5539,8 +5541,8 @@ object Types {
55395541
if (underlying1 eq underlying) tp
55405542
else derivedAnnotatedType(tp, underlying1, mapOver(annot))
55415543

5542-
case tp @ CapturingType(parent, ref) =>
5543-
derivedCapturing(tp, this(parent), this(ref))
5544+
case tp @ CapturingType(parent, refs) =>
5545+
derivedCapturingType(tp, this(parent), refs.flatMap(this(_).captureSet))
55445546

55455547
case _: ThisType
55465548
| _: BoundType
@@ -5861,15 +5863,12 @@ object Types {
58615863
if (underlying.isExactlyNothing) underlying
58625864
else tp.derivedAnnotatedType(underlying, annot)
58635865
}
5864-
override protected def derivedCapturing(tp: CapturingType, parent: Type, capt: Type): Type =
5865-
capt match
5866+
override protected def derivedCapturingType(tp: CapturingType, parent: Type, cs: CaptureSet): Type =
5867+
parent match
58665868
case Range(lo, hi) =>
5867-
range(derivedCapturing(tp, parent, hi), derivedCapturing(tp, parent, lo))
5868-
case _ => parent match
5869-
case Range(lo, hi) =>
5870-
range(derivedCapturing(tp, lo, capt), derivedCapturing(tp, hi, capt))
5871-
case _ =>
5872-
tp.derivedCapturing(parent, capt)
5869+
range(derivedCapturingType(tp, lo, cs), derivedCapturingType(tp, hi, cs))
5870+
case _ =>
5871+
tp.derivedCapturingType(parent, cs)
58735872

58745873
override protected def derivedWildcardType(tp: WildcardType, bounds: Type): WildcardType =
58755874
tp.derivedWildcardType(rangeToBounds(bounds))
@@ -6010,8 +6009,8 @@ object Types {
60106009
case AnnotatedType(underlying, annot) =>
60116010
this(applyToAnnot(x, annot), underlying)
60126011

6013-
case CapturingType(parent, ref) =>
6014-
this(this(x, parent), ref)
6012+
case CapturingType(parent, refs) =>
6013+
(this(x, parent) /: refs.elems)(this)
60156014

60166015
case tp: ProtoType =>
60176016
tp.fold(x, this)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,8 +292,8 @@ class TreePickler(pickler: TastyPickler) {
292292
writeByte(APPLIEDtype)
293293
withLength {
294294
pickleType(defn.Predef_capturing.typeRef)
295-
pickleType(tp.ref)
296295
pickleType(tp.parent)
296+
tp.refs.elems.foreach(pickleType(_))
297297
}
298298
case tpe: PolyType if richTypes =>
299299
pickleMethodic(POLYtype, tpe, EmptyFlags)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -361,8 +361,8 @@ class TreeUnpickler(reader: TastyReader,
361361
val args = until(end)(readType())
362362
tycon match
363363
case tycon: TypeRef if tycon.symbol == defn.Predef_capturing =>
364-
if ctx.settings.Ycc.value then CapturingType.checked(args(1), args(0))
365-
else args(1)
364+
if ctx.settings.Ycc.value then CapturingType.checked(args.head, args.tail*)
365+
else args.head
366366
case _ =>
367367
tycon.appliedTo(args)
368368
case TYPEBOUNDS =>

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

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -900,21 +900,18 @@ object Parsers {
900900

901901
def followingIsCaptureSet(): Boolean =
902902
val lookahead = in.LookaheadScanner()
903-
def recur(): Boolean =
904-
lookahead.isIdent && {
903+
def skipElems(): Unit =
904+
lookahead.nextToken()
905+
if lookahead.isIdent then
905906
lookahead.nextToken()
906-
if lookahead.token == COMMA then
907-
lookahead.nextToken()
908-
recur()
909-
else
910-
lookahead.token == RBRACE && {
911-
lookahead.nextToken()
912-
canStartInfixTypeTokens.contains(lookahead.token)
913-
|| lookahead.token == LBRACKET
914-
}
915-
}
916-
lookahead.nextToken()
917-
recur()
907+
if lookahead.token == COMMA then skipElems()
908+
skipElems()
909+
lookahead.token == RBRACE
910+
&& {
911+
lookahead.nextToken()
912+
canStartInfixTypeTokens.contains(lookahead.token)
913+
|| lookahead.token == LBRACKET
914+
}
918915

919916
/* --------- OPERAND/OPERATOR STACK --------------------------------------- */
920917

@@ -1366,7 +1363,7 @@ object Parsers {
13661363
* FunTypeArgs ::= InfixType
13671364
* | `(' [ [ ‘[using]’ ‘['erased'] FunArgType {`,' FunArgType } ] `)'
13681365
* | '(' [ ‘[using]’ ‘['erased'] TypedFunParam {',' TypedFunParam } ')'
1369-
* CaptureSet ::= `{` CaptureRef {`,` CaptureRef} `}`
1366+
* CaptureSet ::= `{` [CaptureRef {`,` CaptureRef}] `}`
13701367
* CaptureRef ::= Ident
13711368
*/
13721369
def typ(): Tree = {
@@ -1467,10 +1464,12 @@ object Parsers {
14671464
else { accept(TLARROW); typ() }
14681465
}
14691466
else if in.token == LBRACE && followingIsCaptureSet() then
1470-
val refs = inBraces { commaSeparated(captureRef) }
1471-
val t = typ()
1472-
val captured = refs.reduce(InfixOp(_, Ident(tpnme.raw.BAR), _))
1473-
AppliedTypeTree(TypeTree(defn.Predef_capturing.typeRef), captured :: t :: Nil)
1467+
in.nextToken()
1468+
val captured =
1469+
if in.token == RBRACE then TypeTree(defn.NothingType)
1470+
else commaSeparated(captureRef).reduce(InfixOp(_, Ident(tpnme.raw.BAR), _))
1471+
accept(RBRACE)
1472+
AppliedTypeTree(TypeTree(defn.Predef_capturing.typeRef), captured :: typ() :: Nil)
14741473
else if (in.token == INDENT) enclosed(INDENT, typ())
14751474
else infixType()
14761475

0 commit comments

Comments
 (0)