Fix Array type inference

This commit is contained in:
Shunsuke Shibayama 2022-08-19 10:43:57 +09:00
parent 2a68c89140
commit e36746f964
7 changed files with 107 additions and 29 deletions

View file

@ -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)

View file

@ -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()

View file

@ -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,
"{}({}, {}) {} {}", "{}({}, {}) {} {}",

View file

@ -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,

View file

@ -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)
} }

View file

@ -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)
) )
} }
} }

View file

@ -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)
} }