feat: support var-args lambda function

This commit is contained in:
Shunsuke Shibayama 2023-03-03 16:01:20 +09:00
parent cb00efca54
commit 3d310714f1
13 changed files with 123 additions and 47 deletions

View file

@ -69,7 +69,10 @@ impl<Checker: BuildRunnable> Server<Checker> {
pub(crate) fn quick_check_file(&mut self, uri: Url) -> ELSResult<()> { pub(crate) fn quick_check_file(&mut self, uri: Url) -> ELSResult<()> {
// send_log(format!("checking {uri}"))?; // send_log(format!("checking {uri}"))?;
let mut parser = Parser::new(self.file_cache.get_token_stream(&uri).unwrap().clone()); let Some(ts) = self.file_cache.get_token_stream(&uri) else {
return Ok(());
};
let mut parser = Parser::new(ts.clone());
if parser.parse().is_err() { if parser.parse().is_err() {
return Ok(()); return Ok(());
} }

View file

@ -2782,7 +2782,7 @@ impl PyCodeGenerator {
let mut ident = Identifier::public_with_line(DOT, Str::ever("__init__"), line); let mut ident = Identifier::public_with_line(DOT, Str::ever("__init__"), line);
ident.vi.t = __new__.clone(); ident.vi.t = __new__.clone();
let self_param = VarName::from_str_and_line(Str::ever("self"), line); let self_param = VarName::from_str_and_line(Str::ever("self"), line);
let vi = VarInfo::parameter( let vi = VarInfo::nd_parameter(
__new__.return_t().unwrap().clone(), __new__.return_t().unwrap().clone(),
ident.vi.def_loc.clone(), ident.vi.def_loc.clone(),
); );
@ -2797,7 +2797,7 @@ impl PyCodeGenerator {
let param = VarName::from_str_and_line(Str::from(param_name.clone()), line); let param = VarName::from_str_and_line(Str::from(param_name.clone()), line);
let raw = let raw =
erg_parser::ast::NonDefaultParamSignature::new(ParamPattern::VarName(param), None); erg_parser::ast::NonDefaultParamSignature::new(ParamPattern::VarName(param), None);
let vi = VarInfo::parameter(new_first_param.typ().clone(), ident.vi.def_loc.clone()); let vi = VarInfo::nd_parameter(new_first_param.typ().clone(), ident.vi.def_loc.clone());
let param = NonDefaultParamSignature::new(raw, vi, None); let param = NonDefaultParamSignature::new(raw, vi, None);
let params = Params::new(vec![self_param, param], None, vec![], None); let params = Params::new(vec![self_param, param], None, vec![], None);
(param_name, params) (param_name, params)
@ -2876,7 +2876,7 @@ impl PyCodeGenerator {
.map(|s| s.to_string()) .map(|s| s.to_string())
.unwrap_or_else(fresh_varname); .unwrap_or_else(fresh_varname);
let param = VarName::from_str_and_line(Str::from(param_name.clone()), line); let param = VarName::from_str_and_line(Str::from(param_name.clone()), line);
let vi = VarInfo::parameter(new_first_param.typ().clone(), ident.vi.def_loc.clone()); let vi = VarInfo::nd_parameter(new_first_param.typ().clone(), ident.vi.def_loc.clone());
let raw = let raw =
erg_parser::ast::NonDefaultParamSignature::new(ParamPattern::VarName(param), None); erg_parser::ast::NonDefaultParamSignature::new(ParamPattern::VarName(param), None);
let param = NonDefaultParamSignature::new(raw, vi, None); let param = NonDefaultParamSignature::new(raw, vi, None);

View file

@ -672,6 +672,9 @@ impl Context {
(Structural(l), Structural(r)) => self.structural_supertype_of(l, r), (Structural(l), Structural(r)) => self.structural_supertype_of(l, r),
// TODO: If visibility does not match, it should be reported as a cause of an error // TODO: If visibility does not match, it should be reported as a cause of an error
(Structural(l), r) => { (Structural(l), r) => {
if self.supertype_of(l, r) {
return true;
}
let r_fields = self.fields(r); let r_fields = self.fields(r);
for (l_field, l_ty) in self.fields(l) { for (l_field, l_ty) in self.fields(l) {
if let Some((r_field, r_ty)) = r_fields.get_key_value(&l_field) { if let Some((r_field, r_ty)) = r_fields.get_key_value(&l_field) {

View file

@ -67,8 +67,8 @@ impl Context {
let t_show = fn0_met(ref_(Slf), Str).quantify(); let t_show = fn0_met(ref_(Slf), Str).quantify();
show.register_builtin_py_decl(TO_STR, t_show, Public, Some(FUNDAMENTAL_STR)); show.register_builtin_py_decl(TO_STR, t_show, Public, Some(FUNDAMENTAL_STR));
/* In */ /* In */
let mut in_ = Self::builtin_poly_trait(IN, vec![PS::t(TY_T, NonDefault)], 2); let mut in_ = Self::builtin_poly_trait(IN, vec![PS::t_nd(TY_T)], 2);
let params = vec![PS::t(TY_T, NonDefault)]; let params = vec![PS::t_nd(TY_T)];
let input = Self::builtin_poly_trait(INPUT, params.clone(), 2); let input = Self::builtin_poly_trait(INPUT, params.clone(), 2);
let output = Self::builtin_poly_trait(OUTPUT, params, 2); let output = Self::builtin_poly_trait(OUTPUT, params, 2);
let T = mono_q(TY_T, instanceof(Type)); let T = mono_q(TY_T, instanceof(Type));
@ -100,7 +100,7 @@ impl Context {
poly(MUL, vec![]), poly(MUL, vec![]),
], */ ], */
/* Seq */ /* Seq */
let mut seq = Self::builtin_poly_trait(SEQ, vec![PS::t(TY_T, NonDefault)], 2); let mut seq = Self::builtin_poly_trait(SEQ, vec![PS::t_nd(TY_T)], 2);
seq.register_superclass(poly(OUTPUT, vec![ty_tp(T.clone())]), &output); seq.register_superclass(poly(OUTPUT, vec![ty_tp(T.clone())]), &output);
let Slf = mono_q(SELF, subtypeof(poly(SEQ, vec![TyParam::erased(Type)]))); let Slf = mono_q(SELF, subtypeof(poly(SEQ, vec![TyParam::erased(Type)])));
let t = fn0_met(Slf.clone(), Nat).quantify(); let t = fn0_met(Slf.clone(), Nat).quantify();
@ -109,14 +109,14 @@ impl Context {
// Seq.get: |Self <: Seq(T)| Self.(Nat) -> T // Seq.get: |Self <: Seq(T)| Self.(Nat) -> T
seq.register_builtin_erg_decl(FUNC_GET, t, Public); seq.register_builtin_erg_decl(FUNC_GET, t, Public);
/* Iterable */ /* Iterable */
let mut iterable = Self::builtin_poly_trait(ITERABLE, vec![PS::t(TY_T, NonDefault)], 2); let mut iterable = Self::builtin_poly_trait(ITERABLE, vec![PS::t_nd(TY_T)], 2);
iterable.register_superclass(poly(OUTPUT, vec![ty_tp(T.clone())]), &output); iterable.register_superclass(poly(OUTPUT, vec![ty_tp(T.clone())]), &output);
let Slf = mono_q(SELF, subtypeof(poly(ITERABLE, vec![ty_tp(T.clone())]))); let Slf = mono_q(SELF, subtypeof(poly(ITERABLE, vec![ty_tp(T.clone())])));
let t = fn0_met(Slf.clone(), proj(Slf, ITER)).quantify(); let t = fn0_met(Slf.clone(), proj(Slf, ITER)).quantify();
iterable.register_builtin_py_decl(FUNC_ITER, t, Public, Some(FUNDAMENTAL_ITER)); iterable.register_builtin_py_decl(FUNC_ITER, t, Public, Some(FUNDAMENTAL_ITER));
iterable.register_builtin_erg_decl(ITER, Type, Public); iterable.register_builtin_erg_decl(ITER, Type, Public);
let R = mono_q(TY_R, instanceof(Type)); let R = mono_q(TY_R, instanceof(Type));
let params = vec![PS::t(TY_R, WithDefault)]; let params = vec![PS::t(TY_R, false, WithDefault)];
let ty_params = vec![ty_tp(R.clone())]; let ty_params = vec![ty_tp(R.clone())];
/* Num */ /* Num */
/* Add */ /* Add */

View file

@ -97,7 +97,7 @@ impl ClassDefType {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DefaultInfo { pub enum DefaultInfo {
NonDefault, NonDefault, // var-args should be non-default
WithDefault, WithDefault,
} }
@ -141,6 +141,7 @@ pub struct ParamSpec {
pub(crate) name: Option<&'static str>, pub(crate) name: Option<&'static str>,
// TODO: `:` or `<:` // TODO: `:` or `<:`
pub(crate) t: Type, pub(crate) t: Type,
pub is_var_params: bool,
pub default_info: DefaultInfo, pub default_info: DefaultInfo,
loc: AbsLocation, loc: AbsLocation,
} }
@ -149,38 +150,59 @@ impl ParamSpec {
pub const fn new( pub const fn new(
name: Option<&'static str>, name: Option<&'static str>,
t: Type, t: Type,
is_var_params: bool,
default: DefaultInfo, default: DefaultInfo,
loc: AbsLocation, loc: AbsLocation,
) -> Self { ) -> Self {
Self { Self {
name, name,
t, t,
is_var_params,
default_info: default, default_info: default,
loc, loc,
} }
} }
pub const fn named(name: &'static str, t: Type, default: DefaultInfo) -> Self { pub const fn named(
Self::new(Some(name), t, default, AbsLocation::unknown()) name: &'static str,
t: Type,
is_var_params: bool,
default: DefaultInfo,
) -> Self {
Self::new(
Some(name),
t,
is_var_params,
default,
AbsLocation::unknown(),
)
} }
pub const fn named_nd(name: &'static str, t: Type) -> Self { pub const fn named_nd(name: &'static str, t: Type) -> Self {
Self::new( Self::new(
Some(name), Some(name),
t, t,
false,
DefaultInfo::NonDefault, DefaultInfo::NonDefault,
AbsLocation::unknown(), AbsLocation::unknown(),
) )
} }
pub const fn t(name: &'static str, default: DefaultInfo) -> Self { pub const fn t(name: &'static str, is_var_params: bool, default: DefaultInfo) -> Self {
Self::new(Some(name), Type, default, AbsLocation::unknown()) Self::new(
Some(name),
Type,
is_var_params,
default,
AbsLocation::unknown(),
)
} }
pub const fn t_nd(name: &'static str) -> Self { pub const fn t_nd(name: &'static str) -> Self {
Self::new( Self::new(
Some(name), Some(name),
Type, Type,
false,
DefaultInfo::NonDefault, DefaultInfo::NonDefault,
AbsLocation::unknown(), AbsLocation::unknown(),
) )
@ -487,12 +509,12 @@ impl Context {
for param in params.into_iter() { for param in params.into_iter() {
let id = DefId(get_hash(&(&name, &param))); let id = DefId(get_hash(&(&name, &param)));
if let Some(name) = param.name { if let Some(name) = param.name {
let kind = VarKind::parameter(id, param.default_info); let kind = VarKind::parameter(id, param.is_var_params, param.default_info);
let muty = Mutability::from(name); let muty = Mutability::from(name);
let vi = VarInfo::new(param.t, muty, Private, kind, None, None, None, param.loc); let vi = VarInfo::new(param.t, muty, Private, kind, None, None, None, param.loc);
params_.push((Some(VarName::new(Token::static_symbol(name))), vi)); params_.push((Some(VarName::new(Token::static_symbol(name))), vi));
} else { } else {
let kind = VarKind::parameter(id, param.default_info); let kind = VarKind::parameter(id, param.is_var_params, param.default_info);
let muty = Mutability::Immutable; let muty = Mutability::Immutable;
let vi = VarInfo::new(param.t, muty, Private, kind, None, None, None, param.loc); let vi = VarInfo::new(param.t, muty, Private, kind, None, None, None, param.loc);
params_.push((None, vi)); params_.push((None, vi));

View file

@ -321,7 +321,7 @@ impl Context {
Err(errs) => (Type::Failure, errs), Err(errs) => (Type::Failure, errs),
}; };
let def_id = DefId(get_hash(&(&self.name, "_"))); let def_id = DefId(get_hash(&(&self.name, "_")));
let kind = VarKind::parameter(def_id, DefaultInfo::NonDefault); let kind = VarKind::parameter(def_id, is_var_params, DefaultInfo::NonDefault);
let vi = VarInfo::new( let vi = VarInfo::new(
spec_t, spec_t,
Immutable, Immutable,
@ -382,7 +382,7 @@ impl Context {
} }
} }
let def_id = DefId(get_hash(&(&self.name, name))); let def_id = DefId(get_hash(&(&self.name, name)));
let kind = VarKind::parameter(def_id, default); let kind = VarKind::parameter(def_id, is_var_params, default);
let muty = Mutability::from(&name.inspect()[..]); let muty = Mutability::from(&name.inspect()[..]);
let vi = VarInfo::new( let vi = VarInfo::new(
spec_t, spec_t,
@ -440,7 +440,11 @@ impl Context {
log!(err "self_t is None"); log!(err "self_t is None");
} }
} }
let kind = VarKind::parameter(DefId(get_hash(&(&self.name, name))), default); let kind = VarKind::parameter(
DefId(get_hash(&(&self.name, name))),
is_var_params,
default,
);
let vi = VarInfo::new( let vi = VarInfo::new(
spec_t, spec_t,
Immutable, Immutable,
@ -499,7 +503,11 @@ impl Context {
log!(err "self_t is None"); log!(err "self_t is None");
} }
} }
let kind = VarKind::parameter(DefId(get_hash(&(&self.name, name))), default); let kind = VarKind::parameter(
DefId(get_hash(&(&self.name, name))),
is_var_params,
default,
);
let vi = VarInfo::new( let vi = VarInfo::new(
spec_t, spec_t,
Immutable, Immutable,
@ -577,6 +585,11 @@ impl Context {
errs.extend(es); errs.extend(es);
} }
} }
if let Some(var_params) = &mut params.var_params {
if let Err(es) = self.assign_param(var_params, None, ParamKind::VarParams) {
errs.extend(es);
}
}
for default in params.defaults.iter_mut() { for default in params.defaults.iter_mut() {
if let Err(es) = self.assign_param( if let Err(es) = self.assign_param(
&mut default.sig, &mut default.sig,

View file

@ -1008,7 +1008,6 @@ impl ASTLowerer {
} }
} }
/// TODO: varargs
fn lower_lambda(&mut self, lambda: ast::Lambda) -> LowerResult<hir::Lambda> { fn lower_lambda(&mut self, lambda: ast::Lambda) -> LowerResult<hir::Lambda> {
log!(info "entered {}({lambda})", fn_name!()); log!(info "entered {}({lambda})", fn_name!());
let in_statement = cfg!(feature = "py_compatible") let in_statement = cfg!(feature = "py_compatible")
@ -1074,7 +1073,20 @@ impl ASTLowerer {
.iter() .iter()
.partition(|(_, vi)| !vi.kind.has_default()); .partition(|(_, vi)| !vi.kind.has_default());
#[cfg(not(feature = "py_compatible"))] #[cfg(not(feature = "py_compatible"))]
let non_default_params = non_default_params.into_iter(); let (var_params, non_default_params) = {
let (var_params, non_default_params): (Vec<_>, Vec<_>) = non_default_params
.into_iter()
.partition(|(_, vi)| vi.kind.is_var_params());
// vi.t: `[T; _]`
// pt: `name: T`
let var_params = var_params.get(0).map(|(name, vi)| {
ParamTy::pos(
name.as_ref().map(|n| n.inspect().clone()),
vi.t.inner_ts().remove(0),
)
});
(var_params, non_default_params.into_iter())
};
#[cfg(feature = "py_compatible")] #[cfg(feature = "py_compatible")]
let non_default_params = non_default_params.into_iter().filter(|(name, _)| { let non_default_params = non_default_params.into_iter().filter(|(name, _)| {
params params
@ -1117,9 +1129,19 @@ impl ASTLowerer {
self.pop_append_errs(); self.pop_append_errs();
} }
let ty = if is_procedural { let ty = if is_procedural {
proc(non_default_param_tys, None, default_param_tys, body.t()) proc(
non_default_param_tys,
var_params,
default_param_tys,
body.t(),
)
} else { } else {
func(non_default_param_tys, None, default_param_tys, body.t()) func(
non_default_param_tys,
var_params,
default_param_tys,
body.t(),
)
}; };
let t = if ty.has_qvar() { ty.quantify() } else { ty }; let t = if ty.has_qvar() { ty.quantify() } else { ty };
Ok(hir::Lambda::new(id, params, lambda.op, body, t)) Ok(hir::Lambda::new(id, params, lambda.op, body, t))

View file

@ -41,8 +41,11 @@ use Mutability::*;
pub enum VarKind { pub enum VarKind {
Defined(DefId), Defined(DefId),
Declared, Declared,
// TODO: flatten Parameter {
Parameter { def_id: DefId, default: DefaultInfo }, def_id: DefId,
var: bool,
default: DefaultInfo,
},
Auto, Auto,
FixedAuto, FixedAuto,
DoesNotExist, DoesNotExist,
@ -50,8 +53,12 @@ pub enum VarKind {
} }
impl VarKind { impl VarKind {
pub const fn parameter(def_id: DefId, default: DefaultInfo) -> Self { pub const fn parameter(def_id: DefId, var: bool, default: DefaultInfo) -> Self {
Self::Parameter { def_id, default } Self::Parameter {
def_id,
var,
default,
}
} }
pub const fn has_default(&self) -> bool { pub const fn has_default(&self) -> bool {
@ -65,6 +72,13 @@ impl VarKind {
matches!(self, Self::Parameter { .. }) matches!(self, Self::Parameter { .. })
} }
pub const fn is_var_params(&self) -> bool {
match self {
Self::Parameter { var, .. } => *var,
_ => false,
}
}
pub const fn is_defined(&self) -> bool { pub const fn is_defined(&self) -> bool {
matches!(self, Self::Defined(_)) matches!(self, Self::Defined(_))
} }
@ -236,9 +250,10 @@ impl VarInfo {
} }
} }
pub fn parameter(t: Type, def_loc: AbsLocation) -> Self { pub fn nd_parameter(t: Type, def_loc: AbsLocation) -> Self {
let kind = VarKind::Parameter { let kind = VarKind::Parameter {
def_id: DefId(0), def_id: DefId(0),
var: false,
default: DefaultInfo::NonDefault, default: DefaultInfo::NonDefault,
}; };
Self::new(t, Immutable, Private, kind, None, None, None, def_loc) Self::new(t, Immutable, Private, kind, None, None, None, def_loc)

View file

@ -685,23 +685,6 @@ impl Parser {
debug_exit_info!(self); debug_exit_info!(self);
Ok(sig) Ok(sig)
} }
Expr::UnaryOp(unary) => match unary.op.kind {
TokenKind::PreStar => {
let mut exprs = unary.args.into_iter();
let param = self
.convert_rhs_to_param(*exprs.next().unwrap(), false)
.map_err(|_| self.stack_dec(fn_name!()))?;
let params = Params::new(vec![], Some(param), vec![], None);
debug_exit_info!(self);
Ok(LambdaSignature::new(params, None, TypeBoundSpecs::empty()))
}
_ => {
let err = ParseError::simple_syntax_error(line!() as usize, unary.op.loc());
self.errs.push(err);
debug_exit_info!(self);
Err(())
}
},
other => { other => {
let err = ParseError::simple_syntax_error(line!() as usize, other.loc()); let err = ParseError::simple_syntax_error(line!() as usize, other.loc());
self.errs.push(err); self.errs.push(err);

View file

@ -1703,6 +1703,15 @@ impl Parser {
debug_exit_info!(self); debug_exit_info!(self);
Ok(call_or_acc) Ok(call_or_acc)
} }
Some(t) if t.is(PreStar) => {
let _ = self.lpop();
let expr = self.try_reduce_expr(false, in_type_args, in_brace, false)?;
let tuple = self
.try_reduce_nonempty_tuple(ArgKind::Var(PosArg::new(expr)), false)
.map_err(|_| self.stack_dec(fn_name!()))?;
debug_exit_info!(self);
Ok(Expr::Tuple(tuple))
}
Some(t) if t.category_is(TC::UnaryOp) => { Some(t) if t.category_is(TC::UnaryOp) => {
let unaryop = self let unaryop = self
.try_reduce_unary() .try_reduce_unary()

View file

@ -3,3 +3,6 @@ p! 1, 2, "a" # ERR
first *x = x[0] first *x = x[0]
assert first(1, 2, 3) == "b" # ERR assert first(1, 2, 3) == "b" # ERR
f = (*_: Int) -> None
f "a", 1, 2

View file

@ -7,3 +7,6 @@ assert first(1, 2, 3) == 1
sum_ start: Nat, *args: Int = sum_ start: Nat, *args: Int =
sum(args, start:=start) sum(args, start:=start)
assert sum_(0, 1, 2, 3) == 6 assert sum_(0, 1, 2, 3) == 6
f = (*_: Int) -> None
f(1, 2, 3)

View file

@ -303,7 +303,7 @@ fn exec_var_args() -> Result<(), ()> {
#[test] #[test]
fn exec_var_args_err() -> Result<(), ()> { fn exec_var_args_err() -> Result<(), ()> {
expect_failure("tests/should_err/var_args.er", 2) expect_failure("tests/should_err/var_args.er", 3)
} }
#[test] #[test]