mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-30 04:44:44 +00:00
Fix Array type inference
This commit is contained in:
parent
2a68c89140
commit
e36746f964
7 changed files with 107 additions and 29 deletions
|
@ -372,7 +372,7 @@ pub trait ErrorDisplay {
|
|||
self.format_code_and_pointer(),
|
||||
self.core().kind,
|
||||
self.core().desc,
|
||||
fmt_option!(pre format!("\n{GREEN}hint{RESET}: "), &self.core().hint),
|
||||
fmt_option!(pre format!("\n{GREEN}hint{RESET}: "), self.core().hint),
|
||||
)
|
||||
.as_bytes(),
|
||||
)
|
||||
|
@ -392,7 +392,7 @@ pub trait ErrorDisplay {
|
|||
self.format_code_and_pointer(),
|
||||
self.core().kind,
|
||||
self.core().desc,
|
||||
fmt_option!(pre format!("\n{GREEN}hint{RESET}: "), &self.core().hint),
|
||||
fmt_option!(pre format!("\n{GREEN}hint{RESET}: "), self.core().hint),
|
||||
)?;
|
||||
if let Some(inner) = self.ref_inner() {
|
||||
inner.format(f)
|
||||
|
|
|
@ -97,41 +97,41 @@ macro_rules! enum_unwrap {
|
|||
/// assert fmt_option!(Some(1)) == "1"
|
||||
/// assert fmt_option!(None) == ""
|
||||
/// assert fmt_option!(None, else 1) == "1"
|
||||
/// assert fmt_option!(Some(1), post: ",") == "1,"
|
||||
/// assert fmt_option!(Some(1), post ",") == "1,"
|
||||
/// assert fmt_option!("[", Some(1), "]") == "[1]"
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! fmt_option {
|
||||
($ex: expr $(,)*) => {
|
||||
if let Some(x) = $ex {
|
||||
if let Some(x) = &$ex {
|
||||
format!("{}", x)
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
};
|
||||
($ex: expr $(,)*, else $els: expr $(,)*) => {
|
||||
if let Some(x) = $ex {
|
||||
if let Some(x) = &$ex {
|
||||
format!("{}", x)
|
||||
} else {
|
||||
$els.to_string()
|
||||
}
|
||||
};
|
||||
(pre $prefix: expr, $ex: expr $(,)*) => {
|
||||
if let Some(x) = $ex {
|
||||
if let Some(x) = &$ex {
|
||||
format!("{}{}", $prefix, x)
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
};
|
||||
($ex: expr, post $postfix: expr $(,)*) => {
|
||||
if let Some(x) = $ex {
|
||||
if let Some(x) = &$ex {
|
||||
format!("{}{}", x, $postfix)
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
};
|
||||
($prefix: expr, $ex: expr, $postfix: expr $(,)*) => {
|
||||
if let Some(x) = $ex {
|
||||
if let Some(x) = &$ex {
|
||||
format!("{}{}{}", $prefix, x, $postfix)
|
||||
} else {
|
||||
"".to_string()
|
||||
|
|
|
@ -1451,11 +1451,13 @@ impl fmt::Display for SubrType {
|
|||
let mut default_params = String::new();
|
||||
for default_param in self.default_params.iter() {
|
||||
default_params.push_str(&format!(
|
||||
"{} |= {}",
|
||||
"{} |= {}, ",
|
||||
default_param.name.as_ref().unwrap(),
|
||||
default_param.ty
|
||||
));
|
||||
}
|
||||
default_params.pop();
|
||||
default_params.pop();
|
||||
write!(
|
||||
f,
|
||||
"{}({}, {}) {} {}",
|
||||
|
|
|
@ -2270,7 +2270,7 @@ impl Context {
|
|||
/// sub_unify(Nat, Add(?R, ?O)): (?R => Nat, ?O => Nat)
|
||||
/// sub_unify([?T; 0], Mutate): (/* OK */)
|
||||
/// ```
|
||||
fn sub_unify(
|
||||
pub(crate) fn sub_unify(
|
||||
&self,
|
||||
maybe_sub: &Type,
|
||||
maybe_sup: &Type,
|
||||
|
|
|
@ -100,8 +100,13 @@ impl ASTLowerer {
|
|||
hir::Args::empty(),
|
||||
None,
|
||||
);
|
||||
for elem in array.elems.into_iters().0 {
|
||||
hir_array.push(self.lower_expr(elem.expr, check)?);
|
||||
let inner_t = hir_array.t.ref_t().inner_ts().first().unwrap().clone();
|
||||
let (elems, _) = array.elems.into_iters();
|
||||
for elem in elems {
|
||||
let elem = self.lower_expr(elem.expr, check)?;
|
||||
self.ctx
|
||||
.sub_unify(elem.ref_t(), &inner_t, Some(elem.loc()), None)?;
|
||||
hir_array.push(elem);
|
||||
}
|
||||
Ok(hir_array)
|
||||
}
|
||||
|
|
|
@ -385,16 +385,19 @@ pub struct Array {
|
|||
pub l_sqbr: Token,
|
||||
pub r_sqbr: Token,
|
||||
pub elems: Args,
|
||||
pub len: Option<Box<Expr>>, // if some, elems.len() should be 1
|
||||
pub guard: Option<Box<Expr>>,
|
||||
}
|
||||
|
||||
impl NestedDisplay for Array {
|
||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
||||
if let Some(guard) = &self.guard {
|
||||
write!(f, "[{} | {}]", self.elems, guard)
|
||||
} else {
|
||||
write!(f, "[{}]", self.elems)
|
||||
}
|
||||
write!(
|
||||
f,
|
||||
"[{}{}{}]",
|
||||
self.elems,
|
||||
fmt_option!(pre "; ", self.len),
|
||||
fmt_option!(pre "| ", self.guard)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -402,11 +405,18 @@ impl_display_from_nested!(Array);
|
|||
impl_locational!(Array, l_sqbr, r_sqbr);
|
||||
|
||||
impl Array {
|
||||
pub fn new(l_sqbr: Token, r_sqbr: Token, elems: Args, guard: Option<Expr>) -> Self {
|
||||
pub fn new(
|
||||
l_sqbr: Token,
|
||||
r_sqbr: Token,
|
||||
elems: Args,
|
||||
len: Option<Expr>,
|
||||
guard: Option<Expr>,
|
||||
) -> Self {
|
||||
Self {
|
||||
l_sqbr,
|
||||
r_sqbr,
|
||||
elems,
|
||||
len: len.map(Box::new),
|
||||
guard: guard.map(Box::new),
|
||||
}
|
||||
}
|
||||
|
@ -1567,7 +1577,7 @@ pub struct VarSignature {
|
|||
|
||||
impl NestedDisplay for VarSignature {
|
||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
||||
write!(f, "{}{}", self.pat, fmt_option!(pre ": ", &self.t_spec))
|
||||
write!(f, "{}{}", self.pat, fmt_option!(pre ": ", self.t_spec))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1741,11 +1751,11 @@ impl NestedDisplay for ParamSignature {
|
|||
f,
|
||||
"{}{} |= {}",
|
||||
self.pat,
|
||||
fmt_option!(pre ": ", &self.t_spec),
|
||||
fmt_option!(pre ": ", self.t_spec),
|
||||
default_val
|
||||
)
|
||||
} else {
|
||||
write!(f, "{}{}", self.pat, fmt_option!(pre ": ", &self.t_spec),)
|
||||
write!(f, "{}{}", self.pat, fmt_option!(pre ": ", self.t_spec),)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1868,7 +1878,7 @@ impl NestedDisplay for SubrSignature {
|
|||
"{}{}{}",
|
||||
self.name,
|
||||
self.params,
|
||||
fmt_option!(pre ": ", &self.return_t_spec)
|
||||
fmt_option!(pre ": ", self.return_t_spec)
|
||||
)
|
||||
} else {
|
||||
write!(
|
||||
|
@ -1877,7 +1887,7 @@ impl NestedDisplay for SubrSignature {
|
|||
self.name,
|
||||
self.bounds,
|
||||
self.params,
|
||||
fmt_option!(pre ": ", &self.return_t_spec)
|
||||
fmt_option!(pre ": ", self.return_t_spec)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1933,7 +1943,7 @@ impl fmt::Display for LambdaSignature {
|
|||
f,
|
||||
"{}{}",
|
||||
self.params,
|
||||
fmt_option!(pre ": ", &self.return_t_spec)
|
||||
fmt_option!(pre ": ", self.return_t_spec)
|
||||
)
|
||||
} else {
|
||||
write!(
|
||||
|
@ -1941,7 +1951,7 @@ impl fmt::Display for LambdaSignature {
|
|||
"|{}|{}{}",
|
||||
self.bounds,
|
||||
self.params,
|
||||
fmt_option!(pre ": ", &self.return_t_spec)
|
||||
fmt_option!(pre ": ", self.return_t_spec)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -632,7 +632,7 @@ impl Parser {
|
|||
Ok(acc)
|
||||
}
|
||||
|
||||
fn try_reduce_elems(&mut self) -> ParseResult<Vars> {
|
||||
fn try_reduce_elems_pattern(&mut self) -> ParseResult<Vars> {
|
||||
debug_call_info!(self);
|
||||
let mut elems = Vars::empty();
|
||||
match self.peek() {
|
||||
|
@ -801,7 +801,7 @@ impl Parser {
|
|||
Some(t) if t.is(UBar) => Ok(VarPattern::Discard(self.lpop())),
|
||||
Some(t) if t.is(LSqBr) => {
|
||||
let l_sqbr = self.lpop();
|
||||
let elems = self.try_reduce_elems()?;
|
||||
let elems = self.try_reduce_elems_pattern()?;
|
||||
if self.cur_is(RSqBr) {
|
||||
let r_sqbr = self.lpop();
|
||||
Ok(VarPattern::Array(VarArrayPattern::new(
|
||||
|
@ -1060,6 +1060,67 @@ impl Parser {
|
|||
Ok(const_args)
|
||||
}
|
||||
|
||||
/// For parsing elements of arrays and tuples
|
||||
/// The second return value is a specified length, the third return value is a guard
|
||||
fn try_reduce_elems(&mut self) -> ParseResult<(Args, Option<Expr>, Option<Expr>)> {
|
||||
debug_call_info!(self);
|
||||
if self.cur_category_is(TC::REnclosure) {
|
||||
let args = Args::new(vec![], vec![], None);
|
||||
return Ok((args, None, None));
|
||||
}
|
||||
let mut args = match self.try_reduce_arg()? {
|
||||
PosOrKwArg::Pos(arg) => Args::new(vec![arg], vec![], None),
|
||||
PosOrKwArg::Kw(arg) => Args::new(vec![], vec![arg], None),
|
||||
};
|
||||
match self.peek() {
|
||||
Some(semi) if semi.is(Semi) => {
|
||||
return Err(ParseError::feature_error(
|
||||
line!() as usize,
|
||||
semi.loc(),
|
||||
"length specification",
|
||||
))
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
loop {
|
||||
match self.peek() {
|
||||
Some(comma) if comma.is(Comma) => {
|
||||
self.skip();
|
||||
if self.cur_is(Comma) {
|
||||
return Err(self.skip_and_throw_syntax_err(caused_by!()));
|
||||
}
|
||||
if !args.kw_is_empty() {
|
||||
args.push_kw(self.try_reduce_kw_arg()?);
|
||||
} else {
|
||||
match self.try_reduce_arg()? {
|
||||
PosOrKwArg::Pos(arg) => {
|
||||
args.push_pos(arg);
|
||||
}
|
||||
PosOrKwArg::Kw(arg) => {
|
||||
args.push_kw(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(vbar) if vbar.is(VBar) => {
|
||||
return Err(ParseError::feature_error(
|
||||
line!() as usize,
|
||||
vbar.loc(),
|
||||
"guard",
|
||||
))
|
||||
}
|
||||
Some(t) if t.category_is(TC::REnclosure) => {
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
self.skip();
|
||||
return Err(self.skip_and_throw_syntax_err(caused_by!()));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok((args, None, None))
|
||||
}
|
||||
|
||||
fn opt_reduce_args(&mut self) -> Option<ParseResult<Args>> {
|
||||
debug_call_info!(self);
|
||||
match self.peek() {
|
||||
|
@ -1466,12 +1527,12 @@ impl Parser {
|
|||
fn try_reduce_array(&mut self) -> ParseResult<Array> {
|
||||
debug_call_info!(self);
|
||||
let l_sqbr = self.lpop();
|
||||
let elems = self.try_reduce_args()?;
|
||||
let (elems, len, guard) = self.try_reduce_elems()?;
|
||||
let r_sqbr = self.lpop();
|
||||
if !r_sqbr.is(RSqBr) {
|
||||
return Err(ParseError::simple_syntax_error(0, r_sqbr.loc()));
|
||||
}
|
||||
let arr = Array::new(l_sqbr, r_sqbr, elems, None);
|
||||
let arr = Array::new(l_sqbr, r_sqbr, elems, len, guard);
|
||||
Ok(arr)
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue