@@ -98,6 +98,8 @@ pub struct TyUser {
9898 name : String ,
9999 /// Base type for this custom type, e.g. generic record for record with known fields.
100100 base : TyStarlarkValue ,
101+ /// Super types for this type (`base` is included in this list implicitly).
102+ supertypes : Vec < TyBasic > ,
101103 matcher : Option < TypeMatcherFactory > ,
102104 id : TypeInstanceId ,
103105 fields : TyUserFields ,
@@ -114,6 +116,7 @@ impl TyUser {
114116 pub fn new (
115117 name : String ,
116118 base : TyStarlarkValue ,
119+ supertypes : Vec < TyBasic > ,
117120 matcher : Option < TypeMatcherFactory > ,
118121 id : TypeInstanceId ,
119122 fields : TyUserFields ,
@@ -139,6 +142,7 @@ impl TyUser {
139142 Ok ( TyUser {
140143 name,
141144 base,
145+ supertypes,
142146 matcher,
143147 id,
144148 fields,
@@ -244,4 +248,165 @@ impl TyCustomImpl for TyUser {
244248 fn intersects ( x : & Self , y : & Self ) -> bool {
245249 x == y
246250 }
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+ }
247412}
0 commit comments