mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-28 20:14:45 +00:00
fix: minor bugs
This commit is contained in:
parent
5365c87cb4
commit
a8c1113df7
6 changed files with 166 additions and 83 deletions
|
@ -4,7 +4,7 @@ use std::mem;
|
|||
use erg_common::dict::Dict;
|
||||
#[allow(unused_imports)]
|
||||
use erg_common::log;
|
||||
use erg_common::{dict, enum_unwrap, set};
|
||||
use erg_common::{dict, set};
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::feature_error;
|
||||
|
@ -186,14 +186,19 @@ pub(crate) fn __array_getitem__(mut args: ValueArgs, ctx: &Context) -> EvalValue
|
|||
let slf = args
|
||||
.remove_left_or_key("Self")
|
||||
.ok_or_else(|| not_passed("Self"))?;
|
||||
let slf = ctx
|
||||
.convert_value_into_array(slf)
|
||||
.unwrap_or_else(|err| panic!("{err}, {args}"));
|
||||
let slf = match ctx.convert_value_into_array(slf) {
|
||||
Ok(slf) => slf,
|
||||
Err(val) => {
|
||||
return Err(type_mismatch("Array", val, "Self"));
|
||||
}
|
||||
};
|
||||
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) {
|
||||
let Ok(index) = usize::try_from(&index) else {
|
||||
return Err(type_mismatch("Nat", index, "Index"));
|
||||
};
|
||||
if let Some(v) = slf.get(index) {
|
||||
Ok(v.clone().into())
|
||||
} else {
|
||||
Err(ErrorCore::new(
|
||||
|
@ -280,7 +285,9 @@ pub(crate) fn __dict_getitem__(mut args: ValueArgs, ctx: &Context) -> EvalValueR
|
|||
let slf = args
|
||||
.remove_left_or_key("Self")
|
||||
.ok_or_else(|| not_passed("Self"))?;
|
||||
let slf = enum_unwrap!(slf, ValueObj::Dict);
|
||||
let ValueObj::Dict(slf) = slf else {
|
||||
return Err(type_mismatch("Dict", slf, "Self"));
|
||||
};
|
||||
let index = args
|
||||
.remove_left_or_key("Index")
|
||||
.ok_or_else(|| not_passed("Index"))?;
|
||||
|
@ -302,7 +309,9 @@ pub(crate) fn dict_keys(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<T
|
|||
let slf = args
|
||||
.remove_left_or_key("Self")
|
||||
.ok_or_else(|| not_passed("Self"))?;
|
||||
let slf = enum_unwrap!(slf, ValueObj::Dict);
|
||||
let ValueObj::Dict(slf) = slf else {
|
||||
return Err(type_mismatch("Dict", slf, "Self"));
|
||||
};
|
||||
let slf = slf
|
||||
.into_iter()
|
||||
.map(|(k, v)| {
|
||||
|
@ -324,7 +333,9 @@ pub(crate) fn dict_values(mut args: ValueArgs, ctx: &Context) -> EvalValueResult
|
|||
let slf = args
|
||||
.remove_left_or_key("Self")
|
||||
.ok_or_else(|| not_passed("Self"))?;
|
||||
let slf = enum_unwrap!(slf, ValueObj::Dict);
|
||||
let ValueObj::Dict(slf) = slf else {
|
||||
return Err(type_mismatch("Dict", slf, "Self"));
|
||||
};
|
||||
let slf = slf
|
||||
.into_iter()
|
||||
.map(|(k, v)| {
|
||||
|
@ -346,7 +357,9 @@ pub(crate) fn dict_items(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<
|
|||
let slf = args
|
||||
.remove_left_or_key("Self")
|
||||
.ok_or_else(|| not_passed("Self"))?;
|
||||
let slf = enum_unwrap!(slf, ValueObj::Dict);
|
||||
let ValueObj::Dict(slf) = slf else {
|
||||
return Err(type_mismatch("Dict", slf, "Self"));
|
||||
};
|
||||
let slf = slf
|
||||
.into_iter()
|
||||
.map(|(k, v)| {
|
||||
|
@ -369,11 +382,15 @@ pub(crate) fn dict_concat(mut args: ValueArgs, _ctx: &Context) -> EvalValueResul
|
|||
let slf = args
|
||||
.remove_left_or_key("Self")
|
||||
.ok_or_else(|| not_passed("Self"))?;
|
||||
let slf = enum_unwrap!(slf, ValueObj::Dict);
|
||||
let ValueObj::Dict(slf) = slf else {
|
||||
return Err(type_mismatch("Dict", slf, "Self"));
|
||||
};
|
||||
let other = args
|
||||
.remove_left_or_key("Other")
|
||||
.ok_or_else(|| not_passed("Other"))?;
|
||||
let other = enum_unwrap!(other, ValueObj::Dict);
|
||||
let ValueObj::Dict(other) = other else {
|
||||
return Err(type_mismatch("Dict", other, "Other"));
|
||||
};
|
||||
Ok(ValueObj::Dict(slf.concat(other)).into())
|
||||
}
|
||||
|
||||
|
@ -381,11 +398,15 @@ pub(crate) fn dict_diff(mut args: ValueArgs, _ctx: &Context) -> EvalValueResult<
|
|||
let slf = args
|
||||
.remove_left_or_key("Self")
|
||||
.ok_or_else(|| not_passed("Self"))?;
|
||||
let slf = enum_unwrap!(slf, ValueObj::Dict);
|
||||
let ValueObj::Dict(slf) = slf else {
|
||||
return Err(type_mismatch("Dict", slf, "Self"));
|
||||
};
|
||||
let other = args
|
||||
.remove_left_or_key("Other")
|
||||
.ok_or_else(|| not_passed("Other"))?;
|
||||
let other = enum_unwrap!(other, ValueObj::Dict);
|
||||
let ValueObj::Dict(other) = other else {
|
||||
return Err(type_mismatch("Dict", other, "Other"));
|
||||
};
|
||||
Ok(ValueObj::Dict(slf.diff(&other)).into())
|
||||
}
|
||||
|
||||
|
@ -394,7 +415,9 @@ pub(crate) fn array_union(mut args: ValueArgs, ctx: &Context) -> EvalValueResult
|
|||
let slf = args
|
||||
.remove_left_or_key("Self")
|
||||
.ok_or_else(|| not_passed("Self"))?;
|
||||
let slf = enum_unwrap!(slf, ValueObj::Array);
|
||||
let ValueObj::Array(slf) = slf else {
|
||||
return Err(type_mismatch("Array", slf, "Self"));
|
||||
};
|
||||
let slf = slf
|
||||
.iter()
|
||||
.map(|t| ctx.convert_value_into_type(t.clone()).unwrap())
|
||||
|
@ -423,7 +446,12 @@ fn _arr_shape(arr: ValueObj, ctx: &Context) -> Result<Vec<TyParam>, String> {
|
|||
}
|
||||
ValueObj::Type(ref t) if &t.typ().qual_name()[..] == "Array" => {
|
||||
let mut tps = t.typ().typarams();
|
||||
let elem = ctx.convert_tp_into_type(tps.remove(0)).unwrap();
|
||||
let elem = match ctx.convert_tp_into_type(tps.remove(0)) {
|
||||
Ok(elem) => elem,
|
||||
Err(err) => {
|
||||
return Err(err.to_string());
|
||||
}
|
||||
};
|
||||
let len = tps.remove(0);
|
||||
shape.push(len);
|
||||
arr = ValueObj::builtin_type(elem);
|
||||
|
@ -452,24 +480,31 @@ pub(crate) fn array_shape(mut args: ValueArgs, ctx: &Context) -> EvalValueResult
|
|||
}
|
||||
|
||||
pub(crate) fn __range_getitem__(mut args: ValueArgs, _ctx: &Context) -> EvalValueResult<TyParam> {
|
||||
let (_name, fields) = enum_unwrap!(
|
||||
args.remove_left_or_key("Self")
|
||||
.ok_or_else(|| not_passed("Self"))?,
|
||||
ValueObj::DataClass { name, fields }
|
||||
);
|
||||
let slf = args
|
||||
.remove_left_or_key("Self")
|
||||
.ok_or_else(|| not_passed("Self"))?;
|
||||
let ValueObj::DataClass { name: _, fields } = slf else {
|
||||
return Err(type_mismatch("Range", slf, "Self"));
|
||||
};
|
||||
let index = args
|
||||
.remove_left_or_key("Index")
|
||||
.ok_or_else(|| not_passed("Index"))?;
|
||||
let index = enum_unwrap!(index, ValueObj::Nat);
|
||||
let Ok(index) = usize::try_from(&index) else {
|
||||
return Err(type_mismatch("Nat", index, "Index"));
|
||||
};
|
||||
let start = fields
|
||||
.get("start")
|
||||
.ok_or_else(|| no_key(&fields, "start"))?;
|
||||
let start = *enum_unwrap!(start, ValueObj::Nat);
|
||||
let Ok(start) = usize::try_from(start) else {
|
||||
return Err(type_mismatch("Nat", start, "start"));
|
||||
};
|
||||
let end = fields.get("end").ok_or_else(|| no_key(&fields, "end"))?;
|
||||
let end = *enum_unwrap!(end, ValueObj::Nat);
|
||||
let Ok(end) = usize::try_from(end) else {
|
||||
return Err(type_mismatch("Nat", end, "end"));
|
||||
};
|
||||
// FIXME <= if inclusive
|
||||
if start + index < end {
|
||||
Ok(ValueObj::Nat(start + index).into())
|
||||
Ok(ValueObj::Nat((start + index) as u64).into())
|
||||
} else {
|
||||
Err(ErrorCore::new(
|
||||
vec![SubMessage::only_loc(Location::Unknown)],
|
||||
|
|
|
@ -826,55 +826,27 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
|
|||
self.sub_unify(&rsub, &union)?;
|
||||
// self.sub_unify(&intersec, &lsup, loc, param_name)?;
|
||||
// self.sub_unify(&lsub, &union, loc, param_name)?;
|
||||
if union == intersec {
|
||||
match sub_fv
|
||||
.level()
|
||||
.unwrap_or(GENERIC_LEVEL)
|
||||
.cmp(&sup_fv.level().unwrap_or(GENERIC_LEVEL))
|
||||
{
|
||||
std::cmp::Ordering::Less => {
|
||||
maybe_sub.link(&union, self.undoable);
|
||||
maybe_sup.link(maybe_sub, self.undoable);
|
||||
}
|
||||
std::cmp::Ordering::Greater => {
|
||||
maybe_sup.link(&union, self.undoable);
|
||||
maybe_sub.link(maybe_sup, self.undoable);
|
||||
}
|
||||
std::cmp::Ordering::Equal => {
|
||||
// choose named one
|
||||
if sup_fv.is_named_unbound() {
|
||||
maybe_sup.link(&union, self.undoable);
|
||||
maybe_sub.link(maybe_sup, self.undoable);
|
||||
} else {
|
||||
maybe_sub.link(&union, self.undoable);
|
||||
maybe_sup.link(maybe_sub, self.undoable);
|
||||
}
|
||||
}
|
||||
match sub_fv
|
||||
.level()
|
||||
.unwrap_or(GENERIC_LEVEL)
|
||||
.cmp(&sup_fv.level().unwrap_or(GENERIC_LEVEL))
|
||||
{
|
||||
std::cmp::Ordering::Less => {
|
||||
maybe_sub.update_tyvar(union, intersec, self.undoable, false);
|
||||
maybe_sup.link(maybe_sub, self.undoable);
|
||||
}
|
||||
} else {
|
||||
let new_constraint = Constraint::new_sandwiched(union, intersec);
|
||||
match sub_fv
|
||||
.level()
|
||||
.unwrap_or(GENERIC_LEVEL)
|
||||
.cmp(&sup_fv.level().unwrap_or(GENERIC_LEVEL))
|
||||
{
|
||||
std::cmp::Ordering::Less => {
|
||||
maybe_sub.update_constraint(new_constraint, self.undoable, false);
|
||||
maybe_sup.link(maybe_sub, self.undoable);
|
||||
}
|
||||
std::cmp::Ordering::Greater => {
|
||||
maybe_sup.update_constraint(new_constraint, self.undoable, false);
|
||||
std::cmp::Ordering::Greater => {
|
||||
maybe_sup.update_tyvar(union, intersec, self.undoable, false);
|
||||
maybe_sub.link(maybe_sup, self.undoable);
|
||||
}
|
||||
std::cmp::Ordering::Equal => {
|
||||
// choose named one
|
||||
if sup_fv.is_named_unbound() {
|
||||
maybe_sup.update_tyvar(union, intersec, self.undoable, false);
|
||||
maybe_sub.link(maybe_sup, self.undoable);
|
||||
}
|
||||
std::cmp::Ordering::Equal => {
|
||||
// choose named one
|
||||
if sup_fv.is_named_unbound() {
|
||||
maybe_sup.update_constraint(new_constraint, self.undoable, false);
|
||||
maybe_sub.link(maybe_sup, self.undoable);
|
||||
} else {
|
||||
maybe_sub.update_constraint(new_constraint, self.undoable, false);
|
||||
maybe_sup.link(maybe_sub, self.undoable);
|
||||
}
|
||||
} else {
|
||||
maybe_sub.update_tyvar(union, intersec, self.undoable, false);
|
||||
maybe_sup.link(maybe_sub, self.undoable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -947,12 +919,7 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
|
|||
self.sub_unify(&rsub, &union)?;
|
||||
// self.sub_unify(&intersec, &lsup, loc, param_name)?;
|
||||
// self.sub_unify(&lsub, &union, loc, param_name)?;
|
||||
if union == intersec {
|
||||
maybe_sup.link(&union, self.undoable);
|
||||
} else {
|
||||
let new_constraint = Constraint::new_sandwiched(union, intersec);
|
||||
maybe_sup.update_constraint(new_constraint, self.undoable, false);
|
||||
}
|
||||
maybe_sup.update_tyvar(union, intersec, self.undoable, false);
|
||||
}
|
||||
// (Int or ?T) <: (?U or Int)
|
||||
// OK: (Int <: Int); (?T <: ?U)
|
||||
|
|
|
@ -1078,6 +1078,7 @@ impl ASTLowerer {
|
|||
}
|
||||
}
|
||||
}
|
||||
// TODO: expect var_args
|
||||
if let Some(var_args) = var_args {
|
||||
match self.lower_expr(var_args.expr, None) {
|
||||
Ok(expr) => hir_args.var_args = Some(Box::new(hir::PosArg::new(expr))),
|
||||
|
@ -1089,7 +1090,12 @@ impl ASTLowerer {
|
|||
}
|
||||
}
|
||||
for arg in kw_args.into_iter() {
|
||||
match self.lower_expr(arg.expr, None) {
|
||||
let kw_param = expect.as_ref().and_then(|subr| {
|
||||
subr.non_var_params()
|
||||
.find(|pt| pt.name().is_some_and(|n| n == &arg.keyword.content))
|
||||
.map(|pt| pt.typ())
|
||||
});
|
||||
match self.lower_expr(arg.expr, kw_param) {
|
||||
Ok(expr) => hir_args.push_kw(hir::KwArg::new(arg.keyword, expr)),
|
||||
Err(es) => {
|
||||
errs.extend(es);
|
||||
|
|
|
@ -564,10 +564,15 @@ impl SubrType {
|
|||
.non_default_params
|
||||
.iter()
|
||||
.filter(|pt| !pt.name().is_some_and(|n| &n[..] == "self"));
|
||||
let defaults = self.default_params.iter();
|
||||
if let Some(var_params) = self.var_params.as_ref() {
|
||||
non_defaults.chain(std::iter::repeat(var_params.as_ref()))
|
||||
non_defaults
|
||||
.chain([].iter())
|
||||
.chain(std::iter::repeat(var_params.as_ref()))
|
||||
} else {
|
||||
non_defaults.chain(std::iter::repeat(&ParamTy::Pos(Type::Failure)))
|
||||
non_defaults
|
||||
.chain(defaults)
|
||||
.chain(std::iter::repeat(&ParamTy::Pos(Type::Failure)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1771,6 +1776,46 @@ impl Type {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn immutate(&self) -> Option<Self> {
|
||||
match self {
|
||||
Self::FreeVar(fv) if fv.is_linked() => {
|
||||
let t = fv.crack().clone();
|
||||
if let Some(t) = t.immutate() {
|
||||
fv.link(&t);
|
||||
Some(Self::FreeVar(fv.clone()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Self::Mono(name) => match &name[..] {
|
||||
"Int!" => Some(Self::Int),
|
||||
"Nat!" => Some(Self::Nat),
|
||||
"Ratio!" => Some(Self::Ratio),
|
||||
"Float!" => Some(Self::Float),
|
||||
"Complex!" => Some(Self::Complex),
|
||||
"Bool!" => Some(Self::Bool),
|
||||
"Str!" => Some(Self::Str),
|
||||
_ => None,
|
||||
},
|
||||
Self::Poly { name, params } => match &name[..] {
|
||||
"Array!" => Some(Self::Poly {
|
||||
name: "Array".into(),
|
||||
params: params.clone(),
|
||||
}),
|
||||
"Set!" => Some(Self::Poly {
|
||||
name: "Set".into(),
|
||||
params: params.clone(),
|
||||
}),
|
||||
"Dict!" => Some(Self::Poly {
|
||||
name: "Dict".into(),
|
||||
params: params.clone(),
|
||||
}),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn quantify(self) -> Self {
|
||||
debug_assert!(self.is_subr(), "{self} is not subr");
|
||||
match self {
|
||||
|
@ -1835,6 +1880,10 @@ impl Type {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_mut_value_class(&self) -> bool {
|
||||
self.immutate().is_some_and(|t| t.is_value_class())
|
||||
}
|
||||
|
||||
/// Procedure
|
||||
pub fn is_procedure(&self) -> bool {
|
||||
match self {
|
||||
|
@ -3567,6 +3616,21 @@ impl Type {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn update_tyvar(
|
||||
&self,
|
||||
new_sub: Type,
|
||||
new_sup: Type,
|
||||
list: Option<&UndoableLinkedList>,
|
||||
in_instantiation: bool,
|
||||
) {
|
||||
if new_sub == new_sup {
|
||||
self.link(&new_sub, list);
|
||||
} else {
|
||||
let new_constraint = Constraint::new_sandwiched(new_sub, new_sup);
|
||||
self.update_constraint(new_constraint, list, in_instantiation);
|
||||
}
|
||||
}
|
||||
|
||||
fn inc_undo_count(&self) {
|
||||
match self {
|
||||
Self::FreeVar(fv) => fv.inc_undo_count(),
|
||||
|
|
|
@ -668,6 +668,10 @@ impl TryFrom<TyParam> for ValueObj {
|
|||
}
|
||||
Ok(ValueObj::Array(Arc::from(vals)))
|
||||
}
|
||||
TyParam::UnsizedArray(elem) => {
|
||||
let elem = ValueObj::try_from(*elem)?;
|
||||
Ok(ValueObj::UnsizedArray(Box::new(elem)))
|
||||
}
|
||||
TyParam::Tuple(tps) => {
|
||||
let mut vals = vec![];
|
||||
for tp in tps {
|
||||
|
@ -689,6 +693,13 @@ impl TryFrom<TyParam> for ValueObj {
|
|||
}
|
||||
Ok(ValueObj::Record(vals))
|
||||
}
|
||||
TyParam::Set(tps) => {
|
||||
let mut vals = set! {};
|
||||
for tp in tps {
|
||||
vals.insert(ValueObj::try_from(tp)?);
|
||||
}
|
||||
Ok(ValueObj::Set(vals))
|
||||
}
|
||||
TyParam::DataClass { name, fields } => {
|
||||
let mut vals = dict! {};
|
||||
for (k, v) in fields {
|
||||
|
@ -710,7 +721,7 @@ impl TryFrom<TyParam> for ValueObj {
|
|||
TyParam::Type(t) => Ok(ValueObj::builtin_type(*t)),
|
||||
TyParam::Value(v) => Ok(v),
|
||||
_ => {
|
||||
log!(err "Expected value, got {tp} ({tp:?})");
|
||||
log!(err "Expected value, got {tp}");
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1167,7 +1167,7 @@ impl ValueObj {
|
|||
Self::Dict(dict) => {
|
||||
let tp = dict
|
||||
.iter()
|
||||
.map(|(k, v)| (TyParam::value(k.clone()), TyParam::value(v.clone())));
|
||||
.map(|(k, v)| (TyParam::t(k.class()), TyParam::t(v.class())));
|
||||
dict_t(TyParam::Dict(tp.collect()))
|
||||
}
|
||||
Self::Tuple(tup) => tuple_t(tup.iter().map(|v| v.class()).collect()),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue