diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index af737181..4b17510e 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -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) diff --git a/compiler/erg_common/macros.rs b/compiler/erg_common/macros.rs index 592e3949..aa82d7f1 100644 --- a/compiler/erg_common/macros.rs +++ b/compiler/erg_common/macros.rs @@ -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() diff --git a/compiler/erg_common/ty.rs b/compiler/erg_common/ty.rs index d17a9a36..4665341a 100644 --- a/compiler/erg_common/ty.rs +++ b/compiler/erg_common/ty.rs @@ -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, "{}({}, {}) {} {}", diff --git a/compiler/erg_compiler/context.rs b/compiler/erg_compiler/context.rs index c4a80853..9624f4cd 100644 --- a/compiler/erg_compiler/context.rs +++ b/compiler/erg_compiler/context.rs @@ -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, diff --git a/compiler/erg_compiler/lower.rs b/compiler/erg_compiler/lower.rs index b1d8f3a1..c60eca9d 100644 --- a/compiler/erg_compiler/lower.rs +++ b/compiler/erg_compiler/lower.rs @@ -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) } diff --git a/compiler/erg_parser/ast.rs b/compiler/erg_parser/ast.rs index 6a4d55da..1c60f206 100644 --- a/compiler/erg_parser/ast.rs +++ b/compiler/erg_parser/ast.rs @@ -385,16 +385,19 @@ pub struct Array { pub l_sqbr: Token, pub r_sqbr: Token, pub elems: Args, + pub len: Option>, // if some, elems.len() should be 1 pub guard: Option>, } 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) -> Self { + pub fn new( + l_sqbr: Token, + r_sqbr: Token, + elems: Args, + len: Option, + guard: Option, + ) -> 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) ) } } diff --git a/compiler/erg_parser/parse.rs b/compiler/erg_parser/parse.rs index ece0cf32..23219ba2 100644 --- a/compiler/erg_parser/parse.rs +++ b/compiler/erg_parser/parse.rs @@ -632,7 +632,7 @@ impl Parser { Ok(acc) } - fn try_reduce_elems(&mut self) -> ParseResult { + fn try_reduce_elems_pattern(&mut self) -> ParseResult { 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, Option)> { + 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> { debug_call_info!(self); match self.peek() { @@ -1466,12 +1527,12 @@ impl Parser { fn try_reduce_array(&mut self) -> ParseResult { 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) }