in starlark/src/values/typing.rs [175:224]
fn from_dict<'v>(t: DictRef<'v>, heap: &'v Heap) -> anyhow::Result<TypeCompiled> {
// Dictionary with a single element
fn unpack_singleton_dictionary<'v>(x: &Dict<'v>) -> Option<(Value<'v>, Value<'v>)> {
if x.len() == 1 { x.iter().next() } else { None }
}
if t.is_empty() {
Ok(TypeCompiled::is_dict())
} else if let Some((tk, tv)) = unpack_singleton_dictionary(&t) {
// Dict of the form {k: v} must all match the k/v types
let tk = TypeCompiled::new(tk, heap)?;
let tv = TypeCompiled::new(tv, heap)?;
Ok(TypeCompiled::is_dict_of(tk, tv))
} else {
// Dict type, allowed to have more keys that aren't used.
// All specified must be type String.
let ts = t
.iter_hashed()
.map(|(k, kt)| {
let k_str = match k.key().unpack_str() {
None => {
return Err(TypingError::InvalidTypeAnnotation(t.to_string()).into());
}
Some(s) => Hashed::new_unchecked(k.hash(), s.to_owned()),
};
let kt = TypeCompiled::new(kt, heap)?;
Ok((k_str, kt))
})
.collect::<anyhow::Result<Vec<_>>>()?;
Ok(TypeCompiled(box move |v| match Dict::from_value(v) {
None => false,
Some(v) => {
for (k, kt) in &ts {
let ks = k.key().as_str();
let ks = Hashed::new_unchecked(k.hash(), ks);
match v.get_str_hashed(ks) {
None => return false,
Some(kv) => {
if !(kt.0)(kv) {
return false;
}
}
}
}
true
}
}))
}
}