fix: polymorphic type spec instantiation bugs

This commit is contained in:
Shunsuke Shibayama 2024-03-13 22:35:08 +09:00
parent e38674945b
commit 74e89f6d5b
11 changed files with 555 additions and 182 deletions

View file

@ -718,12 +718,19 @@ impl Context {
fn eval_const_def(&mut self, def: &Def) -> EvalResult<ValueObj> {
if def.is_const() {
let mut errs = EvalErrors::empty();
let __name__ = def.sig.ident().unwrap().inspect();
let vis = self.instantiate_vis_modifier(def.sig.vis())?;
let tv_cache = match &def.sig {
Signature::Subr(subr) => {
let ty_cache =
self.instantiate_ty_bounds(&subr.bounds, RegistrationMode::Normal)?;
match self.instantiate_ty_bounds(&subr.bounds, RegistrationMode::Normal) {
Ok(ty_cache) => ty_cache,
Err((ty_cache, es)) => {
errs.extend(es);
ty_cache
}
};
Some(ty_cache)
}
Signature::Var(_) => None,
@ -740,7 +747,8 @@ impl Context {
} else {
None
};
let (_ctx, errs) = self.check_decls_and_pop();
let (_ctx, es) = self.check_decls_and_pop();
errs.extend(es);
self.register_gen_const(
def.sig.ident().unwrap(),
obj,
@ -917,10 +925,16 @@ impl Context {
/// FIXME: grow
fn eval_const_lambda(&self, lambda: &Lambda) -> EvalResult<ValueObj> {
let mut tmp_tv_cache =
self.instantiate_ty_bounds(&lambda.sig.bounds, RegistrationMode::Normal)?;
let mut non_default_params = Vec::with_capacity(lambda.sig.params.non_defaults.len());
let mut errs = EvalErrors::empty();
let mut tmp_tv_cache =
match self.instantiate_ty_bounds(&lambda.sig.bounds, RegistrationMode::Normal) {
Ok(ty_cache) => ty_cache,
Err((ty_cache, es)) => {
errs.extend(es);
ty_cache
}
};
let mut non_default_params = Vec::with_capacity(lambda.sig.params.non_defaults.len());
for sig in lambda.sig.params.non_defaults.iter() {
match self.instantiate_param_ty(
sig,
@ -2090,6 +2104,7 @@ impl Context {
TyParam::ProjCall { obj, attr, args } => Ok(proj_call(*obj, attr, args)),
// TyParam::Erased(_t) => Ok(Type::Obj),
TyParam::Value(v) => self.convert_value_into_type(v).map_err(TyParam::Value),
TyParam::Erased(t) if t.is_type() => Ok(Type::Obj),
// TODO: Dict, Set
other => Err(other),
}

View file

@ -1,10 +1,10 @@
use std::option::Option; // conflicting to Type::Option
use erg_common::levenshtein::get_similar_name;
#[allow(unused)]
use erg_common::log;
use erg_common::traits::{Locational, Stream};
use erg_common::Str;
use erg_common::{assume_unreachable, dict, set, try_map_mut};
use erg_common::{assume_unreachable, dict, failable_map_mut, set, Str};
use ast::{
NonDefaultParamSignature, ParamTySpec, PreDeclTypeSpec, TypeBoundSpec, TypeBoundSpecs, TypeSpec,
@ -166,36 +166,43 @@ impl Context {
&self,
bounds: &TypeBoundSpecs,
mode: RegistrationMode,
) -> TyCheckResult<TyVarCache> {
) -> Failable<TyVarCache> {
let mut errs = TyCheckErrors::empty();
let mut tv_cache = TyVarCache::new(self.level, self);
for bound in bounds.iter() {
self.instantiate_ty_bound(bound, &mut tv_cache, mode)?;
if let Err(es) = self.instantiate_ty_bound(bound, &mut tv_cache, mode) {
errs.extend(es);
}
}
for tv in tv_cache.tyvar_instances.values() {
if tv.constraint().map(|c| c.is_uninited()).unwrap_or(false) {
return Err(TyCheckErrors::from(TyCheckError::no_var_error(
errs.push(TyCheckError::no_var_error(
self.cfg.input.clone(),
line!() as usize,
bounds.loc(),
self.caused_by(),
&tv.local_name(),
self.get_similar_name(&tv.local_name()),
)));
));
}
}
for tp in tv_cache.typaram_instances.values() {
if tp.constraint().map(|c| c.is_uninited()).unwrap_or(false) {
return Err(TyCheckErrors::from(TyCheckError::no_var_error(
errs.push(TyCheckError::no_var_error(
self.cfg.input.clone(),
line!() as usize,
bounds.loc(),
self.caused_by(),
&tp.to_string(),
self.get_similar_name(&tp.to_string()),
)));
));
}
}
Ok(tv_cache)
if errs.is_empty() {
Ok(tv_cache)
} else {
Err((tv_cache, errs))
}
}
pub(crate) fn instantiate_var_sig_t(
@ -237,9 +244,13 @@ impl Context {
}
None => None,
};
let mut tmp_tv_cache = self
.instantiate_ty_bounds(&sig.bounds, PreRegister)
.map_err(|errs| (Type::Failure, errs))?;
let mut tmp_tv_cache = match self.instantiate_ty_bounds(&sig.bounds, PreRegister) {
Ok(tv_cache) => tv_cache,
Err((tv_cache, es)) => {
errs.extend(es);
tv_cache
}
};
let mut non_defaults = vec![];
for (n, param) in sig.params.non_defaults.iter().enumerate() {
let opt_decl_t = opt_decl_sig_t
@ -343,7 +354,7 @@ impl Context {
}
} else {
// preregisterならouter scopeで型宣言(see inference.md)
let level = if mode == PreRegister {
let level = if mode.is_preregister() {
self.level
} else {
self.level + 1
@ -374,7 +385,7 @@ impl Context {
not_found_is_qvar: bool,
) -> Failable<Type> {
let gen_free_t = || {
let level = if mode == PreRegister {
let level = if mode.is_preregister() {
self.level
} else {
self.level + 1
@ -392,7 +403,12 @@ impl Context {
.map_err(|errs| {
(
opt_decl_t.map_or(Type::Failure, |pt| pt.typ().clone()),
errs,
// Ignore errors if `mode == Normal`, because the errors have already been collected.
if mode.is_normal() {
TyCheckErrors::empty()
} else {
errs
},
)
})?
} else {
@ -870,61 +886,121 @@ impl Context {
));
};
let mut errs = TyCheckErrors::empty();
// FIXME: kw args
let mut new_params = vec![];
for ((i, arg), (name, param_vi)) in
args.pos_args().enumerate().zip(ctx.params.iter())
{
let param = self.instantiate_const_expr(
match self.instantiate_arg(
&arg.expr,
Some((ctx, i)),
param_vi,
name.as_ref(),
ctx,
i,
tmp_tv_cache,
not_found_is_qvar,
);
let param = param
.or_else(|e| {
if not_found_is_qvar {
let name = arg.expr.to_string();
// FIXME: handle `::` as a right way
let name = Str::rc(name.trim_start_matches("::"));
let tp = TyParam::named_free_var(
name.clone(),
self.level,
Constraint::Uninited,
);
let varname = VarName::from_str(name);
tmp_tv_cache.push_or_init_typaram(&varname, &tp, self)?;
Ok(tp)
} else {
Err(e)
}
})
.map_err(|err| (Type::Failure, err))?;
let arg_t = self
.get_tp_t(&param)
.map_err(|err| {
log!(err "{param}: {err}");
err
})
.unwrap_or(Obj);
if self.subtype_of(&arg_t, &param_vi.t) {
new_params.push(param);
} else {
new_params.push(TyParam::erased(param_vi.t.clone()));
errs.push(TyCheckError::type_mismatch_error(
self.cfg.input.clone(),
line!() as usize,
arg.expr.loc(),
self.caused_by(),
name.as_ref().map_or("", |n| &n.inspect()[..]),
Some(i),
&param_vi.t,
&arg_t,
None,
None,
));
) {
Ok(tp) => new_params.push(tp),
Err((tp, es)) => {
errs.extend(es);
new_params.push(tp);
}
}
}
let mut missing_args = vec![];
// Fill kw params
for (_, param_vi) in ctx.params.iter().skip(args.pos_args.len()) {
new_params.push(TyParam::erased(param_vi.t.clone()));
}
let mut passed_kw_args = set! {};
for (i, (name, param_vi)) in ctx.params.iter().skip(args.pos_args.len()).enumerate()
{
if let Some(idx) = name.as_ref().and_then(|name| {
args.kw_args
.iter()
.position(|arg| arg.keyword.inspect() == name.inspect())
}) {
let kw_arg = &args.kw_args[idx];
let already_passed =
!passed_kw_args.insert(kw_arg.keyword.inspect().clone());
if already_passed {
errs.push(TyCheckError::multiple_args_error(
self.cfg.input.clone(),
line!() as usize,
kw_arg.loc(),
other,
self.caused_by(),
name.as_ref().map_or("_", |n| &n.inspect()[..]),
));
}
let tp = match self.instantiate_arg(
&kw_arg.expr,
param_vi,
name.as_ref(),
ctx,
i,
tmp_tv_cache,
not_found_is_qvar,
) {
Ok(tp) => tp,
Err((tp, es)) => {
errs.extend(es);
tp
}
};
if let Some(old) = new_params.get_mut(args.pos_args.len() + idx) {
*old = tp;
} else {
log!(err "{tp} / {} / {idx}", args.pos_args.len());
// TODO: too many kw args
}
} else if !param_vi.kind.has_default() {
missing_args
.push(name.as_ref().map_or("_".into(), |n| n.inspect().clone()));
}
}
if !missing_args.is_empty() {
errs.push(TyCheckError::args_missing_error(
self.cfg.input.clone(),
line!() as usize,
args.loc(),
other,
self.caused_by(),
missing_args,
));
}
if ctx.params.len() < args.pos_args.len() + args.kw_args.len() {
errs.push(TyCheckError::too_many_args_error(
self.cfg.input.clone(),
line!() as usize,
args.loc(),
other,
self.caused_by(),
ctx.params.len(),
args.pos_args.len(),
args.kw_args.len(),
));
}
let param_names = ctx
.params
.iter()
.filter_map(|(n, _)| n.as_ref().map(|n| &n.inspect()[..]))
.collect::<Vec<_>>();
for unexpected in args
.kw_args
.iter()
.filter(|kw| !passed_kw_args.contains(&kw.keyword.inspect()[..]))
{
let kw = unexpected.keyword.inspect();
errs.push(TyCheckError::unexpected_kw_arg_error(
self.cfg.input.clone(),
line!() as usize,
unexpected.loc(),
other,
self.caused_by(),
unexpected.keyword.inspect(),
get_similar_name(param_names.iter(), kw).copied(),
));
}
// FIXME: non-builtin
let t = poly(ctx.typ.qual_name(), new_params);
if errs.is_empty() {
@ -936,6 +1012,63 @@ impl Context {
}
}
#[allow(clippy::too_many_arguments)]
fn instantiate_arg(
&self,
arg: &ConstExpr,
param_vi: &VarInfo,
name: Option<&VarName>,
ctx: &Context,
i: usize,
tmp_tv_cache: &mut TyVarCache,
not_found_is_qvar: bool,
) -> Failable<TyParam> {
let param =
self.instantiate_const_expr(arg, Some((ctx, i)), tmp_tv_cache, not_found_is_qvar);
let param = param
.or_else(|e| {
if not_found_is_qvar {
let name = arg.to_string();
// FIXME: handle `::` as a right way
let name = Str::rc(name.trim_start_matches("::"));
let tp =
TyParam::named_free_var(name.clone(), self.level, Constraint::Uninited);
let varname = VarName::from_str(name);
tmp_tv_cache.push_or_init_typaram(&varname, &tp, self)?;
Ok(tp)
} else {
Err(e)
}
})
.map_err(|err| (TyParam::Failure, err))?;
let arg_t = self
.get_tp_t(&param)
.map_err(|err| {
log!(err "{param}: {err}");
err
})
.unwrap_or(Obj);
if self.subtype_of(&arg_t, &param_vi.t) {
Ok(param)
} else {
let tp = TyParam::erased(param_vi.t.clone());
let errs = TyCheckError::type_mismatch_error(
self.cfg.input.clone(),
line!() as usize,
arg.loc(),
self.caused_by(),
name.as_ref().map_or("", |n| &n.inspect()[..]),
Some(i),
&param_vi.t,
&arg_t,
None,
None,
)
.into();
Err((tp, errs))
}
}
fn instantiate_acc(
&self,
acc: &ast::ConstAccessor,
@ -1232,37 +1365,52 @@ impl Context {
Ok(TyParam::Record(tp_rec))
}
ast::ConstExpr::Lambda(lambda) => {
let _tmp_tv_cache =
self.instantiate_ty_bounds(&lambda.sig.bounds, RegistrationMode::Normal)?;
let mut errs = TyCheckErrors::empty();
let _tmp_tv_cache = match self
.instantiate_ty_bounds(&lambda.sig.bounds, RegistrationMode::Normal)
{
Ok(tv_cache) => tv_cache,
Err((tv_cache, es)) => {
errs.extend(es);
tv_cache
}
};
// Since there are type variables and other variables that can be constrained within closures,
// they are `merge`d once and then `purge`d of type variables that are only used internally after instantiation.
tmp_tv_cache.merge(&_tmp_tv_cache);
let mut nd_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,
tmp_tv_cache,
RegistrationMode::Normal,
ParamKind::NonDefault,
not_found_is_qvar,
)
// TODO: continue
.map_err(|(_, errs)| errs)?;
let pt = match self.instantiate_param_ty(
sig,
None,
tmp_tv_cache,
RegistrationMode::Normal,
ParamKind::NonDefault,
not_found_is_qvar,
) {
Ok(pt) => pt,
Err((pt, es)) => {
errs.extend(es);
pt
}
};
nd_params.push(pt);
}
let var_params = if let Some(p) = lambda.sig.params.var_params.as_ref() {
let pt = self
.instantiate_param_ty(
p,
None,
tmp_tv_cache,
RegistrationMode::Normal,
ParamKind::VarParams,
not_found_is_qvar,
)
.map_err(|(_, errs)| errs)?;
let pt = match self.instantiate_param_ty(
p,
None,
tmp_tv_cache,
RegistrationMode::Normal,
ParamKind::VarParams,
not_found_is_qvar,
) {
Ok(pt) => pt,
Err((pt, es)) => {
errs.extend(es);
pt
}
};
Some(pt)
} else {
None
@ -1270,29 +1418,37 @@ impl Context {
let mut d_params = Vec::with_capacity(lambda.sig.params.defaults.len());
for sig in lambda.sig.params.defaults.iter() {
let expr = self.eval_const_expr(&sig.default_val)?;
let pt = self
.instantiate_param_ty(
&sig.sig,
None,
tmp_tv_cache,
RegistrationMode::Normal,
ParamKind::Default(expr.t()),
not_found_is_qvar,
)
.map_err(|(_, errs)| errs)?;
let pt = match self.instantiate_param_ty(
&sig.sig,
None,
tmp_tv_cache,
RegistrationMode::Normal,
ParamKind::Default(expr.t()),
not_found_is_qvar,
) {
Ok(pt) => pt,
Err((pt, es)) => {
errs.extend(es);
pt
}
};
d_params.push(pt);
}
let kw_var_params = if let Some(p) = lambda.sig.params.kw_var_params.as_ref() {
let pt = self
.instantiate_param_ty(
p,
None,
tmp_tv_cache,
RegistrationMode::Normal,
ParamKind::KwVarParams,
not_found_is_qvar,
)
.map_err(|(_, errs)| errs)?;
let pt = match self.instantiate_param_ty(
p,
None,
tmp_tv_cache,
RegistrationMode::Normal,
ParamKind::KwVarParams,
not_found_is_qvar,
) {
Ok(pt) => pt,
Err((pt, es)) => {
errs.extend(es);
pt
}
};
Some(pt)
} else {
None
@ -1344,14 +1500,18 @@ impl Context {
body.push(param);
}
tmp_tv_cache.purge(&_tmp_tv_cache);
Ok(TyParam::Lambda(TyParamLambda::new(
lambda.clone(),
nd_params,
var_params,
d_params,
kw_var_params,
body,
)))
if errs.is_empty() {
Ok(TyParam::Lambda(TyParamLambda::new(
lambda.clone(),
nd_params,
var_params,
d_params,
kw_var_params,
body,
)))
} else {
Err(errs)
}
}
ast::ConstExpr::BinOp(bin) => {
let Some(op) = token_kind_to_op_kind(bin.op.kind) else {
@ -1535,31 +1695,43 @@ impl Context {
tmp_tv_cache: &mut TyVarCache,
mode: RegistrationMode,
not_found_is_qvar: bool,
) -> TyCheckResult<ParamTy> {
let t = self.instantiate_typespec_full(
) -> Failable<ParamTy> {
let mut errs = TyCheckErrors::empty();
let t = match self.instantiate_typespec_full(
&p.ty,
opt_decl_t,
tmp_tv_cache,
mode,
not_found_is_qvar,
)?;
if let Some(default_t) = default_t {
Ok(ParamTy::kw_default(
p.name.as_ref().unwrap().inspect().to_owned(),
t,
self.instantiate_typespec_full(
default_t,
opt_decl_t,
tmp_tv_cache,
mode,
not_found_is_qvar,
)?,
))
) {
Ok(t) => t,
Err(es) => {
errs.extend(es);
Type::Failure
}
};
let pt = if let Some(default_t) = default_t {
let default = match self.instantiate_typespec_full(
default_t,
opt_decl_t,
tmp_tv_cache,
mode,
not_found_is_qvar,
) {
Ok(t) => t,
Err(es) => {
errs.extend(es);
Type::Failure
}
};
ParamTy::kw_default(p.name.as_ref().unwrap().inspect().to_owned(), t, default)
} else {
Ok(ParamTy::pos_or_kw(
p.name.as_ref().map(|t| t.inspect().to_owned()),
t,
))
ParamTy::pos_or_kw(p.name.as_ref().map(|t| t.inspect().to_owned()), t)
};
if errs.is_empty() {
Ok(pt)
} else {
Err((pt, errs))
}
}
@ -1860,8 +2032,15 @@ impl Context {
Ok(int_interval(op, l, r))
}
TypeSpec::Subr(subr) => {
let mut errs = TyCheckErrors::empty();
let mut inner_tv_ctx = if !subr.bounds.is_empty() {
let tv_cache = self.instantiate_ty_bounds(&subr.bounds, mode)?;
let tv_cache = match self.instantiate_ty_bounds(&subr.bounds, mode) {
Ok(tv_cache) => tv_cache,
Err((tv_cache, es)) => {
errs.extend(es);
tv_cache
}
};
Some(tv_cache)
} else {
None
@ -1874,7 +2053,7 @@ impl Context {
} else {
tmp_tv_cache
};
let non_defaults = try_map_mut(subr.non_defaults.iter(), |p| {
let non_defaults = match failable_map_mut(subr.non_defaults.iter(), |p| {
self.instantiate_func_param_spec(
p,
opt_decl_t,
@ -1883,7 +2062,15 @@ impl Context {
mode,
not_found_is_qvar,
)
})?;
}) {
Ok(v) => v,
Err((v, es)) => {
for e in es {
errs.extend(e);
}
v
}
};
let var_params = subr
.var_params
.as_ref()
@ -1896,9 +2083,10 @@ impl Context {
mode,
not_found_is_qvar,
)
.map_err(|(_, es)| es)
})
.transpose()?;
let defaults = try_map_mut(subr.defaults.iter(), |p| {
let defaults = failable_map_mut(subr.defaults.iter(), |p| {
self.instantiate_func_param_spec(
&p.param,
opt_decl_t,
@ -1907,7 +2095,13 @@ impl Context {
mode,
not_found_is_qvar,
)
})?
})
.unwrap_or_else(|(pts, es)| {
for e in es {
errs.extend(e);
}
pts
})
.into_iter()
.collect();
let kw_var_params = subr
@ -1922,24 +2116,35 @@ impl Context {
mode,
not_found_is_qvar,
)
.map_err(|(_, es)| es)
})
.transpose()?;
let return_t = self.instantiate_typespec_full(
let return_t = match self.instantiate_typespec_full(
&subr.return_t,
opt_decl_t,
tmp_tv_ctx,
mode,
not_found_is_qvar,
)?;
) {
Ok(t) => t,
Err(es) => {
errs.extend(es);
Type::Failure
}
};
// no quantification at this point (in `generalize_t`)
Ok(subr_t(
SubrKind::from(subr.arrow.kind),
non_defaults,
var_params,
defaults,
kw_var_params,
return_t,
))
if errs.is_empty() {
Ok(subr_t(
SubrKind::from(subr.arrow.kind),
non_defaults,
var_params,
defaults,
kw_var_params,
return_t,
))
} else {
Err(errs)
}
}
TypeSpec::TypeApp { spec, args } => {
type_feature_error!(
@ -1960,9 +2165,9 @@ impl Context {
tmp_tv_cache.push_refine_var(&name, t.clone(), self);
let pred = self
.instantiate_pred_from_expr(&refine.pred, tmp_tv_cache)
.map_err(|err| {
.map_err(|errs| {
tmp_tv_cache.remove(name.inspect());
err
errs
})?;
tmp_tv_cache.remove(name.inspect());
let refine =

View file

@ -555,6 +555,15 @@ pub enum RegistrationMode {
Normal,
}
impl RegistrationMode {
pub const fn is_preregister(&self) -> bool {
matches!(self, Self::PreRegister)
}
pub const fn is_normal(&self) -> bool {
matches!(self, Self::Normal)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ContextInfo {
mod_id: usize,

View file

@ -17,7 +17,7 @@ use ast::{
ConstIdentifier, Decorator, DefId, Identifier, OperationKind, PolyTypeSpec, PreDeclTypeSpec,
VarName,
};
use erg_parser::ast::{self, ClassAttr, TypeSpecWithOp};
use erg_parser::ast::{self, ClassAttr, RecordAttrOrIdent, TypeSpecWithOp};
use crate::ty::constructors::{
free_var, func, func0, func1, module, proc, py_module, ref_, ref_mut, str_dict_t, tp_enum,
@ -1059,7 +1059,7 @@ impl Context {
for expr in block.iter() {
match expr {
ast::Expr::Def(def) => {
if let Err(errs) = self.register_const_def(def) {
if let Err(errs) = self.register_def(def) {
total_errs.extend(errs);
}
if def.def_kind().is_import() {
@ -1069,7 +1069,7 @@ impl Context {
}
}
ast::Expr::ClassDef(class_def) => {
if let Err(errs) = self.register_const_def(&class_def.def) {
if let Err(errs) = self.register_def(&class_def.def) {
total_errs.extend(errs);
}
let vis = self
@ -1092,7 +1092,7 @@ impl Context {
self.grow(&class.local_name(), kind, vis.clone(), None);
for attr in methods.attrs.iter() {
if let ClassAttr::Def(def) = attr {
if let Err(errs) = self.register_const_def(def) {
if let Err(errs) = self.register_def(def) {
total_errs.extend(errs);
}
}
@ -1113,7 +1113,7 @@ impl Context {
}
}
ast::Expr::PatchDef(patch_def) => {
if let Err(errs) = self.register_const_def(&patch_def.def) {
if let Err(errs) = self.register_def(&patch_def.def) {
total_errs.extend(errs);
}
}
@ -1206,7 +1206,7 @@ impl Context {
}
}
pub(crate) fn register_const_def(&mut self, def: &ast::Def) -> TyCheckResult<()> {
pub(crate) fn register_def(&mut self, def: &ast::Def) -> TyCheckResult<()> {
let id = Some(def.body.id);
let __name__ = def.sig.ident().map(|i| i.inspect()).unwrap_or(UBAR);
let call = if let Some(ast::Expr::Call(call)) = &def.body.block.first() {
@ -1217,7 +1217,9 @@ impl Context {
match &def.sig {
ast::Signature::Subr(sig) => {
if sig.is_const() {
let tv_cache = self.instantiate_ty_bounds(&sig.bounds, PreRegister)?;
let tv_cache = self
.instantiate_ty_bounds(&sig.bounds, PreRegister)
.map_err(|(_, errs)| errs)?;
let vis = self.instantiate_vis_modifier(sig.vis())?;
self.grow(__name__, ContextKind::Proc, vis, Some(tv_cache));
let (obj, const_t) = match self.eval_const_block(&def.body.block) {
@ -2515,7 +2517,9 @@ impl Context {
false
}
// TODO:
_ => false,
PreDeclTypeSpec::Subscr { namespace: ns, .. } => {
self.inc_ref_expr(ns, namespace, tmp_tv_cache)
}
}
}
@ -2556,6 +2560,9 @@ impl Context {
for arg in poly.args.kw_args() {
self.inc_ref_expr(&arg.expr.clone().downgrade(), namespace, tmp_tv_cache);
}
if let Some(arg) = poly.args.kw_var.as_ref() {
self.inc_ref_expr(&arg.expr.clone().downgrade(), namespace, tmp_tv_cache);
}
self.inc_ref_acc(&poly.acc.clone().downgrade(), namespace, tmp_tv_cache)
}
@ -2596,6 +2603,51 @@ impl Context {
res
}
fn inc_ref_params(
&self,
params: &ast::Params,
namespace: &Context,
tmp_tv_cache: &TyVarCache,
) -> bool {
let mut res = false;
for param in params.non_defaults.iter() {
if let Some(expr) = param.t_spec.as_ref().map(|ts| &ts.t_spec_as_expr) {
if self.inc_ref_expr(expr, namespace, tmp_tv_cache) {
res = true;
}
}
}
if let Some(expr) = params
.var_params
.as_ref()
.and_then(|p| p.t_spec.as_ref().map(|ts| &ts.t_spec_as_expr))
{
if self.inc_ref_expr(expr, namespace, tmp_tv_cache) {
res = true;
}
}
for param in params.defaults.iter() {
if let Some(expr) = param.sig.t_spec.as_ref().map(|ts| &ts.t_spec_as_expr) {
if self.inc_ref_expr(expr, namespace, tmp_tv_cache) {
res = true;
}
}
if self.inc_ref_expr(&param.default_val, namespace, tmp_tv_cache) {
res = true;
}
}
if let Some(expr) = params
.kw_var_params
.as_ref()
.and_then(|p| p.t_spec.as_ref().map(|ts| &ts.t_spec_as_expr))
{
if self.inc_ref_expr(expr, namespace, tmp_tv_cache) {
res = true;
}
}
res
}
fn inc_ref_expr(
&self,
expr: &ast::Expr,
@ -2638,6 +2690,24 @@ impl Context {
}
res
}
ast::Expr::Record(ast::Record::Mixed(rec)) => {
let mut res = false;
for val in rec.attrs.iter() {
match val {
RecordAttrOrIdent::Attr(attr) => {
if self.inc_ref_block(&attr.body.block, namespace, tmp_tv_cache) {
res = true;
}
}
RecordAttrOrIdent::Ident(ident) => {
if self.inc_ref_local(ident, namespace, tmp_tv_cache) {
res = true;
}
}
}
}
res
}
ast::Expr::Array(ast::Array::Normal(arr)) => {
let mut res = false;
for val in arr.elems.pos_args().iter() {
@ -2705,6 +2775,29 @@ impl Context {
}
res
}
ast::Expr::TypeAscription(ascription) => {
self.inc_ref_expr(&ascription.expr, namespace, tmp_tv_cache)
}
ast::Expr::Compound(comp) => {
let mut res = false;
for expr in comp.exprs.iter() {
if self.inc_ref_expr(expr, namespace, tmp_tv_cache) {
res = true;
}
}
res
}
ast::Expr::Lambda(lambda) => {
let mut res = false;
// FIXME: assign params
if self.inc_ref_params(&lambda.sig.params, namespace, tmp_tv_cache) {
res = true;
}
if self.inc_ref_block(&lambda.body, namespace, tmp_tv_cache) {
res = true;
}
res
}
other => {
log!(err "inc_ref_expr: {other}");
false