fix: incorrect Dict!.update! typing

This commit is contained in:
Shunsuke Shibayama 2024-12-29 18:28:50 +09:00
parent eedbfc27dc
commit d3304b3491
6 changed files with 52 additions and 17 deletions

View file

@ -547,6 +547,7 @@ impl Context {
return self.supertype_of(&evaled, rhs);
}
}
// REVIEW: is this OK?
if lhs.has_unbound_var() {
return true;
}

View file

@ -3953,17 +3953,20 @@ impl Context {
)
.quantify();
dict_mut.register_py_builtin(PROC_SETDEFAULT, setdefault_t, Some(FUNC_SETDEFAULT), 69);
let update_t = pr_met(
let update_t = kw_var_pr_met(
ref_mut(dict_mut_kv_t.clone(), None),
vec![kw(
KW_ITERABLE,
poly(ITERABLE, vec![ty_tp(tuple_t(vec![K.clone(), V.clone()]))]),
)],
vec![],
None,
vec![kw(
KW_CONFLICT_RESOLVER,
func2(V.clone(), V.clone(), V.clone()),
)],
vec![
kw(
KW_ITERABLE,
// TODO: Iterable((K, V)) | {K: V}(<: Iterable(K))
poly(ITERABLE, vec![ty_tp(tuple_t(vec![K.clone(), V.clone()]))])
| mono(GENERIC_DICT),
),
kw(KW_CONFLICT_RESOLVER, func2(V.clone(), V.clone(), V.clone())),
],
Some(pos(Obj)),
NoneType,
)
.quantify();

View file

@ -15,9 +15,9 @@ class Dict(dict):
return Dict({k: v for k, v in self.items() if k not in other})
# other: Iterable
def update(self, other, conflict_resolver=None):
def update(self, other={}, conflict_resolver=None, **kwargs):
if conflict_resolver is None:
super().update(other)
super().update(other, **kwargs)
elif isinstance(other, dict):
self.merge(other, conflict_resolver)
else:
@ -26,10 +26,15 @@ class Dict(dict):
self[k] = conflict_resolver(self[k], v)
else:
self[k] = v
self.merge(kwargs, conflict_resolver)
# other: Dict
def merge(self, other, conflict_resolver=None):
self.update(other, conflict_resolver)
for k, v in other.items():
if k in self and conflict_resolver is not None:
self[k] = conflict_resolver(self[k], v)
else:
self[k] = v
def insert(self, key, value):
self[key] = value

View file

@ -201,6 +201,8 @@ impl OwnershipChecker {
.find(|(k, _)| k.as_ref() == Some(kw_arg.keyword.inspect()))
{
self.check_expr(&kw_arg.expr, *ownership, false);
} else if let Some((_, ownership)) = args_owns.kw_var_params.as_ref() {
self.check_expr(&kw_arg.expr, *ownership, false);
} else {
todo!()
}

View file

@ -498,20 +498,19 @@ pub fn fn2_met(self_t: Type, l: Type, r: Type, return_t: Type) -> Type {
pub fn pr_met(
self_t: Type,
mut non_default_params: Vec<ParamTy>,
non_default_params: Vec<ParamTy>,
var_params: Option<ParamTy>,
default_params: Vec<ParamTy>,
return_t: Type,
) -> Type {
non_default_params.insert(0, ParamTy::kw(Str::ever("self"), self_t));
Type::Subr(SubrType::new(
SubrKind::Proc,
kw_var_pr_met(
self_t,
non_default_params,
var_params,
default_params,
None,
return_t,
))
)
}
pub fn pr0_met(self_t: Type, return_t: Type) -> Type {
@ -526,6 +525,25 @@ pub fn pr1_kw_met(self_t: Type, input: ParamTy, return_t: Type) -> Type {
pr_met(self_t, vec![input], None, vec![], return_t)
}
pub fn kw_var_pr_met(
self_t: Type,
mut non_default_params: Vec<ParamTy>,
var_params: Option<ParamTy>,
default_params: Vec<ParamTy>,
kw_var_params: Option<ParamTy>,
return_t: Type,
) -> Type {
non_default_params.insert(0, ParamTy::kw(Str::ever("self"), self_t));
Type::Subr(SubrType::new(
SubrKind::Proc,
non_default_params,
var_params,
default_params,
kw_var_params,
return_t,
))
}
/// function type with non-default parameters
#[inline]
pub fn nd_func(params: Vec<ParamTy>, var_params: Option<ParamTy>, ret: Type) -> Type {

View file

@ -20,3 +20,9 @@ Manager.
show_tasks! self, id: Int =
for! self.tasks, task =>
print! task[id]
sd as Dict! {Str: Int} = !{"a": 1}
sd.update!([("b", 2)])
sd.update! {"c": 3}
sd.update! d := 1
assert sd == {"a": 1, "b": 2, "c": 3, "d": 1}