feat: support using attributes in predicate

This commit is contained in:
Shunsuke Shibayama 2024-02-24 13:23:02 +09:00
parent 47818e431e
commit 0bedeb51ab
6 changed files with 194 additions and 21 deletions

View file

@ -1664,7 +1664,9 @@ impl Context {
Predicate::Call { receiver, name, .. } => {
let receiver_t = self.get_tp_t(receiver).unwrap_or(Obj);
if let Some(name) = name {
let ctx = self.get_nominal_type_ctx(&receiver_t).unwrap();
let Some(ctx) = self.get_nominal_type_ctx(&receiver_t) else {
return Obj;
};
if let Some((_, method)) = ctx.get_var_info(name) {
method.t.return_t().cloned().unwrap_or(Obj)
} else {
@ -1674,6 +1676,17 @@ impl Context {
receiver_t.return_t().cloned().unwrap_or(Obj)
}
}
Predicate::Attr { receiver, name } => {
let receiver_t = self.get_tp_t(receiver).unwrap_or(Obj);
let Some(ctx) = self.get_nominal_type_ctx(&receiver_t) else {
return Obj;
};
if let Some((_, field)) = ctx.get_var_info(name) {
field.t.clone()
} else {
Obj
}
}
// REVIEW
Predicate::GeneralEqual { rhs, .. }
| Predicate::GeneralGreaterEqual { rhs, .. }

View file

@ -1589,6 +1589,7 @@ impl Context {
Ok(TyParam::Value(ValueObj::Type(t)))
}
TyParam::ProjCall { obj, attr, args } => self.eval_proj_call(*obj, attr, args, &()),
TyParam::Proj { obj, attr } => self.eval_tp_proj(*obj, attr, &()),
TyParam::Value(_) => Ok(p.clone()),
other => feature_error!(self, Location::Unknown, &format!("evaluating {other}")),
}
@ -1951,6 +1952,51 @@ impl Context {
}
}
pub(crate) fn eval_tp_proj(
&self,
lhs: TyParam,
rhs: Str,
t_loc: &impl Locational,
) -> EvalResult<TyParam> {
// in Methods
if let Some(ctx) = lhs
.qual_name()
.and_then(|name| self.get_same_name_context(&name))
{
if let Some(value) = ctx.rec_get_const_obj(&rhs) {
return Ok(TyParam::value(value.clone()));
}
}
let ty_ctxs = match self
.get_tp_t(&lhs)
.ok()
.and_then(|t| self.get_nominal_super_type_ctxs(&t))
{
Some(ty_ctxs) => ty_ctxs,
None => {
let errs = EvalErrors::from(EvalError::type_not_found(
self.cfg.input.clone(),
line!() as usize,
t_loc.loc(),
self.caused_by(),
&Type::Obj,
));
return Err(errs);
}
};
for ty_ctx in ty_ctxs {
if let Some(value) = ty_ctx.rec_get_const_obj(&rhs) {
return Ok(TyParam::value(value.clone()));
}
for methods in ty_ctx.methods_list.iter() {
if let Some(value) = methods.rec_get_const_obj(&rhs) {
return Ok(TyParam::value(value.clone()));
}
}
}
Ok(lhs.proj(rhs))
}
/// ```erg
/// TyParam::Type(Int) => Int
/// [{1}, {2}, {3}] => [{1, 2, 3}; 3]
@ -2750,6 +2796,10 @@ impl Context {
feature_error!(self, Location::Unknown, "eval_pred: Predicate::Call")
}
}
Predicate::Attr { receiver, name } => {
let receiver = self.eval_tp(receiver)?;
Ok(Predicate::attr(receiver, name))
}
Predicate::GeneralEqual { lhs, rhs } => {
match (self.eval_pred(*lhs)?, self.eval_pred(*rhs)?) {
(Predicate::Value(lhs), Predicate::Value(rhs)) => {

View file

@ -335,6 +335,10 @@ impl Generalizer {
}
Predicate::call(receiver, name, new_args)
}
Predicate::Attr { receiver, name } => {
let receiver = self.generalize_tp(receiver, uninit);
Predicate::attr(receiver, name)
}
Predicate::Value(_) => pred,
Predicate::GeneralEqual { lhs, rhs } => {
let lhs = self.generalize_pred(*lhs, uninit);

View file

@ -1577,6 +1577,10 @@ impl Context {
self.inc_ref_local(local, self, tmp_tv_cache);
Ok(Predicate::Const(local.inspect().clone()))
}
ast::ConstExpr::Accessor(ast::ConstAccessor::Attr(attr)) => {
let obj = self.instantiate_const_expr(&attr.obj, None, tmp_tv_cache, false)?;
Ok(Predicate::attr(obj, attr.name.inspect().clone()))
}
ast::ConstExpr::App(app) => {
let receiver = self.instantiate_const_expr(&app.obj, None, tmp_tv_cache, false)?;
let name = app.attr_name.as_ref().map(|n| n.inspect().to_owned());

View file

@ -20,6 +20,10 @@ pub enum Predicate {
name: Option<Str>,
args: Vec<TyParam>,
},
Attr {
receiver: TyParam,
name: Str,
},
/// TODO: unify with GeneralEqual
/// i == 0 => Eq{ lhs: "i", rhs: 0 }
Equal {
@ -81,6 +85,7 @@ impl fmt::Display for Predicate {
.join(", ")
)
}
Self::Attr { receiver, name } => write!(f, "{receiver}.{name}"),
Self::Equal { lhs, rhs } => write!(f, "{lhs} == {rhs}"),
Self::GreaterEqual { lhs, rhs } => write!(f, "{lhs} >= {rhs}"),
Self::LessEqual { lhs, rhs } => write!(f, "{lhs} <= {rhs}"),
@ -120,6 +125,7 @@ impl LimitedDisplay for Predicate {
.join(", ")
)
}
Self::Attr { receiver, name } => write!(f, "{receiver}.{name}"),
Self::Equal { lhs, rhs } => {
write!(f, "{lhs} == ")?;
rhs.limited_fmt(f, limit - 1)
@ -261,6 +267,7 @@ impl HasLevel for Predicate {
.level()
.zip(args.iter().map(|a| a.level().unwrap_or(usize::MAX)).min())
.map(|(a, b)| a.min(b)),
Self::Attr { receiver, .. } => receiver.level(),
}
}
@ -273,6 +280,9 @@ impl HasLevel for Predicate {
arg.set_level(level);
}
}
Self::Attr { receiver, .. } => {
receiver.set_level(level);
}
Self::Equal { rhs, .. }
| Self::GreaterEqual { rhs, .. }
| Self::LessEqual { rhs, .. }
@ -361,6 +371,10 @@ impl Predicate {
}
}
pub fn attr(receiver: TyParam, name: Str) -> Self {
Self::Attr { receiver, name }
}
pub const fn eq(lhs: Str, rhs: TyParam) -> Self {
Self::Equal { lhs, rhs }
}
@ -616,6 +630,7 @@ impl Predicate {
}
set
}
Self::Attr { receiver, .. } => receiver.qvars(),
Self::Equal { rhs, .. }
| Self::GreaterEqual { rhs, .. }
| Self::LessEqual { rhs, .. }
@ -638,6 +653,7 @@ impl Predicate {
Self::Call { receiver, args, .. } => {
receiver.has_qvar() || args.iter().any(|a| a.has_qvar())
}
Self::Attr { receiver, .. } => receiver.has_qvar(),
Self::Equal { rhs, .. }
| Self::GreaterEqual { rhs, .. }
| Self::LessEqual { rhs, .. }
@ -658,6 +674,7 @@ impl Predicate {
Self::Call { receiver, args, .. } => {
receiver.has_unbound_var() || args.iter().any(|a| a.has_unbound_var())
}
Self::Attr { receiver, .. } => receiver.has_unbound_var(),
Self::Equal { rhs, .. }
| Self::GreaterEqual { rhs, .. }
| Self::LessEqual { rhs, .. }
@ -681,6 +698,7 @@ impl Predicate {
receiver.has_undoable_linked_var()
|| args.iter().any(|a| a.has_undoable_linked_var())
}
Self::Attr { receiver, .. } => receiver.has_undoable_linked_var(),
Self::Equal { rhs, .. }
| Self::GreaterEqual { rhs, .. }
| Self::LessEqual { rhs, .. }
@ -732,7 +750,7 @@ impl Predicate {
pub fn typarams(&self) -> Vec<&TyParam> {
match self {
Self::Value(_) | Self::Const(_) => vec![],
Self::Value(_) | Self::Const(_) | Self::Attr { .. } => vec![],
// REVIEW: Should the receiver be included?
Self::Call { args, .. } => {
let mut vec = vec![];
@ -797,6 +815,7 @@ impl Predicate {
}
set
}
Self::Attr { receiver, .. } => receiver.variables(),
Self::Equal { rhs, .. }
| Self::GreaterEqual { rhs, .. }
| Self::LessEqual { rhs, .. }