fix: minor bugs

This commit is contained in:
Shunsuke Shibayama 2023-10-14 19:39:07 +09:00
parent 5365c87cb4
commit a8c1113df7
6 changed files with 166 additions and 83 deletions

View file

@ -4,7 +4,7 @@ use std::mem;
use erg_common::dict::Dict; use erg_common::dict::Dict;
#[allow(unused_imports)] #[allow(unused_imports)]
use erg_common::log; use erg_common::log;
use erg_common::{dict, enum_unwrap, set}; use erg_common::{dict, set};
use crate::context::Context; use crate::context::Context;
use crate::feature_error; use crate::feature_error;
@ -186,14 +186,19 @@ pub(crate) fn __array_getitem__(mut args: ValueArgs, ctx: &Context) -> EvalValue
let slf = args let slf = args
.remove_left_or_key("Self") .remove_left_or_key("Self")
.ok_or_else(|| not_passed("Self"))?; .ok_or_else(|| not_passed("Self"))?;
let slf = ctx let slf = match ctx.convert_value_into_array(slf) {
.convert_value_into_array(slf) Ok(slf) => slf,
.unwrap_or_else(|err| panic!("{err}, {args}")); Err(val) => {
return Err(type_mismatch("Array", val, "Self"));
}
};
let index = args let index = args
.remove_left_or_key("Index") .remove_left_or_key("Index")
.ok_or_else(|| not_passed("Index"))?; .ok_or_else(|| not_passed("Index"))?;
let index = enum_unwrap!(index, ValueObj::Nat); let Ok(index) = usize::try_from(&index) else {
if let Some(v) = slf.get(index as usize) { return Err(type_mismatch("Nat", index, "Index"));
};
if let Some(v) = slf.get(index) {
Ok(v.clone().into()) Ok(v.clone().into())
} else { } else {
Err(ErrorCore::new( Err(ErrorCore::new(
@ -280,7 +285,9 @@ pub(crate) fn __dict_getitem__(mut args: ValueArgs, ctx: &Context) -> EvalValueR
let slf = args let slf = args
.remove_left_or_key("Self") .remove_left_or_key("Self")
.ok_or_else(|| not_passed("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 let index = args
.remove_left_or_key("Index") .remove_left_or_key("Index")
.ok_or_else(|| not_passed("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 let slf = args
.remove_left_or_key("Self") .remove_left_or_key("Self")
.ok_or_else(|| not_passed("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 let slf = slf
.into_iter() .into_iter()
.map(|(k, v)| { .map(|(k, v)| {
@ -324,7 +333,9 @@ pub(crate) fn dict_values(mut args: ValueArgs, ctx: &Context) -> EvalValueResult
let slf = args let slf = args
.remove_left_or_key("Self") .remove_left_or_key("Self")
.ok_or_else(|| not_passed("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 let slf = slf
.into_iter() .into_iter()
.map(|(k, v)| { .map(|(k, v)| {
@ -346,7 +357,9 @@ pub(crate) fn dict_items(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<
let slf = args let slf = args
.remove_left_or_key("Self") .remove_left_or_key("Self")
.ok_or_else(|| not_passed("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 let slf = slf
.into_iter() .into_iter()
.map(|(k, v)| { .map(|(k, v)| {
@ -369,11 +382,15 @@ pub(crate) fn dict_concat(mut args: ValueArgs, _ctx: &Context) -> EvalValueResul
let slf = args let slf = args
.remove_left_or_key("Self") .remove_left_or_key("Self")
.ok_or_else(|| not_passed("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 let other = args
.remove_left_or_key("Other") .remove_left_or_key("Other")
.ok_or_else(|| not_passed("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()) 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 let slf = args
.remove_left_or_key("Self") .remove_left_or_key("Self")
.ok_or_else(|| not_passed("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 let other = args
.remove_left_or_key("Other") .remove_left_or_key("Other")
.ok_or_else(|| not_passed("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()) 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 let slf = args
.remove_left_or_key("Self") .remove_left_or_key("Self")
.ok_or_else(|| not_passed("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 let slf = slf
.iter() .iter()
.map(|t| ctx.convert_value_into_type(t.clone()).unwrap()) .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" => { ValueObj::Type(ref t) if &t.typ().qual_name()[..] == "Array" => {
let mut tps = t.typ().typarams(); 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); let len = tps.remove(0);
shape.push(len); shape.push(len);
arr = ValueObj::builtin_type(elem); 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> { pub(crate) fn __range_getitem__(mut args: ValueArgs, _ctx: &Context) -> EvalValueResult<TyParam> {
let (_name, fields) = enum_unwrap!( let slf = args
args.remove_left_or_key("Self") .remove_left_or_key("Self")
.ok_or_else(|| not_passed("Self"))?, .ok_or_else(|| not_passed("Self"))?;
ValueObj::DataClass { name, fields } let ValueObj::DataClass { name: _, fields } = slf else {
); return Err(type_mismatch("Range", slf, "Self"));
};
let index = args let index = args
.remove_left_or_key("Index") .remove_left_or_key("Index")
.ok_or_else(|| not_passed("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 let start = fields
.get("start") .get("start")
.ok_or_else(|| no_key(&fields, "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 = 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 // FIXME <= if inclusive
if start + index < end { if start + index < end {
Ok(ValueObj::Nat(start + index).into()) Ok(ValueObj::Nat((start + index) as u64).into())
} else { } else {
Err(ErrorCore::new( Err(ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)], vec![SubMessage::only_loc(Location::Unknown)],

View file

@ -826,55 +826,27 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
self.sub_unify(&rsub, &union)?; self.sub_unify(&rsub, &union)?;
// self.sub_unify(&intersec, &lsup, loc, param_name)?; // self.sub_unify(&intersec, &lsup, loc, param_name)?;
// self.sub_unify(&lsub, &union, loc, param_name)?; // self.sub_unify(&lsub, &union, loc, param_name)?;
if union == intersec { match sub_fv
match sub_fv .level()
.level() .unwrap_or(GENERIC_LEVEL)
.unwrap_or(GENERIC_LEVEL) .cmp(&sup_fv.level().unwrap_or(GENERIC_LEVEL))
.cmp(&sup_fv.level().unwrap_or(GENERIC_LEVEL)) {
{ std::cmp::Ordering::Less => {
std::cmp::Ordering::Less => { maybe_sub.update_tyvar(union, intersec, self.undoable, false);
maybe_sub.link(&union, self.undoable); maybe_sup.link(maybe_sub, 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);
}
}
} }
} else { std::cmp::Ordering::Greater => {
let new_constraint = Constraint::new_sandwiched(union, intersec); maybe_sup.update_tyvar(union, intersec, self.undoable, false);
match sub_fv maybe_sub.link(maybe_sup, self.undoable);
.level() }
.unwrap_or(GENERIC_LEVEL) std::cmp::Ordering::Equal => {
.cmp(&sup_fv.level().unwrap_or(GENERIC_LEVEL)) // choose named one
{ if sup_fv.is_named_unbound() {
std::cmp::Ordering::Less => { maybe_sup.update_tyvar(union, intersec, self.undoable, false);
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);
maybe_sub.link(maybe_sup, self.undoable); maybe_sub.link(maybe_sup, self.undoable);
} } else {
std::cmp::Ordering::Equal => { maybe_sub.update_tyvar(union, intersec, self.undoable, false);
// choose named one maybe_sup.link(maybe_sub, self.undoable);
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);
}
} }
} }
} }
@ -947,12 +919,7 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
self.sub_unify(&rsub, &union)?; self.sub_unify(&rsub, &union)?;
// self.sub_unify(&intersec, &lsup, loc, param_name)?; // self.sub_unify(&intersec, &lsup, loc, param_name)?;
// self.sub_unify(&lsub, &union, loc, param_name)?; // self.sub_unify(&lsub, &union, loc, param_name)?;
if union == intersec { maybe_sup.update_tyvar(union, intersec, self.undoable, false);
maybe_sup.link(&union, self.undoable);
} else {
let new_constraint = Constraint::new_sandwiched(union, intersec);
maybe_sup.update_constraint(new_constraint, self.undoable, false);
}
} }
// (Int or ?T) <: (?U or Int) // (Int or ?T) <: (?U or Int)
// OK: (Int <: Int); (?T <: ?U) // OK: (Int <: Int); (?T <: ?U)

View file

@ -1078,6 +1078,7 @@ impl ASTLowerer {
} }
} }
} }
// TODO: expect var_args
if let Some(var_args) = var_args { if let Some(var_args) = var_args {
match self.lower_expr(var_args.expr, None) { match self.lower_expr(var_args.expr, None) {
Ok(expr) => hir_args.var_args = Some(Box::new(hir::PosArg::new(expr))), 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() { 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)), Ok(expr) => hir_args.push_kw(hir::KwArg::new(arg.keyword, expr)),
Err(es) => { Err(es) => {
errs.extend(es); errs.extend(es);

View file

@ -564,10 +564,15 @@ impl SubrType {
.non_default_params .non_default_params
.iter() .iter()
.filter(|pt| !pt.name().is_some_and(|n| &n[..] == "self")); .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() { 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 { } 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 { pub fn quantify(self) -> Self {
debug_assert!(self.is_subr(), "{self} is not subr"); debug_assert!(self.is_subr(), "{self} is not subr");
match self { 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 /// Procedure
pub fn is_procedure(&self) -> bool { pub fn is_procedure(&self) -> bool {
match self { 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) { fn inc_undo_count(&self) {
match self { match self {
Self::FreeVar(fv) => fv.inc_undo_count(), Self::FreeVar(fv) => fv.inc_undo_count(),

View file

@ -668,6 +668,10 @@ impl TryFrom<TyParam> for ValueObj {
} }
Ok(ValueObj::Array(Arc::from(vals))) Ok(ValueObj::Array(Arc::from(vals)))
} }
TyParam::UnsizedArray(elem) => {
let elem = ValueObj::try_from(*elem)?;
Ok(ValueObj::UnsizedArray(Box::new(elem)))
}
TyParam::Tuple(tps) => { TyParam::Tuple(tps) => {
let mut vals = vec![]; let mut vals = vec![];
for tp in tps { for tp in tps {
@ -689,6 +693,13 @@ impl TryFrom<TyParam> for ValueObj {
} }
Ok(ValueObj::Record(vals)) 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 } => { TyParam::DataClass { name, fields } => {
let mut vals = dict! {}; let mut vals = dict! {};
for (k, v) in fields { for (k, v) in fields {
@ -710,7 +721,7 @@ impl TryFrom<TyParam> for ValueObj {
TyParam::Type(t) => Ok(ValueObj::builtin_type(*t)), TyParam::Type(t) => Ok(ValueObj::builtin_type(*t)),
TyParam::Value(v) => Ok(v), TyParam::Value(v) => Ok(v),
_ => { _ => {
log!(err "Expected value, got {tp} ({tp:?})"); log!(err "Expected value, got {tp}");
Err(()) Err(())
} }
} }

View file

@ -1167,7 +1167,7 @@ impl ValueObj {
Self::Dict(dict) => { Self::Dict(dict) => {
let tp = dict let tp = dict
.iter() .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())) dict_t(TyParam::Dict(tp.collect()))
} }
Self::Tuple(tup) => tuple_t(tup.iter().map(|v| v.class()).collect()), Self::Tuple(tup) => tuple_t(tup.iter().map(|v| v.class()).collect()),