chore: add TyParam::proj_call

This commit is contained in:
Shunsuke Shibayama 2023-07-30 12:44:17 +09:00
parent 664f265716
commit 1ea2c74aaa
15 changed files with 408 additions and 191 deletions

View file

@ -426,7 +426,7 @@ impl Context {
},
_,
) => {
if let Ok(evaled) = self.eval_proj_call(
if let Ok(evaled) = self.eval_proj_call_t(
*l.clone(),
attr_name.clone(),
args.clone(),
@ -447,7 +447,7 @@ impl Context {
args,
},
) => {
if let Ok(evaled) = self.eval_proj_call(
if let Ok(evaled) = self.eval_proj_call_t(
*r.clone(),
attr_name.clone(),
args.clone(),

View file

@ -1050,6 +1050,9 @@ impl Context {
})?;
Ok(TyParam::Value(ValueObj::Type(t)))
}
TyParam::ProjCall { obj, attr, args } => self
.eval_proj_call(*obj, attr, args, &())
.map(TyParam::value),
TyParam::Value(_) => Ok(p.clone()),
_other => feature_error!(self, Location::Unknown, "???"),
}
@ -1145,7 +1148,7 @@ impl Context {
attr_name,
args,
} => self
.eval_proj_call(*lhs, attr_name, args, level, t_loc)
.eval_proj_call_t(*lhs, attr_name, args, level, t_loc)
.map_err(|errs| (Failure, errs)),
Type::Ref(l) => match self.eval_t_params(*l, level, t_loc) {
Ok(t) => Ok(ref_(t)),
@ -1405,6 +1408,7 @@ impl Context {
let lhs = self.convert_tp_into_type(*obj)?;
Ok(lhs.proj(attr))
}
TyParam::ProjCall { obj, attr, args } => Ok(proj_call(*obj, attr, args)),
// TyParam::Erased(_t) => Ok(Type::Obj),
TyParam::Value(v) => self.convert_value_into_type(v).map_err(TyParam::Value),
// TODO: Dict, Set
@ -1412,8 +1416,12 @@ impl Context {
}
}
#[allow(clippy::only_used_in_recursion)]
pub(crate) fn convert_tp_into_value(&self, tp: TyParam) -> Result<ValueObj, TyParam> {
match tp {
TyParam::FreeVar(fv) if fv.is_linked() => {
self.convert_tp_into_value(fv.crack().clone())
}
TyParam::Value(v) => Ok(v),
other => Err(other),
}
@ -1421,6 +1429,9 @@ impl Context {
pub(crate) fn convert_singular_type_into_value(&self, typ: Type) -> Result<ValueObj, Type> {
match typ {
Type::FreeVar(fv) if fv.is_linked() => {
self.convert_singular_type_into_value(fv.crack().clone())
}
Type::Refinement(ref refine) => {
if let Predicate::Equal { rhs, .. } = refine.pred.as_ref() {
self.convert_tp_into_value(rhs.clone()).map_err(|_| typ)
@ -1537,6 +1548,10 @@ impl Context {
fn _convert_type_to_dict_type(&self, ty: Type) -> Result<Dict<Type, Type>, ()> {
match ty {
Type::FreeVar(fv) if fv.is_linked() => {
self._convert_type_to_dict_type(fv.crack().clone())
}
Type::Refinement(refine) => self._convert_type_to_dict_type(*refine.t),
Type::Poly { name, params } if &name[..] == "Dict" => {
let dict = Dict::try_from(params[0].clone())?;
let mut new_dict = dict! {};
@ -1551,14 +1566,20 @@ impl Context {
}
}
fn convert_type_to_array(&self, ty: Type) -> Result<Vec<ValueObj>, Type> {
pub(crate) fn convert_type_to_array(&self, ty: Type) -> Result<Vec<ValueObj>, Type> {
match ty {
Type::FreeVar(fv) if fv.is_linked() => self.convert_type_to_array(fv.crack().clone()),
Type::Refinement(refine) => self.convert_type_to_array(*refine.t),
Type::Poly { name, params } if &name[..] == "Array" || &name[..] == "Array!" => {
let Ok(t) = self.convert_tp_into_type(params[0].clone()) else {
log!(err "cannot convert to type: {}", params[0]);
return Err(poly(name, params));
};
let TyParam::Value(ValueObj::Nat(len)) = params[1] else { unreachable!() };
Ok(vec![ValueObj::builtin_type(t); len as usize])
let Ok(len) = usize::try_from(&params[1]) else {
log!(err "cannot convert to usize: {}", params[1]);
return Err(poly(name, params));
};
Ok(vec![ValueObj::builtin_type(t); len])
}
_ => Err(ty),
}
@ -1848,7 +1869,7 @@ impl Context {
lhs: TyParam,
args: Vec<TyParam>,
t_loc: &impl Locational,
) -> EvalResult<Type> {
) -> EvalResult<ValueObj> {
if let ValueObj::Subr(subr) = obj {
let mut pos_args = vec![];
if subr.sig_t().is_method() {
@ -1872,13 +1893,107 @@ impl Context {
}
}
let args = ValueArgs::new(pos_args, dict! {});
let t = self.call(subr, args, t_loc.loc())?;
let t = self
.convert_value_into_type(t)
.unwrap_or_else(|value| todo!("Type::try_from {value}"));
Ok(t)
let v = self.call(subr, args, t_loc.loc())?;
Ok(v)
} else {
feature_error!(self, t_loc.loc(), "??")
feature_error!(self, t_loc.loc(), "do_proj_call: ??")
}
}
fn do_proj_call_t(
&self,
obj: ValueObj,
lhs: TyParam,
args: Vec<TyParam>,
t_loc: &impl Locational,
) -> EvalResult<Type> {
let v = self.do_proj_call(obj, lhs, args, t_loc)?;
self.convert_value_into_type(v).map_err(|e| {
EvalError::feature_error(
self.cfg.input.clone(),
t_loc.loc(),
&format!("converting {e} to a type"),
self.caused_by(),
)
.into()
})
}
pub(crate) fn eval_proj_call_t(
&self,
lhs: TyParam,
attr_name: Str,
args: Vec<TyParam>,
level: usize,
t_loc: &impl Locational,
) -> EvalResult<Type> {
let t = self.get_tp_t(&lhs)?;
for ty_ctx in self.get_nominal_super_type_ctxs(&t).ok_or_else(|| {
EvalError::type_not_found(
self.cfg.input.clone(),
line!() as usize,
t_loc.loc(),
self.caused_by(),
&t,
)
})? {
if let Ok(obj) = ty_ctx.get_const_local(&Token::symbol(&attr_name), &self.name) {
return self.do_proj_call_t(obj, lhs, args, t_loc);
}
for (_class, methods) in ty_ctx.methods_list.iter() {
if let Ok(obj) = methods.get_const_local(&Token::symbol(&attr_name), &self.name) {
return self.do_proj_call_t(obj, lhs, args, t_loc);
}
}
}
if let TyParam::FreeVar(fv) = &lhs {
if let Some((sub, sup)) = fv.get_subsup() {
if self.is_trait(&sup) && !self.trait_impl_exists(&sub, &sup) {
// to prevent double error reporting
lhs.link(&TyParam::t(Never));
let sub = if cfg!(feature = "debug") {
sub
} else {
self.readable_type(sub)
};
let sup = if cfg!(feature = "debug") {
sup
} else {
self.readable_type(sup)
};
return Err(EvalErrors::from(EvalError::no_trait_impl_error(
self.cfg.input.clone(),
line!() as usize,
&sub,
&sup,
t_loc.loc(),
self.caused_by(),
self.get_simple_type_mismatch_hint(&sup, &sub),
)));
}
}
}
// if the target can't be found in the supertype, the type will be dereferenced.
// In many cases, it is still better to determine the type variable than if the target is not found.
let coerced = self.coerce_tp(lhs.clone(), t_loc)?;
if lhs != coerced {
let proj = proj_call(coerced, attr_name, args);
self.eval_t_params(proj, level, t_loc)
.map(|t| {
lhs.coerce();
t
})
.map_err(|(_, errs)| errs)
} else {
let proj = proj_call(lhs, attr_name, args);
Err(EvalErrors::from(EvalError::no_candidate_error(
self.cfg.input.clone(),
line!() as usize,
&proj,
t_loc.loc(),
self.caused_by(),
self.get_no_candidate_hint(&proj),
)))
}
}
@ -1887,9 +2002,8 @@ impl Context {
lhs: TyParam,
attr_name: Str,
args: Vec<TyParam>,
level: usize,
t_loc: &impl Locational,
) -> EvalResult<Type> {
) -> EvalResult<ValueObj> {
let t = self.get_tp_t(&lhs)?;
for ty_ctx in self.get_nominal_super_type_ctxs(&t).ok_or_else(|| {
EvalError::type_not_found(
@ -1940,13 +2054,7 @@ impl Context {
// In many cases, it is still better to determine the type variable than if the target is not found.
let coerced = self.coerce_tp(lhs.clone(), t_loc)?;
if lhs != coerced {
let proj = proj_call(coerced, attr_name, args);
self.eval_t_params(proj, level, t_loc)
.map(|t| {
lhs.coerce();
t
})
.map_err(|(_, errs)| errs)
self.eval_proj_call(coerced, attr_name, args, t_loc)
} else {
let proj = proj_call(lhs, attr_name, args);
Err(EvalErrors::from(EvalError::no_candidate_error(
@ -2087,6 +2195,11 @@ impl Context {
)
}
},
TyParam::ProjCall { obj, attr, args } => {
let v = self.eval_proj_call(*obj, attr, args, &())?;
log!(err "{v}");
Ok(v_enum(set![v]))
}
other => feature_error!(
self,
Location::Unknown,

View file

@ -693,7 +693,7 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
}
let proj = self
.ctx
.eval_proj_call(lhs, attr_name, new_args, self.ctx.level, self.loc)
.eval_proj_call_t(lhs, attr_name, new_args, self.ctx.level, self.loc)
.unwrap_or(Failure);
Ok(proj)
}

View file

@ -1262,7 +1262,13 @@ impl Context {
.register_marker_trait(self, poly(INDEXABLE, vec![ty_tp(input), ty_tp(T.clone())]))
.unwrap();
array_
.register_marker_trait(self, poly(SHAPE, vec![TyParam::Array(vec![N.clone()])]))
.register_marker_trait(
self,
poly(
SHAPE,
vec![ty_tp(arr_t.clone()).proj_call(FUNC_SHAPE.into(), vec![])],
),
)
.unwrap();
let mut array_sized = Self::builtin_methods(Some(mono(SIZED)), 2);
array_sized.register_builtin_erg_impl(
@ -1275,12 +1281,25 @@ impl Context {
// union: (self: [Type; _]) -> Type
let array_union_t = fn0_met(array_t(Type, TyParam::erased(Nat)), Type).quantify();
let union = ValueObj::Subr(ConstSubr::Builtin(BuiltinConstSubr::new(
UNION_FUNC,
FUNC_UNION,
array_union,
array_union_t,
None,
)));
array_.register_builtin_const(UNION_FUNC, Visibility::BUILTIN_PUBLIC, union);
array_.register_builtin_const(FUNC_UNION, Visibility::BUILTIN_PUBLIC, union);
// shape: (self: [Type; _]) -> [Nat; _]
let array_shape_t = fn0_met(
array_t(Type, TyParam::erased(Nat)),
unknown_len_array_t(Nat),
)
.quantify();
let shape = ValueObj::Subr(ConstSubr::Builtin(BuiltinConstSubr::new(
FUNC_SHAPE,
array_shape,
array_shape_t,
None,
)));
array_.register_builtin_const(FUNC_SHAPE, Visibility::BUILTIN_PUBLIC, shape);
let mut array_eq = Self::builtin_methods(Some(mono(EQ)), 2);
array_eq.register_builtin_erg_impl(
OP_EQ,
@ -1598,7 +1617,7 @@ impl Context {
// __Tuple_getitem__: (self: Tuple(Ts), _: {N}) -> Ts[N]
let input_t = tp_enum(Nat, set! {N.clone()});
let return_t = proj_call(Ts.clone(), FUNDAMENTAL_GETITEM, vec![N.clone()]);
let union_t = proj_call(Ts.clone(), UNION_FUNC, vec![]);
let union_t = proj_call(Ts.clone(), FUNC_UNION, vec![]);
let tuple_getitem_t =
fn1_met(_tuple_t.clone(), input_t.clone(), return_t.clone()).quantify();
tuple_.register_builtin_py_impl(
@ -1623,13 +1642,13 @@ impl Context {
let mut tuple_iterable = Self::builtin_methods(
Some(poly(
ITERABLE,
vec![ty_tp(proj_call(Ts.clone(), UNION_FUNC, vec![]))],
vec![ty_tp(proj_call(Ts.clone(), FUNC_UNION, vec![]))],
)),
2,
);
let tuple_iterator = poly(
TUPLE_ITERATOR,
vec![ty_tp(proj_call(Ts, UNION_FUNC, vec![]))],
vec![ty_tp(proj_call(Ts, FUNC_UNION, vec![]))],
);
// Tuple(Ts) -> TupleIterator(Ts.union())
let t = fn0_met(_tuple_t.clone(), tuple_iterator.clone()).quantify();
@ -1791,7 +1810,7 @@ impl Context {
Some(SYMMETRIC_DIFFERENCE),
3,
);
frozenset.register_py_builtin(UNION_FUNC, bin_t, Some(UNION_FUNC), 3);
frozenset.register_py_builtin(FUNC_UNION, bin_t, Some(FUNC_UNION), 3);
let memview_t = mono(MEMORYVIEW);
let mut memoryview = Self::builtin_mono_class(MEMORYVIEW, 2);
memoryview.register_superclass(Obj, &obj);

View file

@ -1,7 +1,10 @@
use std::fmt::Display;
use std::mem;
use erg_common::dict::Dict;
use erg_common::enum_unwrap;
#[allow(unused_imports)]
use erg_common::log;
use erg_common::{enum_unwrap, ArcArray};
use crate::context::Context;
use crate::feature_error;
@ -16,13 +19,42 @@ use super::{DICT_ITEMS, DICT_KEYS, DICT_VALUES};
const ERR: Color = THEME.colors.error;
const WARN: Color = THEME.colors.warning;
const SUP_ERR: StyledStr = StyledStr::new("Super", Some(ERR), None);
const SUP_WARN: StyledStr = StyledStr::new("Super", Some(WARN), None);
const CLASS_ERR: StyledStr = StyledStr::new("Class", Some(ERR), None);
const REQ_ERR: StyledStr = StyledStr::new("Requirement", Some(ERR), None);
const REQ_WARN: StyledStr = StyledStr::new("Requirement", Some(WARN), None);
const BASE_ERR: StyledStr = StyledStr::new("Base", Some(ERR), None);
const BASE_WARN: StyledStr = StyledStr::new("Base", Some(WARN), None);
fn not_passed(t: impl Display) -> EvalValueError {
let text = t.to_string();
let param = StyledStr::new(&text, Some(ERR), None);
ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
format!("{param} is not passed"),
line!() as usize,
ErrorKind::KeyError,
Location::Unknown,
)
.into()
}
fn no_key(slf: impl Display, key: impl Display) -> EvalValueError {
ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
format!("{slf} has no key {key}"),
line!() as usize,
ErrorKind::KeyError,
Location::Unknown,
)
.into()
}
fn type_mismatch(expected: impl Display, got: impl Display, param: &str) -> EvalValueError {
let got = StyledString::new(format!("{got}"), Some(ERR), None);
let param = StyledStr::new(param, Some(WARN), None);
ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
format!("non-{expected} object {got} is passed to {param}"),
line!() as usize,
ErrorKind::TypeError,
Location::Unknown,
)
.into()
}
/// Base := Type or NoneType, Impl := Type -> ClassType
pub(crate) fn class_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
@ -35,15 +67,7 @@ pub(crate) fn class_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<
if let Some(base) = value.as_type(ctx) {
Ok(ValueObj::gen_t(GenTypeObj::class(t, Some(base), impls)))
} else {
let base = StyledString::new(format!("{value}"), Some(ERR), None);
Err(ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
format!("non-type object {base} is passed to {BASE_WARN}",),
line!() as usize,
ErrorKind::TypeError,
Location::Unknown,
)
.into())
Err(type_mismatch("type", value, "Base"))
}
}
None => Ok(ValueObj::gen_t(GenTypeObj::class(t, None, impls))),
@ -52,27 +76,11 @@ pub(crate) fn class_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<
/// Super: ClassType, Impl := Type, Additional := Type -> ClassType
pub(crate) fn inherit_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
let sup = args.remove_left_or_key("Super").ok_or_else(|| {
let sup = StyledStr::new("Super", Some(ERR), None);
ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
format!("{sup} is not passed"),
line!() as usize,
ErrorKind::KeyError,
Location::Unknown,
)
})?;
let sup = args
.remove_left_or_key("Super")
.ok_or_else(|| not_passed("Super"))?;
let Some(sup) = sup.as_type(ctx) else {
let sup_ty = StyledString::new(format!("{sup}"), Some(ERR), None);
return Err(ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
format!(
"non-class object {sup_ty} is passed to {SUP_WARN}",
),
line!() as usize,
ErrorKind::TypeError,
Location::Unknown,
).into());
return Err(type_mismatch("class", sup, "Super"));
};
let impls = args.remove_left_or_key("Impl");
let impls = impls.map(|v| v.as_type(ctx).unwrap());
@ -87,15 +95,9 @@ pub(crate) fn inherit_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResul
/// Class: ClassType -> ClassType (with `InheritableType`)
/// This function is used by the compiler to mark a class as inheritable and does nothing in terms of actual operation.
pub(crate) fn inheritable_func(mut args: ValueArgs, _ctx: &Context) -> EvalValueResult<ValueObj> {
let class = args.remove_left_or_key("Class").ok_or_else(|| {
ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
format!("{CLASS_ERR} is not passed"),
line!() as usize,
ErrorKind::KeyError,
Location::Unknown,
)
})?;
let class = args
.remove_left_or_key("Class")
.ok_or_else(|| not_passed("Class"))?;
match class {
ValueObj::Type(TypeObj::Generated(mut gen)) => {
if let Some(typ) = gen.impls_mut() {
@ -124,26 +126,11 @@ pub(crate) fn inheritable_func(mut args: ValueArgs, _ctx: &Context) -> EvalValue
/// Base: Type, Impl := Type -> TraitType
pub(crate) fn trait_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
let req = args.remove_left_or_key("Requirement").ok_or_else(|| {
ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
format!("{REQ_ERR} is not passed"),
line!() as usize,
ErrorKind::KeyError,
Location::Unknown,
)
})?;
let req = args
.remove_left_or_key("Requirement")
.ok_or_else(|| not_passed("Requirement"))?;
let Some(req) = req.as_type(ctx) else {
let req = StyledString::new(format!("{req}"), Some(ERR), None);
return Err(ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
format!(
"non-type object {req} is passed to {REQ_WARN}",
),
line!() as usize,
ErrorKind::TypeError,
Location::Unknown,
).into());
return Err(type_mismatch("type", req, "Requirement"));
};
let impls = args.remove_left_or_key("Impl");
let impls = impls.map(|v| v.as_type(ctx).unwrap());
@ -153,26 +140,11 @@ pub(crate) fn trait_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<
/// Base: Type, Impl := Type -> Patch
pub(crate) fn patch_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
let base = args.remove_left_or_key("Base").ok_or_else(|| {
ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
format!("{BASE_ERR} is not passed"),
line!() as usize,
ErrorKind::KeyError,
Location::Unknown,
)
})?;
let base = args
.remove_left_or_key("Base")
.ok_or_else(|| not_passed("Base"))?;
let Some(base) = base.as_type(ctx) else {
let base = StyledString::new(format!("{base}"), Some(ERR), None);
return Err(ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
format!(
"non-type object {base} is passed to {BASE_WARN}",
),
line!() as usize,
ErrorKind::TypeError,
Location::Unknown,
).into());
return Err(type_mismatch("type", base, "Base"));
};
let impls = args.remove_left_or_key("Impl");
let impls = impls.map(|v| v.as_type(ctx).unwrap());
@ -182,26 +154,11 @@ pub(crate) fn patch_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<
/// Super: TraitType, Impl := Type, Additional := Type -> TraitType
pub(crate) fn subsume_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
let sup = args.remove_left_or_key("Super").ok_or_else(|| {
ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
format!("{SUP_ERR} is not passed"),
line!() as usize,
ErrorKind::KeyError,
Location::Unknown,
)
})?;
let sup = args
.remove_left_or_key("Super")
.ok_or_else(|| not_passed("Super"))?;
let Some(sup) = sup.as_type(ctx) else {
let sup = StyledString::new(format!("{sup}"), Some(ERR), None);
return Err(ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
format!(
"non-trait object {sup} is passed to {SUP_WARN}",
),
line!() as usize,
ErrorKind::TypeError,
Location::Unknown,
).into());
return Err(type_mismatch("trait", sup, "Super"));
};
let impls = args.remove_left_or_key("Impl");
let impls = impls.map(|v| v.as_type(ctx).unwrap());
@ -214,36 +171,27 @@ pub(crate) fn subsume_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResul
}
pub(crate) fn structural_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
let type_ = args.remove_left_or_key("Type").ok_or_else(|| {
ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
format!("{BASE_ERR} is not passed"),
line!() as usize,
ErrorKind::KeyError,
Location::Unknown,
)
})?;
let type_ = args
.remove_left_or_key("Type")
.ok_or_else(|| not_passed("Type"))?;
let Some(base) = type_.as_type(ctx) else {
let type_ = StyledString::new(format!("{type_}"), Some(ERR), None);
return Err(ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
format!(
"non-type object {type_} is passed to {BASE_WARN}",
),
line!() as usize,
ErrorKind::TypeError,
Location::Unknown,
).into());
return Err(type_mismatch("type", type_, "Type"));
};
let t = base.typ().clone().structuralize();
Ok(ValueObj::gen_t(GenTypeObj::structural(t, base)))
}
pub(crate) fn __array_getitem__(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
let slf = args
.remove_left_or_key("Self")
.ok_or_else(|| not_passed("Self"))?;
let slf = ctx
.convert_value_into_array(args.remove_left_or_key("Self").unwrap())
.convert_value_into_array(slf)
.unwrap_or_else(|err| panic!("{err}, {args}"));
let index = enum_unwrap!(args.remove_left_or_key("Index").unwrap(), ValueObj::Nat);
let index = args
.remove_left_or_key("Index")
.ok_or_else(|| not_passed("Index"))?;
let index = enum_unwrap!(index, ValueObj::Nat);
if let Some(v) = slf.get(index as usize) {
Ok(v.clone())
} else {
@ -328,9 +276,13 @@ pub(crate) fn sub_tpdict_get<'d>(
}
pub(crate) fn __dict_getitem__(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
let slf = args.remove_left_or_key("Self").unwrap();
let slf = args
.remove_left_or_key("Self")
.ok_or_else(|| not_passed("Self"))?;
let slf = enum_unwrap!(slf, ValueObj::Dict);
let index = args.remove_left_or_key("Index").unwrap();
let index = args
.remove_left_or_key("Index")
.ok_or_else(|| not_passed("Index"))?;
if let Some(v) = slf.get(&index).or_else(|| sub_vdict_get(&slf, &index, ctx)) {
Ok(v.clone())
} else {
@ -340,20 +292,15 @@ pub(crate) fn __dict_getitem__(mut args: ValueArgs, ctx: &Context) -> EvalValueR
} else {
index
};
Err(ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
format!("{slf} has no key {index}"),
line!() as usize,
ErrorKind::IndexError,
Location::Unknown,
)
.into())
Err(no_key(slf, index))
}
}
/// `{Str: Int, Int: Float}.keys() == DictKeys(Str or Int)`
pub(crate) fn dict_keys(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
let slf = args.remove_left_or_key("Self").unwrap();
let slf = args
.remove_left_or_key("Self")
.ok_or_else(|| not_passed("Self"))?;
let slf = enum_unwrap!(slf, ValueObj::Dict);
let slf = slf
.into_iter()
@ -373,7 +320,9 @@ pub(crate) fn dict_keys(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<V
/// `{Str: Int, Int: Float}.values() == DictValues(Int or Float)`
pub(crate) fn dict_values(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
let slf = args.remove_left_or_key("Self").unwrap();
let slf = args
.remove_left_or_key("Self")
.ok_or_else(|| not_passed("Self"))?;
let slf = enum_unwrap!(slf, ValueObj::Dict);
let slf = slf
.into_iter()
@ -393,7 +342,9 @@ pub(crate) fn dict_values(mut args: ValueArgs, ctx: &Context) -> EvalValueResult
/// `{Str: Int, Int: Float}.items() == DictItems((Str, Int) or (Int, Float))`
pub(crate) fn dict_items(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
let slf = args.remove_left_or_key("Self").unwrap();
let slf = args
.remove_left_or_key("Self")
.ok_or_else(|| not_passed("Self"))?;
let slf = enum_unwrap!(slf, ValueObj::Dict);
let slf = slf
.into_iter()
@ -413,7 +364,9 @@ pub(crate) fn dict_items(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<
/// `[Int, Str].union() == Int or Str`
pub(crate) fn array_union(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
let slf = args.remove_left_or_key("Self").unwrap();
let slf = args
.remove_left_or_key("Self")
.ok_or_else(|| not_passed("Self"))?;
let slf = enum_unwrap!(slf, ValueObj::Array);
let slf = slf
.iter()
@ -425,15 +378,70 @@ pub(crate) fn array_union(mut args: ValueArgs, ctx: &Context) -> EvalValueResult
Ok(ValueObj::builtin_type(union))
}
// TODO
fn _arr_shape(arr: ArcArray<ValueObj>, ctx: &Context) -> Result<Vec<ValueObj>, String> {
let mut shape = vec![];
let mut arr = arr;
loop {
shape.push(ValueObj::from(arr.len()));
match arr.get(0) {
Some(ValueObj::Array(arr_)) => {
arr = arr_.clone();
}
Some(ValueObj::Type(t)) => {
let Ok(arr_) = ctx.convert_type_to_array(t.typ().clone()) else {
break;
};
arr = arr_.into();
}
_ => {
break;
}
}
}
Ok(shape)
}
/// ```erg
/// Array(Int, 2).shape() == [2,]
/// Array(Array(Int, 2), N).shape() == [N, 2]
/// [1, 2].shape() == [2,]
/// [[1, 2], [3, 4], [5, 6]].shape() == [3, 2]
/// ```
pub(crate) fn array_shape(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
let arr = args
.remove_left_or_key("Self")
.ok_or_else(|| not_passed("Self"))?;
let arr = match arr {
ValueObj::Array(arr) => arr,
ValueObj::Type(t) => ctx
.convert_type_to_array(t.into_typ())
.map_err(|arr| type_mismatch("array", arr, "Self"))?
.into(),
_ => {
return Err(type_mismatch("array", arr, "Self"));
}
};
let res = _arr_shape(arr, ctx).unwrap();
let arr = ValueObj::Array(ArcArray::from(res));
Ok(arr)
}
pub(crate) fn __range_getitem__(mut args: ValueArgs, _ctx: &Context) -> EvalValueResult<ValueObj> {
let (_name, fields) = enum_unwrap!(
args.remove_left_or_key("Self").unwrap(),
args.remove_left_or_key("Self")
.ok_or_else(|| not_passed("Self"))?,
ValueObj::DataClass { name, fields }
);
let index = enum_unwrap!(args.remove_left_or_key("Index").unwrap(), ValueObj::Nat);
let start = fields.get("start").unwrap();
let index = args
.remove_left_or_key("Index")
.ok_or_else(|| not_passed("Index"))?;
let index = enum_unwrap!(index, ValueObj::Nat);
let start = fields
.get("start")
.ok_or_else(|| no_key(&fields, "start"))?;
let start = *enum_unwrap!(start, ValueObj::Nat);
let end = fields.get("end").unwrap();
let end = fields.get("end").ok_or_else(|| no_key(&fields, "end"))?;
let end = *enum_unwrap!(end, ValueObj::Nat);
// FIXME <= if inclusive
if start + index < end {

View file

@ -245,7 +245,8 @@ const ISSUBSET: &str = "issubset";
const ISSUPERSET: &str = "issuperset";
const SYMMETRIC_DIFFERENCE: &str = "symmetric_difference";
const MEMORYVIEW: &str = "MemoryView";
const UNION_FUNC: &str = "union";
const FUNC_UNION: &str = "union";
const FUNC_SHAPE: &str = "shape";
const FUNC_INC: &str = "inc";
const PROC_INC: &str = "inc!";
const FUNC_DEC: &str = "dec";

View file

@ -347,7 +347,7 @@ impl Context {
Some(FUNDAMENTAL_EXIT),
);
/* Shape */
let S = mono_q(TY_S, instanceof(unknown_len_array_t(Nat)));
let S = mono_q_tp(TY_S, instanceof(unknown_len_array_t(Nat)));
let params = vec![PS::named_nd("S", unknown_len_array_t(Nat))];
let shape = Self::builtin_poly_trait(SHAPE, params.clone(), 2);
/* Num */
@ -545,7 +545,7 @@ impl Context {
Const,
None,
);
self.register_builtin_type(poly(SHAPE, vec![ty_tp(S)]), shape, vis.clone(), Const, None);
self.register_builtin_type(poly(SHAPE, vec![S]), shape, vis.clone(), Const, None);
self.register_builtin_type(poly(ADD, ty_params.clone()), add, vis.clone(), Const, None);
self.register_builtin_type(poly(SUB, ty_params.clone()), sub, vis.clone(), Const, None);
self.register_builtin_type(poly(MUL, ty_params.clone()), mul, vis.clone(), Const, None);

View file

@ -2390,7 +2390,7 @@ impl Context {
attr_name,
args,
} => {
if let Ok(typ) = self.eval_proj_call(
if let Ok(typ) = self.eval_proj_call_t(
*lhs.clone(),
attr_name.clone(),
args.clone(),

View file

@ -380,6 +380,18 @@ impl Context {
}
Ok(TyParam::app(name, new_args))
}
TyParam::ProjCall { obj, attr, args } => {
let obj = self.instantiate_tp(*obj, tmp_tv_cache, loc)?;
let mut new_args = Vec::with_capacity(args.len());
for arg in args {
new_args.push(self.instantiate_tp(arg, tmp_tv_cache, loc)?);
}
Ok(TyParam::proj_call(obj, attr, new_args))
}
TyParam::Proj { obj, attr } => {
let obj = self.instantiate_tp(*obj, tmp_tv_cache, loc)?;
Ok(TyParam::proj(obj, attr))
}
TyParam::Type(t) => {
let t = self.instantiate_t_inner(*t, tmp_tv_cache, loc)?;
Ok(TyParam::t(t))

View file

@ -1308,7 +1308,10 @@ impl Context {
.typ()
.typarams()
.into_iter()
.map(|tp| ParamSpec::t_nd(tp.qual_name().unwrap_or(Str::ever("_"))))
.map(|tp| {
let name = tp.qual_name().unwrap_or(Str::ever("_"));
ParamSpec::named_nd(name, self.get_tp_t(&tp).unwrap_or(Type::Obj))
})
.collect();
let mut ctx = Self::poly_class(
gen.typ().qual_name(),

View file

@ -379,9 +379,6 @@ impl Context {
self.sub_unify_tp(lhs, lhs2, _variance, loc, allow_divergence)?;
self.sub_unify_tp(rhs, rhs2, _variance, loc, allow_divergence)
}
(TyParam::Lambda(_l), TyParam::Lambda(_r)) => {
todo!("{_l}/{_r}")
}
(sub, TyParam::Erased(t)) => {
let sub_t = self.get_tp_t(sub)?;
if self.subtype_of(&sub_t, t) {
@ -463,6 +460,24 @@ impl Context {
}
Ok(())
}
(
TyParam::ProjCall { obj, attr, args },
TyParam::ProjCall {
obj: o2,
attr: a2,
args: args2,
},
) => {
if attr == a2 {
self.sub_unify_tp(obj, o2, _variance, loc, allow_divergence)?;
for (l, r) in args.iter().zip(args2.iter()) {
self.sub_unify_tp(l, r, _variance, loc, allow_divergence)?;
}
Ok(())
} else {
todo!()
}
}
(l, r) => {
log!(err "{l} / {r}");
type_feature_error!(self, loc.loc(), &format!("unifying {l} and {r}"))

View file

@ -9,8 +9,8 @@ use erg_parser::desugar::Desugarer;
use crate::context::instantiate::TyVarCache;
use crate::lower::ASTLowerer;
use crate::ty::constructors::{mono, poly, ty_tp, type_q, v_enum};
use crate::ty::free::HasLevel;
use crate::ty::constructors::{mono, mono_q_tp, poly, v_enum};
use crate::ty::free::{Constraint, HasLevel};
use crate::ty::value::{GenTypeObj, TypeObj, ValueObj};
use crate::ty::{HasType, Type, Visibility};
@ -703,7 +703,10 @@ impl ASTLowerer {
let params = subr
.non_default_params
.iter()
.map(|p| ty_tp(type_q(p.name().unwrap_or(&Str::ever("_")))))
.map(|p| {
let c = Constraint::new_type_of(p.typ().clone());
mono_q_tp(p.name().unwrap_or(&Str::ever("_")), c)
})
.collect();
let t = poly(format!("{}{ident}", self.module.context.path()), params);
let ty_obj = GenTypeObj::class(t.clone(), None, None);

View file

@ -43,7 +43,7 @@ pub use value::ValueObj;
use value::ValueObj::{Inf, NegInf};
pub use vis::*;
use self::constructors::subr_t;
use self::constructors::{proj_call, subr_t};
pub const STR_OMIT_THRESHOLD: usize = 16;
pub const CONTAINER_OMIT_THRESHOLD: usize = 8;
@ -2904,7 +2904,7 @@ impl Type {
other => other.clone(),
})
.collect();
lhs.proj_call(attr_name.clone(), args)
proj_call(lhs, attr_name.clone(), args)
}
Self::Structural(ty) => ty.derefine().structuralize(),
Self::Guard(guard) => {
@ -3043,7 +3043,7 @@ impl Type {
args,
} => {
let args = args.into_iter().map(|tp| tp.replace(target, to)).collect();
lhs.replace(target, to).proj_call(attr_name, args)
proj_call(lhs.replace(target, to), attr_name, args)
}
Self::Structural(ty) => ty._replace(target, to).structuralize(),
Self::Guard(guard) => Self::Guard(GuardType::new(
@ -3086,7 +3086,7 @@ impl Type {
args,
} => {
let args = args.into_iter().map(|tp| tp.normalize()).collect();
lhs.normalize().proj_call(attr_name, args)
proj_call(lhs.normalize(), attr_name, args)
}
Self::Ref(t) => Self::Ref(Box::new(t.normalize())),
Self::RefMut { before, after } => Self::RefMut {

View file

@ -214,6 +214,11 @@ pub enum TyParam {
obj: Box<TyParam>,
attr: Str,
},
ProjCall {
obj: Box<TyParam>,
attr: Str,
args: Vec<TyParam>,
},
App {
name: Str,
args: Vec<TyParam>,
@ -343,6 +348,20 @@ impl LimitedDisplay for TyParam {
write!(f, ".")?;
write!(f, "{attr}")
}
Self::ProjCall { obj, attr, args } => {
obj.limited_fmt(f, limit - 1)?;
write!(f, ".")?;
write!(f, "{attr}")?;
write!(f, "(")?;
for (i, arg) in args.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
arg.limited_fmt(f, limit - 1)?;
}
write!(f, ")")?;
Ok(())
}
Self::Array(arr) => {
write!(f, "[")?;
for (i, t) in arr.iter().enumerate() {
@ -657,6 +676,17 @@ impl<'a> TryFrom<&'a TyParam> for &'a Type {
}
}
impl TryFrom<&TyParam> for usize {
type Error = ();
fn try_from(tp: &TyParam) -> Result<Self, ()> {
match tp {
TyParam::FreeVar(fv) if fv.is_linked() => usize::try_from(&*fv.crack()),
TyParam::Value(v) => usize::try_from(v),
_ => Err(()),
}
}
}
impl HasLevel for TyParam {
fn level(&self) -> Option<Level> {
match self {
@ -839,10 +869,10 @@ impl TyParam {
}
}
pub fn proj_call(self, attr_name: Str, args: Vec<TyParam>) -> Type {
Type::ProjCall {
lhs: Box::new(self),
attr_name,
pub fn proj_call(self, attr: Str, args: Vec<TyParam>) -> Self {
Self::ProjCall {
obj: Box::new(self),
attr,
args,
}
}

View file

@ -832,6 +832,19 @@ impl TryFrom<&ValueObj> for f64 {
}
}
impl TryFrom<&ValueObj> for usize {
type Error = ();
fn try_from(val: &ValueObj) -> Result<usize, Self::Error> {
match val {
ValueObj::Int(i) => usize::try_from(*i).map_err(|_| ()),
ValueObj::Nat(n) => usize::try_from(*n).map_err(|_| ()),
ValueObj::Float(f) => Ok(*f as usize),
ValueObj::Bool(b) => Ok(if *b { 1 } else { 0 }),
_ => Err(()),
}
}
}
impl<'a> TryFrom<&'a ValueObj> for &'a Type {
type Error = ();
fn try_from(val: &'a ValueObj) -> Result<Self, ()> {