mirror of
https://github.com/erg-lang/erg.git
synced 2025-10-03 05:54:33 +00:00
fix: array type inferring
This commit is contained in:
parent
142db9b697
commit
f4e1d494a4
15 changed files with 276 additions and 69 deletions
|
@ -274,7 +274,7 @@ impl Context {
|
|||
if let Err(err) = self.overwrite_typarams(typ, rhs) {
|
||||
Self::undo_substitute_typarams(typ);
|
||||
if DEBUG_MODE {
|
||||
panic!("err: {err}");
|
||||
panic!("{typ} / {rhs}: err: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -398,16 +398,18 @@ impl Context {
|
|||
}
|
||||
}
|
||||
|
||||
fn eval_const_array(&self, arr: &Array) -> EvalResult<ValueObj> {
|
||||
pub(crate) fn eval_const_normal_array(&self, arr: &NormalArray) -> EvalResult<ValueObj> {
|
||||
let mut elems = vec![];
|
||||
match arr {
|
||||
Array::Normal(arr) => {
|
||||
for elem in arr.elems.pos_args().iter() {
|
||||
let elem = self.eval_const_expr(&elem.expr)?;
|
||||
elems.push(elem);
|
||||
}
|
||||
Ok(ValueObj::Array(ArcArray::from(elems)))
|
||||
}
|
||||
|
||||
fn eval_const_array(&self, arr: &Array) -> EvalResult<ValueObj> {
|
||||
match arr {
|
||||
Array::Normal(arr) => self.eval_const_normal_array(arr),
|
||||
_ => Err(EvalErrors::from(EvalError::not_const_expr(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
|
@ -1847,7 +1849,13 @@ impl Context {
|
|||
if st.has_no_unbound_var() && qt.has_no_unbound_var() {
|
||||
return Ok(());
|
||||
}
|
||||
if let Err(errs) = self.sub_unify(&st, &qt, &(), None) {
|
||||
let qt = if qt.has_undoable_linked_var() {
|
||||
let mut tv_cache = TyVarCache::new(self.level, self);
|
||||
self.detach(qt, &mut tv_cache)
|
||||
} else {
|
||||
qt
|
||||
};
|
||||
if let Err(errs) = self.undoable_sub_unify(&st, &qt, &(), None) {
|
||||
log!(err "{errs}");
|
||||
}
|
||||
Ok(())
|
||||
|
@ -1913,7 +1921,13 @@ impl Context {
|
|||
if !st.is_unbound_var() || !st.is_generalized() {
|
||||
self.overwrite_typarams(&qt, &st)?;
|
||||
}
|
||||
if let Err(errs) = self.sub_unify(&st, &qt, &(), None) {
|
||||
let qt = if qt.has_undoable_linked_var() {
|
||||
let mut tv_cache = TyVarCache::new(self.level, self);
|
||||
self.detach(qt, &mut tv_cache)
|
||||
} else {
|
||||
qt
|
||||
};
|
||||
if let Err(errs) = self.undoable_sub_unify(&st, &qt, &(), None) {
|
||||
log!(err "{errs}");
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -4,7 +4,7 @@ use erg_common::consts::DEBUG_MODE;
|
|||
use erg_common::set::Set;
|
||||
use erg_common::traits::{Locational, Stream};
|
||||
use erg_common::Str;
|
||||
use erg_common::{dict, fn_name, set};
|
||||
use erg_common::{dict, fn_name, get_hash, set};
|
||||
#[allow(unused_imports)]
|
||||
use erg_common::{fmt_vec, log};
|
||||
|
||||
|
@ -912,6 +912,8 @@ impl Context {
|
|||
}
|
||||
|
||||
fn poly_class_trait_impl_exists(&self, class: &Type, trait_: &Type) -> bool {
|
||||
let class_hash = get_hash(&class);
|
||||
let trait_hash = get_hash(&trait_);
|
||||
for imp in self.get_trait_impls(trait_).into_iter() {
|
||||
self.substitute_typarams(&imp.sub_type, class).unwrap_or(());
|
||||
self.substitute_typarams(&imp.sup_trait, trait_)
|
||||
|
@ -920,10 +922,22 @@ impl Context {
|
|||
{
|
||||
Self::undo_substitute_typarams(&imp.sub_type);
|
||||
Self::undo_substitute_typarams(&imp.sup_trait);
|
||||
if class_hash != get_hash(&class) {
|
||||
class.undo();
|
||||
}
|
||||
if trait_hash != get_hash(&trait_) {
|
||||
trait_.undo();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
Self::undo_substitute_typarams(&imp.sub_type);
|
||||
Self::undo_substitute_typarams(&imp.sup_trait);
|
||||
if class_hash != get_hash(&class) {
|
||||
class.undo();
|
||||
}
|
||||
if trait_hash != get_hash(&trait_) {
|
||||
trait_.undo();
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
|
|
@ -94,6 +94,12 @@ impl TyVarCache {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, name: &str) {
|
||||
self.tyvar_instances.remove(name);
|
||||
self.typaram_instances.remove(name);
|
||||
self.var_infos.remove(name);
|
||||
}
|
||||
|
||||
/// Warn when a type does not need to be a type variable, such as `|T| T -> Int` (it should be `Obj -> Int`).
|
||||
///
|
||||
/// TODO: This warning is currently disabled because it raises a false warning in cases like `|T|(x: T) -> (y: T) -> (x, y)`.
|
||||
|
|
|
@ -836,13 +836,21 @@ impl Context {
|
|||
self.instantiate_acc(acc, erased_idx, tmp_tv_cache, not_found_is_qvar)
|
||||
}
|
||||
ast::ConstExpr::App(app) => {
|
||||
let ast::ConstAccessor::Local(ident) = &app.acc else {
|
||||
return type_feature_error!(self, app.loc(), "instantiating const callee");
|
||||
};
|
||||
let &ctx = self
|
||||
.get_singular_ctxs_by_ident(ident, self)?
|
||||
.first()
|
||||
.unwrap_or(&self);
|
||||
let obj = self.instantiate_const_expr(
|
||||
&app.obj,
|
||||
erased_idx,
|
||||
tmp_tv_cache,
|
||||
not_found_is_qvar,
|
||||
)?;
|
||||
let ctx = self
|
||||
.get_singular_ctxs(&app.obj.clone().downgrade(), self)
|
||||
.ok()
|
||||
.and_then(|ctxs| ctxs.first().copied())
|
||||
.or_else(|| {
|
||||
let typ = self.get_tp_t(&obj).ok()?;
|
||||
self.get_nominal_type_ctx(&typ).map(|(_, ctx)| ctx)
|
||||
})
|
||||
.unwrap_or(self);
|
||||
let mut args = vec![];
|
||||
for (i, arg) in app.args.pos_args().enumerate() {
|
||||
let arg_t = self.instantiate_const_expr(
|
||||
|
@ -853,9 +861,14 @@ impl Context {
|
|||
)?;
|
||||
args.push(arg_t);
|
||||
}
|
||||
if ctx.kind.is_type() && !ctx.params.is_empty() {
|
||||
if let Some(attr_name) = app.attr_name.as_ref() {
|
||||
Ok(obj.proj_call(attr_name.inspect().clone(), args))
|
||||
} else if ctx.kind.is_type() && !ctx.params.is_empty() {
|
||||
Ok(TyParam::t(poly(ctx.name.clone(), args)))
|
||||
} else {
|
||||
let ast::ConstExpr::Accessor(ast::ConstAccessor::Local(ident)) = app.obj.as_ref() else {
|
||||
return type_feature_error!(self, app.loc(), "instantiating const callee");
|
||||
};
|
||||
Ok(TyParam::app(ident.inspect().clone(), args))
|
||||
}
|
||||
}
|
||||
|
@ -1240,7 +1253,7 @@ impl Context {
|
|||
fn instantiate_pred(
|
||||
&self,
|
||||
expr: &ast::ConstExpr,
|
||||
_tmp_tv_cache: &mut TyVarCache,
|
||||
tmp_tv_cache: &mut TyVarCache,
|
||||
) -> TyCheckResult<Predicate> {
|
||||
match expr {
|
||||
ast::ConstExpr::Lit(lit) => {
|
||||
|
@ -1248,11 +1261,12 @@ impl Context {
|
|||
Ok(Predicate::Value(value))
|
||||
}
|
||||
ast::ConstExpr::Accessor(ast::ConstAccessor::Local(local)) => {
|
||||
self.inc_ref_local(local, self, tmp_tv_cache);
|
||||
Ok(Predicate::Const(local.inspect().clone()))
|
||||
}
|
||||
ast::ConstExpr::BinOp(bin) => {
|
||||
let lhs = self.instantiate_pred(&bin.lhs, _tmp_tv_cache)?;
|
||||
let rhs = self.instantiate_pred(&bin.rhs, _tmp_tv_cache)?;
|
||||
let lhs = self.instantiate_pred(&bin.lhs, tmp_tv_cache)?;
|
||||
let rhs = self.instantiate_pred(&bin.rhs, tmp_tv_cache)?;
|
||||
match bin.op.kind {
|
||||
TokenKind::DblEq
|
||||
| TokenKind::NotEq
|
||||
|
@ -1299,7 +1313,7 @@ impl Context {
|
|||
}
|
||||
}
|
||||
ast::ConstExpr::UnaryOp(unop) => {
|
||||
let pred = self.instantiate_pred(&unop.expr, _tmp_tv_cache)?;
|
||||
let pred = self.instantiate_pred(&unop.expr, tmp_tv_cache)?;
|
||||
match unop.op.kind {
|
||||
TokenKind::PreBitNot => Ok(!pred),
|
||||
_ => type_feature_error!(
|
||||
|
@ -1568,7 +1582,20 @@ impl Context {
|
|||
mode,
|
||||
not_found_is_qvar,
|
||||
)?;
|
||||
let pred = self.instantiate_pred(&refine.pred, tmp_tv_cache)?;
|
||||
let name = VarName::new(refine.var.clone());
|
||||
let tp = TyParam::named_free_var(
|
||||
refine.var.inspect().clone(),
|
||||
self.level,
|
||||
Constraint::new_type_of(t.clone()),
|
||||
);
|
||||
tmp_tv_cache.push_or_init_typaram(&name, &tp, self);
|
||||
let pred = self
|
||||
.instantiate_pred(&refine.pred, tmp_tv_cache)
|
||||
.map_err(|err| {
|
||||
tmp_tv_cache.remove(name.inspect());
|
||||
err
|
||||
})?;
|
||||
tmp_tv_cache.remove(name.inspect());
|
||||
let refine =
|
||||
Type::Refinement(RefinementType::new(refine.var.inspect().clone(), t, pred));
|
||||
Ok(refine)
|
||||
|
|
|
@ -20,6 +20,7 @@ use std::option::Option; // conflicting to Type::Option
|
|||
use std::path::{Path, PathBuf};
|
||||
|
||||
use erg_common::config::ErgConfig;
|
||||
use erg_common::consts::DEBUG_MODE;
|
||||
use erg_common::consts::PYTHON_MODE;
|
||||
use erg_common::dict::Dict;
|
||||
use erg_common::error::Location;
|
||||
|
@ -140,13 +141,20 @@ impl ClassDefType {
|
|||
ClassDefType::ImplTrait { class, impl_trait }
|
||||
}
|
||||
|
||||
pub fn class(&self) -> &Type {
|
||||
pub fn get_class(&self) -> &Type {
|
||||
match self {
|
||||
ClassDefType::Simple(class) => class,
|
||||
ClassDefType::ImplTrait { class, .. } => class,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_impl_trait(&self) -> Option<&Type> {
|
||||
match self {
|
||||
ClassDefType::Simple(_) => None,
|
||||
ClassDefType::ImplTrait { impl_trait, .. } => Some(impl_trait),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_class_of(&self, t: &Type) -> bool {
|
||||
match self {
|
||||
ClassDefType::Simple(class) => class == t,
|
||||
|
@ -1130,6 +1138,7 @@ impl Context {
|
|||
}
|
||||
|
||||
pub fn pop(&mut self) -> Context {
|
||||
self.check_types();
|
||||
if let Some(parent) = self.outer.as_mut() {
|
||||
let parent = mem::take(parent);
|
||||
let ctx = mem::take(self);
|
||||
|
@ -1143,6 +1152,7 @@ impl Context {
|
|||
|
||||
/// unlike `pop`, `outer` must be `None`.
|
||||
pub fn pop_mod(&mut self) -> Option<Context> {
|
||||
self.check_types();
|
||||
if self.outer.is_some() {
|
||||
log!(err "not in the top-level context");
|
||||
if self.kind.is_module() {
|
||||
|
@ -1257,6 +1267,32 @@ impl Context {
|
|||
.last()
|
||||
.and_then(|caller| ControlKind::try_from(&caller[..]).ok())
|
||||
}
|
||||
|
||||
pub(crate) fn check_types(&self) {
|
||||
if DEBUG_MODE {
|
||||
for (_, (t, ctx)) in self.poly_types.iter() {
|
||||
if t.has_undoable_linked_var() {
|
||||
panic!("{t} has undoable linked vars");
|
||||
}
|
||||
ctx.check_types();
|
||||
}
|
||||
for (typ, methods) in self.methods_list.iter() {
|
||||
if typ.get_class().has_undoable_linked_var() {
|
||||
panic!("{typ} has undoable linked vars");
|
||||
}
|
||||
if typ
|
||||
.get_impl_trait()
|
||||
.is_some_and(|t| t.has_undoable_linked_var())
|
||||
{
|
||||
panic!("{typ} has undoable linked vars");
|
||||
}
|
||||
methods.check_types();
|
||||
}
|
||||
if let Some(outer) = self.get_outer() {
|
||||
outer.check_types();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
|
|
|
@ -313,7 +313,7 @@ impl<'c, 'l, L: Locational> Unifier<'c, 'l, L> {
|
|||
.is_sub_constraint_of(&sub_fv.constraint().unwrap(), &new_constraint)
|
||||
|| sub_fv.constraint().unwrap().get_type() == Some(&Type)
|
||||
{
|
||||
sub_fv.update_constraint(new_constraint, false);
|
||||
maybe_sub.replace_constraint(new_constraint, self.undoable, false);
|
||||
}
|
||||
} else {
|
||||
maybe_sub.link(sup_tp, self.undoable);
|
||||
|
@ -353,7 +353,7 @@ impl<'c, 'l, L: Locational> Unifier<'c, 'l, L> {
|
|||
.is_sub_constraint_of(&sup_fv.constraint().unwrap(), &new_constraint)
|
||||
|| sup_fv.constraint().unwrap().get_type() == Some(&Type)
|
||||
{
|
||||
sup_fv.update_constraint(new_constraint, false);
|
||||
maybe_sup.replace_constraint(new_constraint, self.undoable, false);
|
||||
}
|
||||
} else {
|
||||
maybe_sup.link(sub_tp, self.undoable);
|
||||
|
@ -589,12 +589,12 @@ impl<'c, 'l, L: Locational> Unifier<'c, 'l, L> {
|
|||
|
||||
fn coerce_greater_than(&self, target: &TyParam, value: &TyParam) -> TyCheckResult<()> {
|
||||
match target {
|
||||
TyParam::FreeVar(fv) => {
|
||||
TyParam::FreeVar(_fv) => {
|
||||
if let Ok(evaled) = self.ctx.eval_tp(value.clone()) {
|
||||
let pred = Predicate::ge(FRESH_GEN.fresh_varname(), evaled);
|
||||
let new_type = self.ctx.type_from_pred(pred);
|
||||
let new_constr = Constraint::new_type_of(Type::from(new_type));
|
||||
fv.update_constraint(new_constr, false);
|
||||
target.replace_constraint(new_constr, self.undoable, false);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -777,20 +777,20 @@ impl<'c, 'l, L: Locational> Unifier<'c, 'l, L> {
|
|||
.cmp(&sup_fv.level().unwrap_or(GENERIC_LEVEL))
|
||||
{
|
||||
std::cmp::Ordering::Less => {
|
||||
sub_fv.update_constraint(new_constraint, false);
|
||||
maybe_sub.replace_constraint(new_constraint, self.undoable, false);
|
||||
maybe_sup.link(maybe_sub, self.undoable);
|
||||
}
|
||||
std::cmp::Ordering::Greater => {
|
||||
sup_fv.update_constraint(new_constraint, false);
|
||||
maybe_sup.replace_constraint(new_constraint, self.undoable, false);
|
||||
maybe_sub.link(maybe_sup, self.undoable);
|
||||
}
|
||||
std::cmp::Ordering::Equal => {
|
||||
// choose named one
|
||||
if sup_fv.is_named_unbound() {
|
||||
sup_fv.update_constraint(new_constraint, false);
|
||||
maybe_sup.replace_constraint(new_constraint, self.undoable, false);
|
||||
maybe_sub.link(maybe_sup, self.undoable);
|
||||
} else {
|
||||
sub_fv.update_constraint(new_constraint, false);
|
||||
maybe_sup.replace_constraint(new_constraint, self.undoable, false);
|
||||
maybe_sup.link(maybe_sub, self.undoable);
|
||||
}
|
||||
}
|
||||
|
@ -869,7 +869,7 @@ impl<'c, 'l, L: Locational> Unifier<'c, 'l, L> {
|
|||
maybe_sup.link(&union, self.undoable);
|
||||
} else {
|
||||
let new_constraint = Constraint::new_sandwiched(union, intersec);
|
||||
sup_fv.update_constraint(new_constraint, false);
|
||||
maybe_sup.replace_constraint(new_constraint, self.undoable, false);
|
||||
}
|
||||
}
|
||||
// (Int or ?T) <: (?U or Int)
|
||||
|
@ -955,14 +955,14 @@ impl<'c, 'l, L: Locational> Unifier<'c, 'l, L> {
|
|||
maybe_sup.link(&new_sub, self.undoable); // Bool <: ?T <: Bool or Y ==> ?T == Bool
|
||||
} else {
|
||||
let constr = Constraint::new_sandwiched(new_sub, mem::take(&mut sup));
|
||||
sup_fv.update_constraint(constr, true);
|
||||
maybe_sup.replace_constraint(constr, self.undoable, true);
|
||||
}
|
||||
}
|
||||
// sub_unify(Nat, ?T(: Type)): (/* ?T(:> Nat) */)
|
||||
else if let Some(ty) = sup_fv.get_type() {
|
||||
if self.ctx.supertype_of(&Type, &ty) {
|
||||
let constr = Constraint::new_supertype_of(maybe_sub.clone());
|
||||
sup_fv.update_constraint(constr, true);
|
||||
maybe_sup.replace_constraint(constr, self.undoable, true);
|
||||
} else {
|
||||
todo!("{maybe_sub} <: {maybe_sup}")
|
||||
}
|
||||
|
@ -1022,14 +1022,14 @@ impl<'c, 'l, L: Locational> Unifier<'c, 'l, L> {
|
|||
maybe_sub.link(&sub, self.undoable);
|
||||
} else {
|
||||
let constr = Constraint::new_sandwiched(sub, new_sup);
|
||||
sub_fv.update_constraint(constr, true);
|
||||
maybe_sub.replace_constraint(constr, self.undoable, true);
|
||||
}
|
||||
}
|
||||
// sub_unify(?T(: Type), Int): (?T(<: Int))
|
||||
else if let Some(ty) = sub_fv.get_type() {
|
||||
if self.ctx.supertype_of(&Type, &ty) {
|
||||
let constr = Constraint::new_subtype_of(maybe_sup.clone());
|
||||
sub_fv.update_constraint(constr, true);
|
||||
maybe_sub.replace_constraint(constr, self.undoable, true);
|
||||
} else {
|
||||
todo!("{maybe_sub} <: {maybe_sup}")
|
||||
}
|
||||
|
@ -1458,4 +1458,15 @@ impl Context {
|
|||
let unifier = Unifier::new(self, loc, false, param_name.cloned());
|
||||
unifier.sub_unify(maybe_sub, maybe_sup)
|
||||
}
|
||||
|
||||
pub(crate) fn undoable_sub_unify(
|
||||
&self,
|
||||
maybe_sub: &Type,
|
||||
maybe_sup: &Type,
|
||||
loc: &impl Locational,
|
||||
param_name: Option<&Str>,
|
||||
) -> TyCheckResult<()> {
|
||||
let unifier = Unifier::new(self, loc, true, param_name.cloned());
|
||||
unifier.sub_unify(maybe_sub, maybe_sup)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,10 +10,10 @@ use erg_parser::desugar::Desugarer;
|
|||
use crate::context::instantiate::TyVarCache;
|
||||
use crate::context::{ClassDefType, Context, MethodPair, TraitImpl};
|
||||
use crate::lower::ASTLowerer;
|
||||
use crate::ty::constructors::{mono, mono_q_tp, poly, v_enum};
|
||||
use crate::ty::constructors::{array_t, mono, mono_q_tp, poly, v_enum};
|
||||
use crate::ty::free::{Constraint, HasLevel};
|
||||
use crate::ty::value::{GenTypeObj, TypeObj, ValueObj};
|
||||
use crate::ty::{HasType, Type, Visibility};
|
||||
use crate::ty::{HasType, TyParam, Type, Visibility};
|
||||
|
||||
use crate::compile::AccessKind;
|
||||
use crate::error::{LowerError, LowerErrors, LowerResult};
|
||||
|
@ -264,11 +264,9 @@ impl ASTLowerer {
|
|||
elems.push(hir::PosArg::new(elem));
|
||||
}
|
||||
let elems = hir::Args::new(elems, None, vec![], None);
|
||||
let t = array_t(Type::Failure, TyParam::value(elems.len()));
|
||||
Ok(hir::Array::Normal(hir::NormalArray::new(
|
||||
arr.l_sqbr,
|
||||
arr.r_sqbr,
|
||||
Type::Failure,
|
||||
elems,
|
||||
arr.l_sqbr, arr.r_sqbr, t, elems,
|
||||
)))
|
||||
}
|
||||
other => Err(LowerErrors::from(LowerError::declare_error(
|
||||
|
|
|
@ -20,7 +20,7 @@ use erg_parser::ast::{
|
|||
};
|
||||
use erg_parser::token::{Token, TokenKind, DOT};
|
||||
|
||||
use crate::ty::constructors::{array_t, dict_t, set_t, tuple_t};
|
||||
use crate::ty::constructors::{dict_t, set_t, tuple_t};
|
||||
use crate::ty::typaram::TyParam;
|
||||
use crate::ty::value::{GenTypeObj, ValueObj};
|
||||
use crate::ty::{Field, HasType, Type, VisibilityModifier};
|
||||
|
@ -774,8 +774,7 @@ impl_locational!(NormalArray, l_sqbr, elems, r_sqbr);
|
|||
impl_t!(NormalArray);
|
||||
|
||||
impl NormalArray {
|
||||
pub fn new(l_sqbr: Token, r_sqbr: Token, elem_t: Type, elems: Args) -> Self {
|
||||
let t = array_t(elem_t, TyParam::value(elems.len()));
|
||||
pub fn new(l_sqbr: Token, r_sqbr: Token, t: Type, elems: Args) -> Self {
|
||||
Self {
|
||||
l_sqbr,
|
||||
r_sqbr,
|
||||
|
|
|
@ -26,7 +26,7 @@ use crate::artifact::{CompleteArtifact, IncompleteArtifact};
|
|||
use crate::context::instantiate::TyVarCache;
|
||||
use crate::module::SharedCompilerResource;
|
||||
use crate::ty::constructors::{
|
||||
array_t, free_var, func, guard, mono, poly, proc, refinement, set_t, ty_tp, v_enum,
|
||||
array_t, free_var, func, guard, mono, poly, proc, refinement, set_t, singleton, ty_tp, v_enum,
|
||||
};
|
||||
use crate::ty::free::Constraint;
|
||||
use crate::ty::typaram::TyParam;
|
||||
|
@ -290,6 +290,7 @@ impl ASTLowerer {
|
|||
fn lower_normal_array(&mut self, array: ast::NormalArray) -> LowerResult<hir::NormalArray> {
|
||||
log!(info "entered {}({array})", fn_name!());
|
||||
let mut new_array = vec![];
|
||||
let eval_result = self.module.context.eval_const_normal_array(&array);
|
||||
let (elems, ..) = array.elems.deconstruct();
|
||||
let mut union = Type::Never;
|
||||
for elem in elems.into_iter() {
|
||||
|
@ -330,12 +331,14 @@ impl ASTLowerer {
|
|||
} else {
|
||||
union
|
||||
};
|
||||
Ok(hir::NormalArray::new(
|
||||
array.l_sqbr,
|
||||
array.r_sqbr,
|
||||
elem_t,
|
||||
hir::Args::values(new_array, None),
|
||||
))
|
||||
let elems = hir::Args::values(new_array, None);
|
||||
let t = array_t(elem_t, TyParam::value(elems.len()));
|
||||
let t = if let Ok(value) = eval_result {
|
||||
singleton(t, TyParam::Value(value))
|
||||
} else {
|
||||
t
|
||||
};
|
||||
Ok(hir::NormalArray::new(array.l_sqbr, array.r_sqbr, t, elems))
|
||||
}
|
||||
|
||||
fn lower_array_with_length(
|
||||
|
|
|
@ -849,7 +849,7 @@ impl<T: Send + Sync + 'static + Clone> Free<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + fmt::Debug + Send + Sync + 'static> Free<T> {
|
||||
impl<T: Clone + Send + Sync + 'static> Free<T> {
|
||||
/// interior-mut
|
||||
/// SAFETY: use `Type/TyParam::link` instead of this.
|
||||
/// This method may cause circular references.
|
||||
|
|
|
@ -43,7 +43,7 @@ pub use value::ValueObj;
|
|||
use value::ValueObj::{Inf, NegInf};
|
||||
pub use vis::*;
|
||||
|
||||
use self::constructors::{bounded, proj_call, subr_t};
|
||||
use self::constructors::{bounded, free_var, named_free_var, proj_call, subr_t};
|
||||
|
||||
pub const STR_OMIT_THRESHOLD: usize = 16;
|
||||
pub const CONTAINER_OMIT_THRESHOLD: usize = 8;
|
||||
|
@ -3194,6 +3194,46 @@ impl Type {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn undo(&self) {
|
||||
match self {
|
||||
Self::FreeVar(fv) if fv.is_undoable_linked() => fv.undo(),
|
||||
Self::FreeVar(fv) if fv.constraint_is_sandwiched() => {
|
||||
let (sub, sup) = fv.get_subsup().unwrap();
|
||||
sub.undo();
|
||||
sup.undo();
|
||||
}
|
||||
Self::Poly { params, .. } => {
|
||||
for param in params {
|
||||
param.undo();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn undoable_update_constraint(&self, new_constraint: Constraint) {
|
||||
let level = self.level().unwrap();
|
||||
let new = if let Some(name) = self.unbound_name() {
|
||||
named_free_var(name, level, new_constraint)
|
||||
} else {
|
||||
free_var(level, new_constraint)
|
||||
};
|
||||
self.undoable_link(&new);
|
||||
}
|
||||
|
||||
pub(crate) fn replace_constraint(
|
||||
&self,
|
||||
new_constraint: Constraint,
|
||||
undoable: bool,
|
||||
in_instantiation: bool,
|
||||
) {
|
||||
if undoable {
|
||||
self.undoable_update_constraint(new_constraint);
|
||||
} else {
|
||||
self.update_constraint(new_constraint, in_instantiation);
|
||||
}
|
||||
}
|
||||
|
||||
fn inc_undo_count(&self) {
|
||||
match self {
|
||||
Self::FreeVar(fv) => fv.inc_undo_count(),
|
||||
|
|
|
@ -877,11 +877,15 @@ impl TyParam {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn free_var(level: usize, t: Type) -> Self {
|
||||
pub fn free_instance(level: usize, t: Type) -> Self {
|
||||
let constraint = Constraint::new_type_of(t);
|
||||
Self::FreeVar(FreeTyParam::new_unbound(level, constraint))
|
||||
}
|
||||
|
||||
pub fn free_var(level: usize, constr: Constraint) -> Self {
|
||||
Self::FreeVar(FreeTyParam::new_unbound(level, constr))
|
||||
}
|
||||
|
||||
pub fn named_free_var(name: Str, level: usize, constr: Constraint) -> Self {
|
||||
Self::FreeVar(FreeTyParam::new_named_unbound(name, level, constr))
|
||||
}
|
||||
|
@ -1297,6 +1301,43 @@ impl TyParam {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn undo(&self) {
|
||||
match self {
|
||||
Self::FreeVar(fv) if fv.is_undoable_linked() => fv.undo(),
|
||||
Self::Type(t) => t.undo(),
|
||||
Self::Value(ValueObj::Type(t)) => t.typ().undo(),
|
||||
Self::App { args, .. } => {
|
||||
for arg in args {
|
||||
arg.undo();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn undoable_update_constraint(&self, new_constraint: Constraint) {
|
||||
let level = self.level().unwrap();
|
||||
let new = if let Some(name) = self.unbound_name() {
|
||||
Self::named_free_var(name, level, new_constraint)
|
||||
} else {
|
||||
Self::free_var(level, new_constraint)
|
||||
};
|
||||
self.undoable_link(&new);
|
||||
}
|
||||
|
||||
pub(crate) fn replace_constraint(
|
||||
&self,
|
||||
new_constraint: Constraint,
|
||||
undoable: bool,
|
||||
in_instantiation: bool,
|
||||
) {
|
||||
if undoable {
|
||||
self.undoable_update_constraint(new_constraint);
|
||||
} else {
|
||||
self.update_constraint(new_constraint, in_instantiation);
|
||||
}
|
||||
}
|
||||
|
||||
fn inc_undo_count(&self) {
|
||||
match self {
|
||||
Self::FreeVar(fv) => fv.inc_undo_count(),
|
||||
|
|
|
@ -2022,14 +2022,20 @@ impl ConstUnaryOp {
|
|||
/// ex. `Vec Int` of `Option Vec Int`
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct ConstApp {
|
||||
pub acc: ConstAccessor,
|
||||
pub obj: Box<ConstExpr>,
|
||||
pub attr_name: Option<ConstIdentifier>,
|
||||
pub args: ConstArgs,
|
||||
}
|
||||
|
||||
impl NestedDisplay for ConstApp {
|
||||
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, level: usize) -> std::fmt::Result {
|
||||
writeln!(f, "{}:", self.acc)?;
|
||||
self.args.fmt_nest(f, level + 1)
|
||||
writeln!(f, "{}", self.obj)?;
|
||||
if let Some(attr_name) = &self.attr_name {
|
||||
writeln!(f, "{}", attr_name)?;
|
||||
}
|
||||
writeln!(f, "(")?;
|
||||
self.args.fmt_nest(f, level + 1)?;
|
||||
writeln!(f, ")")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2038,20 +2044,31 @@ impl_display_from_nested!(ConstApp);
|
|||
impl Locational for ConstApp {
|
||||
fn loc(&self) -> Location {
|
||||
if self.args.is_empty() {
|
||||
self.acc.loc()
|
||||
self.obj.loc()
|
||||
} else {
|
||||
Location::concat(&self.acc, &self.args)
|
||||
Location::concat(self.obj.as_ref(), &self.args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ConstApp {
|
||||
pub const fn new(acc: ConstAccessor, args: ConstArgs) -> Self {
|
||||
Self { acc, args }
|
||||
pub fn new(obj: ConstExpr, attr_name: Option<ConstIdentifier>, args: ConstArgs) -> Self {
|
||||
Self {
|
||||
obj: Box::new(obj),
|
||||
attr_name,
|
||||
args,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn downgrade(self) -> Call {
|
||||
Expr::Accessor(self.acc.downgrade()).call(self.args.downgrade())
|
||||
if let Some(attr_name) = self.attr_name {
|
||||
self.obj
|
||||
.downgrade()
|
||||
.attr_expr(attr_name)
|
||||
.call(self.args.downgrade())
|
||||
} else {
|
||||
self.obj.downgrade().call(self.args.downgrade())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -124,13 +124,14 @@ impl Parser {
|
|||
}
|
||||
Expr::Call(call) => {
|
||||
let obj = Self::validate_const_expr(*call.obj)?;
|
||||
let ConstExpr::Accessor(acc) = obj else {
|
||||
/*let ConstExpr::Accessor(acc) = obj else {
|
||||
return Err(ParseError::feature_error(
|
||||
line!() as usize,
|
||||
obj.loc(),
|
||||
"complex const function call",
|
||||
));
|
||||
};
|
||||
};*/
|
||||
let attr_name = call.attr_name;
|
||||
let (pos_args, _, _, paren) = call.args.deconstruct();
|
||||
let mut const_pos_args = vec![];
|
||||
for elem in pos_args.into_iter() {
|
||||
|
@ -138,7 +139,7 @@ impl Parser {
|
|||
const_pos_args.push(ConstPosArg::new(const_expr));
|
||||
}
|
||||
let args = ConstArgs::pos_only(const_pos_args, paren);
|
||||
Ok(ConstExpr::App(ConstApp::new(acc, args)))
|
||||
Ok(ConstExpr::App(ConstApp::new(obj, attr_name, args)))
|
||||
}
|
||||
Expr::Def(def) => Self::validate_const_def(def).map(ConstExpr::Def),
|
||||
Expr::Lambda(lambda) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue