Skip to content

Commit 5598e6c

Browse files
stepanchegfacebook-github-bot
authored andcommitted
Support supertypes in TyUser
Summary: Used in the following diff D48933487. `AbstractProvider` is a supertype for user provider and builtin provider. Reviewed By: ianlevesque Differential Revision: D48933486 fbshipit-source-id: 73ac65833054c5836402f3905e497102b19e03c3
1 parent eaee4cc commit 5598e6c

File tree

4 files changed

+181
-0
lines changed

4 files changed

+181
-0
lines changed

starlark/src/typing/custom.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ pub trait TyCustomImpl: Debug + Display + Hash + Ord + Allocative + Send + Sync
8484
let _ignore = (x, y);
8585
true
8686
}
87+
/// Additional types that this type intersects with.
88+
fn intersects_with(&self, _other: &TyBasic) -> bool {
89+
false
90+
}
8791

8892
/// Create runtime type matcher for values.
8993
fn matcher<T: TypeMatcherAlloc>(&self, factory: T) -> T::Result;
@@ -104,6 +108,7 @@ pub(crate) trait TyCustomDyn: Debug + Display + Allocative + Send + Sync + 'stat
104108
oracle: TypingOracleCtx,
105109
) -> Result<Ty, TypingOrInternalError>;
106110
fn is_callable_dyn(&self) -> bool;
111+
fn is_intersects_with_dyn(&self, other: &TyBasic) -> bool;
107112
fn as_function_dyn(&self) -> Option<&TyFunction>;
108113
fn iter_item_dyn(&self) -> Result<Ty, ()>;
109114
fn index_dyn(&self, index: &TyBasic, ctx: &TypingOracleCtx) -> Result<Ty, ()>;
@@ -168,6 +173,10 @@ impl<T: TyCustomImpl> TyCustomDyn for T {
168173
self.is_callable()
169174
}
170175

176+
fn is_intersects_with_dyn(&self, other: &TyBasic) -> bool {
177+
self.intersects_with(other)
178+
}
179+
171180
fn as_function_dyn(&self) -> Option<&TyFunction> {
172181
self.as_function()
173182
}
@@ -250,6 +259,9 @@ impl TyCustom {
250259
}
251260

252261
pub(crate) fn intersects_with(&self, other: &TyBasic) -> bool {
262+
if self.0.is_intersects_with_dyn(other) {
263+
return true;
264+
}
253265
match other {
254266
TyBasic::Custom(other) => Self::intersects(self, other),
255267
TyBasic::Name(name) => self.as_name() == Some(name.as_str()),

starlark/src/typing/user.rs

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}

starlark/src/values/types/enumeration/enum_type.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ where
301301
let ty_enum_value = Ty::custom(TyUser::new(
302302
variable_name.to_owned(),
303303
TyStarlarkValue::new::<EnumValue>(),
304+
Vec::new(),
304305
Some(TypeMatcherFactory::new(EnumTypeMatcher { id: self.id })),
305306
self.id,
306307
TyUserFields::no_fields(),
@@ -311,6 +312,7 @@ where
311312
let ty_enum_type = Ty::custom(TyUser::new(
312313
format!("enum[{}]", variable_name),
313314
TyStarlarkValue::new::<EnumType>(),
315+
Vec::new(),
314316
None,
315317
TypeInstanceId::gen(),
316318
TyUserFields::no_fields(),

starlark/src/values/types/record/record_type.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ where
301301
let ty_record = Ty::custom(TyUser::new(
302302
variable_name.to_owned(),
303303
TyStarlarkValue::new::<Record>(),
304+
Vec::new(),
304305
Some(TypeMatcherFactory::new(RecordTypeMatcher { id: self.id })),
305306
self.id,
306307
TyUserFields {
@@ -315,6 +316,7 @@ where
315316
let ty_record_type = Ty::custom(TyUser::new(
316317
format!("record[{}]", variable_name),
317318
TyStarlarkValue::new::<RecordType>(),
319+
Vec::new(),
318320
None,
319321
TypeInstanceId::gen(),
320322
TyUserFields::no_fields(),

0 commit comments

Comments
 (0)