Implement default parameter

This commit is contained in:
Shunsuke Shibayama 2022-10-18 10:27:57 +09:00
parent af65a48355
commit d0456ec1ee
10 changed files with 375 additions and 171 deletions

View file

@ -4,6 +4,7 @@
use std::fmt;
use std::process;
use crate::ty::codeobj::MakeFunctionFlags;
use crate::ty::codeobj::{CodeObj, CodeObjFlags};
use erg_common::astr::AtomicStr;
use erg_common::cache::CacheSet;
@ -21,7 +22,7 @@ use erg_parser::ast::DefId;
use erg_parser::ast::DefKind;
use Opcode::*;
use erg_parser::ast::{ParamPattern, ParamSignature, Params, VarName};
use erg_parser::ast::{NonDefaultParamSignature, ParamPattern, VarName};
use erg_parser::token::{Token, TokenKind};
use crate::compile::{AccessKind, Name, StoreLoadKind};
@ -29,7 +30,7 @@ use crate::context::eval::type_from_token_kind;
use crate::error::CompileError;
use crate::hir::{
Accessor, Args, Array, AttrDef, Attribute, BinOp, Block, Call, ClassDef, Def, DefBody, Expr,
Identifier, Lambda, Literal, PosArg, Record, Signature, SubrSignature, Tuple, UnaryOp,
Identifier, Lambda, Literal, Params, PosArg, Record, Signature, SubrSignature, Tuple, UnaryOp,
VarSignature, HIR,
};
use crate::ty::free::fresh_varname;
@ -858,6 +859,18 @@ impl CodeGenerator {
log!(info "entered {} ({lambda})", fn_name!());
let mut make_function_flag = 0u8;
let params = self.gen_param_names(&lambda.params);
if !lambda.params.defaults.is_empty() {
let defaults_len = lambda.params.defaults.len();
lambda
.params
.defaults
.into_iter()
.for_each(|default| self.emit_expr(default.default_val));
self.write_instr(BUILD_TUPLE);
self.write_arg(defaults_len as u8);
self.stack_dec_n(defaults_len - 1);
make_function_flag += MakeFunctionFlags::Defaults as u8;
}
let code = self.emit_block(lambda.body, Some("<lambda>".into()), params);
if !self.cur_block_codeobj().cellvars.is_empty() {
let cellvars_len = self.cur_block_codeobj().cellvars.len() as u8;
@ -867,7 +880,7 @@ impl CodeGenerator {
}
self.write_instr(BUILD_TUPLE);
self.write_arg(cellvars_len);
make_function_flag += 8;
make_function_flag += MakeFunctionFlags::Closure as u8;
}
self.emit_load_const(code);
self.emit_load_const("<lambda>");
@ -875,6 +888,9 @@ impl CodeGenerator {
self.write_arg(make_function_flag);
// stack_dec: <lambda code obj> + <name "<lambda>"> -> <function>
self.stack_dec();
if make_function_flag & MakeFunctionFlags::Defaults as u8 != 0 {
self.stack_dec();
}
}
fn emit_unaryop(&mut self, unary: UnaryOp) {
@ -1671,9 +1687,9 @@ impl CodeGenerator {
let ident = Identifier::public_with_line(Token::dummy(), Str::ever("__init__"), line);
let param_name = fresh_varname();
let param = VarName::from_str_and_line(Str::from(param_name.clone()), line);
let param = ParamSignature::new(ParamPattern::VarName(param), None, None);
let param = NonDefaultParamSignature::new(ParamPattern::VarName(param), None);
let self_param = VarName::from_str_and_line(Str::ever("self"), line);
let self_param = ParamSignature::new(ParamPattern::VarName(self_param), None, None);
let self_param = NonDefaultParamSignature::new(ParamPattern::VarName(self_param), None);
let params = Params::new(vec![self_param, param], None, vec![], None);
let subr_sig = SubrSignature::new(ident, params, __new__.clone());
let mut attrs = vec![];
@ -1729,7 +1745,7 @@ impl CodeGenerator {
let ident = Identifier::public_with_line(Token::dummy(), Str::ever("new"), line);
let param_name = fresh_varname();
let param = VarName::from_str_and_line(Str::from(param_name.clone()), line);
let param = ParamSignature::new(ParamPattern::VarName(param), None, None);
let param = NonDefaultParamSignature::new(ParamPattern::VarName(param), None);
let sig = SubrSignature::new(ident, Params::new(vec![param], None, vec![], None), __new__);
let arg = PosArg::new(Expr::Accessor(Accessor::private_with_line(
Str::from(param_name),

View file

@ -512,20 +512,32 @@ impl Context {
let tv_ctx = TyVarInstContext::new(self.level, bounds, self);
let mut non_default_params = Vec::with_capacity(lambda.sig.params.non_defaults.len());
for sig in lambda.sig.params.non_defaults.iter() {
let pt =
self.instantiate_param_ty(sig, None, Some(&tv_ctx), RegistrationMode::Normal)?;
let pt = self.instantiate_param_ty(
sig,
None,
None,
Some(&tv_ctx),
RegistrationMode::Normal,
)?;
non_default_params.push(pt);
}
let var_params = if let Some(p) = lambda.sig.params.var_args.as_ref() {
let pt = self.instantiate_param_ty(p, None, Some(&tv_ctx), RegistrationMode::Normal)?;
let pt =
self.instantiate_param_ty(p, None, None, Some(&tv_ctx), RegistrationMode::Normal)?;
Some(pt)
} else {
None
};
let mut default_params = Vec::with_capacity(lambda.sig.params.defaults.len());
for sig in lambda.sig.params.defaults.iter() {
let pt =
self.instantiate_param_ty(sig, None, Some(&tv_ctx), RegistrationMode::Normal)?;
let expr = self.eval_const_expr(&sig.default_val)?;
let pt = self.instantiate_param_ty(
&sig.sig,
Some(expr.t()),
None,
Some(&tv_ctx),
RegistrationMode::Normal,
)?;
default_params.push(pt);
}
// HACK: should avoid cloning

View file

@ -13,8 +13,8 @@ use erg_common::Str;
use erg_common::{assume_unreachable, enum_unwrap, set, try_map_mut};
use ast::{
ParamSignature, ParamTySpec, PreDeclTypeSpec, SimpleTypeSpec, TypeBoundSpec, TypeBoundSpecs,
TypeSpec,
NonDefaultParamSignature, ParamTySpec, PreDeclTypeSpec, SimpleTypeSpec, TypeBoundSpec,
TypeBoundSpecs, TypeSpec,
};
use erg_parser::ast;
use erg_parser::token::TokenKind;
@ -507,6 +507,7 @@ impl Context {
pub(crate) fn instantiate_sub_sig_t(
&self,
sig: &ast::SubrSignature,
default_ts: Vec<Type>,
mode: RegistrationMode,
) -> TyCheckResult<Type> {
// -> Result<Type, (Type, TyCheckErrors)> {
@ -521,22 +522,34 @@ impl Context {
let opt_decl_t = opt_decl_sig_t
.as_ref()
.and_then(|subr| subr.non_default_params.get(n));
non_defaults.push(self.instantiate_param_ty(p, opt_decl_t, Some(&tv_ctx), mode)?);
non_defaults.push(self.instantiate_param_ty(
p,
None,
opt_decl_t,
Some(&tv_ctx),
mode,
)?);
}
let var_args = if let Some(var_args) = sig.params.var_args.as_ref() {
let opt_decl_t = opt_decl_sig_t
.as_ref()
.and_then(|subr| subr.var_params.as_ref().map(|v| v.as_ref()));
Some(self.instantiate_param_ty(var_args, opt_decl_t, Some(&tv_ctx), mode)?)
Some(self.instantiate_param_ty(var_args, None, opt_decl_t, Some(&tv_ctx), mode)?)
} else {
None
};
let mut defaults = vec![];
for (n, p) in sig.params.defaults.iter().enumerate() {
for ((n, p), default_t) in sig.params.defaults.iter().enumerate().zip(default_ts) {
let opt_decl_t = opt_decl_sig_t
.as_ref()
.and_then(|subr| subr.default_params.get(n));
defaults.push(self.instantiate_param_ty(p, opt_decl_t, Some(&tv_ctx), mode)?);
defaults.push(self.instantiate_param_ty(
&p.sig,
Some(default_t),
opt_decl_t,
Some(&tv_ctx),
mode,
)?);
}
let spec_return_t = if let Some(s) = sig.return_t_spec.as_ref() {
let opt_decl_t = opt_decl_sig_t
@ -562,7 +575,7 @@ impl Context {
/// spec_t == Noneかつリテラル推論が不可能なら型変数を発行する
pub(crate) fn instantiate_param_sig_t(
&self,
sig: &ParamSignature,
sig: &NonDefaultParamSignature,
opt_decl_t: Option<&ParamTy>,
tmp_tv_ctx: Option<&TyVarInstContext>,
mode: RegistrationMode,
@ -599,21 +612,15 @@ impl Context {
pub(crate) fn instantiate_param_ty(
&self,
sig: &ParamSignature,
sig: &NonDefaultParamSignature,
opt_default_t: Option<Type>,
opt_decl_t: Option<&ParamTy>,
tmp_tv_ctx: Option<&TyVarInstContext>,
mode: RegistrationMode,
) -> TyCheckResult<ParamTy> {
let t = self.instantiate_param_sig_t(sig, opt_decl_t, tmp_tv_ctx, mode)?;
match (sig.inspect(), &sig.opt_default_val) {
(Some(name), Some(default)) => {
let default = self.instantiate_const_expr(default)?;
Ok(ParamTy::kw_default(
name.clone(),
t,
self.get_tp_t(&default)?,
))
}
match (sig.inspect(), opt_default_t) {
(Some(name), Some(default_t)) => Ok(ParamTy::kw_default(name.clone(), t, default_t)),
(Some(name), None) => Ok(ParamTy::kw(name.clone(), t)),
(None, None) => Ok(ParamTy::anonymous(t)),
_ => unreachable!(),

View file

@ -13,9 +13,9 @@ use erg_common::Str;
use erg_common::{enum_unwrap, get_hash, log, option_enum_unwrap, set};
use ast::{DefId, Identifier, VarName};
use erg_parser::ast;
use erg_parser::ast::{self, Decorator};
use crate::ty::constructors::{func, func1, proc, ref_, ref_mut, v_enum};
use crate::ty::constructors::{free_var, func, func1, proc, ref_, ref_mut, v_enum};
use crate::ty::free::{Constraint, Cyclicity, FreeKind};
use crate::ty::value::{GenTypeObj, TypeKind, TypeObj, ValueObj};
use crate::ty::{HasType, ParamTy, SubrType, Type};
@ -115,19 +115,23 @@ impl Context {
_ => None,
})
.collect::<Set<_>>();
let t = self.instantiate_sub_sig_t(sig, PreRegister).map_err(|e| {
let vi = VarInfo::new(
Type::Failure,
muty,
vis,
kind.clone(),
Some(comptime_decos.clone()),
self.impl_of(),
None,
);
self.decls.insert(sig.ident.name.clone(), vi);
e
})?;
let default_ts =
vec![free_var(self.level, Constraint::new_type_of(Type::Type)); sig.params.len()];
let t = self
.instantiate_sub_sig_t(sig, default_ts, PreRegister)
.map_err(|e| {
let vi = VarInfo::new(
Type::Failure,
muty,
vis,
kind.clone(),
Some(comptime_decos.clone()),
self.impl_of(),
None,
);
self.decls.insert(sig.ident.name.clone(), vi);
e
})?;
let vi = VarInfo::new(
t,
muty,
@ -190,7 +194,8 @@ impl Context {
/// 宣言が既にある場合、opt_decl_tに宣言の型を渡す
fn assign_param(
&mut self,
sig: &ast::ParamSignature,
sig: &ast::NonDefaultParamSignature,
default_val_exists: bool,
outer: Option<ParamIdx>,
nth: usize,
opt_decl_t: Option<&ParamTy>,
@ -222,7 +227,7 @@ impl Context {
} else {
ParamIdx::Nth(nth)
};
let default = if sig.opt_default_val.is_some() {
let default = if default_val_exists {
DefaultInfo::WithDefault
} else {
DefaultInfo::NonDefault
@ -262,7 +267,7 @@ impl Context {
} else {
ParamIdx::Nth(nth)
};
let default = if sig.opt_default_val.is_some() {
let default = if default_val_exists {
DefaultInfo::WithDefault
} else {
DefaultInfo::NonDefault
@ -301,7 +306,7 @@ impl Context {
} else {
ParamIdx::Nth(nth)
};
let default = if sig.opt_default_val.is_some() {
let default = if default_val_exists {
DefaultInfo::WithDefault
} else {
DefaultInfo::NonDefault
@ -324,7 +329,7 @@ impl Context {
pub(crate) fn assign_params(
&mut self,
params: &ast::Params,
params: &hir::Params,
opt_decl_subr_t: Option<SubrType>,
) -> TyCheckResult<()> {
if let Some(decl_subr_t) = opt_decl_subr_t {
@ -339,7 +344,7 @@ impl Context {
.zip(decl_subr_t.non_default_params.iter())
.enumerate()
{
self.assign_param(sig, None, nth, Some(pt))?;
self.assign_param(sig, false, None, nth, Some(pt))?;
}
for (nth, (sig, pt)) in params
.defaults
@ -347,17 +352,14 @@ impl Context {
.zip(decl_subr_t.default_params.iter())
.enumerate()
{
// TODO: .clone()
self.assign_param(sig, None, nth, Some(pt))?;
self.assign_param(&sig.sig, true, None, nth, Some(pt))?;
}
} else {
for (nth, sig) in params
.non_defaults
.iter()
.chain(params.defaults.iter())
.enumerate()
{
self.assign_param(sig, None, nth, None)?;
for (nth, sig) in params.non_defaults.iter().enumerate() {
self.assign_param(sig, false, None, nth, None)?;
}
for (nth, sig) in params.defaults.iter().enumerate() {
self.assign_param(&sig.sig, true, None, nth, None)?;
}
}
Ok(())
@ -368,23 +370,24 @@ impl Context {
/// * AssignError: if `name` has already been registered
pub(crate) fn assign_subr(
&mut self,
sig: &ast::SubrSignature,
ident: &Identifier,
decorators: &Set<Decorator>,
id: DefId,
body_t: &Type,
) -> TyCheckResult<Type> {
// already defined as const
if sig.is_const() {
let vi = self.decls.remove(sig.ident.inspect()).unwrap();
if ident.is_const() {
let vi = self.decls.remove(ident.inspect()).unwrap();
let t = vi.t.clone();
self.locals.insert(sig.ident.name.clone(), vi);
self.locals.insert(ident.name.clone(), vi);
return Ok(t);
}
let muty = if sig.ident.is_const() {
let muty = if ident.is_const() {
Mutability::Const
} else {
Mutability::Immutable
};
let name = &sig.ident.name;
let name = &ident.name;
// FIXME: constでない関数
let t = self
.get_current_scope_var(name.inspect())
@ -394,7 +397,7 @@ impl Context {
let var_args = t.var_args();
let default_params = t.default_params().unwrap();
if let Some(spec_ret_t) = t.return_t() {
self.sub_unify(body_t, spec_ret_t, sig.loc(), None)
self.sub_unify(body_t, spec_ret_t, ident.loc(), None)
.map_err(|errs| {
TyCheckErrors::new(
errs.into_iter()
@ -413,7 +416,7 @@ impl Context {
)
})?;
}
let sub_t = if sig.ident.is_procedural() {
let sub_t = if ident.is_procedural() {
proc(
non_default_params.clone(),
var_args.cloned(),
@ -448,7 +451,7 @@ impl Context {
return Err(TyCheckErrors::from(TyCheckError::violate_decl_error(
self.cfg.input.clone(),
line!() as usize,
sig.loc(),
ident.loc(),
self.caused_by(),
name.inspect(),
&vi.t,
@ -456,8 +459,7 @@ impl Context {
)));
}
}
let comptime_decos = sig
.decorators
let comptime_decos = decorators
.iter()
.filter_map(|deco| match &deco.0 {
ast::Expr::Accessor(ast::Accessor::Ident(local)) if local.is_const() => {
@ -469,7 +471,7 @@ impl Context {
let vi = VarInfo::new(
found_t,
muty,
sig.ident.vis(),
ident.vis(),
VarKind::Defined(id),
Some(comptime_decos),
self.impl_of(),
@ -481,21 +483,25 @@ impl Context {
Ok(t)
}
pub(crate) fn fake_subr_assign(&mut self, sig: &ast::SubrSignature, failure_t: Type) {
pub(crate) fn fake_subr_assign(
&mut self,
ident: &Identifier,
decorators: &Set<Decorator>,
failure_t: Type,
) {
// already defined as const
if sig.is_const() {
let vi = self.decls.remove(sig.ident.inspect()).unwrap();
self.locals.insert(sig.ident.name.clone(), vi);
if ident.is_const() {
let vi = self.decls.remove(ident.inspect()).unwrap();
self.locals.insert(ident.name.clone(), vi);
}
let muty = if sig.ident.is_const() {
let muty = if ident.is_const() {
Mutability::Const
} else {
Mutability::Immutable
};
let name = &sig.ident.name;
let name = &ident.name;
self.decls.remove(name);
let comptime_decos = sig
.decorators
let comptime_decos = decorators
.iter()
.filter_map(|deco| match &deco.0 {
ast::Expr::Accessor(ast::Accessor::Ident(local)) if local.is_const() => {
@ -507,7 +513,7 @@ impl Context {
let vi = VarInfo::new(
failure_t,
muty,
sig.ident.vis(),
ident.vis(),
VarKind::DoesNotExist,
Some(comptime_decos),
self.impl_of(),

View file

@ -12,7 +12,7 @@ use erg_common::{
impl_nested_display_for_enum, impl_stream_for_wrapper,
};
use erg_parser::ast::{fmt_lines, DefId, DefKind, Params, TypeSpec, VarName};
use erg_parser::ast::{fmt_lines, DefId, DefKind, NonDefaultParamSignature, TypeSpec, VarName};
use erg_parser::token::{Token, TokenKind};
use crate::ty::constructors::{array_t, dict_t, set_t, tuple_t};
@ -1216,6 +1216,115 @@ impl VarSignature {
}
}
/// Once the default_value is set to Some, all subsequent values must be Some
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct DefaultParamSignature {
pub sig: NonDefaultParamSignature,
pub default_val: Expr,
}
impl NestedDisplay for DefaultParamSignature {
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result {
write!(f, "{} := {}", self.sig, self.default_val,)
}
}
impl_display_from_nested!(DefaultParamSignature);
impl Locational for DefaultParamSignature {
fn loc(&self) -> Location {
Location::concat(&self.sig, &self.default_val)
}
}
impl DefaultParamSignature {
pub const fn new(sig: NonDefaultParamSignature, default_val: Expr) -> Self {
Self { sig, default_val }
}
pub const fn inspect(&self) -> Option<&Str> {
self.sig.pat.inspect()
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Params {
pub non_defaults: Vec<NonDefaultParamSignature>,
pub var_args: Option<Box<NonDefaultParamSignature>>,
pub defaults: Vec<DefaultParamSignature>,
pub parens: Option<(Token, Token)>,
}
impl fmt::Display for Params {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"({}, {}, {})",
fmt_vec(&self.non_defaults),
fmt_option!(pre "...", &self.var_args),
fmt_vec(&self.defaults)
)
}
}
impl Locational for Params {
fn loc(&self) -> Location {
// FIXME: varargs
if let Some((l, r)) = &self.parens {
Location::concat(l, r)
} else if !self.non_defaults.is_empty() {
Location::concat(&self.non_defaults[0], self.non_defaults.last().unwrap())
} else if let Some(var_args) = &self.var_args {
if !self.defaults.is_empty() {
Location::concat(var_args.as_ref(), self.defaults.last().unwrap())
} else {
var_args.loc()
}
} else if !self.defaults.is_empty() {
Location::concat(&self.defaults[0], self.defaults.last().unwrap())
} else {
panic!()
}
}
}
type RawParams = (
Vec<NonDefaultParamSignature>,
Option<Box<NonDefaultParamSignature>>,
Vec<DefaultParamSignature>,
Option<(Token, Token)>,
);
impl Params {
pub const fn new(
non_defaults: Vec<NonDefaultParamSignature>,
var_args: Option<Box<NonDefaultParamSignature>>,
defaults: Vec<DefaultParamSignature>,
parens: Option<(Token, Token)>,
) -> Self {
Self {
non_defaults,
var_args,
defaults,
parens,
}
}
pub fn deconstruct(self) -> RawParams {
(self.non_defaults, self.var_args, self.defaults, self.parens)
}
#[inline]
pub fn len(&self) -> usize {
self.non_defaults.len() + self.defaults.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct SubrSignature {
pub ident: Identifier,

View file

@ -759,6 +759,22 @@ impl ASTLowerer {
Ok(hir::Call::new(class, Some(attr_name), args))
}
fn lower_params(&mut self, params: ast::Params) -> LowerResult<hir::Params> {
log!(info "entered {}({})", fn_name!(), params);
let mut hir_defaults = vec![];
for default in params.defaults.into_iter() {
let default_val = self.lower_expr(default.default_val)?;
hir_defaults.push(hir::DefaultParamSignature::new(default.sig, default_val));
}
let hir_params = hir::Params::new(
params.non_defaults,
params.var_args,
hir_defaults,
params.parens,
);
Ok(hir_params)
}
/// TODO: varargs
fn lower_lambda(&mut self, lambda: ast::Lambda) -> LowerResult<hir::Lambda> {
log!(info "entered {}({lambda})", fn_name!());
@ -775,7 +791,8 @@ impl ASTLowerer {
.instantiate_ty_bounds(&lambda.sig.bounds, RegistrationMode::Normal)?;
let tv_ctx = TyVarInstContext::new(self.ctx.level, bounds, &self.ctx);
self.ctx.grow(&name, kind, Private, Some(tv_ctx));
if let Err(errs) = self.ctx.assign_params(&lambda.sig.params, None) {
let params = self.lower_params(lambda.sig.params)?;
if let Err(errs) = self.ctx.assign_params(&params, None) {
self.errs.extend(errs.into_iter());
}
if let Err(errs) = self.ctx.preregister(&lambda.body) {
@ -818,7 +835,7 @@ impl ASTLowerer {
} else {
quant(t, bounds)
};
Ok(hir::Lambda::new(id, lambda.sig.params, lambda.op, body, t))
Ok(hir::Lambda::new(id, params, lambda.op, body, t))
}
fn lower_def(&mut self, def: ast::Def) -> LowerResult<hir::Def> {
@ -951,7 +968,8 @@ impl ASTLowerer {
.unwrap_or(Type::Failure);
match t {
Type::Subr(t) => {
if let Err(errs) = self.ctx.assign_params(&sig.params, Some(t.clone())) {
let params = self.lower_params(sig.params)?;
if let Err(errs) = self.ctx.assign_params(&params, Some(t.clone())) {
self.errs.extend(errs.into_iter());
}
if let Err(errs) = self.ctx.preregister(&body.block) {
@ -961,9 +979,9 @@ impl ASTLowerer {
Ok(block) => {
let found_body_t = block.ref_t();
let expect_body_t = t.return_t.as_ref();
if !sig.is_const() {
if !sig.ident.is_const() {
if let Err(e) = self.return_t_check(
sig.loc(),
sig.ident.loc(),
sig.ident.inspect(),
expect_body_t,
found_body_t,
@ -972,20 +990,21 @@ impl ASTLowerer {
}
}
let id = body.id;
let t =
self.ctx
.outer
.as_mut()
.unwrap()
.assign_subr(&sig, id, found_body_t)?;
let t = self.ctx.outer.as_mut().unwrap().assign_subr(
&sig.ident,
&sig.decorators,
id,
found_body_t,
)?;
let ident = hir::Identifier::bare(sig.ident.dot, sig.ident.name);
let sig = hir::SubrSignature::new(ident, sig.params, t);
let sig = hir::SubrSignature::new(ident, params, t);
let body = hir::DefBody::new(body.op, block, body.id);
Ok(hir::Def::new(hir::Signature::Subr(sig), body))
}
Err(errs) => {
self.ctx.outer.as_mut().unwrap().assign_subr(
&sig,
&sig.ident,
&sig.decorators,
ast::DefId(0),
&Type::Failure,
)?;
@ -994,20 +1013,21 @@ impl ASTLowerer {
}
}
Type::Failure => {
if let Err(errs) = self.ctx.assign_params(&sig.params, None) {
let params = self.lower_params(sig.params)?;
if let Err(errs) = self.ctx.assign_params(&params, None) {
self.errs.extend(errs.into_iter());
}
if let Err(errs) = self.ctx.preregister(&body.block) {
self.errs.extend(errs.into_iter());
}
self.ctx
.outer
.as_mut()
.unwrap()
.fake_subr_assign(&sig, Type::Failure);
self.ctx.outer.as_mut().unwrap().fake_subr_assign(
&sig.ident,
&sig.decorators,
Type::Failure,
);
let block = self.lower_block(body.block)?;
let ident = hir::Identifier::bare(sig.ident.dot, sig.ident.name);
let sig = hir::SubrSignature::new(ident, sig.params, Type::Failure);
let sig = hir::SubrSignature::new(ident, params, Type::Failure);
let body = hir::DefBody::new(body.op, block, body.id);
Ok(hir::Def::new(hir::Signature::Subr(sig), body))
}

View file

@ -94,6 +94,29 @@ impl CodeObjFlags {
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum MakeFunctionFlags {
None = 0,
Defaults = 1,
KwDefaults = 2,
Annotations = 4,
Closure = 8,
}
impl From<u8> for MakeFunctionFlags {
fn from(flags: u8) -> Self {
match flags {
0 => Self::None,
1 => Self::Defaults,
2 => Self::KwDefaults,
4 => Self::Annotations,
8 => Self::Closure,
_ => unreachable!(),
}
}
}
/// Implementation of `PyCodeObject`, see Include/cpython/code.h in CPython for details.
///
/// 各属性をErg側のObjに変換すると遅くなりそうなので、アクサスされたときのみ変換して提供する

View file

@ -2422,7 +2422,7 @@ impl ParamTuplePattern {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ParamRecordAttr {
pub lhs: Identifier,
pub rhs: ParamSignature,
pub rhs: NonDefaultParamSignature,
}
impl NestedDisplay for ParamRecordAttr {
@ -2435,7 +2435,7 @@ impl_display_from_nested!(ParamRecordAttr);
impl_locational!(ParamRecordAttr, lhs, rhs);
impl ParamRecordAttr {
pub const fn new(lhs: Identifier, rhs: ParamSignature) -> Self {
pub const fn new(lhs: Identifier, rhs: NonDefaultParamSignature) -> Self {
Self { lhs, rhs }
}
}
@ -2554,35 +2554,22 @@ impl ParamPattern {
/// Once the default_value is set to Some, all subsequent values must be Some
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ParamSignature {
pub struct NonDefaultParamSignature {
pub pat: ParamPattern,
pub t_spec: Option<TypeSpecWithOp>,
pub opt_default_val: Option<ConstExpr>,
}
impl NestedDisplay for ParamSignature {
impl NestedDisplay for NonDefaultParamSignature {
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result {
if let Some(default_val) = &self.opt_default_val {
write!(
f,
"{}{} := {}",
self.pat,
fmt_option!(self.t_spec),
default_val,
)
} else {
write!(f, "{}{}", self.pat, fmt_option!(self.t_spec),)
}
write!(f, "{}{}", self.pat, fmt_option!(self.t_spec),)
}
}
impl_display_from_nested!(ParamSignature);
impl_display_from_nested!(NonDefaultParamSignature);
impl Locational for ParamSignature {
impl Locational for NonDefaultParamSignature {
fn loc(&self) -> Location {
if let Some(default) = &self.opt_default_val {
Location::concat(&self.pat, default)
} else if let Some(t_spec) = &self.t_spec {
if let Some(t_spec) = &self.t_spec {
Location::concat(&self.pat, t_spec)
} else {
self.pat.loc()
@ -2590,33 +2577,52 @@ impl Locational for ParamSignature {
}
}
impl ParamSignature {
pub const fn new(
pat: ParamPattern,
t_spec: Option<TypeSpecWithOp>,
opt_default_val: Option<ConstExpr>,
) -> Self {
Self {
pat,
t_spec,
opt_default_val,
}
impl NonDefaultParamSignature {
pub const fn new(pat: ParamPattern, t_spec: Option<TypeSpecWithOp>) -> Self {
Self { pat, t_spec }
}
pub const fn inspect(&self) -> Option<&Str> {
self.pat.inspect()
}
}
pub fn has_default(&self) -> bool {
self.opt_default_val.is_some()
/// Once the default_value is set to Some, all subsequent values must be Some
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct DefaultParamSignature {
pub sig: NonDefaultParamSignature,
pub default_val: Expr,
}
impl NestedDisplay for DefaultParamSignature {
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result {
write!(f, "{} := {}", self.sig, self.default_val,)
}
}
impl_display_from_nested!(DefaultParamSignature);
impl Locational for DefaultParamSignature {
fn loc(&self) -> Location {
Location::concat(&self.sig, &self.default_val)
}
}
impl DefaultParamSignature {
pub const fn new(sig: NonDefaultParamSignature, default_val: Expr) -> Self {
Self { sig, default_val }
}
pub const fn inspect(&self) -> Option<&Str> {
self.sig.pat.inspect()
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Params {
pub non_defaults: Vec<ParamSignature>,
pub var_args: Option<Box<ParamSignature>>,
pub defaults: Vec<ParamSignature>,
pub non_defaults: Vec<NonDefaultParamSignature>,
pub var_args: Option<Box<NonDefaultParamSignature>>,
pub defaults: Vec<DefaultParamSignature>,
pub parens: Option<(Token, Token)>,
}
@ -2654,17 +2660,17 @@ impl Locational for Params {
}
type RawParams = (
Vec<ParamSignature>,
Option<Box<ParamSignature>>,
Vec<ParamSignature>,
Vec<NonDefaultParamSignature>,
Option<Box<NonDefaultParamSignature>>,
Vec<DefaultParamSignature>,
Option<(Token, Token)>,
);
impl Params {
pub fn new(
non_defaults: Vec<ParamSignature>,
var_args: Option<ParamSignature>,
defaults: Vec<ParamSignature>,
non_defaults: Vec<NonDefaultParamSignature>,
var_args: Option<NonDefaultParamSignature>,
defaults: Vec<DefaultParamSignature>,
parens: Option<(Token, Token)>,
) -> Self {
Self {

View file

@ -13,8 +13,8 @@ use erg_common::{enum_unwrap, get_hash, log, set};
use crate::ast::{
Accessor, Args, Array, ArrayComprehension, ArrayWithLength, BinOp, Block, Call, DataPack, Def,
DefBody, DefId, Dict, Expr, Identifier, KeyValue, KwArg, Lambda, LambdaSignature, Literal,
Methods, Module, NormalArray, NormalDict, NormalRecord, NormalSet, NormalTuple, ParamPattern,
ParamSignature, Params, PosArg, Record, RecordAttrs, Set as astSet, SetWithLength,
Methods, Module, NonDefaultParamSignature, NormalArray, NormalDict, NormalRecord, NormalSet,
NormalTuple, ParamPattern, Params, PosArg, Record, RecordAttrs, Set as astSet, SetWithLength,
ShortenedRecord, Signature, SubrSignature, Tuple, TypeAscription, TypeBoundSpecs, TypeSpec,
UnaryOp, VarName, VarPattern, VarRecordAttr, VarSignature,
};
@ -255,7 +255,7 @@ impl Desugarer {
name.col_end().unwrap() + 1, // HACK: `(name) %x = ...`という形を想定
));
let param =
ParamSignature::new(ParamPattern::VarName(param), None, None);
NonDefaultParamSignature::new(ParamPattern::VarName(param), None);
let params = Params::new(vec![param], None, vec![], None);
let sig = Signature::Subr(SubrSignature::new(
set! {},

View file

@ -1985,12 +1985,9 @@ impl Parser {
return Err(());
}
// e.g. (x, y:=1) -> ...
// Syntax error will occur when trying to use it as a tuple
PosOrKwArg::Kw(arg) => {
args.push_kw(arg);
/*self.level -= 1;
let err = ParseError::simple_syntax_error(line!() as usize, arg.loc());
self.errs.push(err);
return Err(());*/
}
}
}
@ -2369,7 +2366,7 @@ impl Parser {
&mut self,
arg: PosArg,
allow_self: bool,
) -> ParseResult<ParamSignature> {
) -> ParseResult<NonDefaultParamSignature> {
debug_call_info!(self);
let param = self
.convert_rhs_to_param(arg.expr, allow_self)
@ -2382,7 +2379,7 @@ impl Parser {
&mut self,
expr: Expr,
allow_self: bool,
) -> ParseResult<ParamSignature> {
) -> ParseResult<NonDefaultParamSignature> {
debug_call_info!(self);
match expr {
Expr::Accessor(Accessor::Ident(ident)) => {
@ -2394,13 +2391,13 @@ impl Parser {
}
// FIXME deny: public
let pat = ParamPattern::VarName(ident.name);
let param = ParamSignature::new(pat, None, None);
let param = NonDefaultParamSignature::new(pat, None);
self.level -= 1;
Ok(param)
}
Expr::Lit(lit) => {
let pat = ParamPattern::Lit(lit);
let param = ParamSignature::new(pat, None, None);
let param = NonDefaultParamSignature::new(pat, None);
self.level -= 1;
Ok(param)
}
@ -2409,7 +2406,7 @@ impl Parser {
.convert_array_to_param_array_pat(array)
.map_err(|_| self.stack_dec())?;
let pat = ParamPattern::Array(array_pat);
let param = ParamSignature::new(pat, None, None);
let param = NonDefaultParamSignature::new(pat, None);
self.level -= 1;
Ok(param)
}
@ -2418,7 +2415,7 @@ impl Parser {
.convert_record_to_param_record_pat(record)
.map_err(|_| self.stack_dec())?;
let pat = ParamPattern::Record(record_pat);
let param = ParamSignature::new(pat, None, None);
let param = NonDefaultParamSignature::new(pat, None);
self.level -= 1;
Ok(param)
}
@ -2427,7 +2424,7 @@ impl Parser {
.convert_tuple_to_param_tuple_pat(tuple)
.map_err(|_| self.stack_dec())?;
let pat = ParamPattern::Tuple(tuple_pat);
let param = ParamSignature::new(pat, None, None);
let param = NonDefaultParamSignature::new(pat, None);
self.level -= 1;
Ok(param)
}
@ -2444,7 +2441,7 @@ impl Parser {
let var = option_enum_unwrap!(*var, Expr::Accessor:(Accessor::Ident:(_)))
.unwrap_or_else(|| todo!());
let pat = ParamPattern::Ref(var.name);
let param = ParamSignature::new(pat, None, None);
let param = NonDefaultParamSignature::new(pat, None);
self.level -= 1;
Ok(param)
}
@ -2453,7 +2450,7 @@ impl Parser {
let var = option_enum_unwrap!(*var, Expr::Accessor:(Accessor::Ident:(_)))
.unwrap_or_else(|| todo!());
let pat = ParamPattern::RefMut(var.name);
let param = ParamSignature::new(pat, None, None);
let param = NonDefaultParamSignature::new(pat, None);
self.level -= 1;
Ok(param)
}
@ -2474,11 +2471,14 @@ impl Parser {
}
}
fn convert_kw_arg_to_default_param(&mut self, arg: KwArg) -> ParseResult<ParamSignature> {
fn convert_kw_arg_to_default_param(
&mut self,
arg: KwArg,
) -> ParseResult<DefaultParamSignature> {
debug_call_info!(self);
let pat = ParamPattern::VarName(VarName::new(arg.keyword));
let expr = Self::validate_const_expr(arg.expr).map_err(|e| self.errs.push(e))?;
let param = ParamSignature::new(pat, arg.t_spec, Some(expr));
let sig = NonDefaultParamSignature::new(pat, arg.t_spec);
let param = DefaultParamSignature::new(sig, arg.expr);
self.level -= 1;
Ok(param)
}
@ -2532,8 +2532,10 @@ impl Parser {
Record::Shortened(rec) => {
let mut pats = vec![];
for ident in rec.idents.into_iter() {
let rhs =
ParamSignature::new(ParamPattern::VarName(ident.name.clone()), None, None);
let rhs = NonDefaultParamSignature::new(
ParamPattern::VarName(ident.name.clone()),
None,
);
pats.push(ParamRecordAttr::new(ident.clone(), rhs));
}
let attrs = ParamRecordAttrs::new(pats);
@ -2563,13 +2565,13 @@ impl Parser {
&mut self,
tasc: TypeAscription,
allow_self: bool,
) -> ParseResult<ParamSignature> {
) -> ParseResult<NonDefaultParamSignature> {
debug_call_info!(self);
let param = self
.convert_rhs_to_param(*tasc.expr, allow_self)
.map_err(|_| self.stack_dec())?;
let t_spec = TypeSpecWithOp::new(tasc.op, tasc.t_spec);
let param = ParamSignature::new(param.pat, Some(t_spec), None);
let param = NonDefaultParamSignature::new(param.pat, Some(t_spec));
self.level -= 1;
Ok(param)
}
@ -2596,7 +2598,7 @@ impl Parser {
let arr = self
.convert_array_to_param_array_pat(array)
.map_err(|_| self.stack_dec())?;
let param = ParamSignature::new(ParamPattern::Array(arr), None, None);
let param = NonDefaultParamSignature::new(ParamPattern::Array(arr), None);
let params = Params::new(vec![param], None, vec![], None);
self.level -= 1;
Ok(LambdaSignature::new(params, None, TypeBoundSpecs::empty()))
@ -2605,7 +2607,7 @@ impl Parser {
let rec = self
.convert_record_to_param_record_pat(record)
.map_err(|_| self.stack_dec())?;
let param = ParamSignature::new(ParamPattern::Record(rec), None, None);
let param = NonDefaultParamSignature::new(ParamPattern::Record(rec), None);
let params = Params::new(vec![param], None, vec![], None);
self.level -= 1;
Ok(LambdaSignature::new(params, None, TypeBoundSpecs::empty()))
@ -2626,7 +2628,10 @@ impl Parser {
}
}
fn convert_accessor_to_param_sig(&mut self, accessor: Accessor) -> ParseResult<ParamSignature> {
fn convert_accessor_to_param_sig(
&mut self,
accessor: Accessor,
) -> ParseResult<NonDefaultParamSignature> {
debug_call_info!(self);
match accessor {
Accessor::Ident(ident) => {
@ -2636,7 +2641,7 @@ impl Parser {
ParamPattern::VarName(ident.name)
};
self.level -= 1;
Ok(ParamSignature::new(pat, None, None))
Ok(NonDefaultParamSignature::new(pat, None))
}
other => {
self.level -= 1;
@ -2806,7 +2811,7 @@ impl Parser {
});
let mut defaults = vec![];
for param in lambda.sig.params.defaults.into_iter() {
let param = match (param.pat, param.t_spec) {
let param = match (param.sig.pat, param.sig.t_spec) {
(ParamPattern::VarName(name), Some(t_spec_with_op)) => {
ParamTySpec::new(Some(name.into_token()), t_spec_with_op.t_spec)
}