Skip to content

Commit

Permalink
fix: dict type bug
Browse files Browse the repository at this point in the history
  • Loading branch information
mtshiba committed Oct 17, 2024
1 parent b238de3 commit 41537f2
Show file tree
Hide file tree
Showing 9 changed files with 208 additions and 70 deletions.
104 changes: 67 additions & 37 deletions crates/erg_compiler/context/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use erg_common::log;
use erg_common::set::Set;
use erg_common::shared::Shared;
use erg_common::traits::{Locational, Stream};
use erg_common::{dict, fmt_vec, fn_name, option_enum_unwrap, set, set_recursion_limit, Triple};
use erg_common::{dict, fmt_vec, fn_name, set, set_recursion_limit, Triple};
use erg_common::{ArcArray, Str};
use OpKind::*;

Expand Down Expand Up @@ -667,10 +667,52 @@ impl Context {
}

fn tp_eval_const_call(&self, call: &Call) -> Failable<TyParam> {
if let Expr::Accessor(acc) = call.obj.as_ref() {
match acc {
Accessor::Ident(ident) => {
let obj = self.rec_get_const_obj(ident.inspect()).ok_or_else(|| {
if let Some(attr) = &call.attr_name {
let obj = self
.eval_const_expr(&call.obj)
.map_err(|(val, errs)| (TyParam::value(val), errs))?;
let callee = self
.eval_attr(obj.clone(), attr)
.map_err(|err| (TyParam::Failure, err.into()))?;
let ValueObj::Subr(subr) = callee else {
return Err((
TyParam::Failure,
EvalError::type_mismatch_error(
self.cfg.input.clone(),
line!() as usize,
Location::concat(call.obj.as_ref(), attr),
self.caused_by(),
attr.inspect(),
None,
&mono("Subroutine"),
&callee.t(),
self.get_candidates(&callee.t()),
None,
)
.into(),
));
};
let (mut args, mut errs) = match self.eval_args(&call.args) {
Ok(args) => (args, EvalErrors::empty()),
Err((args, es)) => (args, es),
};
args.pos_args.insert(0, obj);
let tp = match self.call(subr.clone(), args, call.loc()) {
Ok(tp) => tp,
Err((tp, es)) => {
errs.extend(es);
tp
}
};
if errs.is_empty() {
Ok(tp)
} else {
Err((tp, errs))
}
} else {
match call.obj.as_ref() {
Expr::Accessor(Accessor::Ident(ident)) => {
let callee = self.rec_get_const_obj(ident.inspect()).ok_or_else(|| {
(
TyParam::Failure,
EvalError::not_comptime_fn_error(
Expand All @@ -685,31 +727,29 @@ impl Context {
)
})?;
// TODO: __call__
let subr = option_enum_unwrap!(obj, ValueObj::Subr)
.ok_or_else(|| {
(
TyParam::Failure,
EvalError::type_mismatch_error(
self.cfg.input.clone(),
line!() as usize,
ident.loc(),
self.caused_by(),
ident.inspect(),
None,
&mono("Subroutine"),
&obj.t(),
self.get_candidates(&obj.t()),
None,
)
.into(),
let ValueObj::Subr(subr) = callee else {
return Err((
TyParam::Failure,
EvalError::type_mismatch_error(
self.cfg.input.clone(),
line!() as usize,
ident.loc(),
self.caused_by(),
ident.inspect(),
None,
&mono("Subroutine"),
&callee.t(),
self.get_candidates(&callee.t()),
None,
)
})?
.clone();
.into(),
));
};
let (args, mut errs) = match self.eval_args(&call.args) {
Ok(args) => (args, EvalErrors::empty()),
Err((args, es)) => (args, es),
};
let tp = match self.call(subr, args, call.loc()) {
let tp = match self.call(subr.clone(), args, call.loc()) {
Ok(tp) => tp,
Err((tp, es)) => {
errs.extend(es);
Expand All @@ -723,7 +763,7 @@ impl Context {
}
}
// TODO: eval attr
Accessor::Attr(_attr) => Err((
Expr::Accessor(Accessor::Attr(_attr)) => Err((
TyParam::Failure,
EvalErrors::from(EvalError::not_const_expr(
self.cfg.input.clone(),
Expand All @@ -733,7 +773,7 @@ impl Context {
)),
)),
// TODO: eval type app
Accessor::TypeApp(_type_app) => Err((
Expr::Accessor(Accessor::TypeApp(_type_app)) => Err((
TyParam::Failure,
EvalErrors::from(EvalError::not_const_expr(
self.cfg.input.clone(),
Expand All @@ -753,16 +793,6 @@ impl Context {
)),
)),
}
} else {
Err((
TyParam::Failure,
EvalErrors::from(EvalError::not_const_expr(
self.cfg.input.clone(),
line!() as usize,
call.loc(),
self.caused_by(),
)),
))
}
}

Expand Down
24 changes: 18 additions & 6 deletions crates/erg_compiler/context/initialize/classes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1698,11 +1698,17 @@ impl Context {
t_singleton(unknown_len_list_t(T.clone())),
)
.quantify();
generic_list.register_builtin_erg_impl(
let list_constructor = ValueObj::Subr(ConstSubr::Builtin(BuiltinConstSubr::new(
FUNDAMENTAL_GETITEM,
list_constructor,
t_getitem.clone(),
None,
)));
generic_list.register_builtin_const(
FUNDAMENTAL_GETITEM,
t_getitem,
Immutable,
Visibility::BUILTIN_PUBLIC,
Some(t_getitem),
list_constructor,
);
}
let mut list_hash = Self::builtin_methods(Some(mono(HASH)), 1);
Expand Down Expand Up @@ -2249,11 +2255,17 @@ impl Context {
t_singleton(Type::from(dict! { T.clone() => U.clone() })),
)
.quantify();
generic_dict.register_builtin_erg_impl(
let dict_constructor = ValueObj::Subr(ConstSubr::Builtin(BuiltinConstSubr::new(
FUNDAMENTAL_GETITEM,
dict_constructor,
t_getitem.clone(),
None,
)));
generic_dict.register_builtin_const(
FUNDAMENTAL_GETITEM,
t_getitem,
Immutable,
Visibility::BUILTIN_PUBLIC,
Some(t_getitem),
dict_constructor,
);
}
let dic_t = poly(DICT, vec![D.clone()]);
Expand Down
43 changes: 42 additions & 1 deletion crates/erg_compiler/context/initialize/const_func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::context::eval::UndoableLinkedList;
use crate::context::initialize::closed_range;
use crate::context::Context;
use crate::feature_error;
use crate::ty::constructors::{and, mono, tuple_t, v_enum};
use crate::ty::constructors::{and, dict_mut, list_mut, mono, tuple_t, v_enum};
use crate::ty::value::{EvalValueError, EvalValueResult, GenTypeObj, TypeObj, ValueObj};
use crate::ty::{Field, TyParam, Type, ValueArgs};
use erg_common::error::{ErrorCore, ErrorKind, Location, SubMessage};
Expand Down Expand Up @@ -483,6 +483,47 @@ pub(crate) fn dict_diff(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<T
Ok(ValueObj::Dict(slf.diff(&other)).into())
}

pub(crate) fn list_constructor(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<TyParam> {
let _cls = args
.remove_left_or_key("Cls")
.ok_or_else(|| not_passed("Cls"))?;
let elem = args
.remove_left_or_key("elem")
.ok_or_else(|| not_passed("elem"))?;
let Ok(elem_t) = ctx.convert_value_into_type(elem.clone()) else {
return Err(type_mismatch("Type", elem, "elem"));
};
let len = args
.remove_left_or_key("len")
.map(TyParam::value)
.unwrap_or(TyParam::erased(Type::Nat));
Ok(ValueObj::builtin_class(list_mut(elem_t, len)).into())
}

pub(crate) fn dict_constructor(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<TyParam> {
let _cls = args
.remove_left_or_key("Cls")
.ok_or_else(|| not_passed("Cls"))?;
let key_value = args
.remove_left_or_key("key_value")
.ok_or_else(|| not_passed("key_value"))?;
let (key_t, value_t) = match key_value {
ValueObj::Tuple(ts) | ValueObj::List(ts) => {
let key = ts.first().ok_or_else(|| not_passed("key"))?;
let value = ts.get(1).ok_or_else(|| not_passed("value"))?;
let Ok(key_t) = ctx.convert_value_into_type(key.clone()) else {
return Err(type_mismatch("Type", key, "key"));
};
let Ok(value_t) = ctx.convert_value_into_type(value.clone()) else {
return Err(type_mismatch("Type", value, "value"));
};
(key_t, value_t)
}
_ => return Err(type_mismatch("Tuple", key_value, "key_value")),
};
Ok(ValueObj::builtin_class(dict_mut(dict! { key_t => value_t }.into())).into())
}

/// `[Int, Str].union() == Int or Str`
pub(crate) fn list_union(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<TyParam> {
let slf = args
Expand Down
1 change: 1 addition & 0 deletions crates/erg_compiler/context/initialize/procs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ impl Context {
None,
NoneType,
)
.quantify()
} else {
nd_proc(
vec![
Expand Down
59 changes: 55 additions & 4 deletions crates/erg_compiler/context/unify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use erg_common::fresh::FRESH_GEN;
use erg_common::traits::Locational;
use erg_common::Str;
#[allow(unused_imports)]
use erg_common::{fmt_vec, fn_name, log};
use erg_common::{dict, fmt_vec, fn_name, log};

use crate::context::eval::Substituter;
use crate::context::instantiate::TyVarCache;
Expand Down Expand Up @@ -2075,6 +2075,47 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
return Some(self.ctx.union_refinement(lhs, rhs).into());
}
}
(
Poly {
name: ln,
params: lps,
},
Poly {
name: rn,
params: rps,
},
) if ln == rn && (lhs.is_dict() || lhs.is_dict_mut()) => {
let Ok(ValueObj::Dict(l_dict)) = self.ctx.convert_tp_into_value(lps[0].clone())
else {
return None;
};
let Ok(ValueObj::Dict(r_dict)) = self.ctx.convert_tp_into_value(rps[0].clone())
else {
return None;
};
if l_dict.len() == 1 && r_dict.len() == 1 {
let l_key = self
.ctx
.convert_value_into_type(l_dict.keys().next()?.clone())
.ok()?;
let r_key = self
.ctx
.convert_value_into_type(r_dict.keys().next()?.clone())
.ok()?;
let l_value = self
.ctx
.convert_value_into_type(l_dict.values().next()?.clone())
.ok()?;
let r_value = self
.ctx
.convert_value_into_type(r_dict.values().next()?.clone())
.ok()?;
let unified_key = self.unify(&l_key, &r_key)?;
let unified_value = self.unify(&l_value, &r_value)?;
let unified_dict = TyParam::t(dict! { unified_key => unified_value }.into());
return Some(poly(ln.clone(), vec![unified_dict]));
}
}
_ => {}
}
let l_sups = self.ctx.get_super_classes(lhs)?;
Expand All @@ -2092,16 +2133,26 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
continue;
};
let mut tv_cache = TyVarCache::new(self.ctx.level, self.ctx);
let l_sup = self.ctx.detach(l_sup.clone(), &mut tv_cache);
let detached_l_sup = self.ctx.detach(l_sup.clone(), &mut tv_cache);
drop(l_substituter);
let Ok(r_substituter) = Substituter::substitute_typarams(self.ctx, &r_sup, rhs)
else {
continue;
};
let mut tv_cache = TyVarCache::new(self.ctx.level, self.ctx);
let r_sup = self.ctx.detach(r_sup.clone(), &mut tv_cache);
let detached_r_sup = self.ctx.detach(r_sup.clone(), &mut tv_cache);
drop(r_substituter);
if let Some(t) = self.ctx.max(&l_sup, &r_sup).either() {
if let Some(t) = self.ctx.max(&detached_l_sup, &detached_r_sup).either() {
for l_tp in l_sup.typarams() {
if l_tp.has_qvar() && t.contains_tp(&l_tp) {
return None;
}
}
for r_tp in r_sup.typarams() {
if r_tp.has_qvar() && t.contains_tp(&r_tp) {
return None;
}
}
return Some(t.clone());
}
}
Expand Down
Loading

0 comments on commit 41537f2

Please sign in to comment.