@@ -98,6 +98,8 @@ pub struct TyUser {
98
98
name : String ,
99
99
/// Base type for this custom type, e.g. generic record for record with known fields.
100
100
base : TyStarlarkValue ,
101
+ /// Super types for this type (`base` is included in this list implicitly).
102
+ supertypes : Vec < TyBasic > ,
101
103
matcher : Option < TypeMatcherFactory > ,
102
104
id : TypeInstanceId ,
103
105
fields : TyUserFields ,
@@ -114,6 +116,7 @@ impl TyUser {
114
116
pub fn new (
115
117
name : String ,
116
118
base : TyStarlarkValue ,
119
+ supertypes : Vec < TyBasic > ,
117
120
matcher : Option < TypeMatcherFactory > ,
118
121
id : TypeInstanceId ,
119
122
fields : TyUserFields ,
@@ -139,6 +142,7 @@ impl TyUser {
139
142
Ok ( TyUser {
140
143
name,
141
144
base,
145
+ supertypes,
142
146
matcher,
143
147
id,
144
148
fields,
@@ -244,4 +248,165 @@ impl TyCustomImpl for TyUser {
244
248
fn intersects ( x : & Self , y : & Self ) -> bool {
245
249
x == y
246
250
}
251
+
252
+ fn intersects_with ( & self , other : & TyBasic ) -> bool {
253
+ self . supertypes . iter ( ) . any ( |x| x == other)
254
+ }
255
+ }
256
+
257
+ #[ cfg( test) ]
258
+ mod tests {
259
+ use allocative:: Allocative ;
260
+ use dupe:: Dupe ;
261
+ use starlark_derive:: starlark_module;
262
+ use starlark_derive:: starlark_value;
263
+ use starlark_derive:: NoSerialize ;
264
+ use starlark_derive:: ProvidesStaticType ;
265
+
266
+ use crate as starlark;
267
+ use crate :: assert:: Assert ;
268
+ use crate :: environment:: GlobalsBuilder ;
269
+ use crate :: eval:: Arguments ;
270
+ use crate :: eval:: Evaluator ;
271
+ use crate :: typing:: Ty ;
272
+ use crate :: typing:: TyFunction ;
273
+ use crate :: typing:: TyStarlarkValue ;
274
+ use crate :: typing:: TyUser ;
275
+ use crate :: typing:: TyUserFields ;
276
+ use crate :: values:: starlark_value_as_type:: StarlarkValueAsType ;
277
+ use crate :: values:: typing:: TypeInstanceId ;
278
+ use crate :: values:: AllocValue ;
279
+ use crate :: values:: Heap ;
280
+ use crate :: values:: StarlarkValue ;
281
+ use crate :: values:: Value ;
282
+
283
+ #[ derive(
284
+ Debug ,
285
+ derive_more:: Display ,
286
+ ProvidesStaticType ,
287
+ Allocative ,
288
+ NoSerialize
289
+ ) ]
290
+ #[ display( fmt = "plant" ) ]
291
+ #[ allocative( skip) ] // TODO(nga): derive.
292
+ enum AbstractPlant { }
293
+
294
+ #[ starlark_value( type = "plant" ) ]
295
+ impl < ' v > StarlarkValue < ' v > for AbstractPlant {
296
+ fn get_type_starlark_repr ( ) -> Ty {
297
+ Ty :: starlark_value :: < Self > ( )
298
+ }
299
+ }
300
+
301
+ #[ derive(
302
+ Debug ,
303
+ derive_more:: Display ,
304
+ ProvidesStaticType ,
305
+ Allocative ,
306
+ NoSerialize
307
+ ) ]
308
+ #[ display( fmt = "fruit_callable" ) ]
309
+ struct FruitCallable {
310
+ name : String ,
311
+ ty_fruit_callable : Ty ,
312
+ ty_fruit : Ty ,
313
+ }
314
+
315
+ impl < ' v > AllocValue < ' v > for FruitCallable {
316
+ fn alloc_value ( self , heap : & ' v Heap ) -> Value < ' v > {
317
+ heap. alloc_simple ( self )
318
+ }
319
+ }
320
+
321
+ #[ starlark_value( type = "fruit_callable" ) ]
322
+ impl < ' v > StarlarkValue < ' v > for FruitCallable {
323
+ fn get_type_starlark_repr ( ) -> Ty {
324
+ Ty :: starlark_value :: < Self > ( )
325
+ }
326
+
327
+ fn typechecker_ty ( & self ) -> Option < Ty > {
328
+ Some ( self . ty_fruit_callable . dupe ( ) )
329
+ }
330
+
331
+ fn eval_type ( & self ) -> Option < Ty > {
332
+ Some ( self . ty_fruit . dupe ( ) )
333
+ }
334
+
335
+ fn invoke (
336
+ & self ,
337
+ _me : Value < ' v > ,
338
+ _args : & Arguments < ' v , ' _ > ,
339
+ _eval : & mut Evaluator < ' v , ' _ > ,
340
+ ) -> anyhow:: Result < Value < ' v > > {
341
+ unreachable ! ( "not needed in tests, but typechecker requires it" )
342
+ }
343
+ }
344
+
345
+ #[ derive(
346
+ Debug ,
347
+ derive_more:: Display ,
348
+ ProvidesStaticType ,
349
+ Allocative ,
350
+ NoSerialize
351
+ ) ]
352
+ struct Fruit {
353
+ name : String ,
354
+ }
355
+
356
+ #[ starlark_value( type = "fruit" ) ]
357
+ impl < ' v > StarlarkValue < ' v > for Fruit { }
358
+
359
+ #[ starlark_module]
360
+ fn globals ( globals : & mut GlobalsBuilder ) {
361
+ fn fruit ( name : String ) -> anyhow:: Result < FruitCallable > {
362
+ let ty_fruit = Ty :: custom ( TyUser :: new (
363
+ name. clone ( ) ,
364
+ TyStarlarkValue :: new :: < Fruit > ( ) ,
365
+ AbstractPlant :: get_type_starlark_repr ( )
366
+ . iter_union ( )
367
+ . to_vec ( ) ,
368
+ None ,
369
+ TypeInstanceId :: gen ( ) ,
370
+ TyUserFields :: no_fields ( ) ,
371
+ None ,
372
+ None ,
373
+ None ,
374
+ ) ?) ;
375
+ let ty_fruit_callable = Ty :: custom ( TyUser :: new (
376
+ format ! ( "fruit[{}]" , name) ,
377
+ TyStarlarkValue :: new :: < FruitCallable > ( ) ,
378
+ Vec :: new ( ) ,
379
+ None ,
380
+ TypeInstanceId :: gen ( ) ,
381
+ TyUserFields :: no_fields ( ) ,
382
+ Some ( TyFunction :: new ( vec ! [ ] , ty_fruit. clone ( ) ) ) ,
383
+ None ,
384
+ None ,
385
+ ) ?) ;
386
+ Ok ( FruitCallable {
387
+ name,
388
+ ty_fruit,
389
+ ty_fruit_callable,
390
+ } )
391
+ }
392
+
393
+ const Plant : StarlarkValueAsType < AbstractPlant > = StarlarkValueAsType :: new ( ) ;
394
+ }
395
+
396
+ #[ test]
397
+ fn test_intersect ( ) {
398
+ let mut a = Assert :: new ( ) ;
399
+ a. globals_add ( globals) ;
400
+ a. pass (
401
+ r#"
402
+ Apple = fruit("apple")
403
+
404
+ def make_apple() -> Apple:
405
+ return Apple()
406
+
407
+ def make_plant() -> Plant:
408
+ return make_apple()
409
+ "# ,
410
+ ) ;
411
+ }
247
412
}
0 commit comments