Skip to content

Commit 13fbb62

Browse files
stepanchegfacebook-github-bot
authored andcommitted
Prohibit {X: Y} in runtime type expressions
Summary: Only `dict[X, Y]` is allowed now, same as in type expressions in function signatures. Reviewed By: cjhopman Differential Revision: D48933716 fbshipit-source-id: 04f57d310f860b595e11dcd5c2d032c200ddf2da
1 parent 4264537 commit 13fbb62

File tree

2 files changed

+7
-38
lines changed

2 files changed

+7
-38
lines changed

starlark/src/values/typing/type_compiled/compiled.rs

Lines changed: 5 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ use starlark_derive::starlark_value;
3030
use starlark_map::StarlarkHasher;
3131
use starlark_syntax::slice_vec_ext::SliceExt;
3232
use starlark_syntax::slice_vec_ext::VecExt;
33-
use starlark_syntax::syntax::type_expr::type_str_literal_is_wildcard;
3433
use thiserror::Error;
3534

3635
use crate as starlark;
@@ -41,7 +40,6 @@ use crate::environment::MethodsBuilder;
4140
use crate::environment::MethodsStatic;
4241
use crate::private::Private;
4342
use crate::typing::Ty;
44-
use crate::values::dict::Dict;
4543
use crate::values::dict::DictRef;
4644
use crate::values::layout::avalue::alloc_static;
4745
use crate::values::layout::avalue::AValueImpl;
@@ -53,7 +51,6 @@ use crate::values::type_repr::StarlarkTypeRepr;
5351
use crate::values::types::tuple::value::Tuple;
5452
use crate::values::typing::type_compiled::factory::TypeCompiledFactory;
5553
use crate::values::typing::type_compiled::matcher::TypeMatcher;
56-
use crate::values::typing::type_compiled::matchers::IsDict;
5754
use crate::values::AllocValue;
5855
use crate::values::Demand;
5956
use crate::values::Freeze;
@@ -74,6 +71,8 @@ enum TypingError {
7471
/// The given type annotation does not represent a type
7572
#[error("Type `{0}` is not a valid type annotation")]
7673
InvalidTypeAnnotation(String),
74+
#[error("`{{A: B}}` cannot be used as type, perhaps you meant `dict[A, B]`")]
75+
Dict,
7776
/// The given type annotation does not exist, but the user might have forgotten quotes around
7877
/// it
7978
#[error(r#"Found `{0}` instead of a valid type annotation. Perhaps you meant `"{1}"`?"#)]
@@ -380,10 +379,6 @@ impl<'v> TypeCompiled<Value<'v>> {
380379
}))
381380
}
382381

383-
fn type_dict(heap: &'v Heap) -> TypeCompiled<Value<'v>> {
384-
Self::alloc(IsDict, Ty::any_dict(), heap)
385-
}
386-
387382
pub(crate) fn type_list_of(
388383
t: TypeCompiled<Value<'v>>,
389384
heap: &'v Heap,
@@ -417,10 +412,6 @@ impl<'v> TypeCompiled<Value<'v>> {
417412
TypeCompiledFactory::alloc_ty(&ty, heap)
418413
}
419414

420-
pub(crate) fn is_wildcard_value(x: Value) -> bool {
421-
x.unpack_str().map(type_str_literal_is_wildcard) == Some(true)
422-
}
423-
424415
/// For `p: "xxx"`, parse that `"xxx"` as type.
425416
pub(crate) fn from_str(t: &str, heap: &'v Heap) -> TypeCompiled<Value<'v>> {
426417
TypeCompiledFactory::alloc_ty(&Ty::name(t), heap)
@@ -442,27 +433,6 @@ impl<'v> TypeCompiled<Value<'v>> {
442433
}
443434
}
444435

445-
fn from_dict(t: DictRef<'v>, heap: &'v Heap) -> anyhow::Result<TypeCompiled<Value<'v>>> {
446-
// Dictionary with a single element
447-
fn unpack_singleton_dictionary<'v>(x: &Dict<'v>) -> Option<(Value<'v>, Value<'v>)> {
448-
if x.len() == 1 { x.iter().next() } else { None }
449-
}
450-
451-
if let Some((tk, tv)) = unpack_singleton_dictionary(&t) {
452-
if TypeCompiled::is_wildcard_value(tk) && TypeCompiled::is_wildcard_value(tv) {
453-
Ok(TypeCompiled::type_dict(heap))
454-
} else {
455-
// Dict of the form {k: v} must all match the k/v types
456-
let tk = TypeCompiled::new(tk, heap)?;
457-
let tv = TypeCompiled::new(tv, heap)?;
458-
Ok(TypeCompiled::type_dict_of(tk, tv, heap))
459-
}
460-
} else {
461-
// Dict type with zero or multiple fields is not allowed
462-
Err(TypingError::InvalidTypeAnnotation(t.to_string()).into())
463-
}
464-
}
465-
466436
pub(crate) fn from_ty(ty: &Ty, heap: &'v Heap) -> Self {
467437
TypeCompiledFactory::alloc_ty(ty, heap)
468438
}
@@ -479,8 +449,6 @@ impl<'v> TypeCompiled<Value<'v>> {
479449
Ok(TypeCompiled::from_ty(&Ty::tuple(elems), heap))
480450
} else if let Some(t) = ListRef::from_value(ty) {
481451
TypeCompiled::from_list(t, heap)
482-
} else if let Some(t) = DictRef::from_value(ty) {
483-
TypeCompiled::from_dict(t, heap)
484452
} else if ty.request_value::<&dyn TypeCompiledDyn>().is_some() {
485453
// This branch is optimization: `TypeCompiledAsStarlarkValue` implements `eval_type`,
486454
// but this branch avoids copying the type.
@@ -503,7 +471,9 @@ impl TypeCompiled<FrozenValue> {
503471
}
504472

505473
fn invalid_type_annotation<'v>(ty: Value<'v>, heap: &'v Heap) -> TypingError {
506-
if let Some(name) = ty
474+
if DictRef::from_value(ty).is_some() {
475+
TypingError::Dict
476+
} else if let Some(name) = ty
507477
.get_attr("type", heap)
508478
.ok()
509479
.flatten()

starlark/src/values/typing/type_compiled/tests.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,9 @@ isinstance([1,2,"test"], ["_a"])
125125
// Checking types fails for invalid types
126126
a.fail("isinstance(None, isinstance)", "not a valid type");
127127
a.fail("isinstance(None, [])", "not a valid type");
128-
a.fail("isinstance(None, {'1': '', '2': ''})", "not a valid type");
129128
a.fail(
130-
"isinstance({}, {1: 'string', 2: 'bool'})",
131-
"not a valid type",
129+
"isinstance(None, {'1': '', '2': ''})",
130+
"cannot be used as type",
132131
);
133132

134133
// Should check the type of default parameters that aren't used

0 commit comments

Comments
 (0)