mirror of
https://github.com/erg-lang/erg.git
synced 2025-10-03 22:14:37 +00:00
Update eval.rs
This commit is contained in:
parent
a7f9a4ecb7
commit
4622a0b6be
1 changed files with 226 additions and 89 deletions
|
@ -37,7 +37,7 @@ use crate::error::{EvalError, EvalErrors, EvalResult, Failable, SingleEvalResult
|
||||||
use crate::varinfo::{AbsLocation, VarInfo};
|
use crate::varinfo::{AbsLocation, VarInfo};
|
||||||
|
|
||||||
use super::instantiate::TyVarCache;
|
use super::instantiate::TyVarCache;
|
||||||
use Type::{Failure, Never, Subr};
|
use Type::{Failure, Never};
|
||||||
|
|
||||||
macro_rules! feature_error {
|
macro_rules! feature_error {
|
||||||
($ctx: expr, $loc: expr, $name: expr) => {
|
($ctx: expr, $loc: expr, $name: expr) => {
|
||||||
|
@ -1748,21 +1748,38 @@ impl Context {
|
||||||
|
|
||||||
fn eval_unary_val(&self, op: OpKind, val: ValueObj) -> EvalResult<ValueObj> {
|
fn eval_unary_val(&self, op: OpKind, val: ValueObj) -> EvalResult<ValueObj> {
|
||||||
match op {
|
match op {
|
||||||
Pos => Err(EvalErrors::from(EvalError::unreachable(
|
Pos => match val {
|
||||||
self.cfg.input.clone(),
|
ValueObj::Nat(_)
|
||||||
fn_name!(),
|
| ValueObj::Int(_)
|
||||||
line!(),
|
| ValueObj::Float(_)
|
||||||
))),
|
| ValueObj::Inf
|
||||||
Neg => Err(EvalErrors::from(EvalError::unreachable(
|
| ValueObj::NegInf => Ok(val),
|
||||||
self.cfg.input.clone(),
|
_ => Err(EvalErrors::from(EvalError::unreachable(
|
||||||
fn_name!(),
|
self.cfg.input.clone(),
|
||||||
line!(),
|
fn_name!(),
|
||||||
))),
|
line!(),
|
||||||
Invert => Err(EvalErrors::from(EvalError::unreachable(
|
))),
|
||||||
self.cfg.input.clone(),
|
},
|
||||||
fn_name!(),
|
Neg => match val {
|
||||||
line!(),
|
ValueObj::Nat(n) => Ok(ValueObj::Int(-(n as i32))),
|
||||||
))),
|
ValueObj::Int(i) => Ok(ValueObj::Int(-i)),
|
||||||
|
ValueObj::Float(f) => Ok(ValueObj::Float(-f)),
|
||||||
|
ValueObj::Inf => Ok(ValueObj::NegInf),
|
||||||
|
ValueObj::NegInf => Ok(ValueObj::Inf),
|
||||||
|
_ => Err(EvalErrors::from(EvalError::unreachable(
|
||||||
|
self.cfg.input.clone(),
|
||||||
|
fn_name!(),
|
||||||
|
line!(),
|
||||||
|
))),
|
||||||
|
},
|
||||||
|
Invert => match val {
|
||||||
|
ValueObj::Bool(b) => Ok(ValueObj::Bool(!b)),
|
||||||
|
_ => Err(EvalErrors::from(EvalError::unreachable(
|
||||||
|
self.cfg.input.clone(),
|
||||||
|
fn_name!(),
|
||||||
|
line!(),
|
||||||
|
))),
|
||||||
|
},
|
||||||
Not => match val {
|
Not => match val {
|
||||||
ValueObj::Bool(b) => Ok(ValueObj::Bool(!b)),
|
ValueObj::Bool(b) => Ok(ValueObj::Bool(!b)),
|
||||||
ValueObj::Type(lhs) => Ok(self.eval_not_type(lhs)),
|
ValueObj::Type(lhs) => Ok(self.eval_not_type(lhs)),
|
||||||
|
@ -1815,16 +1832,13 @@ impl Context {
|
||||||
pub(crate) fn eval_tp(&self, p: TyParam) -> Failable<TyParam> {
|
pub(crate) fn eval_tp(&self, p: TyParam) -> Failable<TyParam> {
|
||||||
let mut errs = EvalErrors::empty();
|
let mut errs = EvalErrors::empty();
|
||||||
let tp = match p {
|
let tp = match p {
|
||||||
TyParam::FreeVar(fv) if fv.is_linked() => {
|
TyParam::FreeVar(fv) if fv.is_linked() => match self.eval_tp(fv.unwrap_linked()) {
|
||||||
let tp = fv.crack().clone();
|
Ok(tp) => tp,
|
||||||
match self.eval_tp(tp) {
|
Err((tp, es)) => {
|
||||||
Ok(tp) => tp,
|
errs.extend(es);
|
||||||
Err((tp, es)) => {
|
tp
|
||||||
errs.extend(es);
|
|
||||||
tp
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
TyParam::FreeVar(_) => p,
|
TyParam::FreeVar(_) => p,
|
||||||
TyParam::Mono(name) => match self
|
TyParam::Mono(name) => match self
|
||||||
.rec_get_const_obj(&name)
|
.rec_get_const_obj(&name)
|
||||||
|
@ -2050,8 +2064,7 @@ impl Context {
|
||||||
let mut errs = EvalErrors::empty();
|
let mut errs = EvalErrors::empty();
|
||||||
match substituted {
|
match substituted {
|
||||||
Type::FreeVar(fv) if fv.is_linked() => {
|
Type::FreeVar(fv) if fv.is_linked() => {
|
||||||
let t = fv.crack().clone();
|
self.eval_t_params(fv.unwrap_linked(), level, t_loc)
|
||||||
self.eval_t_params(t, level, t_loc)
|
|
||||||
}
|
}
|
||||||
Type::FreeVar(fv) if fv.constraint_is_sandwiched() => {
|
Type::FreeVar(fv) if fv.constraint_is_sandwiched() => {
|
||||||
let (sub, sup) = fv.get_subsup().unwrap();
|
let (sub, sup) = fv.get_subsup().unwrap();
|
||||||
|
@ -2074,9 +2087,9 @@ impl Context {
|
||||||
*pt.typ_mut() = match self.eval_t_params(mem::take(pt.typ_mut()), level, t_loc)
|
*pt.typ_mut() = match self.eval_t_params(mem::take(pt.typ_mut()), level, t_loc)
|
||||||
{
|
{
|
||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err((_, errs)) => {
|
Err((t, es)) => {
|
||||||
// `mem::take` replaces the type with `Type::Failure`, so it can return as is
|
errs.extend(es);
|
||||||
return Err((Subr(subr), errs));
|
t
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -2084,19 +2097,28 @@ impl Context {
|
||||||
*var_args.typ_mut() =
|
*var_args.typ_mut() =
|
||||||
match self.eval_t_params(mem::take(var_args.typ_mut()), level, t_loc) {
|
match self.eval_t_params(mem::take(var_args.typ_mut()), level, t_loc) {
|
||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err((_, errs)) => return Err((Subr(subr), errs)),
|
Err((t, es)) => {
|
||||||
|
errs.extend(es);
|
||||||
|
t
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
for pt in subr.default_params.iter_mut() {
|
for pt in subr.default_params.iter_mut() {
|
||||||
*pt.typ_mut() = match self.eval_t_params(mem::take(pt.typ_mut()), level, t_loc)
|
*pt.typ_mut() = match self.eval_t_params(mem::take(pt.typ_mut()), level, t_loc)
|
||||||
{
|
{
|
||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err((_, errs)) => return Err((Subr(subr), errs)),
|
Err((t, es)) => {
|
||||||
|
errs.extend(es);
|
||||||
|
t
|
||||||
|
}
|
||||||
};
|
};
|
||||||
if let Some(default) = pt.default_typ_mut() {
|
if let Some(default) = pt.default_typ_mut() {
|
||||||
*default = match self.eval_t_params(mem::take(default), level, t_loc) {
|
*default = match self.eval_t_params(mem::take(default), level, t_loc) {
|
||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err((_, errs)) => return Err((Subr(subr), errs)),
|
Err((t, es)) => {
|
||||||
|
errs.extend(es);
|
||||||
|
t
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2104,31 +2126,37 @@ impl Context {
|
||||||
*kw_var_args.typ_mut() =
|
*kw_var_args.typ_mut() =
|
||||||
match self.eval_t_params(mem::take(kw_var_args.typ_mut()), level, t_loc) {
|
match self.eval_t_params(mem::take(kw_var_args.typ_mut()), level, t_loc) {
|
||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err((_, errs)) => return Err((Subr(subr), errs)),
|
Err((t, es)) => {
|
||||||
|
errs.extend(es);
|
||||||
|
t
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
match self.eval_t_params(*subr.return_t, level, t_loc) {
|
let return_t = match self.eval_t_params(*subr.return_t, level, t_loc) {
|
||||||
Ok(return_t) => Ok(subr_t(
|
Ok(return_t) => return_t,
|
||||||
subr.kind,
|
Err((return_t, es)) => {
|
||||||
subr.non_default_params,
|
errs.extend(es);
|
||||||
subr.var_params.map(|v| *v),
|
return_t
|
||||||
subr.default_params,
|
|
||||||
subr.kw_var_params.map(|v| *v),
|
|
||||||
return_t,
|
|
||||||
)),
|
|
||||||
Err((_, errs)) => {
|
|
||||||
let subr = subr_t(
|
|
||||||
subr.kind,
|
|
||||||
subr.non_default_params,
|
|
||||||
subr.var_params.map(|v| *v),
|
|
||||||
subr.default_params,
|
|
||||||
subr.kw_var_params.map(|v| *v),
|
|
||||||
Failure,
|
|
||||||
);
|
|
||||||
Err((subr, errs))
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
let subr = subr_t(
|
||||||
|
subr.kind,
|
||||||
|
subr.non_default_params,
|
||||||
|
subr.var_params.map(|v| *v),
|
||||||
|
subr.default_params,
|
||||||
|
subr.kw_var_params.map(|v| *v),
|
||||||
|
return_t,
|
||||||
|
);
|
||||||
|
if errs.is_empty() {
|
||||||
|
Ok(subr)
|
||||||
|
} else {
|
||||||
|
Err((subr, errs))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Type::Quantified(quant) => match self.eval_t_params(*quant, level, t_loc) {
|
||||||
|
Ok(t) => Ok(t.quantify()),
|
||||||
|
Err((t, es)) => Err((t.quantify(), es)),
|
||||||
|
},
|
||||||
Type::Refinement(refine) => {
|
Type::Refinement(refine) => {
|
||||||
if refine.pred.variables().is_empty() {
|
if refine.pred.variables().is_empty() {
|
||||||
let pred = match self.eval_pred(*refine.pred) {
|
let pred = match self.eval_pred(*refine.pred) {
|
||||||
|
@ -2158,27 +2186,33 @@ impl Context {
|
||||||
.map_err(|errs| (Failure, errs)),
|
.map_err(|errs| (Failure, errs)),
|
||||||
Type::Ref(l) => match self.eval_t_params(*l, level, t_loc) {
|
Type::Ref(l) => match self.eval_t_params(*l, level, t_loc) {
|
||||||
Ok(t) => Ok(ref_(t)),
|
Ok(t) => Ok(ref_(t)),
|
||||||
Err((_, errs)) => Err((ref_(Failure), errs)),
|
Err((t, errs)) => Err((ref_(t), errs)),
|
||||||
},
|
},
|
||||||
Type::RefMut { before, after } => {
|
Type::RefMut { before, after } => {
|
||||||
let before = match self.eval_t_params(*before, level, t_loc) {
|
let before = match self.eval_t_params(*before, level, t_loc) {
|
||||||
Ok(before) => before,
|
Ok(before) => before,
|
||||||
Err((_, errs)) => {
|
Err((before, es)) => {
|
||||||
return Err((ref_mut(Failure, after.map(|x| *x)), errs));
|
errs.extend(es);
|
||||||
|
before
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let after = if let Some(after) = after {
|
let after = if let Some(after) = after {
|
||||||
let aft = match self.eval_t_params(*after, level, t_loc) {
|
let aft = match self.eval_t_params(*after, level, t_loc) {
|
||||||
Ok(aft) => aft,
|
Ok(aft) => aft,
|
||||||
Err((_, errs)) => {
|
Err((aft, es)) => {
|
||||||
return Err((ref_mut(before, Some(Failure)), errs));
|
errs.extend(es);
|
||||||
|
aft
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Some(aft)
|
Some(aft)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
Ok(ref_mut(before, after))
|
if errs.is_empty() {
|
||||||
|
Ok(ref_mut(before, after))
|
||||||
|
} else {
|
||||||
|
Err((ref_mut(before, after), errs))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Type::Poly { name, mut params } => {
|
Type::Poly { name, mut params } => {
|
||||||
for p in params.iter_mut() {
|
for p in params.iter_mut() {
|
||||||
|
@ -2209,82 +2243,115 @@ impl Context {
|
||||||
Type::And(l, r) => {
|
Type::And(l, r) => {
|
||||||
let l = match self.eval_t_params(*l, level, t_loc) {
|
let l = match self.eval_t_params(*l, level, t_loc) {
|
||||||
Ok(l) => l,
|
Ok(l) => l,
|
||||||
Err((_, errs)) => {
|
Err((l, es)) => {
|
||||||
return Err((Failure, errs));
|
errs.extend(es);
|
||||||
|
l
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let r = match self.eval_t_params(*r, level, t_loc) {
|
let r = match self.eval_t_params(*r, level, t_loc) {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err((_, errs)) => {
|
Err((r, es)) => {
|
||||||
// L and Never == Never
|
errs.extend(es);
|
||||||
return Err((Failure, errs));
|
r
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(self.intersection(&l, &r))
|
let intersec = self.intersection(&l, &r);
|
||||||
|
if errs.is_empty() {
|
||||||
|
Ok(intersec)
|
||||||
|
} else {
|
||||||
|
Err((intersec, errs))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Type::Or(l, r) => {
|
Type::Or(l, r) => {
|
||||||
let l = match self.eval_t_params(*l, level, t_loc) {
|
let l = match self.eval_t_params(*l, level, t_loc) {
|
||||||
Ok(l) => l,
|
Ok(l) => l,
|
||||||
Err((_, errs)) => {
|
Err((l, es)) => {
|
||||||
return Err((Failure, errs));
|
errs.extend(es);
|
||||||
|
l
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let r = match self.eval_t_params(*r, level, t_loc) {
|
let r = match self.eval_t_params(*r, level, t_loc) {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err((_, errs)) => {
|
Err((r, es)) => {
|
||||||
// L or Never == L
|
errs.extend(es);
|
||||||
return Err((l, errs));
|
r
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(self.union(&l, &r))
|
let union = self.union(&l, &r);
|
||||||
|
if errs.is_empty() {
|
||||||
|
Ok(union)
|
||||||
|
} else {
|
||||||
|
Err((union, errs))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Type::Not(ty) => match self.eval_t_params(*ty, level, t_loc) {
|
Type::Not(ty) => match self.eval_t_params(*ty, level, t_loc) {
|
||||||
Ok(ty) => Ok(self.complement(&ty)),
|
Ok(ty) => Ok(self.complement(&ty)),
|
||||||
Err((_, errs)) => Err((Failure, errs)),
|
Err((ty, errs)) => Err((self.complement(&ty), errs)),
|
||||||
|
},
|
||||||
|
Type::Structural(typ) => match self.eval_t_params(*typ, level, t_loc) {
|
||||||
|
Ok(typ) => Ok(typ.structuralize()),
|
||||||
|
Err((t, errs)) => Err((t.structuralize(), errs)),
|
||||||
},
|
},
|
||||||
Type::Structural(typ) => {
|
|
||||||
let typ = self.eval_t_params(*typ, level, t_loc)?;
|
|
||||||
Ok(typ.structuralize())
|
|
||||||
}
|
|
||||||
Type::Record(rec) => {
|
Type::Record(rec) => {
|
||||||
let mut fields = dict! {};
|
let mut fields = dict! {};
|
||||||
for (name, tp) in rec.into_iter() {
|
for (name, ty) in rec.into_iter() {
|
||||||
fields.insert(name, self.eval_t_params(tp, level, t_loc)?);
|
match self.eval_t_params(ty, level, t_loc) {
|
||||||
|
Ok(ty) => {
|
||||||
|
fields.insert(name, ty);
|
||||||
|
}
|
||||||
|
Err((tp, es)) => {
|
||||||
|
fields.insert(name, tp);
|
||||||
|
errs.extend(es);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(Type::Record(fields))
|
Ok(Type::Record(fields))
|
||||||
}
|
}
|
||||||
Type::NamedTuple(tuple) => {
|
Type::NamedTuple(tuple) => {
|
||||||
let mut new_tuple = vec![];
|
let mut new_tuple = vec![];
|
||||||
for (name, tp) in tuple.into_iter() {
|
for (name, ty) in tuple.into_iter() {
|
||||||
new_tuple.push((name, self.eval_t_params(tp, level, t_loc)?));
|
match self.eval_t_params(ty, level, t_loc) {
|
||||||
|
Ok(ty) => new_tuple.push((name, ty)),
|
||||||
|
Err((ty, es)) => {
|
||||||
|
new_tuple.push((name, ty));
|
||||||
|
errs.extend(es);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(Type::NamedTuple(new_tuple))
|
Ok(Type::NamedTuple(new_tuple))
|
||||||
}
|
}
|
||||||
Type::Bounded { sub, sup } => {
|
Type::Bounded { sub, sup } => {
|
||||||
let sub = match self.eval_t_params(*sub, level, t_loc) {
|
let sub = match self.eval_t_params(*sub, level, t_loc) {
|
||||||
Ok(sub) => sub,
|
Ok(sub) => sub,
|
||||||
Err((_, errs)) => {
|
Err((sub, es)) => {
|
||||||
return Err((Failure, errs));
|
errs.extend(es);
|
||||||
|
sub
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let sup = match self.eval_t_params(*sup, level, t_loc) {
|
let sup = match self.eval_t_params(*sup, level, t_loc) {
|
||||||
Ok(sup) => sup,
|
Ok(sup) => sup,
|
||||||
Err((_, errs)) => {
|
Err((sup, es)) => {
|
||||||
return Err((Failure, errs));
|
errs.extend(es);
|
||||||
|
sup
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(bounded(sub, sup))
|
if errs.is_empty() {
|
||||||
}
|
Ok(bounded(sub, sup))
|
||||||
Type::Guard(grd) => {
|
} else {
|
||||||
let to = self.eval_t_params(*grd.to, level, t_loc)?;
|
Err((bounded(sub, sup), errs))
|
||||||
Ok(guard(grd.namespace, grd.target, to))
|
}
|
||||||
}
|
}
|
||||||
|
Type::Guard(grd) => match self.eval_t_params(*grd.to, level, t_loc) {
|
||||||
|
Ok(to) => Ok(guard(grd.namespace, grd.target, to)),
|
||||||
|
Err((to, es)) => Err((guard(grd.namespace, grd.target, to), es)),
|
||||||
|
},
|
||||||
other if other.is_monomorphic() => Ok(other),
|
other if other.is_monomorphic() => Ok(other),
|
||||||
other => feature_error!(self, t_loc.loc(), &format!("eval {other}"))
|
other => feature_error!(self, t_loc.loc(), &format!("eval {other}"))
|
||||||
.map_err(|errs| (other, errs)),
|
.map_err(|errs| (other, errs)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This may do nothing (be careful with recursive calls).
|
||||||
/// lhs: mainly class
|
/// lhs: mainly class
|
||||||
pub(crate) fn eval_proj(
|
pub(crate) fn eval_proj(
|
||||||
&self,
|
&self,
|
||||||
|
@ -2658,10 +2725,12 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Failable<Type>
|
||||||
pub(crate) fn convert_value_into_type(&self, val: ValueObj) -> Result<Type, ValueObj> {
|
pub(crate) fn convert_value_into_type(&self, val: ValueObj) -> Result<Type, ValueObj> {
|
||||||
match val {
|
match val {
|
||||||
ValueObj::Failure => Ok(Type::Failure),
|
ValueObj::Failure => Ok(Type::Failure),
|
||||||
ValueObj::Ellipsis => Ok(Type::Ellipsis),
|
ValueObj::Ellipsis => Ok(Type::Ellipsis),
|
||||||
|
ValueObj::NotImplemented => Ok(Type::NotImplementedType),
|
||||||
ValueObj::Type(t) => Ok(t.into_typ()),
|
ValueObj::Type(t) => Ok(t.into_typ()),
|
||||||
ValueObj::Record(rec) => {
|
ValueObj::Record(rec) => {
|
||||||
let mut fields = dict! {};
|
let mut fields = dict! {};
|
||||||
|
@ -2813,6 +2882,30 @@ impl Context {
|
||||||
}
|
}
|
||||||
Ok(new_dict)
|
Ok(new_dict)
|
||||||
}
|
}
|
||||||
|
Type::Proj { lhs, rhs } => {
|
||||||
|
let old = proj(*lhs.clone(), rhs.clone());
|
||||||
|
let eval = self.eval_proj(*lhs, rhs, self.level, &()).map_err(|_| ())?;
|
||||||
|
if eval != old {
|
||||||
|
self.convert_type_to_dict_type(eval)
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Type::ProjCall {
|
||||||
|
lhs,
|
||||||
|
attr_name,
|
||||||
|
args,
|
||||||
|
} => {
|
||||||
|
let old = proj_call(*lhs.clone(), attr_name.clone(), args.clone());
|
||||||
|
let eval = self
|
||||||
|
.eval_proj_call_t(*lhs, attr_name, args, self.level, &())
|
||||||
|
.map_err(|_| ())?;
|
||||||
|
if eval != old {
|
||||||
|
self.convert_type_to_dict_type(eval)
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2833,6 +2926,31 @@ impl Context {
|
||||||
}
|
}
|
||||||
Ok(tys)
|
Ok(tys)
|
||||||
}
|
}
|
||||||
|
Type::NamedTuple(tuple) => Ok(tuple.into_iter().map(|(_, ty)| ty).collect()),
|
||||||
|
Type::Proj { lhs, rhs } => {
|
||||||
|
let old = proj(*lhs.clone(), rhs.clone());
|
||||||
|
let eval = self.eval_proj(*lhs, rhs, self.level, &()).map_err(|_| ())?;
|
||||||
|
if eval != old {
|
||||||
|
self.convert_type_to_tuple_type(eval)
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Type::ProjCall {
|
||||||
|
lhs,
|
||||||
|
attr_name,
|
||||||
|
args,
|
||||||
|
} => {
|
||||||
|
let old = proj_call(*lhs.clone(), attr_name.clone(), args.clone());
|
||||||
|
let eval = self
|
||||||
|
.eval_proj_call_t(*lhs, attr_name, args, self.level, &())
|
||||||
|
.map_err(|_| ())?;
|
||||||
|
if eval != old {
|
||||||
|
self.convert_type_to_tuple_type(eval)
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2858,6 +2976,24 @@ impl Context {
|
||||||
};
|
};
|
||||||
Ok(vec![ValueObj::builtin_type(t); len])
|
Ok(vec![ValueObj::builtin_type(t); len])
|
||||||
}
|
}
|
||||||
|
Type::Proj { lhs, rhs } => {
|
||||||
|
let old = proj(*lhs.clone(), rhs.clone());
|
||||||
|
match self.eval_proj(*lhs, rhs, self.level, &()) {
|
||||||
|
Ok(eval) if eval != old => self.convert_type_to_list(eval),
|
||||||
|
_ => Err(old),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Type::ProjCall {
|
||||||
|
lhs,
|
||||||
|
attr_name,
|
||||||
|
args,
|
||||||
|
} => {
|
||||||
|
let old = proj_call(*lhs.clone(), attr_name.clone(), args.clone());
|
||||||
|
match self.eval_proj_call_t(*lhs, attr_name, args, self.level, &()) {
|
||||||
|
Ok(eval) if eval != old => self.convert_type_to_list(eval),
|
||||||
|
_ => Err(old),
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => Err(ty),
|
_ => Err(ty),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3075,6 +3211,7 @@ impl Context {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This may do nothing (be careful with recursive calls)
|
||||||
pub(crate) fn eval_proj_call_t(
|
pub(crate) fn eval_proj_call_t(
|
||||||
&self,
|
&self,
|
||||||
lhs: TyParam,
|
lhs: TyParam,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue