@@ -6,6 +6,9 @@ import core.*
6
6
import Types .* , Symbols .* , Contexts .* , Annotations .* , Flags .*
7
7
import CaptureSet .IdempotentCaptRefMap
8
8
import StdNames .nme
9
+ import ast .tpd .*
10
+ import Decorators .*
11
+ import typer .ErrorReporting .errorType
9
12
10
13
/**
11
14
@@ -77,20 +80,29 @@ Subtype rules
77
80
78
81
Representation:
79
82
80
- EX a.T[a] is represented as
83
+ EX a.T[a] is represented as a dependent function type
81
84
82
- r @ RecType(T[TermRef[r.recThis, caps.cap]]
85
+ (a: Exists) => T[a]]
86
+
87
+ where Exists is defined in caps like this:
88
+
89
+ sealed trait Exists extends Capability
90
+
91
+ The defn.RefinedFunctionOf extractor will exclude existential types from
92
+ its results, so only normal refined functions match.
93
+
94
+ Let `boundvar(ex)` be the TermParamRef defined by the extistential type `ex`.
83
95
84
96
Subtype checking algorithm, general scheme:
85
97
86
98
Maintain two structures in TypeComparer:
87
99
88
- openExistentials: List[RecThis ]
89
- assocExistentials: Map[RecThis , List[RecThis ]]
100
+ openExistentials: List[TermParamRef ]
101
+ assocExistentials: Map[TermParamRef , List[TermParamRef ]]
90
102
91
103
`openExistentials` corresponds to the list of existential variables stored in the environment.
92
104
`assocExistentials` maps existential variables bound by existentials appearing on the right
93
- of a subtype judgement to a list of possible associations. Initally this is openExistentials
105
+ of a subtype judgement to a list of possible associations. Initially this is openExistentials
94
106
at the time when the existential on the right was dropped. It can become a single existential
95
107
when the existentially bound key variable is unified with one of the variables in the
96
108
environment.
@@ -100,38 +112,31 @@ Subtype checking algorithm, steps to add for tp1 <:< tp2:
100
112
If tp1 is an existential EX a.tp1a:
101
113
102
114
val saved = openExistentials
103
- openExistentials = tp1.recThis :: openExistentials
115
+ openExistentials = boundvar( tp1) :: openExistentials
104
116
try tp1a <:< tp2
105
117
finally openExistentials = saved
106
118
107
119
If tp2 is an existential EX a.tp2a:
108
120
109
121
val saved = assocExistentials
110
- assocExistentials = assocExistentials + (tp2.recThis -> openExistentials
122
+ assocExistentials = assocExistentials + (boundvar( tp2) -> openExistentials
111
123
try tp1 <:< tp2a
112
124
finally assocExistentials = saved
113
125
114
- If tp1 and tp2 are existentially bound variables `TermRef(pre1/pre2: RecThis, cap)` :
126
+ If tp1 and tp2 are existentially bound variables:
115
127
116
- assocExistentials(pre2 ).contains(pre1 ) &&
117
- { assocExistentials(pre2 ) = List(pre1 ); true }
128
+ assocExistentials(tpi ).contains(tpj ) &&
129
+ { assocExistentials(tpi ) = List(tpj ); true }
118
130
119
131
Existential source syntax:
120
132
121
133
Existential types are ususally not written in source, since we still allow the `^`
122
134
syntax that can express most of them more concesely (see below for translation rules).
123
135
But we should also allow to write existential types explicity, even if it ends up mainly
124
- for debugging. To express them, we add the following trait definition in the caps object:
125
-
126
- trait Exists[X]
127
-
128
- A typical expression of an existential is then
136
+ for debugging. To express them, we use the encoding with `Exists`, so a typical
137
+ expression of an existential would be
129
138
130
- Exists[(x: Capability) => A ->{x} B]
131
-
132
- Existential types are expanded at Typer to the RecType syntax presented above. It is checked
133
- that the type argument is a dependent function type with one argument of type `Capability` and
134
- that this argument is used only in capture sets of the result type.
139
+ (x: Exists) => A ->{x} B
135
140
136
141
Existential types can only appear at the top-level of _legal existential scopes_. These are:
137
142
@@ -183,6 +188,23 @@ Expansion of ^:
183
188
*/
184
189
object Existential :
185
190
191
+ def fromDepFun (arg : Tree )(using Context ): Type = arg.tpe match
192
+ case RefinedType (parent, nme.apply, info : MethodType ) if defn.isNonRefinedFunction(parent) =>
193
+ info match
194
+ case info @ MethodType (_ :: Nil )
195
+ if info.paramInfos.head.derivesFrom(defn.Caps_Capability ) =>
196
+ apply(ref => info.resultType.substParams(info, ref :: Nil ))
197
+ case _ =>
198
+ errorType(em " Malformed existential: dependent function must have a singgle parameter of type caps.Capability " , arg.srcPos)
199
+ case _ =>
200
+ errorType(em " Malformed existential: dependent function type expected " , arg.srcPos)
201
+
202
+ def apply (fn : TermRef => Type )(using Context ): RecType =
203
+ RecType (rt => fn(exBoundRef(rt)))
204
+
205
+ def exBoundRef (rt : RecType )(using Context ): TermRef =
206
+ TermRef (rt.recThis, defn.captureRoot)
207
+
186
208
private class PackMap (sym : Symbol , rt : RecType )(using Context ) extends DeepTypeMap , IdempotentCaptRefMap :
187
209
def apply (tp : Type ): Type = tp match
188
210
case ref : TermRef if ref.symbol == sym => TermRef (rt.recThis, defn.captureRoot)
@@ -209,9 +231,14 @@ object Existential:
209
231
def fromSymbol (tp : Type , sym : Symbol )(using Context ): RecType =
210
232
RecType (PackMap (sym, _)(tp))
211
233
212
- def unapply (rt : RecType )(using Context ): Option [Type ] =
213
- if isCaptureChecking && rt.parent.existsPart(isExBound(_, rt))
214
- then Some (rt.parent)
215
- else None
234
+ def isExistentialMethod (mt : MethodType )(using Context ): Boolean = mt.paramInfos match
235
+ case (info : TypeRef ) :: rest => info.symbol == defn.Caps_Exists && rest.isEmpty
236
+ case _ => false
216
237
238
+ def unapply (tp : RefinedType )(using Context ): Option [(TermParamRef , Type )] =
239
+ tp.refinedInfo match
240
+ case mt : MethodType
241
+ if isExistentialMethod(mt) && defn.isNonRefinedFunction(tp.parent) =>
242
+ Some (mt.paramRefs.head, mt.resultType)
243
+ case _ => None
217
244
end Existential
0 commit comments