Merge pull request #264 from erg-lang/fix-#255

Fix #255
This commit is contained in:
Shunsuke Shibayama 2022-11-29 15:02:06 +09:00 committed by GitHub
commit 38d69e6b96
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 201 additions and 92 deletions

View file

@ -1926,9 +1926,10 @@ impl PyCodeGenerator {
self.emit_call_local(ident, call.args)
}
other => {
let is_py_api = other.is_py_api();
self.emit_push_null();
self.emit_expr(other);
self.emit_args_311(call.args, Name);
self.emit_args_311(call.args, Name, is_py_api);
}
}
}
@ -1952,11 +1953,12 @@ impl PyCodeGenerator {
Some(8) => self.emit_with_instr_308(args),
_ => todo!(),
},
// "pyimport" | "py" |
// "pyimport" | "py" are here
_ => {
let is_py_api = local.is_py_api();
self.emit_push_null();
self.emit_load_name_instr(local);
self.emit_args_311(args, Name);
self.emit_args_311(args, Name, is_py_api);
}
}
}
@ -1973,9 +1975,10 @@ impl PyCodeGenerator {
} else if let Some(func_name) = fake_method_to_func(&class, method_name.inspect()) {
return self.emit_call_fake_method(obj, func_name, method_name, args);
}
let is_py_api = obj.is_py_api();
self.emit_expr(obj);
self.emit_load_method_instr(method_name);
self.emit_args_311(args, Method);
self.emit_args_311(args, Method, is_py_api);
}
fn emit_var_args_311(&mut self, pos_len: usize, var_args: &PosArg) {
@ -2004,7 +2007,7 @@ impl PyCodeGenerator {
}
}
fn emit_args_311(&mut self, mut args: Args, kind: AccessKind) {
fn emit_args_311(&mut self, mut args: Args, kind: AccessKind, is_py_api: bool) {
let argc = args.len();
let pos_len = args.pos_args.len();
let mut kws = Vec::with_capacity(args.kw_len());
@ -2019,7 +2022,12 @@ impl PyCodeGenerator {
}
}
while let Some(arg) = args.try_remove_kw(0) {
kws.push(ValueObj::Str(arg.keyword.content.clone()));
let kw = if is_py_api {
arg.keyword.content
} else {
Str::from(format!("::{}", arg.keyword.content))
};
kws.push(ValueObj::Str(kw));
self.emit_expr(arg.expr);
}
let kwsc = if !kws.is_empty() {
@ -2095,7 +2103,7 @@ impl PyCodeGenerator {
self.emit_push_null();
self.emit_load_name_instr(method_name);
args.insert_pos(0, PosArg::new(obj));
self.emit_args_311(args, Name);
self.emit_args_311(args, Name, true);
}
// assert takes 1 or 2 arguments (0: cond, 1: message)

View file

@ -931,38 +931,25 @@ impl Context {
if (params_len < pos_args.len() || params_len < pos_args.len() + kw_args.len())
&& subr.var_params.is_none()
{
return Err(TyCheckErrors::from(TyCheckError::too_many_args_error(
self.cfg.input.clone(),
line!() as usize,
callee.loc(),
&callee.to_string(),
self.caused_by(),
params_len,
pos_args.len(),
kw_args.len(),
)));
return Err(self.gen_too_many_args_error(&callee, subr, pos_args, kw_args));
}
let mut passed_params = set! {};
let non_default_params_len = if attr_name.is_some() && is_method {
subr.non_default_params.len() - 1
let non_default_params = if is_method {
let mut non_default_params = subr.non_default_params.iter();
let self_pt = non_default_params.next().unwrap();
if let Err(mut es) =
self.sub_unify(obj.ref_t(), self_pt.typ(), obj.loc(), self_pt.name())
{
errs.append(&mut es);
}
non_default_params
} else {
subr.non_default_params.len()
subr.non_default_params.iter()
};
let non_default_params_len = non_default_params.len();
let mut nth = 1;
if pos_args.len() >= non_default_params_len {
let (non_default_args, var_args) = pos_args.split_at(non_default_params_len);
let non_default_params = if is_method {
let mut non_default_params = subr.non_default_params.iter();
let self_pt = non_default_params.next().unwrap();
if let Err(mut es) =
self.sub_unify(obj.ref_t(), self_pt.typ(), obj.loc(), self_pt.name())
{
errs.append(&mut es);
}
non_default_params
} else {
subr.non_default_params.iter()
};
for (nd_arg, nd_param) in non_default_args.iter().zip(non_default_params) {
if let Err(mut es) = self.substitute_pos_arg(
&callee,
@ -1010,7 +997,7 @@ impl Context {
attr_name,
kw_arg,
nth,
&subr.default_params,
subr,
&mut passed_params,
) {
errs.append(&mut es);
@ -1031,24 +1018,41 @@ impl Context {
}
}
} else {
let missing_len = subr.non_default_params.len() - pos_args.len();
let missing_params = subr
.non_default_params
.iter()
.rev()
.take(missing_len)
.rev()
.map(|pt| pt.name().cloned().unwrap_or(Str::ever("")))
.collect();
return Err(TyCheckErrors::from(TyCheckError::args_missing_error(
self.cfg.input.clone(),
line!() as usize,
callee.loc(),
&callee.to_string(),
self.caused_by(),
missing_len,
missing_params,
)));
// pos_args.len() < non_default_params_len
for kw_arg in kw_args.iter() {
if let Err(mut es) = self.substitute_kw_arg(
&callee,
attr_name,
kw_arg,
nth,
subr,
&mut passed_params,
) {
errs.append(&mut es);
}
nth += 1;
}
let missing_len = non_default_params_len - pos_args.len() - passed_params.len();
if missing_len > 0 {
let missing_params = subr
.non_default_params
.iter()
.rev()
.take(missing_len)
.rev()
.map(|pt| pt.name().cloned().unwrap_or(Str::ever("")))
.filter(|pt| !passed_params.contains(pt))
.collect();
return Err(TyCheckErrors::from(TyCheckError::args_missing_error(
self.cfg.input.clone(),
line!() as usize,
callee.loc(),
&callee.to_string(),
self.caused_by(),
missing_len,
missing_params,
)));
}
}
if errs.is_empty() {
Ok(())
@ -1088,6 +1092,76 @@ impl Context {
}
}
fn gen_too_many_args_error(
&self,
callee: &hir::Expr,
subr_ty: &SubrType,
pos_args: &[hir::PosArg],
kw_args: &[hir::KwArg],
) -> TyCheckErrors {
let mut unknown_args = vec![];
let mut passed_args: Vec<&hir::KwArg> = vec![];
let mut duplicated_args = vec![];
for kw_arg in kw_args.iter() {
if subr_ty
.non_default_params
.iter()
.all(|pt| pt.name() != Some(kw_arg.keyword.inspect()))
&& subr_ty
.var_params
.as_ref()
.map(|pt| pt.name() != Some(kw_arg.keyword.inspect()))
.unwrap_or(true)
&& subr_ty
.default_params
.iter()
.all(|pt| pt.name() != Some(kw_arg.keyword.inspect()))
{
unknown_args.push(kw_arg);
}
if passed_args.iter().any(|a| a.keyword == kw_arg.keyword) {
duplicated_args.push(kw_arg);
} else {
passed_args.push(kw_arg);
}
}
if unknown_args.is_empty() && duplicated_args.is_empty() {
let params_len = subr_ty.non_default_params.len() + subr_ty.default_params.len();
TyCheckErrors::from(TyCheckError::too_many_args_error(
self.cfg.input.clone(),
line!() as usize,
callee.loc(),
&callee.to_string(),
self.caused_by(),
params_len,
pos_args.len(),
kw_args.len(),
))
} else {
let unknown_arg_errors = unknown_args.into_iter().map(|arg| {
TyCheckError::unexpected_kw_arg_error(
self.cfg.input.clone(),
line!() as usize,
arg.loc(),
&callee.to_string(),
self.caused_by(),
arg.keyword.inspect(),
)
});
let duplicated_arg_errors = duplicated_args.into_iter().map(|arg| {
TyCheckError::multiple_args_error(
self.cfg.input.clone(),
line!() as usize,
arg.loc(),
&callee.to_string(),
self.caused_by(),
arg.keyword.inspect(),
)
});
unknown_arg_errors.chain(duplicated_arg_errors).collect()
}
}
fn substitute_pos_arg(
&self,
callee: &hir::Expr,
@ -1190,7 +1264,7 @@ impl Context {
attr_name: &Option<Identifier>,
arg: &hir::KwArg,
nth: usize,
default_params: &[ParamTy],
subr_ty: &SubrType,
passed_params: &mut Set<Str>,
) -> TyCheckResult<()> {
let arg_t = arg.expr.ref_t();
@ -1207,8 +1281,10 @@ impl Context {
} else {
passed_params.insert(kw_name.clone());
}
if let Some(pt) = default_params
if let Some(pt) = subr_ty
.non_default_params
.iter()
.chain(subr_ty.default_params.iter())
.find(|pt| pt.name().unwrap() == kw_name)
{
self.sub_unify(arg_t, pt.typ(), arg.loc(), Some(kw_name))
@ -1263,7 +1339,6 @@ impl Context {
) -> TyCheckResult<VarInfo> {
if let hir::Expr::Accessor(hir::Accessor::Ident(local)) = obj {
if local.vis().is_private() {
#[allow(clippy::single_match)]
match &local.inspect()[..] {
"match" => {
return self.get_match_call_t(SubrKind::Func, pos_args, kw_args);
@ -1271,20 +1346,6 @@ impl Context {
"match!" => {
return self.get_match_call_t(SubrKind::Proc, pos_args, kw_args);
}
/*"import" | "pyimport" | "py" => {
return self.get_import_call_t(pos_args, kw_args);
}*/
// handle assert casting
/*"assert" => {
if let Some(arg) = pos_args.first() {
match &arg.expr {
hir::Expr::BinOp(bin) if bin.op.is(TokenKind::InOp) && bin.rhs.ref_t() == &Type => {
let t = self.eval_const_expr(bin.lhs.as_ref(), None)?.as_type().unwrap();
}
_ => {}
}
}
},*/
_ => {}
}
}

View file

@ -422,6 +422,10 @@ impl Identifier {
Self::new(dot, name, None, VarInfo::const_default())
}
pub fn is_py_api(&self) -> bool {
self.vi.py_name.is_some()
}
pub fn is_const(&self) -> bool {
self.name.is_const()
}
@ -539,6 +543,13 @@ impl Accessor {
}
}
pub fn is_py_api(&self) -> bool {
match self {
Self::Ident(ident) => ident.is_py_api(),
Self::Attr(attr) => attr.ident.is_py_api(),
}
}
// 参照するオブジェクト自体が持っている固有の名前(クラス、モジュールなど)
pub fn qual_name(&self) -> Option<&str> {
match self {
@ -1919,6 +1930,13 @@ impl Expr {
}
}
pub fn is_py_api(&self) -> bool {
match self {
Expr::Accessor(acc) => acc.is_py_api(),
_ => false,
}
}
pub fn is_type_asc(&self) -> bool {
matches!(self, Expr::TypeAsc(_))
}

View file

@ -136,20 +136,23 @@ impl OwnershipChecker {
} else {
args_owns.non_defaults.len()
};
let (non_default_args, var_args) = call.args.pos_args.split_at(non_defaults_len);
for (nd_arg, ownership) in
non_default_args.iter().zip(args_owns.non_defaults.iter())
{
self.check_expr(&nd_arg.expr, *ownership, false);
}
if let Some(ownership) = args_owns.var_params.as_ref() {
for var_arg in var_args.iter() {
self.check_expr(&var_arg.expr, *ownership, false);
if call.args.pos_args.len() > non_defaults_len {
let (non_default_args, var_args) =
call.args.pos_args.split_at(non_defaults_len);
for (nd_arg, (_, ownership)) in
non_default_args.iter().zip(args_owns.non_defaults.iter())
{
self.check_expr(&nd_arg.expr, *ownership, false);
}
} else {
let kw_args = var_args;
for (arg, (_, ownership)) in kw_args.iter().zip(args_owns.defaults.iter()) {
self.check_expr(&arg.expr, *ownership, false);
if let Some((_, ownership)) = args_owns.var_params.as_ref() {
for var_arg in var_args.iter() {
self.check_expr(&var_arg.expr, *ownership, false);
}
} else {
let kw_args = var_args;
for (arg, (_, ownership)) in kw_args.iter().zip(args_owns.defaults.iter()) {
self.check_expr(&arg.expr, *ownership, false);
}
}
}
for kw_arg in call.args.kw_args.iter() {
@ -159,6 +162,12 @@ impl OwnershipChecker {
.find(|(k, _)| k == kw_arg.keyword.inspect())
{
self.check_expr(&kw_arg.expr, *ownership, false);
} else if let Some((_, ownership)) = args_owns
.non_defaults
.iter()
.find(|(k, _)| k.as_ref() == Some(kw_arg.keyword.inspect()))
{
self.check_expr(&kw_arg.expr, *ownership, false);
} else {
todo!()
}

View file

@ -431,6 +431,7 @@ impl ScriptGenerator {
}
fn transpile_simple_call(&mut self, mut call: Call) -> String {
let is_py_api = call.obj.is_py_api();
let mut code = format!("({})", self.transpile_expr(*call.obj));
if let Some(attr) = call.attr_name {
code += &format!(".{}", Self::transpile_ident(attr));
@ -441,7 +442,12 @@ impl ScriptGenerator {
code.push(',');
}
while let Some(arg) = call.args.try_remove_kw(0) {
code += &format!("{}={},", arg.keyword, self.transpile_expr(arg.expr));
let escape = if is_py_api { "" } else { "__" };
code += &format!(
"{}{escape}={},",
arg.keyword.content,
self.transpile_expr(arg.expr)
);
}
code.push(')');
code

View file

@ -882,22 +882,26 @@ impl Ownership {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ArgsOwnership {
pub non_defaults: Vec<Ownership>,
pub var_params: Option<Ownership>,
pub non_defaults: Vec<(Option<Str>, Ownership)>,
pub var_params: Option<(Str, Ownership)>,
pub defaults: Vec<(Str, Ownership)>,
}
impl fmt::Display for ArgsOwnership {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "(")?;
for (i, o) in self.non_defaults.iter().enumerate() {
for (i, (name, o)) in self.non_defaults.iter().enumerate() {
if i != 0 {
write!(f, ", ")?;
}
write!(f, "{o:?}")?;
if let Some(name) = name {
write!(f, "{name}: {o:?}")?;
} else {
write!(f, "{o:?}")?;
}
}
if let Some(o) = self.var_params.as_ref() {
write!(f, ", ...{o:?}")?;
if let Some((name, o)) = self.var_params.as_ref() {
write!(f, ", ...{name}: {o:?}")?;
}
for (name, o) in self.defaults.iter() {
write!(f, ", {name} := {o:?}")?;
@ -909,8 +913,8 @@ impl fmt::Display for ArgsOwnership {
impl ArgsOwnership {
pub const fn new(
non_defaults: Vec<Ownership>,
var_params: Option<Ownership>,
non_defaults: Vec<(Option<Str>, Ownership)>,
var_params: Option<(Str, Ownership)>,
defaults: Vec<(Str, Ownership)>,
) -> Self {
Self {
@ -1678,9 +1682,12 @@ impl Type {
Self::RefMut { .. } => Ownership::RefMut,
_ => Ownership::Owned,
};
nd_args.push(ownership);
nd_args.push((nd_param.name().cloned(), ownership));
}
let var_args = subr.var_params.as_ref().map(|t| t.typ().ownership());
let var_args = subr
.var_params
.as_ref()
.map(|t| (t.name().unwrap().clone(), t.typ().ownership()));
let mut d_args = vec![];
for d_param in subr.default_params.iter() {
let ownership = match d_param.typ() {