Fix method call bug

This commit is contained in:
Shunsuke Shibayama 2022-10-13 00:56:43 +09:00
parent a0b2917359
commit aa2b45bf86
15 changed files with 106 additions and 101 deletions

View file

@ -16,7 +16,7 @@ use erg_parser::ast::*;
use erg_parser::token::{Token, TokenKind};
use crate::ty::constructors::dict_t;
use crate::ty::constructors::proj_method;
use crate::ty::constructors::proj_call;
use crate::ty::constructors::{
array_t, mono, not, poly, proj, ref_, ref_mut, refinement, subr_t, v_enum,
};
@ -854,11 +854,11 @@ impl Context {
// ?T(<: Add(?R(:> Int))).Output == ?T(<: Add(?R)).Output
// ?T(:> Int, <: Add(?R(:> Int))).Output == Int
Type::Proj { lhs, rhs } => self.eval_proj(*lhs, rhs, level, t_loc),
Type::ProjMethod {
Type::ProjCall {
lhs,
method_name,
attr_name,
args,
} => self.eval_proj_method(*lhs, method_name, args, level, t_loc),
} => self.eval_proj_call(*lhs, attr_name, args, level, t_loc),
Type::Ref(l) => Ok(ref_(self.eval_t_params(*l, level, t_loc)?)),
Type::RefMut { before, after } => {
let before = self.eval_t_params(*before, level, t_loc)?;
@ -999,10 +999,10 @@ impl Context {
}
}
fn eval_proj_method(
fn eval_proj_call(
&self,
lhs: TyParam,
method_name: Str,
attr_name: Str,
args: Vec<TyParam>,
level: usize,
t_loc: Location,
@ -1014,11 +1014,11 @@ impl Context {
line!() as usize,
t_loc,
self.caused_by(),
&method_name,
&attr_name,
None, // TODO:
)
})? {
if let Ok(obj) = ty_ctx.get_const_local(&Token::symbol(&method_name), &self.name) {
if let Ok(obj) = ty_ctx.get_const_local(&Token::symbol(&attr_name), &self.name) {
if let ValueObj::Subr(subr) = obj {
let is_method = subr.sig_t().self_t().is_some();
let mut pos_args = vec![];
@ -1037,7 +1037,7 @@ impl Context {
}
}
for (_class, methods) in ty_ctx.methods_list.iter() {
if let Ok(obj) = methods.get_const_local(&Token::symbol(&method_name), &self.name) {
if let Ok(obj) = methods.get_const_local(&Token::symbol(&attr_name), &self.name) {
if let ValueObj::Subr(subr) = obj {
let mut pos_args = vec![];
for pos_arg in args.into_iter() {
@ -1073,13 +1073,13 @@ impl Context {
// In many cases, it is still better to determine the type variable than if the target is not found.
let coerced = self.deref_tp(lhs.clone(), Variance::Covariant, t_loc)?;
if lhs != coerced {
let proj = proj_method(coerced, method_name, args);
let proj = proj_call(coerced, attr_name, args);
self.eval_t_params(proj, level, t_loc).map(|t| {
self.coerce_tp(&lhs);
t
})
} else {
let proj = proj_method(lhs, method_name, args);
let proj = proj_call(lhs, attr_name, args);
Err(EvalErrors::from(EvalError::no_candidate_error(
self.cfg.input.clone(),
line!() as usize,

View file

@ -1020,7 +1020,7 @@ impl Context {
let dict_getitem_t = fn1_met(
dict_t.clone(),
mono_q("T"),
proj_method(mono_q_tp("D"), "__getitem__", vec![ty_tp(mono_q("T"))]),
proj_call(mono_q_tp("D"), "__getitem__", vec![ty_tp(mono_q("T"))]),
);
let dict_getitem_t = quant(
dict_getitem_t,
@ -1057,7 +1057,7 @@ impl Context {
tuple_.register_superclass(mono("GenericTuple"), &generic_tuple);
tuple_.register_marker_trait(poly("Output", vec![ty_tp(mono_q("Ts"))]));
// __Tuple_getitem__: (self: Tuple(Ts), _: {N}) -> Ts[N]
let return_t = proj_method(mono_q_tp("Ts"), "__getitem__", vec![mono_q_tp("N")]);
let return_t = proj_call(mono_q_tp("Ts"), "__getitem__", vec![mono_q_tp("N")]);
let tuple_getitem_t = fn1_met(
tuple_t.clone(),
tp_enum(Nat, set! {mono_q_tp("N")}),

View file

@ -525,11 +525,11 @@ impl Context {
fn search_callee_t(
&self,
obj: &hir::Expr,
method_name: &Option<Identifier>,
attr_name: &Option<Identifier>,
input: &Input,
namespace: &Str,
) -> SingleTyCheckResult<Type> {
if let Some(method_name) = method_name.as_ref() {
if let Some(attr_name) = attr_name.as_ref() {
for ctx in self
.get_nominal_super_type_ctxs(obj.ref_t())
.ok_or_else(|| {
@ -545,19 +545,19 @@ impl Context {
{
if let Some(vi) = ctx
.locals
.get(method_name.inspect())
.or_else(|| ctx.decls.get(method_name.inspect()))
.get(attr_name.inspect())
.or_else(|| ctx.decls.get(attr_name.inspect()))
{
self.validate_visibility(method_name, vi, input, namespace)?;
self.validate_visibility(attr_name, vi, input, namespace)?;
return Ok(vi.t());
}
for (_, methods_ctx) in ctx.methods_list.iter() {
if let Some(vi) = methods_ctx
.locals
.get(method_name.inspect())
.or_else(|| methods_ctx.decls.get(method_name.inspect()))
.get(attr_name.inspect())
.or_else(|| methods_ctx.decls.get(attr_name.inspect()))
{
self.validate_visibility(method_name, vi, input, namespace)?;
self.validate_visibility(attr_name, vi, input, namespace)?;
return Ok(vi.t());
}
}
@ -565,34 +565,34 @@ impl Context {
if let Ok(singular_ctx) = self.get_singular_ctx(obj, namespace) {
if let Some(vi) = singular_ctx
.locals
.get(method_name.inspect())
.or_else(|| singular_ctx.decls.get(method_name.inspect()))
.get(attr_name.inspect())
.or_else(|| singular_ctx.decls.get(attr_name.inspect()))
{
self.validate_visibility(method_name, vi, input, namespace)?;
self.validate_visibility(attr_name, vi, input, namespace)?;
return Ok(vi.t());
}
for (_, method_ctx) in singular_ctx.methods_list.iter() {
if let Some(vi) = method_ctx
.locals
.get(method_name.inspect())
.or_else(|| method_ctx.decls.get(method_name.inspect()))
.get(attr_name.inspect())
.or_else(|| method_ctx.decls.get(attr_name.inspect()))
{
self.validate_visibility(method_name, vi, input, namespace)?;
self.validate_visibility(attr_name, vi, input, namespace)?;
return Ok(vi.t());
}
}
return Err(TyCheckError::singular_no_attr_error(
self.cfg.input.clone(),
line!() as usize,
method_name.loc(),
attr_name.loc(),
namespace.into(),
obj.qual_name().unwrap_or("?"),
obj.ref_t(),
method_name.inspect(),
self.get_similar_attr_from_singular(obj, method_name.inspect()),
attr_name.inspect(),
self.get_similar_attr_from_singular(obj, attr_name.inspect()),
));
}
match self.get_method_type_by_name(method_name) {
match self.get_method_type_by_name(attr_name) {
Ok(t) => {
self.sub_unify(obj.ref_t(), &t.definition_type, obj.loc(), None)
// HACK: change this func's return type to TyCheckResult<Type>
@ -608,11 +608,11 @@ impl Context {
Err(TyCheckError::no_attr_error(
self.cfg.input.clone(),
line!() as usize,
method_name.loc(),
attr_name.loc(),
namespace.into(),
obj.ref_t(),
method_name.inspect(),
self.get_similar_attr(obj.ref_t(), method_name.inspect()),
attr_name.inspect(),
self.get_similar_attr(obj.ref_t(), attr_name.inspect()),
))
} else {
Ok(obj.t())
@ -759,17 +759,17 @@ impl Context {
fn substitute_call(
&self,
obj: &hir::Expr,
method_name: &Option<Identifier>,
attr_name: &Option<Identifier>,
instance: &Type,
pos_args: &[hir::PosArg],
kw_args: &[hir::KwArg],
) -> TyCheckResult<()> {
match instance {
Type::FreeVar(fv) if fv.is_linked() => {
self.substitute_call(obj, method_name, &fv.crack(), pos_args, kw_args)
self.substitute_call(obj, attr_name, &fv.crack(), pos_args, kw_args)
}
Type::FreeVar(fv) => {
if let Some(_method_name) = method_name {
if let Some(_attr_name) = attr_name {
todo!()
} else {
let is_procedural = obj
@ -789,16 +789,21 @@ impl Context {
}
}
Type::Refinement(refine) => {
self.substitute_call(obj, method_name, &refine.t, pos_args, kw_args)
self.substitute_call(obj, attr_name, &refine.t, pos_args, kw_args)
}
Type::Subr(subr) => {
let callee = if let Some(ident) = method_name {
let attr = hir::Attribute::new(
obj.clone(),
hir::Identifier::bare(ident.dot.clone(), ident.name.clone()),
Type::Uninited,
);
hir::Expr::Accessor(hir::Accessor::Attr(attr))
let not_method_but_attr = subr.self_t().is_none();
let callee = if let Some(ident) = attr_name {
if not_method_but_attr {
obj.clone()
} else {
let attr = hir::Attribute::new(
obj.clone(),
hir::Identifier::bare(ident.dot.clone(), ident.name.clone()),
Type::Uninited,
);
hir::Expr::Accessor(hir::Accessor::Attr(attr))
}
} else {
obj.clone()
};
@ -818,7 +823,7 @@ impl Context {
)));
}
let mut passed_params = set! {};
let non_default_params_len = if method_name.is_some() {
let non_default_params_len = if attr_name.is_some() && !not_method_but_attr {
subr.non_default_params.len() - 1
} else {
subr.non_default_params.len()
@ -895,13 +900,13 @@ impl Context {
Ok(())
}
other => {
if let Some(method_name) = method_name {
if let Some(attr_name) = attr_name {
Err(TyCheckErrors::from(TyCheckError::type_mismatch_error(
self.cfg.input.clone(),
line!() as usize,
Location::concat(obj, method_name),
Location::concat(obj, attr_name),
self.caused_by(),
&(obj.to_string() + &method_name.to_string()),
&(obj.to_string() + &attr_name.to_string()),
&mono("Callable"),
other,
self.get_candidates(other),
@ -1073,7 +1078,7 @@ impl Context {
pub(crate) fn get_call_t(
&self,
obj: &hir::Expr,
method_name: &Option<Identifier>,
attr_name: &Option<Identifier>,
pos_args: &[hir::PosArg],
kw_args: &[hir::KwArg],
input: &Input,
@ -1103,10 +1108,10 @@ impl Context {
}
}
}
let found = self.search_callee_t(obj, method_name, input, namespace)?;
let found = self.search_callee_t(obj, attr_name, input, namespace)?;
log!(
"Found:\ncallee: {obj}{}\nfound: {found}",
fmt_option!(pre ".", method_name.as_ref().map(|ident| &ident.name))
fmt_option!(pre ".", attr_name.as_ref().map(|ident| &ident.name))
);
let instance = self.instantiate(found, obj)?;
log!(
@ -1114,7 +1119,7 @@ impl Context {
fmt_slice(pos_args),
fmt_slice(kw_args)
);
self.substitute_call(obj, method_name, &instance, pos_args, kw_args)?;
self.substitute_call(obj, attr_name, &instance, pos_args, kw_args)?;
log!(info "Substituted:\ninstance: {instance}");
let res = self.eval_t_params(instance, self.level, obj.loc())?;
log!(info "Params evaluated:\nres: {res}\n");

View file

@ -1070,16 +1070,16 @@ impl Context {
let lhs = self.instantiate_t(*lhs, tmp_tv_ctx, loc)?;
Ok(proj(lhs, rhs))
}
ProjMethod {
ProjCall {
lhs,
method_name,
attr_name,
mut args,
} => {
let lhs = self.instantiate_tp(*lhs, tmp_tv_ctx, loc)?;
for arg in args.iter_mut() {
*arg = self.instantiate_tp(mem::take(arg), tmp_tv_ctx, loc)?;
}
Ok(proj_method(lhs, method_name, args))
Ok(proj_call(lhs, attr_name, args))
}
Poly { name, mut params } => {
for param in params.iter_mut() {

View file

@ -187,16 +187,16 @@ impl Context {
let lhs = self.generalize_t_inner(*lhs, bounds, lazy_inits);
proj(lhs, rhs)
}
ProjMethod {
ProjCall {
lhs,
method_name,
attr_name,
mut args,
} => {
let lhs = self.generalize_tp(*lhs, bounds, lazy_inits);
for arg in args.iter_mut() {
*arg = self.generalize_tp(mem::take(arg), bounds, lazy_inits);
}
proj_method(lhs, method_name, args)
proj_call(lhs, attr_name, args)
}
And(l, r) => {
let l = self.generalize_t_inner(*l, bounds, lazy_inits);