mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-30 12:51:10 +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.format_code_and_pointer(),
|
||||||
self.core().kind,
|
self.core().kind,
|
||||||
self.core().desc,
|
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(),
|
.as_bytes(),
|
||||||
)
|
)
|
||||||
|
@ -392,7 +392,7 @@ pub trait ErrorDisplay {
|
||||||
self.format_code_and_pointer(),
|
self.format_code_and_pointer(),
|
||||||
self.core().kind,
|
self.core().kind,
|
||||||
self.core().desc,
|
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() {
|
if let Some(inner) = self.ref_inner() {
|
||||||
inner.format(f)
|
inner.format(f)
|
||||||
|
|
|
@ -97,41 +97,41 @@ macro_rules! enum_unwrap {
|
||||||
/// assert fmt_option!(Some(1)) == "1"
|
/// assert fmt_option!(Some(1)) == "1"
|
||||||
/// assert fmt_option!(None) == ""
|
/// assert fmt_option!(None) == ""
|
||||||
/// assert fmt_option!(None, else 1) == "1"
|
/// 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]"
|
/// assert fmt_option!("[", Some(1), "]") == "[1]"
|
||||||
/// ```
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! fmt_option {
|
macro_rules! fmt_option {
|
||||||
($ex: expr $(,)*) => {
|
($ex: expr $(,)*) => {
|
||||||
if let Some(x) = $ex {
|
if let Some(x) = &$ex {
|
||||||
format!("{}", x)
|
format!("{}", x)
|
||||||
} else {
|
} else {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
($ex: expr $(,)*, else $els: expr $(,)*) => {
|
($ex: expr $(,)*, else $els: expr $(,)*) => {
|
||||||
if let Some(x) = $ex {
|
if let Some(x) = &$ex {
|
||||||
format!("{}", x)
|
format!("{}", x)
|
||||||
} else {
|
} else {
|
||||||
$els.to_string()
|
$els.to_string()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
(pre $prefix: expr, $ex: expr $(,)*) => {
|
(pre $prefix: expr, $ex: expr $(,)*) => {
|
||||||
if let Some(x) = $ex {
|
if let Some(x) = &$ex {
|
||||||
format!("{}{}", $prefix, x)
|
format!("{}{}", $prefix, x)
|
||||||
} else {
|
} else {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
($ex: expr, post $postfix: expr $(,)*) => {
|
($ex: expr, post $postfix: expr $(,)*) => {
|
||||||
if let Some(x) = $ex {
|
if let Some(x) = &$ex {
|
||||||
format!("{}{}", x, $postfix)
|
format!("{}{}", x, $postfix)
|
||||||
} else {
|
} else {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
($prefix: expr, $ex: expr, $postfix: expr $(,)*) => {
|
($prefix: expr, $ex: expr, $postfix: expr $(,)*) => {
|
||||||
if let Some(x) = $ex {
|
if let Some(x) = &$ex {
|
||||||
format!("{}{}{}", $prefix, x, $postfix)
|
format!("{}{}{}", $prefix, x, $postfix)
|
||||||
} else {
|
} else {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
|
|
|
@ -1451,11 +1451,13 @@ impl fmt::Display for SubrType {
|
||||||
let mut default_params = String::new();
|
let mut default_params = String::new();
|
||||||
for default_param in self.default_params.iter() {
|
for default_param in self.default_params.iter() {
|
||||||
default_params.push_str(&format!(
|
default_params.push_str(&format!(
|
||||||
"{} |= {}",
|
"{} |= {}, ",
|
||||||
default_param.name.as_ref().unwrap(),
|
default_param.name.as_ref().unwrap(),
|
||||||
default_param.ty
|
default_param.ty
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
default_params.pop();
|
||||||
|
default_params.pop();
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{}({}, {}) {} {}",
|
"{}({}, {}) {} {}",
|
||||||
|
|
|
@ -2270,7 +2270,7 @@ impl Context {
|
||||||
/// sub_unify(Nat, Add(?R, ?O)): (?R => Nat, ?O => Nat)
|
/// sub_unify(Nat, Add(?R, ?O)): (?R => Nat, ?O => Nat)
|
||||||
/// sub_unify([?T; 0], Mutate): (/* OK */)
|
/// sub_unify([?T; 0], Mutate): (/* OK */)
|
||||||
/// ```
|
/// ```
|
||||||
fn sub_unify(
|
pub(crate) fn sub_unify(
|
||||||
&self,
|
&self,
|
||||||
maybe_sub: &Type,
|
maybe_sub: &Type,
|
||||||
maybe_sup: &Type,
|
maybe_sup: &Type,
|
||||||
|
|
|
@ -100,8 +100,13 @@ impl ASTLowerer {
|
||||||
hir::Args::empty(),
|
hir::Args::empty(),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
for elem in array.elems.into_iters().0 {
|
let inner_t = hir_array.t.ref_t().inner_ts().first().unwrap().clone();
|
||||||
hir_array.push(self.lower_expr(elem.expr, check)?);
|
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)
|
Ok(hir_array)
|
||||||
}
|
}
|
||||||
|
|
|
@ -385,16 +385,19 @@ pub struct Array {
|
||||||
pub l_sqbr: Token,
|
pub l_sqbr: Token,
|
||||||
pub r_sqbr: Token,
|
pub r_sqbr: Token,
|
||||||
pub elems: Args,
|
pub elems: Args,
|
||||||
|
pub len: Option<Box<Expr>>, // if some, elems.len() should be 1
|
||||||
pub guard: Option<Box<Expr>>,
|
pub guard: Option<Box<Expr>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NestedDisplay for Array {
|
impl NestedDisplay for Array {
|
||||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
||||||
if let Some(guard) = &self.guard {
|
write!(
|
||||||
write!(f, "[{} | {}]", self.elems, guard)
|
f,
|
||||||
} else {
|
"[{}{}{}]",
|
||||||
write!(f, "[{}]", self.elems)
|
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_locational!(Array, l_sqbr, r_sqbr);
|
||||||
|
|
||||||
impl Array {
|
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 {
|
Self {
|
||||||
l_sqbr,
|
l_sqbr,
|
||||||
r_sqbr,
|
r_sqbr,
|
||||||
elems,
|
elems,
|
||||||
|
len: len.map(Box::new),
|
||||||
guard: guard.map(Box::new),
|
guard: guard.map(Box::new),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1567,7 +1577,7 @@ pub struct VarSignature {
|
||||||
|
|
||||||
impl NestedDisplay for VarSignature {
|
impl NestedDisplay for VarSignature {
|
||||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
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,
|
f,
|
||||||
"{}{} |= {}",
|
"{}{} |= {}",
|
||||||
self.pat,
|
self.pat,
|
||||||
fmt_option!(pre ": ", &self.t_spec),
|
fmt_option!(pre ": ", self.t_spec),
|
||||||
default_val
|
default_val
|
||||||
)
|
)
|
||||||
} else {
|
} 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.name,
|
||||||
self.params,
|
self.params,
|
||||||
fmt_option!(pre ": ", &self.return_t_spec)
|
fmt_option!(pre ": ", self.return_t_spec)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
write!(
|
write!(
|
||||||
|
@ -1877,7 +1887,7 @@ impl NestedDisplay for SubrSignature {
|
||||||
self.name,
|
self.name,
|
||||||
self.bounds,
|
self.bounds,
|
||||||
self.params,
|
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,
|
f,
|
||||||
"{}{}",
|
"{}{}",
|
||||||
self.params,
|
self.params,
|
||||||
fmt_option!(pre ": ", &self.return_t_spec)
|
fmt_option!(pre ": ", self.return_t_spec)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
write!(
|
write!(
|
||||||
|
@ -1941,7 +1951,7 @@ impl fmt::Display for LambdaSignature {
|
||||||
"|{}|{}{}",
|
"|{}|{}{}",
|
||||||
self.bounds,
|
self.bounds,
|
||||||
self.params,
|
self.params,
|
||||||
fmt_option!(pre ": ", &self.return_t_spec)
|
fmt_option!(pre ": ", self.return_t_spec)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -632,7 +632,7 @@ impl Parser {
|
||||||
Ok(acc)
|
Ok(acc)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_reduce_elems(&mut self) -> ParseResult<Vars> {
|
fn try_reduce_elems_pattern(&mut self) -> ParseResult<Vars> {
|
||||||
debug_call_info!(self);
|
debug_call_info!(self);
|
||||||
let mut elems = Vars::empty();
|
let mut elems = Vars::empty();
|
||||||
match self.peek() {
|
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(UBar) => Ok(VarPattern::Discard(self.lpop())),
|
||||||
Some(t) if t.is(LSqBr) => {
|
Some(t) if t.is(LSqBr) => {
|
||||||
let l_sqbr = self.lpop();
|
let l_sqbr = self.lpop();
|
||||||
let elems = self.try_reduce_elems()?;
|
let elems = self.try_reduce_elems_pattern()?;
|
||||||
if self.cur_is(RSqBr) {
|
if self.cur_is(RSqBr) {
|
||||||
let r_sqbr = self.lpop();
|
let r_sqbr = self.lpop();
|
||||||
Ok(VarPattern::Array(VarArrayPattern::new(
|
Ok(VarPattern::Array(VarArrayPattern::new(
|
||||||
|
@ -1060,6 +1060,67 @@ impl Parser {
|
||||||
Ok(const_args)
|
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>> {
|
fn opt_reduce_args(&mut self) -> Option<ParseResult<Args>> {
|
||||||
debug_call_info!(self);
|
debug_call_info!(self);
|
||||||
match self.peek() {
|
match self.peek() {
|
||||||
|
@ -1466,12 +1527,12 @@ impl Parser {
|
||||||
fn try_reduce_array(&mut self) -> ParseResult<Array> {
|
fn try_reduce_array(&mut self) -> ParseResult<Array> {
|
||||||
debug_call_info!(self);
|
debug_call_info!(self);
|
||||||
let l_sqbr = self.lpop();
|
let l_sqbr = self.lpop();
|
||||||
let elems = self.try_reduce_args()?;
|
let (elems, len, guard) = self.try_reduce_elems()?;
|
||||||
let r_sqbr = self.lpop();
|
let r_sqbr = self.lpop();
|
||||||
if !r_sqbr.is(RSqBr) {
|
if !r_sqbr.is(RSqBr) {
|
||||||
return Err(ParseError::simple_syntax_error(0, r_sqbr.loc()));
|
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)
|
Ok(arr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue