mirror of
https://github.com/erg-lang/erg.git
synced 2025-10-02 13:41:10 +00:00
Merge pull request #404 from erg-lang/feat-structural
Add `Structural` types
This commit is contained in:
commit
1dbfb4b834
31 changed files with 1062 additions and 172 deletions
|
@ -30,6 +30,7 @@ homepage = "https://erg-lang.org/"
|
||||||
[features]
|
[features]
|
||||||
# when "debug" feature is turned on, that of the following crates will also be turned on.
|
# when "debug" feature is turned on, that of the following crates will also be turned on.
|
||||||
debug = ["erg_common/debug", "erg_parser/debug", "erg_compiler/debug"] # "els/debug"
|
debug = ["erg_common/debug", "erg_parser/debug", "erg_compiler/debug"] # "els/debug"
|
||||||
|
backtrace = ["erg_common/backtrace"]
|
||||||
japanese = [
|
japanese = [
|
||||||
"erg_common/japanese",
|
"erg_common/japanese",
|
||||||
"erg_parser/japanese",
|
"erg_parser/japanese",
|
||||||
|
|
|
@ -11,6 +11,7 @@ homepage.workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
debug = ["dep:backtrace-on-stack-overflow"]
|
debug = ["dep:backtrace-on-stack-overflow"]
|
||||||
|
backtrace = ["dep:backtrace-on-stack-overflow"]
|
||||||
japanese = []
|
japanese = []
|
||||||
simplified_chinese = []
|
simplified_chinese = []
|
||||||
traditional_chinese = []
|
traditional_chinese = []
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#[cfg(all(unix, feature = "debug"))]
|
#[cfg(all(unix, any(feature = "debug", feature = "backtrace")))]
|
||||||
pub use backtrace_on_stack_overflow;
|
pub use backtrace_on_stack_overflow;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! enable_overflow_stacktrace {
|
macro_rules! enable_overflow_stacktrace {
|
||||||
() => {
|
() => {
|
||||||
#[cfg(all(unix, feature = "debug"))]
|
#[cfg(all(unix, any(feature = "debug", feature = "backtrace")))]
|
||||||
unsafe {
|
unsafe {
|
||||||
$crate::spawn::backtrace_on_stack_overflow::enable()
|
$crate::spawn::backtrace_on_stack_overflow::enable()
|
||||||
};
|
};
|
||||||
|
|
|
@ -40,10 +40,10 @@ impl std::hash::Hash for Field {
|
||||||
|
|
||||||
impl fmt::Display for Field {
|
impl fmt::Display for Field {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
if self.vis == Visibility::Public {
|
if self.vis.is_public() {
|
||||||
write!(f, ".{}", self.symbol)
|
write!(f, ".{}", self.symbol)
|
||||||
} else {
|
} else {
|
||||||
write!(f, "{}", self.symbol)
|
write!(f, "::{}", self.symbol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ use crate::ty::{Predicate, RefinementType, SubrKind, SubrType, Type};
|
||||||
use Predicate as Pred;
|
use Predicate as Pred;
|
||||||
|
|
||||||
use erg_common::dict::Dict;
|
use erg_common::dict::Dict;
|
||||||
|
use erg_common::vis::Field;
|
||||||
use erg_common::{assume_unreachable, log};
|
use erg_common::{assume_unreachable, log};
|
||||||
use TyParamOrdering::*;
|
use TyParamOrdering::*;
|
||||||
use Type::*;
|
use Type::*;
|
||||||
|
@ -716,10 +717,45 @@ impl Context {
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
(Structural(l), Structural(r)) => self.structural_supertype_of(l, r, allow_cast),
|
||||||
|
// TODO: If visibility does not match, it should be reported as a cause of an error
|
||||||
|
(Structural(l), r) => {
|
||||||
|
let r_fields = self.fields(r);
|
||||||
|
for (l_field, l_ty) in self.fields(l) {
|
||||||
|
if let Some((r_field, r_ty)) = r_fields.get_key_value(&l_field) {
|
||||||
|
let compatible = self.supertype_of(&l_ty, r_ty, allow_cast);
|
||||||
|
if r_field.vis != l_field.vis || !compatible {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
(_l, _r) => false,
|
(_l, _r) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: we need consider duplicating keys
|
||||||
|
pub fn fields(&self, t: &Type) -> Dict<Field, Type> {
|
||||||
|
match t {
|
||||||
|
Type::FreeVar(fv) if fv.is_linked() => self.fields(&fv.crack()),
|
||||||
|
Type::Record(fields) => fields.clone(),
|
||||||
|
Type::Refinement(refine) => self.fields(&refine.t),
|
||||||
|
Type::Structural(t) => self.fields(t),
|
||||||
|
other => {
|
||||||
|
let (_, ctx) = self
|
||||||
|
.get_nominal_type_ctx(other)
|
||||||
|
.unwrap_or_else(|| panic!("{other} is not found"));
|
||||||
|
ctx.type_dir()
|
||||||
|
.into_iter()
|
||||||
|
.map(|(name, vi)| (Field::new(vi.vis, name.inspect().clone()), vi.t.clone()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn poly_supertype_of(
|
pub(crate) fn poly_supertype_of(
|
||||||
&self,
|
&self,
|
||||||
typ: &Type,
|
typ: &Type,
|
||||||
|
|
|
@ -498,11 +498,20 @@ impl Context {
|
||||||
default_params.clone(),
|
default_params.clone(),
|
||||||
return_t,
|
return_t,
|
||||||
);
|
);
|
||||||
|
let block =
|
||||||
|
erg_parser::Parser::validate_const_block(lambda.body.clone()).map_err(|_| {
|
||||||
|
EvalErrors::from(EvalError::not_const_expr(
|
||||||
|
self.cfg.input.clone(),
|
||||||
|
line!() as usize,
|
||||||
|
lambda.loc(),
|
||||||
|
self.caused_by(),
|
||||||
|
))
|
||||||
|
})?;
|
||||||
let sig_t = self.generalize_t(sig_t);
|
let sig_t = self.generalize_t(sig_t);
|
||||||
let subr = ConstSubr::User(UserConstSubr::new(
|
let subr = ConstSubr::User(UserConstSubr::new(
|
||||||
Str::ever("<lambda>"),
|
Str::ever("<lambda>"),
|
||||||
lambda.sig.params.clone(),
|
lambda.sig.params.clone(),
|
||||||
lambda.body.clone(),
|
block,
|
||||||
sig_t,
|
sig_t,
|
||||||
));
|
));
|
||||||
Ok(ValueObj::Subr(subr))
|
Ok(ValueObj::Subr(subr))
|
||||||
|
|
|
@ -9,7 +9,7 @@ use erg_common::{fmt_vec, log};
|
||||||
|
|
||||||
use crate::ty::constructors::*;
|
use crate::ty::constructors::*;
|
||||||
use crate::ty::free::{CanbeFree, Constraint, Free, HasLevel};
|
use crate::ty::free::{CanbeFree, Constraint, Free, HasLevel};
|
||||||
use crate::ty::typaram::TyParam;
|
use crate::ty::typaram::{TyParam, TyParamLambda};
|
||||||
use crate::ty::value::ValueObj;
|
use crate::ty::value::ValueObj;
|
||||||
use crate::ty::{HasType, Predicate, SubrType, Type};
|
use crate::ty::{HasType, Predicate, SubrType, Type};
|
||||||
|
|
||||||
|
@ -64,6 +64,38 @@ impl Context {
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
|
TyParam::Record(rec) => TyParam::Record(
|
||||||
|
rec.into_iter()
|
||||||
|
.map(|(field, tp)| (field, self.generalize_tp(tp, variance, uninit)))
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
TyParam::Lambda(lambda) => {
|
||||||
|
let nd_params = lambda
|
||||||
|
.nd_params
|
||||||
|
.into_iter()
|
||||||
|
.map(|pt| pt.map_type(|t| self.generalize_t_inner(t, variance, uninit)))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let var_params = lambda
|
||||||
|
.var_params
|
||||||
|
.map(|pt| pt.map_type(|t| self.generalize_t_inner(t, variance, uninit)));
|
||||||
|
let d_params = lambda
|
||||||
|
.d_params
|
||||||
|
.into_iter()
|
||||||
|
.map(|pt| pt.map_type(|t| self.generalize_t_inner(t, variance, uninit)))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let body = lambda
|
||||||
|
.body
|
||||||
|
.into_iter()
|
||||||
|
.map(|tp| self.generalize_tp(tp, variance, uninit))
|
||||||
|
.collect();
|
||||||
|
TyParam::Lambda(TyParamLambda::new(
|
||||||
|
lambda.const_,
|
||||||
|
nd_params,
|
||||||
|
var_params,
|
||||||
|
d_params,
|
||||||
|
body,
|
||||||
|
))
|
||||||
|
}
|
||||||
TyParam::FreeVar(_) => free,
|
TyParam::FreeVar(_) => free,
|
||||||
TyParam::Proj { obj, attr } => {
|
TyParam::Proj { obj, attr } => {
|
||||||
let obj = self.generalize_tp(*obj, variance, uninit);
|
let obj = self.generalize_tp(*obj, variance, uninit);
|
||||||
|
@ -185,6 +217,13 @@ impl Context {
|
||||||
return_t,
|
return_t,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Record(rec) => {
|
||||||
|
let fields = rec
|
||||||
|
.into_iter()
|
||||||
|
.map(|(name, t)| (name, self.generalize_t_inner(t, variance, uninit)))
|
||||||
|
.collect();
|
||||||
|
Type::Record(fields)
|
||||||
|
}
|
||||||
Callable { .. } => todo!(),
|
Callable { .. } => todo!(),
|
||||||
Ref(t) => ref_(self.generalize_t_inner(*t, variance, uninit)),
|
Ref(t) => ref_(self.generalize_t_inner(*t, variance, uninit)),
|
||||||
RefMut { before, after } => {
|
RefMut { before, after } => {
|
||||||
|
@ -235,6 +274,9 @@ impl Context {
|
||||||
or(l, r)
|
or(l, r)
|
||||||
}
|
}
|
||||||
Not(l) => not(self.generalize_t_inner(*l, variance, uninit)),
|
Not(l) => not(self.generalize_t_inner(*l, variance, uninit)),
|
||||||
|
Structural(t) => self
|
||||||
|
.generalize_t_inner(*t, variance, uninit)
|
||||||
|
.structuralize(),
|
||||||
// REVIEW: その他何でもそのまま通していいのか?
|
// REVIEW: その他何でもそのまま通していいのか?
|
||||||
other => other,
|
other => other,
|
||||||
}
|
}
|
||||||
|
@ -367,6 +409,41 @@ impl Context {
|
||||||
}
|
}
|
||||||
Ok(TyParam::Set(new_set))
|
Ok(TyParam::Set(new_set))
|
||||||
}
|
}
|
||||||
|
TyParam::Record(rec) => {
|
||||||
|
let mut new_rec = dict! {};
|
||||||
|
for (field, tp) in rec.into_iter() {
|
||||||
|
new_rec.insert(field, self.deref_tp(tp, variance, qnames, loc)?);
|
||||||
|
}
|
||||||
|
Ok(TyParam::Record(new_rec))
|
||||||
|
}
|
||||||
|
TyParam::Lambda(lambda) => {
|
||||||
|
let nd_params = lambda
|
||||||
|
.nd_params
|
||||||
|
.into_iter()
|
||||||
|
.map(|pt| pt.try_map_type(|t| self.deref_tyvar(t, variance, qnames, loc)))
|
||||||
|
.collect::<TyCheckResult<_>>()?;
|
||||||
|
let var_params = lambda
|
||||||
|
.var_params
|
||||||
|
.map(|pt| pt.try_map_type(|t| self.deref_tyvar(t, variance, qnames, loc)))
|
||||||
|
.transpose()?;
|
||||||
|
let d_params = lambda
|
||||||
|
.d_params
|
||||||
|
.into_iter()
|
||||||
|
.map(|pt| pt.try_map_type(|t| self.deref_tyvar(t, variance, qnames, loc)))
|
||||||
|
.collect::<TyCheckResult<_>>()?;
|
||||||
|
let body = lambda
|
||||||
|
.body
|
||||||
|
.into_iter()
|
||||||
|
.map(|tp| self.deref_tp(tp, variance, qnames, loc))
|
||||||
|
.collect::<TyCheckResult<Vec<_>>>()?;
|
||||||
|
Ok(TyParam::Lambda(TyParamLambda::new(
|
||||||
|
lambda.const_,
|
||||||
|
nd_params,
|
||||||
|
var_params,
|
||||||
|
d_params,
|
||||||
|
body,
|
||||||
|
)))
|
||||||
|
}
|
||||||
TyParam::Proj { obj, attr } => {
|
TyParam::Proj { obj, attr } => {
|
||||||
let obj = self.deref_tp(*obj, variance, qnames, loc)?;
|
let obj = self.deref_tp(*obj, variance, qnames, loc)?;
|
||||||
Ok(TyParam::Proj {
|
Ok(TyParam::Proj {
|
||||||
|
@ -686,6 +763,10 @@ impl Context {
|
||||||
}
|
}
|
||||||
self.eval_proj_call(lhs, attr_name, new_args, self.level, loc)
|
self.eval_proj_call(lhs, attr_name, new_args, self.level, loc)
|
||||||
}
|
}
|
||||||
|
Type::Structural(t) => {
|
||||||
|
let t = self.deref_tyvar(*t, variance, qnames, loc)?;
|
||||||
|
Ok(t.structuralize())
|
||||||
|
}
|
||||||
t => Ok(t),
|
t => Ok(t),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -210,6 +210,32 @@ pub fn subsume_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<Value
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn structural_func(mut args: ValueArgs, _ctx: &Context) -> EvalValueResult<ValueObj> {
|
||||||
|
let type_ = args.remove_left_or_key("Type").ok_or_else(|| {
|
||||||
|
ErrorCore::new(
|
||||||
|
vec![SubMessage::only_loc(Location::Unknown)],
|
||||||
|
format!("{BASE_ERR} is not passed"),
|
||||||
|
line!() as usize,
|
||||||
|
ErrorKind::KeyError,
|
||||||
|
Location::Unknown,
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
let Some(base) = type_.as_type() else {
|
||||||
|
let type_ = StyledString::new(format!("{type_}"), Some(ERR), None);
|
||||||
|
return Err(ErrorCore::new(
|
||||||
|
vec![SubMessage::only_loc(Location::Unknown)],
|
||||||
|
format!(
|
||||||
|
"non-type object {type_} is passed to {BASE_WARN}",
|
||||||
|
),
|
||||||
|
line!() as usize,
|
||||||
|
ErrorKind::TypeError,
|
||||||
|
Location::Unknown,
|
||||||
|
).into());
|
||||||
|
};
|
||||||
|
let t = base.typ().clone().structuralize();
|
||||||
|
Ok(ValueObj::gen_t(GenTypeObj::structural(t, base)))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn __array_getitem__(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
|
pub fn __array_getitem__(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
|
||||||
let slf = ctx
|
let slf = ctx
|
||||||
.convert_value_into_array(args.remove_left_or_key("Self").unwrap())
|
.convert_value_into_array(args.remove_left_or_key("Self").unwrap())
|
||||||
|
|
|
@ -411,6 +411,13 @@ impl Context {
|
||||||
None,
|
None,
|
||||||
));
|
));
|
||||||
self.register_builtin_const(SUBSUME, vis, ValueObj::Subr(subsume));
|
self.register_builtin_const(SUBSUME, vis, ValueObj::Subr(subsume));
|
||||||
|
let structural = ConstSubr::Builtin(BuiltinConstSubr::new(
|
||||||
|
STRUCTURAL,
|
||||||
|
structural_func,
|
||||||
|
func1(Type, Type),
|
||||||
|
None,
|
||||||
|
));
|
||||||
|
self.register_builtin_const(STRUCTURAL, vis, ValueObj::Subr(structural));
|
||||||
// decorators
|
// decorators
|
||||||
let inheritable_t = func1(ClassType, ClassType);
|
let inheritable_t = func1(ClassType, ClassType);
|
||||||
let inheritable = ConstSubr::Builtin(BuiltinConstSubr::new(
|
let inheritable = ConstSubr::Builtin(BuiltinConstSubr::new(
|
||||||
|
|
|
@ -300,6 +300,7 @@ const INHERIT: &str = "Inherit";
|
||||||
const INHERITABLE: &str = "Inheritable";
|
const INHERITABLE: &str = "Inheritable";
|
||||||
const DEL: &str = "Del";
|
const DEL: &str = "Del";
|
||||||
const PATCH: &str = "Patch";
|
const PATCH: &str = "Patch";
|
||||||
|
const STRUCTURAL: &str = "Structural";
|
||||||
|
|
||||||
const OP_IN: &str = "__in__";
|
const OP_IN: &str = "__in__";
|
||||||
const OP_NOT_IN: &str = "__notin__";
|
const OP_NOT_IN: &str = "__notin__";
|
||||||
|
|
|
@ -628,18 +628,18 @@ impl Context {
|
||||||
);
|
);
|
||||||
Ok(vi)
|
Ok(vi)
|
||||||
} else {
|
} else {
|
||||||
let t = Type::Record(record.clone());
|
|
||||||
Err(TyCheckError::no_attr_error(
|
Err(TyCheckError::no_attr_error(
|
||||||
self.cfg.input.clone(),
|
self.cfg.input.clone(),
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
ident.loc(),
|
ident.loc(),
|
||||||
namespace.into(),
|
namespace.into(),
|
||||||
&t,
|
t,
|
||||||
ident.inspect(),
|
ident.inspect(),
|
||||||
self.get_similar_attr(&t, ident.inspect()),
|
self.get_similar_attr(t, ident.inspect()),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Type::Structural(t) => self.get_attr_info_from_attributive(t, ident, namespace),
|
||||||
other => {
|
other => {
|
||||||
if let Some(v) = self.rec_get_const_obj(&other.local_name()) {
|
if let Some(v) = self.rec_get_const_obj(&other.local_name()) {
|
||||||
match v {
|
match v {
|
||||||
|
@ -752,6 +752,9 @@ impl Context {
|
||||||
input: &Input,
|
input: &Input,
|
||||||
namespace: &Str,
|
namespace: &Str,
|
||||||
) -> SingleTyCheckResult<VarInfo> {
|
) -> SingleTyCheckResult<VarInfo> {
|
||||||
|
if let Ok(vi) = self.get_attr_info_from_attributive(obj.ref_t(), attr_name, namespace) {
|
||||||
|
return Ok(vi);
|
||||||
|
}
|
||||||
for ctx in self
|
for ctx in self
|
||||||
.get_nominal_super_type_ctxs(obj.ref_t())
|
.get_nominal_super_type_ctxs(obj.ref_t())
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
|
|
|
@ -7,6 +7,7 @@ use erg_common::dict::Dict;
|
||||||
use erg_common::log;
|
use erg_common::log;
|
||||||
use erg_common::set::Set;
|
use erg_common::set::Set;
|
||||||
use erg_common::traits::{Locational, Stream};
|
use erg_common::traits::{Locational, Stream};
|
||||||
|
use erg_common::vis::Field;
|
||||||
use erg_common::Str;
|
use erg_common::Str;
|
||||||
use erg_common::{assume_unreachable, dict, enum_unwrap, set, try_map_mut};
|
use erg_common::{assume_unreachable, dict, enum_unwrap, set, try_map_mut};
|
||||||
|
|
||||||
|
@ -22,8 +23,10 @@ use crate::feature_error;
|
||||||
use crate::ty::constructors::*;
|
use crate::ty::constructors::*;
|
||||||
use crate::ty::free::CanbeFree;
|
use crate::ty::free::CanbeFree;
|
||||||
use crate::ty::free::{Constraint, HasLevel};
|
use crate::ty::free::{Constraint, HasLevel};
|
||||||
|
use crate::ty::typaram::TyParamLambda;
|
||||||
use crate::ty::typaram::{IntervalOp, OpKind, TyParam, TyParamOrdering};
|
use crate::ty::typaram::{IntervalOp, OpKind, TyParam, TyParamOrdering};
|
||||||
use crate::ty::value::ValueObj;
|
use crate::ty::value::ValueObj;
|
||||||
|
use crate::ty::SubrType;
|
||||||
use crate::ty::{HasType, ParamTy, Predicate, SubrKind, Type};
|
use crate::ty::{HasType, ParamTy, Predicate, SubrKind, Type};
|
||||||
use crate::type_feature_error;
|
use crate::type_feature_error;
|
||||||
use crate::unreachable_error;
|
use crate::unreachable_error;
|
||||||
|
@ -126,6 +129,10 @@ impl TyVarCache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.tyvar_instances.is_empty() && self.typaram_instances.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn merge(&mut self, outer: &Self) {
|
pub fn merge(&mut self, outer: &Self) {
|
||||||
for (name, ty) in outer.tyvar_instances.iter() {
|
for (name, ty) in outer.tyvar_instances.iter() {
|
||||||
if self.tyvar_instances.contains_key(name) {
|
if self.tyvar_instances.contains_key(name) {
|
||||||
|
@ -589,6 +596,21 @@ impl Context {
|
||||||
let t = self.instantiate_const_expr_as_type(&first.expr, None, tmp_tv_cache)?;
|
let t = self.instantiate_const_expr_as_type(&first.expr, None, tmp_tv_cache)?;
|
||||||
Ok(ref_mut(t, None))
|
Ok(ref_mut(t, None))
|
||||||
}
|
}
|
||||||
|
"Structural" => {
|
||||||
|
let mut args = simple.args.pos_args();
|
||||||
|
let Some(first) = args.next() else {
|
||||||
|
return Err(TyCheckErrors::from(TyCheckError::args_missing_error(
|
||||||
|
self.cfg.input.clone(),
|
||||||
|
line!() as usize,
|
||||||
|
simple.args.loc(),
|
||||||
|
"Structural",
|
||||||
|
self.caused_by(),
|
||||||
|
vec![Str::from("Type")],
|
||||||
|
)));
|
||||||
|
};
|
||||||
|
let t = self.instantiate_const_expr_as_type(&first.expr, None, tmp_tv_cache)?;
|
||||||
|
Ok(t.structuralize())
|
||||||
|
}
|
||||||
"Self" => self.rec_get_self_t().ok_or_else(|| {
|
"Self" => self.rec_get_self_t().ok_or_else(|| {
|
||||||
TyCheckErrors::from(TyCheckError::unreachable(
|
TyCheckErrors::from(TyCheckError::unreachable(
|
||||||
self.cfg.input.clone(),
|
self.cfg.input.clone(),
|
||||||
|
@ -624,11 +646,11 @@ impl Context {
|
||||||
if let Some(decl_t) = opt_decl_t {
|
if let Some(decl_t) = opt_decl_t {
|
||||||
return Ok(decl_t.typ().clone());
|
return Ok(decl_t.typ().clone());
|
||||||
}
|
}
|
||||||
if let Some((typ, _)) = self.get_type(&Str::rc(other)) {
|
if let Some((typ, _)) = self.get_type(simple.ident.inspect()) {
|
||||||
Ok(typ.clone())
|
Ok(typ.clone())
|
||||||
} else if not_found_is_qvar {
|
} else if not_found_is_qvar {
|
||||||
let tyvar = named_free_var(Str::rc(other), self.level, Constraint::Uninited);
|
let tyvar = named_free_var(Str::rc(other), self.level, Constraint::Uninited);
|
||||||
tmp_tv_cache.push_or_init_tyvar(&Str::rc(other), &tyvar);
|
tmp_tv_cache.push_or_init_tyvar(simple.ident.inspect(), &tyvar);
|
||||||
Ok(tyvar)
|
Ok(tyvar)
|
||||||
} else {
|
} else {
|
||||||
Err(TyCheckErrors::from(TyCheckError::no_type_error(
|
Err(TyCheckErrors::from(TyCheckError::no_type_error(
|
||||||
|
@ -683,6 +705,46 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn instantiate_local(
|
||||||
|
&self,
|
||||||
|
name: &Str,
|
||||||
|
erased_idx: Option<(&Context, usize)>,
|
||||||
|
tmp_tv_cache: &mut TyVarCache,
|
||||||
|
loc: &impl Locational,
|
||||||
|
) -> TyCheckResult<TyParam> {
|
||||||
|
if &name[..] == "_" {
|
||||||
|
let t = if let Some((ctx, i)) = erased_idx {
|
||||||
|
ctx.params[i].1.t.clone()
|
||||||
|
} else {
|
||||||
|
Type::Uninited
|
||||||
|
};
|
||||||
|
return Ok(TyParam::erased(t));
|
||||||
|
}
|
||||||
|
if let Some(tp) = tmp_tv_cache.get_typaram(name) {
|
||||||
|
return Ok(tp.clone());
|
||||||
|
} else if let Some(t) = tmp_tv_cache.get_tyvar(name) {
|
||||||
|
return Ok(TyParam::t(t.clone()));
|
||||||
|
}
|
||||||
|
if let Some(tv_ctx) = &self.tv_cache {
|
||||||
|
if let Some(t) = tv_ctx.get_tyvar(name) {
|
||||||
|
return Ok(TyParam::t(t.clone()));
|
||||||
|
} else if let Some(tp) = tv_ctx.get_typaram(name) {
|
||||||
|
return Ok(tp.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(value) = self.rec_get_const_obj(name) {
|
||||||
|
return Ok(TyParam::Value(value.clone()));
|
||||||
|
}
|
||||||
|
Err(TyCheckErrors::from(TyCheckError::no_var_error(
|
||||||
|
self.cfg.input.clone(),
|
||||||
|
line!() as usize,
|
||||||
|
loc.loc(),
|
||||||
|
self.caused_by(),
|
||||||
|
name,
|
||||||
|
self.get_similar_name(name),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn instantiate_const_expr(
|
pub(crate) fn instantiate_const_expr(
|
||||||
&self,
|
&self,
|
||||||
expr: &ast::ConstExpr,
|
expr: &ast::ConstExpr,
|
||||||
|
@ -691,39 +753,13 @@ impl Context {
|
||||||
) -> TyCheckResult<TyParam> {
|
) -> TyCheckResult<TyParam> {
|
||||||
match expr {
|
match expr {
|
||||||
ast::ConstExpr::Lit(lit) => Ok(TyParam::Value(self.eval_lit(lit)?)),
|
ast::ConstExpr::Lit(lit) => Ok(TyParam::Value(self.eval_lit(lit)?)),
|
||||||
|
ast::ConstExpr::Accessor(ast::ConstAccessor::Attr(attr)) => {
|
||||||
|
let obj = self.instantiate_const_expr(&attr.obj, erased_idx, tmp_tv_cache)?;
|
||||||
|
Ok(obj.proj(attr.name.inspect()))
|
||||||
|
}
|
||||||
ast::ConstExpr::Accessor(ast::ConstAccessor::Local(local)) => {
|
ast::ConstExpr::Accessor(ast::ConstAccessor::Local(local)) => {
|
||||||
self.inc_ref_const_local(local);
|
self.inc_ref_const_local(local);
|
||||||
if &local.inspect()[..] == "_" {
|
self.instantiate_local(local.inspect(), erased_idx, tmp_tv_cache, local)
|
||||||
let t = if let Some((ctx, i)) = erased_idx {
|
|
||||||
ctx.params[i].1.t.clone()
|
|
||||||
} else {
|
|
||||||
Type::Uninited
|
|
||||||
};
|
|
||||||
return Ok(TyParam::erased(t));
|
|
||||||
}
|
|
||||||
if let Some(tp) = tmp_tv_cache.get_typaram(local.inspect()) {
|
|
||||||
return Ok(tp.clone());
|
|
||||||
} else if let Some(t) = tmp_tv_cache.get_tyvar(local.inspect()) {
|
|
||||||
return Ok(TyParam::t(t.clone()));
|
|
||||||
}
|
|
||||||
if let Some(tv_ctx) = &self.tv_cache {
|
|
||||||
if let Some(t) = tv_ctx.get_tyvar(local.inspect()) {
|
|
||||||
return Ok(TyParam::t(t.clone()));
|
|
||||||
} else if let Some(tp) = tv_ctx.get_typaram(local.inspect()) {
|
|
||||||
return Ok(tp.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(value) = self.rec_get_const_obj(local.inspect()) {
|
|
||||||
return Ok(TyParam::Value(value.clone()));
|
|
||||||
}
|
|
||||||
Err(TyCheckErrors::from(TyCheckError::no_var_error(
|
|
||||||
self.cfg.input.clone(),
|
|
||||||
line!() as usize,
|
|
||||||
local.loc(),
|
|
||||||
self.caused_by(),
|
|
||||||
local.inspect(),
|
|
||||||
self.get_similar_name(local.inspect()),
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
ast::ConstExpr::Array(array) => {
|
ast::ConstExpr::Array(array) => {
|
||||||
let mut tp_arr = vec![];
|
let mut tp_arr = vec![];
|
||||||
|
@ -763,6 +799,76 @@ impl Context {
|
||||||
}
|
}
|
||||||
Ok(TyParam::Tuple(tp_tuple))
|
Ok(TyParam::Tuple(tp_tuple))
|
||||||
}
|
}
|
||||||
|
ast::ConstExpr::Record(rec) => {
|
||||||
|
let mut tp_rec = dict! {};
|
||||||
|
for attr in rec.attrs.iter() {
|
||||||
|
let field = Field::new(attr.ident.vis(), attr.ident.inspect().clone());
|
||||||
|
let val = self.instantiate_const_expr(
|
||||||
|
attr.body.block.get(0).unwrap(),
|
||||||
|
None,
|
||||||
|
tmp_tv_cache,
|
||||||
|
)?;
|
||||||
|
tp_rec.insert(field, val);
|
||||||
|
}
|
||||||
|
Ok(TyParam::Record(tp_rec))
|
||||||
|
}
|
||||||
|
ast::ConstExpr::Lambda(lambda) => {
|
||||||
|
let mut _tmp_tv_cache =
|
||||||
|
self.instantiate_ty_bounds(&lambda.sig.bounds, RegistrationMode::Normal)?;
|
||||||
|
let tmp_tv_cache = if tmp_tv_cache.is_empty() {
|
||||||
|
&mut _tmp_tv_cache
|
||||||
|
} else {
|
||||||
|
// TODO: prohibit double quantification
|
||||||
|
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,
|
||||||
|
)?;
|
||||||
|
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,
|
||||||
|
)?;
|
||||||
|
Some(pt)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
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()),
|
||||||
|
)?;
|
||||||
|
d_params.push(pt);
|
||||||
|
}
|
||||||
|
let mut body = vec![];
|
||||||
|
for expr in lambda.body.iter() {
|
||||||
|
let param = self.instantiate_const_expr(expr, None, tmp_tv_cache)?;
|
||||||
|
body.push(param);
|
||||||
|
}
|
||||||
|
Ok(TyParam::Lambda(TyParamLambda::new(
|
||||||
|
lambda.clone(),
|
||||||
|
nd_params,
|
||||||
|
var_params,
|
||||||
|
d_params,
|
||||||
|
body,
|
||||||
|
)))
|
||||||
|
}
|
||||||
ast::ConstExpr::BinOp(bin) => {
|
ast::ConstExpr::BinOp(bin) => {
|
||||||
let Some(op) = token_kind_to_op_kind(bin.op.kind) else {
|
let Some(op) = token_kind_to_op_kind(bin.op.kind) else {
|
||||||
return type_feature_error!(
|
return type_feature_error!(
|
||||||
|
@ -819,6 +925,34 @@ impl Context {
|
||||||
.unwrap_or(Type::Never);
|
.unwrap_or(Type::Never);
|
||||||
Ok(tp_enum(t, set))
|
Ok(tp_enum(t, set))
|
||||||
}
|
}
|
||||||
|
TyParam::Tuple(ts) => {
|
||||||
|
let mut tps = vec![];
|
||||||
|
for tp in ts {
|
||||||
|
let t = self.instantiate_tp_as_type(tp, loc)?;
|
||||||
|
tps.push(t);
|
||||||
|
}
|
||||||
|
Ok(tuple_t(tps))
|
||||||
|
}
|
||||||
|
TyParam::Record(rec) => {
|
||||||
|
let mut rec_t = dict! {};
|
||||||
|
for (field, tp) in rec {
|
||||||
|
let t = self.instantiate_tp_as_type(tp, loc)?;
|
||||||
|
rec_t.insert(field, t);
|
||||||
|
}
|
||||||
|
Ok(Type::Record(rec_t))
|
||||||
|
}
|
||||||
|
TyParam::Lambda(lambda) => {
|
||||||
|
let return_t = self
|
||||||
|
.instantiate_tp_as_type(lambda.body.last().unwrap().clone(), &lambda.const_)?;
|
||||||
|
let subr = SubrType::new(
|
||||||
|
SubrKind::from(lambda.const_.op.kind),
|
||||||
|
lambda.nd_params,
|
||||||
|
lambda.var_params,
|
||||||
|
lambda.d_params,
|
||||||
|
return_t,
|
||||||
|
);
|
||||||
|
Ok(Type::Subr(subr))
|
||||||
|
}
|
||||||
other => {
|
other => {
|
||||||
type_feature_error!(self, loc.loc(), &format!("instantiate `{other}` as type"))
|
type_feature_error!(self, loc.loc(), &format!("instantiate `{other}` as type"))
|
||||||
}
|
}
|
||||||
|
@ -1245,6 +1379,44 @@ impl Context {
|
||||||
.collect::<TyCheckResult<_>>()?;
|
.collect::<TyCheckResult<_>>()?;
|
||||||
Ok(TyParam::Tuple(tup))
|
Ok(TyParam::Tuple(tup))
|
||||||
}
|
}
|
||||||
|
TyParam::Record(rec) => {
|
||||||
|
let rec = rec
|
||||||
|
.into_iter()
|
||||||
|
.map(|(k, v)| {
|
||||||
|
let v = self.instantiate_tp(v, tmp_tv_cache, loc)?;
|
||||||
|
Ok((k, v))
|
||||||
|
})
|
||||||
|
.collect::<TyCheckResult<_>>()?;
|
||||||
|
Ok(TyParam::Record(rec))
|
||||||
|
}
|
||||||
|
TyParam::Lambda(lambda) => {
|
||||||
|
let nd_params = lambda
|
||||||
|
.nd_params
|
||||||
|
.into_iter()
|
||||||
|
.map(|pt| pt.try_map_type(|t| self.instantiate_t_inner(t, tmp_tv_cache, loc)))
|
||||||
|
.collect::<TyCheckResult<_>>()?;
|
||||||
|
let var_params = lambda
|
||||||
|
.var_params
|
||||||
|
.map(|pt| pt.try_map_type(|t| self.instantiate_t_inner(t, tmp_tv_cache, loc)))
|
||||||
|
.transpose()?;
|
||||||
|
let d_params = lambda
|
||||||
|
.d_params
|
||||||
|
.into_iter()
|
||||||
|
.map(|pt| pt.try_map_type(|t| self.instantiate_t_inner(t, tmp_tv_cache, loc)))
|
||||||
|
.collect::<TyCheckResult<_>>()?;
|
||||||
|
let body = lambda
|
||||||
|
.body
|
||||||
|
.into_iter()
|
||||||
|
.map(|v| self.instantiate_tp(v, tmp_tv_cache, loc))
|
||||||
|
.collect::<TyCheckResult<_>>()?;
|
||||||
|
Ok(TyParam::Lambda(TyParamLambda::new(
|
||||||
|
lambda.const_,
|
||||||
|
nd_params,
|
||||||
|
var_params,
|
||||||
|
d_params,
|
||||||
|
body,
|
||||||
|
)))
|
||||||
|
}
|
||||||
TyParam::UnaryOp { op, val } => {
|
TyParam::UnaryOp { op, val } => {
|
||||||
let res = self.instantiate_tp(*val, tmp_tv_cache, loc)?;
|
let res = self.instantiate_tp(*val, tmp_tv_cache, loc)?;
|
||||||
Ok(TyParam::unary(op, res))
|
Ok(TyParam::unary(op, res))
|
||||||
|
@ -1429,6 +1601,10 @@ impl Context {
|
||||||
log!(err "a quantified type should not be instantiated: {subr}");
|
log!(err "a quantified type should not be instantiated: {subr}");
|
||||||
unreachable_error!(TyCheckErrors, TyCheckError, self)
|
unreachable_error!(TyCheckErrors, TyCheckError, self)
|
||||||
}
|
}
|
||||||
|
Structural(t) => {
|
||||||
|
let t = self.instantiate_t_inner(*t, tmp_tv_cache, loc)?;
|
||||||
|
Ok(t.structuralize())
|
||||||
|
}
|
||||||
FreeVar(fv) if fv.is_linked() => {
|
FreeVar(fv) if fv.is_linked() => {
|
||||||
self.instantiate_t_inner(fv.crack().clone(), tmp_tv_cache, loc)
|
self.instantiate_t_inner(fv.crack().clone(), tmp_tv_cache, loc)
|
||||||
}
|
}
|
||||||
|
|
|
@ -391,21 +391,7 @@ impl fmt::Display for Context {
|
||||||
|
|
||||||
impl ContextProvider for Context {
|
impl ContextProvider for Context {
|
||||||
fn dir(&self) -> Vec<(&VarName, &VarInfo)> {
|
fn dir(&self) -> Vec<(&VarName, &VarInfo)> {
|
||||||
let mut vars: Vec<_> = self
|
let mut vars = self.type_dir();
|
||||||
.locals
|
|
||||||
.iter()
|
|
||||||
.chain(
|
|
||||||
self.params
|
|
||||||
.iter()
|
|
||||||
.filter_map(|(k, v)| k.as_ref().map(|k| (k, v))),
|
|
||||||
)
|
|
||||||
.chain(self.methods_list.iter().flat_map(|(_, ctx)| ctx.dir()))
|
|
||||||
.collect();
|
|
||||||
for sup in self.super_classes.iter() {
|
|
||||||
if let Some((_, sup_ctx)) = self.get_nominal_type_ctx(sup) {
|
|
||||||
vars.extend(sup_ctx.type_dir());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(outer) = self.get_outer() {
|
if let Some(outer) = self.get_outer() {
|
||||||
vars.extend(outer.dir());
|
vars.extend(outer.dir());
|
||||||
} else if let Some(builtins) = self.get_builtins() {
|
} else if let Some(builtins) = self.get_builtins() {
|
||||||
|
@ -992,10 +978,23 @@ impl Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_dir(&self) -> Vec<(&VarName, &VarInfo)> {
|
fn type_dir(&self) -> Vec<(&VarName, &VarInfo)> {
|
||||||
self.locals
|
let mut vars: Vec<_> = self
|
||||||
|
.locals
|
||||||
.iter()
|
.iter()
|
||||||
.chain(self.methods_list.iter().flat_map(|(_, ctx)| ctx.dir()))
|
.chain(self.decls.iter())
|
||||||
.collect()
|
.chain(
|
||||||
|
self.params
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(k, v)| k.as_ref().map(|k| (k, v))),
|
||||||
|
)
|
||||||
|
.chain(self.methods_list.iter().flat_map(|(_, ctx)| ctx.type_dir()))
|
||||||
|
.collect();
|
||||||
|
for sup in self.super_classes.iter() {
|
||||||
|
if let Some((_, sup_ctx)) = self.get_nominal_type_ctx(sup) {
|
||||||
|
vars.extend(sup_ctx.type_dir());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vars
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn mod_cache(&self) -> &SharedModuleCache {
|
pub(crate) fn mod_cache(&self) -> &SharedModuleCache {
|
||||||
|
|
|
@ -15,8 +15,8 @@ use erg_common::vis::Visibility;
|
||||||
use erg_common::Str;
|
use erg_common::Str;
|
||||||
use erg_common::{enum_unwrap, get_hash, log, set};
|
use erg_common::{enum_unwrap, get_hash, log, set};
|
||||||
|
|
||||||
use ast::{Decorator, DefId, Identifier, OperationKind, SimpleTypeSpec, VarName};
|
use ast::{ConstIdentifier, Decorator, DefId, Identifier, OperationKind, SimpleTypeSpec, VarName};
|
||||||
use erg_parser::ast::{self, ConstIdentifier};
|
use erg_parser::ast;
|
||||||
|
|
||||||
use crate::ty::constructors::{
|
use crate::ty::constructors::{
|
||||||
free_var, func, func0, func1, proc, ref_, ref_mut, unknown_len_array_t, v_enum,
|
free_var, func, func0, func1, proc, ref_, ref_mut, unknown_len_array_t, v_enum,
|
||||||
|
@ -671,6 +671,7 @@ impl Context {
|
||||||
};
|
};
|
||||||
sub_t.lift();
|
sub_t.lift();
|
||||||
let found_t = self.generalize_t(sub_t);
|
let found_t = self.generalize_t(sub_t);
|
||||||
|
// let found_t = self.eliminate_needless_quant(found_t, crate::context::Variance::Covariant, sig)?;
|
||||||
let py_name = if let Some(vi) = self.decls.remove(name) {
|
let py_name = if let Some(vi) = self.decls.remove(name) {
|
||||||
let allow_cast = true;
|
let allow_cast = true;
|
||||||
if !self.supertype_of(&vi.t, &found_t, allow_cast) {
|
if !self.supertype_of(&vi.t, &found_t, allow_cast) {
|
||||||
|
@ -716,7 +717,8 @@ impl Context {
|
||||||
py_name,
|
py_name,
|
||||||
self.absolutize(name.loc()),
|
self.absolutize(name.loc()),
|
||||||
);
|
);
|
||||||
log!(info "Registered {}::{name}: {}", self.name, &vi.t);
|
let vis = if vi.vis.is_private() { "::" } else { "." };
|
||||||
|
log!(info "Registered {}{}{name}: {}", self.name, vis, &vi.t);
|
||||||
self.locals.insert(name.clone(), vi.clone());
|
self.locals.insert(name.clone(), vi.clone());
|
||||||
errs?;
|
errs?;
|
||||||
Ok(vi)
|
Ok(vi)
|
||||||
|
@ -1099,7 +1101,17 @@ impl Context {
|
||||||
Self::methods(None, self.cfg.clone(), self.shared.clone(), 2, self.level);
|
Self::methods(None, self.cfg.clone(), self.shared.clone(), 2, self.level);
|
||||||
let new_t = if let Some(base) = gen.base_or_sup() {
|
let new_t = if let Some(base) = gen.base_or_sup() {
|
||||||
match base {
|
match base {
|
||||||
TypeObj::Builtin(Type::Record(_)) => {}
|
TypeObj::Builtin(Type::Record(rec)) => {
|
||||||
|
for (field, t) in rec.iter() {
|
||||||
|
let varname = VarName::from_str(field.symbol.clone());
|
||||||
|
let vi = VarInfo::instance_attr(
|
||||||
|
field.clone(),
|
||||||
|
t.clone(),
|
||||||
|
self.impl_of(),
|
||||||
|
);
|
||||||
|
ctx.decls.insert(varname, vi);
|
||||||
|
}
|
||||||
|
}
|
||||||
other => {
|
other => {
|
||||||
methods.register_fixed_auto_impl(
|
methods.register_fixed_auto_impl(
|
||||||
"base",
|
"base",
|
||||||
|
@ -1167,6 +1179,17 @@ impl Context {
|
||||||
// `Super.Requirement := {x = Int}` and `Self.Additional := {y = Int}`
|
// `Super.Requirement := {x = Int}` and `Self.Additional := {y = Int}`
|
||||||
// => `Self.Requirement := {x = Int; y = Int}`
|
// => `Self.Requirement := {x = Int; y = Int}`
|
||||||
let param_t = if let Some(additional) = gen.additional() {
|
let param_t = if let Some(additional) = gen.additional() {
|
||||||
|
if let TypeObj::Builtin(Type::Record(rec)) = additional {
|
||||||
|
for (field, t) in rec.iter() {
|
||||||
|
let varname = VarName::from_str(field.symbol.clone());
|
||||||
|
let vi = VarInfo::instance_attr(
|
||||||
|
field.clone(),
|
||||||
|
t.clone(),
|
||||||
|
self.impl_of(),
|
||||||
|
);
|
||||||
|
ctx.decls.insert(varname, vi);
|
||||||
|
}
|
||||||
|
}
|
||||||
self.intersection(param_t, additional.typ())
|
self.intersection(param_t, additional.typ())
|
||||||
} else {
|
} else {
|
||||||
param_t.clone()
|
param_t.clone()
|
||||||
|
@ -1216,22 +1239,7 @@ impl Context {
|
||||||
);
|
);
|
||||||
let Some(TypeObj::Builtin(Type::Record(req))) = gen.base_or_sup() else { todo!("{gen}") };
|
let Some(TypeObj::Builtin(Type::Record(req))) = gen.base_or_sup() else { todo!("{gen}") };
|
||||||
for (field, t) in req.iter() {
|
for (field, t) in req.iter() {
|
||||||
let muty = if field.is_const() {
|
let vi = VarInfo::instance_attr(field.clone(), t.clone(), self.impl_of());
|
||||||
Mutability::Const
|
|
||||||
} else {
|
|
||||||
Mutability::Immutable
|
|
||||||
};
|
|
||||||
let vi = VarInfo::new(
|
|
||||||
t.clone(),
|
|
||||||
muty,
|
|
||||||
field.vis,
|
|
||||||
VarKind::Declared,
|
|
||||||
None,
|
|
||||||
self.impl_of(),
|
|
||||||
None,
|
|
||||||
// TODO:
|
|
||||||
AbsLocation::unknown(),
|
|
||||||
);
|
|
||||||
ctx.decls
|
ctx.decls
|
||||||
.insert(VarName::from_str(field.symbol.clone()), vi);
|
.insert(VarName::from_str(field.symbol.clone()), vi);
|
||||||
}
|
}
|
||||||
|
@ -1262,22 +1270,8 @@ impl Context {
|
||||||
);
|
);
|
||||||
if let Some(additional) = additional {
|
if let Some(additional) = additional {
|
||||||
for (field, t) in additional.iter() {
|
for (field, t) in additional.iter() {
|
||||||
let muty = if field.is_const() {
|
let vi =
|
||||||
Mutability::Const
|
VarInfo::instance_attr(field.clone(), t.clone(), self.impl_of());
|
||||||
} else {
|
|
||||||
Mutability::Immutable
|
|
||||||
};
|
|
||||||
let vi = VarInfo::new(
|
|
||||||
t.clone(),
|
|
||||||
muty,
|
|
||||||
field.vis,
|
|
||||||
VarKind::Declared,
|
|
||||||
None,
|
|
||||||
self.impl_of(),
|
|
||||||
None,
|
|
||||||
// TODO:
|
|
||||||
AbsLocation::unknown(),
|
|
||||||
);
|
|
||||||
ctx.decls
|
ctx.decls
|
||||||
.insert(VarName::from_str(field.symbol.clone()), vi);
|
.insert(VarName::from_str(field.symbol.clone()), vi);
|
||||||
}
|
}
|
||||||
|
|
|
@ -257,6 +257,9 @@ impl Context {
|
||||||
self.sub_unify_tp(lhs, lhs2, _variance, loc, allow_divergence)?;
|
self.sub_unify_tp(lhs, lhs2, _variance, loc, allow_divergence)?;
|
||||||
self.sub_unify_tp(rhs, rhs2, _variance, loc, allow_divergence)
|
self.sub_unify_tp(rhs, rhs2, _variance, loc, allow_divergence)
|
||||||
}
|
}
|
||||||
|
(TyParam::Lambda(_l), TyParam::Lambda(_r)) => {
|
||||||
|
todo!("{_l}/{_r}")
|
||||||
|
}
|
||||||
(l, TyParam::Erased(t)) => {
|
(l, TyParam::Erased(t)) => {
|
||||||
let sub_t = self.get_tp_t(l)?;
|
let sub_t = self.get_tp_t(l)?;
|
||||||
if self.subtype_of(&sub_t, t, allow_cast) {
|
if self.subtype_of(&sub_t, t, allow_cast) {
|
||||||
|
@ -344,6 +347,9 @@ impl Context {
|
||||||
self.reunify_tp(lhs, lhs2, loc)?;
|
self.reunify_tp(lhs, lhs2, loc)?;
|
||||||
self.reunify_tp(rhs, rhs2, loc)
|
self.reunify_tp(rhs, rhs2, loc)
|
||||||
}
|
}
|
||||||
|
(TyParam::Lambda(_l), TyParam::Lambda(_r)) => {
|
||||||
|
todo!("{_l}/{_r}")
|
||||||
|
}
|
||||||
(l, r) if self.eq_tp(l, r, allow_cast) => Ok(()),
|
(l, r) if self.eq_tp(l, r, allow_cast) => Ok(()),
|
||||||
(l, r) => panic!("type-parameter re-unification failed:\nl: {l}\nr: {r}"),
|
(l, r) => panic!("type-parameter re-unification failed:\nl: {l}\nr: {r}"),
|
||||||
}
|
}
|
||||||
|
@ -628,6 +634,9 @@ impl Context {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
// e.g. T/Structural({ .method = (self: T) -> Int })
|
||||||
|
(Type::FreeVar(fv), Type::Structural(_sup)) if fv.is_unbound() => Ok(()),
|
||||||
|
(Type::Structural(_sub), Type::FreeVar(fv)) if fv.is_unbound() => Ok(()),
|
||||||
(_, Type::FreeVar(rfv)) if rfv.is_unbound() => {
|
(_, Type::FreeVar(rfv)) if rfv.is_unbound() => {
|
||||||
// NOTE: cannot `borrow_mut` because of cycle reference
|
// NOTE: cannot `borrow_mut` because of cycle reference
|
||||||
let rfv_ref = unsafe { rfv.as_ptr().as_mut().unwrap() };
|
let rfv_ref = unsafe { rfv.as_ptr().as_mut().unwrap() };
|
||||||
|
@ -845,6 +854,18 @@ impl Context {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(Type::Structural(l), Type::Structural(r)) => self.sub_unify(l, r, loc, param_name),
|
||||||
|
(sub, Type::Structural(sup)) => {
|
||||||
|
let sub_fields = self.fields(sub);
|
||||||
|
for (sup_field, sup_ty) in self.fields(sup) {
|
||||||
|
if let Some((_, sub_ty)) = sub_fields.get_key_value(&sup_field) {
|
||||||
|
self.sub_unify(sub_ty, &sup_ty, loc, param_name)?;
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
(
|
(
|
||||||
_,
|
_,
|
||||||
Type::Poly {
|
Type::Poly {
|
||||||
|
|
|
@ -268,8 +268,10 @@ impl ASTLowerer {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fake_lower_record(&self, rec: ast::Record) -> LowerResult<hir::Record> {
|
fn fake_lower_record(&self, rec: ast::Record) -> LowerResult<hir::Record> {
|
||||||
match rec {
|
let rec = match rec {
|
||||||
ast::Record::Normal(rec) => {
|
ast::Record::Normal(rec) => rec,
|
||||||
|
ast::Record::Mixed(_mixed) => unreachable!(),
|
||||||
|
};
|
||||||
let mut elems = Vec::new();
|
let mut elems = Vec::new();
|
||||||
for elem in rec.attrs.into_iter() {
|
for elem in rec.attrs.into_iter() {
|
||||||
let elem = self.fake_lower_def(elem)?;
|
let elem = self.fake_lower_def(elem)?;
|
||||||
|
@ -278,14 +280,6 @@ impl ASTLowerer {
|
||||||
let attrs = hir::RecordAttrs::new(elems);
|
let attrs = hir::RecordAttrs::new(elems);
|
||||||
Ok(hir::Record::new(rec.l_brace, rec.r_brace, attrs))
|
Ok(hir::Record::new(rec.l_brace, rec.r_brace, attrs))
|
||||||
}
|
}
|
||||||
other => Err(LowerErrors::from(LowerError::declare_error(
|
|
||||||
self.cfg().input.clone(),
|
|
||||||
line!() as usize,
|
|
||||||
other.loc(),
|
|
||||||
self.module.context.caused_by(),
|
|
||||||
))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fake_lower_set(&self, set: ast::Set) -> LowerResult<hir::Set> {
|
fn fake_lower_set(&self, set: ast::Set) -> LowerResult<hir::Set> {
|
||||||
match set {
|
match set {
|
||||||
|
|
|
@ -1975,11 +1975,12 @@ impl ASTLowerer {
|
||||||
match expr {
|
match expr {
|
||||||
acc @ hir::Expr::Accessor(_) => Some(acc),
|
acc @ hir::Expr::Accessor(_) => Some(acc),
|
||||||
hir::Expr::Call(mut call) => match call.obj.show_acc().as_ref().map(|s| &s[..]) {
|
hir::Expr::Call(mut call) => match call.obj.show_acc().as_ref().map(|s| &s[..]) {
|
||||||
Some("Class") => call.args.remove_left_or_key("Requirement"),
|
Some("Class" | "Trait") => call.args.remove_left_or_key("Requirement"),
|
||||||
Some("Inherit") => call.args.remove_left_or_key("Super"),
|
Some("Inherit") => call.args.remove_left_or_key("Super"),
|
||||||
Some("Inheritable") => {
|
Some("Inheritable") => {
|
||||||
Self::get_require_or_sup_or_base(call.args.remove_left_or_key("Class").unwrap())
|
Self::get_require_or_sup_or_base(call.args.remove_left_or_key("Class").unwrap())
|
||||||
}
|
}
|
||||||
|
Some("Structural") => call.args.remove_left_or_key("Type"),
|
||||||
Some("Patch") => call.args.remove_left_or_key("Base"),
|
Some("Patch") => call.args.remove_left_or_key("Base"),
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,7 +5,7 @@ use erg_common::dict::Dict;
|
||||||
use erg_common::log;
|
use erg_common::log;
|
||||||
use erg_common::Str;
|
use erg_common::Str;
|
||||||
|
|
||||||
use erg_parser::ast::{Block, Params};
|
use erg_parser::ast::{ConstBlock, Params};
|
||||||
|
|
||||||
use super::constructors::subr_t;
|
use super::constructors::subr_t;
|
||||||
use super::value::{EvalValueResult, ValueObj};
|
use super::value::{EvalValueResult, ValueObj};
|
||||||
|
@ -17,12 +17,12 @@ use crate::context::Context;
|
||||||
pub struct UserConstSubr {
|
pub struct UserConstSubr {
|
||||||
name: Str,
|
name: Str,
|
||||||
params: Params,
|
params: Params,
|
||||||
block: Block,
|
block: ConstBlock,
|
||||||
sig_t: Type,
|
sig_t: Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserConstSubr {
|
impl UserConstSubr {
|
||||||
pub const fn new(name: Str, params: Params, block: Block, sig_t: Type) -> Self {
|
pub const fn new(name: Str, params: Params, block: ConstBlock, sig_t: Type) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
params,
|
params,
|
||||||
|
|
|
@ -13,7 +13,7 @@ pub mod typaram;
|
||||||
pub mod value;
|
pub mod value;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::{Range, RangeInclusive};
|
use std::ops::{BitAnd, BitOr, Deref, Not, Range, RangeInclusive};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use constructors::dict_t;
|
use constructors::dict_t;
|
||||||
|
@ -212,6 +212,21 @@ impl ParamTy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn try_map_type<F, E>(self, f: F) -> Result<Self, E>
|
||||||
|
where
|
||||||
|
F: FnOnce(Type) -> Result<Type, E>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Pos { name, ty } => Ok(Self::Pos { name, ty: f(ty)? }),
|
||||||
|
Self::Kw { name, ty } => Ok(Self::Kw { name, ty: f(ty)? }),
|
||||||
|
Self::KwWithDefault { name, ty, default } => Ok(Self::KwWithDefault {
|
||||||
|
name,
|
||||||
|
ty: f(ty)?,
|
||||||
|
default,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn deconstruct(self) -> (Option<Str>, Type, Option<Type>) {
|
pub fn deconstruct(self) -> (Option<Str>, Type, Option<Type>) {
|
||||||
match self {
|
match self {
|
||||||
Self::Pos { name, ty } => (name, ty, None),
|
Self::Pos { name, ty } => (name, ty, None),
|
||||||
|
@ -246,6 +261,7 @@ impl TryFrom<Type> for SubrType {
|
||||||
match t {
|
match t {
|
||||||
Type::FreeVar(fv) if fv.is_linked() => Self::try_from(fv.crack().clone()),
|
Type::FreeVar(fv) if fv.is_linked() => Self::try_from(fv.crack().clone()),
|
||||||
Type::Subr(st) => Ok(st),
|
Type::Subr(st) => Ok(st),
|
||||||
|
Type::Quantified(quant) => SubrType::try_from(*quant),
|
||||||
Type::Refinement(refine) => Self::try_from(*refine.t),
|
Type::Refinement(refine) => Self::try_from(*refine.t),
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
|
@ -258,6 +274,7 @@ impl<'t> TryFrom<&'t Type> for &'t SubrType {
|
||||||
match t {
|
match t {
|
||||||
Type::FreeVar(fv) if fv.is_linked() => Self::try_from(fv.unsafe_crack()),
|
Type::FreeVar(fv) if fv.is_linked() => Self::try_from(fv.unsafe_crack()),
|
||||||
Type::Subr(st) => Ok(st),
|
Type::Subr(st) => Ok(st),
|
||||||
|
Type::Quantified(quant) => <&SubrType>::try_from(quant.as_ref()),
|
||||||
Type::Refinement(refine) => Self::try_from(refine.t.as_ref()),
|
Type::Refinement(refine) => Self::try_from(refine.t.as_ref()),
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
|
@ -705,6 +722,7 @@ pub enum Type {
|
||||||
attr_name: Str,
|
attr_name: Str,
|
||||||
args: Vec<TyParam>,
|
args: Vec<TyParam>,
|
||||||
}, // e.g. Ts.__getitem__(N)
|
}, // e.g. Ts.__getitem__(N)
|
||||||
|
Structural(Box<Type>),
|
||||||
FreeVar(FreeTyVar), // a reference to the type of other expression, see docs/compiler/inference.md
|
FreeVar(FreeTyVar), // a reference to the type of other expression, see docs/compiler/inference.md
|
||||||
Failure, // indicates a failure of type inference and behaves as `Never`.
|
Failure, // indicates a failure of type inference and behaves as `Never`.
|
||||||
/// used to represent `TyParam` is not initialized (see `erg_compiler::context::instantiate_tp`)
|
/// used to represent `TyParam` is not initialized (see `erg_compiler::context::instantiate_tp`)
|
||||||
|
@ -749,14 +767,18 @@ impl PartialEq for Type {
|
||||||
(Self::Subr(l), Self::Subr(r)) => l == r,
|
(Self::Subr(l), Self::Subr(r)) => l == r,
|
||||||
(
|
(
|
||||||
Self::Callable {
|
Self::Callable {
|
||||||
param_ts: _lps,
|
param_ts: lps,
|
||||||
return_t: _lr,
|
return_t: lr,
|
||||||
},
|
},
|
||||||
Self::Callable {
|
Self::Callable {
|
||||||
param_ts: _rps,
|
param_ts: rps,
|
||||||
return_t: _rr,
|
return_t: rr,
|
||||||
},
|
},
|
||||||
) => todo!(),
|
) => {
|
||||||
|
lps.len() != rps.len()
|
||||||
|
&& lps.iter().zip(rps.iter()).all(|(l, r)| l == r)
|
||||||
|
&& (lr == rr)
|
||||||
|
}
|
||||||
(Self::Record(lhs), Self::Record(rhs)) => {
|
(Self::Record(lhs), Self::Record(rhs)) => {
|
||||||
for (l_field, l_t) in lhs.iter() {
|
for (l_field, l_t) in lhs.iter() {
|
||||||
if let Some(r_t) = rhs.get(l_field) {
|
if let Some(r_t) = rhs.get(l_field) {
|
||||||
|
@ -804,6 +826,7 @@ impl PartialEq for Type {
|
||||||
args: ra,
|
args: ra,
|
||||||
},
|
},
|
||||||
) => lhs == r && attr_name == rn && args == ra,
|
) => lhs == r && attr_name == rn && args == ra,
|
||||||
|
(Self::Structural(l), Self::Structural(r)) => l == r,
|
||||||
(Self::FreeVar(fv), other) if fv.is_linked() => &*fv.crack() == other,
|
(Self::FreeVar(fv), other) if fv.is_linked() => &*fv.crack() == other,
|
||||||
(_self, Self::FreeVar(fv)) if fv.is_linked() => _self == &*fv.crack(),
|
(_self, Self::FreeVar(fv)) if fv.is_linked() => _self == &*fv.crack(),
|
||||||
(Self::FreeVar(l), Self::FreeVar(r)) => l == r,
|
(Self::FreeVar(l), Self::FreeVar(r)) => l == r,
|
||||||
|
@ -929,6 +952,11 @@ impl LimitedDisplay for Type {
|
||||||
}
|
}
|
||||||
write!(f, ")")
|
write!(f, ")")
|
||||||
}
|
}
|
||||||
|
Self::Structural(ty) => {
|
||||||
|
write!(f, "Structural(")?;
|
||||||
|
ty.limited_fmt(f, limit - 1)?;
|
||||||
|
write!(f, ")")
|
||||||
|
}
|
||||||
_ => write!(f, "{}", self.qual_name()),
|
_ => write!(f, "{}", self.qual_name()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1000,6 +1028,27 @@ impl From<Dict<Type, Type>> for Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl BitAnd for Type {
|
||||||
|
type Output = Self;
|
||||||
|
fn bitand(self, rhs: Self) -> Self::Output {
|
||||||
|
Self::And(Box::new(self), Box::new(rhs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitOr for Type {
|
||||||
|
type Output = Self;
|
||||||
|
fn bitor(self, rhs: Self) -> Self::Output {
|
||||||
|
Self::Or(Box::new(self), Box::new(rhs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Not for Type {
|
||||||
|
type Output = Self;
|
||||||
|
fn not(self) -> Self::Output {
|
||||||
|
Self::Not(Box::new(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_t_from_tp(tp: &TyParam) -> Option<Type> {
|
fn get_t_from_tp(tp: &TyParam) -> Option<Type> {
|
||||||
match tp {
|
match tp {
|
||||||
TyParam::FreeVar(fv) if fv.is_linked() => get_t_from_tp(&fv.crack()),
|
TyParam::FreeVar(fv) if fv.is_linked() => get_t_from_tp(&fv.crack()),
|
||||||
|
@ -1129,6 +1178,7 @@ impl HasLevel for Type {
|
||||||
Some(min)
|
Some(min)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Self::Structural(ty) => ty.level(),
|
||||||
Self::Quantified(quant) => quant.level(),
|
Self::Quantified(quant) => quant.level(),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
@ -1189,6 +1239,13 @@ impl HasLevel for Type {
|
||||||
pred.set_level(level);
|
pred.set_level(level);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Self::ProjCall { lhs, args, .. } => {
|
||||||
|
lhs.set_level(level);
|
||||||
|
for arg in args.iter() {
|
||||||
|
arg.set_level(level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::Structural(ty) => ty.set_level(level),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1284,6 +1341,7 @@ impl StructuralEq for Type {
|
||||||
.zip(args2.iter())
|
.zip(args2.iter())
|
||||||
.all(|(a, b)| a.structural_eq(b))
|
.all(|(a, b)| a.structural_eq(b))
|
||||||
}
|
}
|
||||||
|
(Self::Structural(l), Self::Structural(r)) => l.structural_eq(r),
|
||||||
// TODO: commutative
|
// TODO: commutative
|
||||||
(Self::And(l, r), Self::And(l2, r2)) => l.structural_eq(l2) && r.structural_eq(r2),
|
(Self::And(l, r), Self::And(l2, r2)) => l.structural_eq(l2) && r.structural_eq(r2),
|
||||||
(Self::Or(l, r), Self::Or(l2, r2)) => l.structural_eq(l2) && r.structural_eq(r2),
|
(Self::Or(l, r), Self::Or(l2, r2)) => l.structural_eq(l2) && r.structural_eq(r2),
|
||||||
|
@ -1334,6 +1392,10 @@ impl Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn structuralize(self) -> Self {
|
||||||
|
Self::Structural(Box::new(self))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_simple_class(&self) -> bool {
|
pub fn is_simple_class(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::FreeVar(fv) if fv.is_linked() => fv.crack().is_simple_class(),
|
Self::FreeVar(fv) if fv.is_linked() => fv.crack().is_simple_class(),
|
||||||
|
@ -1503,10 +1565,25 @@ impl Type {
|
||||||
.map(|(sub, sup)| sub.contains_tvar(name) || sup.contains_tvar(name))
|
.map(|(sub, sup)| sub.contains_tvar(name) || sup.contains_tvar(name))
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
Self::Record(rec) => rec.iter().any(|(_, t)| t.contains_tvar(name)),
|
||||||
Self::Poly { params, .. } => params.iter().any(|tp| tp.contains_var(name)),
|
Self::Poly { params, .. } => params.iter().any(|tp| tp.contains_var(name)),
|
||||||
|
Self::Quantified(t) => t.contains_tvar(name),
|
||||||
Self::Subr(subr) => subr.contains_tvar(name),
|
Self::Subr(subr) => subr.contains_tvar(name),
|
||||||
// TODO: preds
|
// TODO: preds
|
||||||
Self::Refinement(refine) => refine.t.contains_tvar(name),
|
Self::Refinement(refine) => refine.t.contains_tvar(name),
|
||||||
|
Self::Structural(ty) => ty.contains_tvar(name),
|
||||||
|
Self::Proj { lhs, .. } => lhs.contains_tvar(name),
|
||||||
|
Self::ProjCall { lhs, args, .. } => {
|
||||||
|
lhs.contains_var(name) || args.iter().any(|t| t.contains_var(name))
|
||||||
|
}
|
||||||
|
Self::And(lhs, rhs) => lhs.contains_tvar(name) || rhs.contains_tvar(name),
|
||||||
|
Self::Or(lhs, rhs) => lhs.contains_tvar(name) || rhs.contains_tvar(name),
|
||||||
|
Self::Not(t) => t.contains_tvar(name),
|
||||||
|
Self::Ref(t) => t.contains_tvar(name),
|
||||||
|
Self::RefMut { before, after } => {
|
||||||
|
before.contains_tvar(name)
|
||||||
|
|| after.as_ref().map_or(false, |t| t.contains_tvar(name))
|
||||||
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1614,6 +1691,7 @@ impl Type {
|
||||||
},
|
},
|
||||||
Self::Proj { .. } => Str::ever("Proj"),
|
Self::Proj { .. } => Str::ever("Proj"),
|
||||||
Self::ProjCall { .. } => Str::ever("ProjCall"),
|
Self::ProjCall { .. } => Str::ever("ProjCall"),
|
||||||
|
Self::Structural(_) => Str::ever("Structural"),
|
||||||
Self::Failure => Str::ever("Failure"),
|
Self::Failure => Str::ever("Failure"),
|
||||||
Self::Uninited => Str::ever("Uninited"),
|
Self::Uninited => Str::ever("Uninited"),
|
||||||
}
|
}
|
||||||
|
@ -1809,6 +1887,7 @@ impl Type {
|
||||||
Self::ProjCall { lhs, args, .. } => lhs
|
Self::ProjCall { lhs, args, .. } => lhs
|
||||||
.qvars()
|
.qvars()
|
||||||
.concat(args.iter().fold(set! {}, |acc, tp| acc.concat(tp.qvars()))),
|
.concat(args.iter().fold(set! {}, |acc, tp| acc.concat(tp.qvars()))),
|
||||||
|
Self::Structural(ty) => ty.qvars(),
|
||||||
_ => set! {},
|
_ => set! {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1866,6 +1945,7 @@ impl Type {
|
||||||
Self::ProjCall { lhs, args, .. } => {
|
Self::ProjCall { lhs, args, .. } => {
|
||||||
lhs.has_qvar() || args.iter().any(|tp| tp.has_qvar())
|
lhs.has_qvar() || args.iter().any(|tp| tp.has_qvar())
|
||||||
}
|
}
|
||||||
|
Self::Structural(ty) => ty.has_qvar(),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1917,6 +1997,10 @@ impl Type {
|
||||||
Self::Quantified(quant) => quant.has_unbound_var(),
|
Self::Quantified(quant) => quant.has_unbound_var(),
|
||||||
Self::Poly { params, .. } => params.iter().any(|p| p.has_unbound_var()),
|
Self::Poly { params, .. } => params.iter().any(|p| p.has_unbound_var()),
|
||||||
Self::Proj { lhs, .. } => lhs.has_no_unbound_var(),
|
Self::Proj { lhs, .. } => lhs.has_no_unbound_var(),
|
||||||
|
Self::ProjCall { lhs, args, .. } => {
|
||||||
|
lhs.has_no_unbound_var() && args.iter().all(|t| t.has_no_unbound_var())
|
||||||
|
}
|
||||||
|
Self::Structural(ty) => ty.has_unbound_var(),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1941,6 +2025,9 @@ impl Type {
|
||||||
),
|
),
|
||||||
Self::Callable { param_ts, .. } => Some(param_ts.len() + 1),
|
Self::Callable { param_ts, .. } => Some(param_ts.len() + 1),
|
||||||
Self::Poly { params, .. } => Some(params.len()),
|
Self::Poly { params, .. } => Some(params.len()),
|
||||||
|
Self::Proj { lhs, .. } => lhs.typarams_len(),
|
||||||
|
Self::ProjCall { args, .. } => Some(1 + args.len()),
|
||||||
|
Self::Structural(ty) => ty.typarams_len(),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1977,6 +2064,11 @@ impl Type {
|
||||||
Self::Quantified(quant) => quant.typarams(),
|
Self::Quantified(quant) => quant.typarams(),
|
||||||
Self::Callable { param_ts: _, .. } => todo!(),
|
Self::Callable { param_ts: _, .. } => todo!(),
|
||||||
Self::Poly { params, .. } => params.clone(),
|
Self::Poly { params, .. } => params.clone(),
|
||||||
|
Self::Proj { lhs, .. } => lhs.typarams(),
|
||||||
|
Self::ProjCall { lhs, args, .. } => {
|
||||||
|
[vec![*lhs.clone()], args.deref().to_vec()].concat()
|
||||||
|
}
|
||||||
|
Self::Structural(ty) => ty.typarams(),
|
||||||
_ => vec![],
|
_ => vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2135,17 +2227,11 @@ impl Type {
|
||||||
before: Box::new(before.derefine()),
|
before: Box::new(before.derefine()),
|
||||||
after: after.as_ref().map(|t| Box::new(t.derefine())),
|
after: after.as_ref().map(|t| Box::new(t.derefine())),
|
||||||
},
|
},
|
||||||
Self::And(l, r) => {
|
Self::And(l, r) => l.derefine() & r.derefine(),
|
||||||
let l = l.derefine();
|
Self::Or(l, r) => l.derefine() | r.derefine(),
|
||||||
let r = r.derefine();
|
Self::Not(ty) => !ty.derefine(),
|
||||||
Self::And(Box::new(l), Box::new(r))
|
Self::Proj { lhs, rhs } => lhs.derefine().proj(rhs.clone()),
|
||||||
}
|
Self::Structural(ty) => ty.derefine().structuralize(),
|
||||||
Self::Or(l, r) => {
|
|
||||||
let l = l.derefine();
|
|
||||||
let r = r.derefine();
|
|
||||||
Self::Or(Box::new(l), Box::new(r))
|
|
||||||
}
|
|
||||||
Self::Not(ty) => Self::Not(Box::new(ty.derefine())),
|
|
||||||
other => other.clone(),
|
other => other.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2218,17 +2304,9 @@ impl Type {
|
||||||
before: Box::new(before._replace(target, to)),
|
before: Box::new(before._replace(target, to)),
|
||||||
after: after.map(|t| Box::new(t._replace(target, to))),
|
after: after.map(|t| Box::new(t._replace(target, to))),
|
||||||
},
|
},
|
||||||
Self::And(l, r) => {
|
Self::And(l, r) => l._replace(target, to) & r._replace(target, to),
|
||||||
let l = l._replace(target, to);
|
Self::Or(l, r) => l._replace(target, to) | r._replace(target, to),
|
||||||
let r = r._replace(target, to);
|
Self::Not(ty) => !ty._replace(target, to),
|
||||||
Self::And(Box::new(l), Box::new(r))
|
|
||||||
}
|
|
||||||
Self::Or(l, r) => {
|
|
||||||
let l = l._replace(target, to);
|
|
||||||
let r = r._replace(target, to);
|
|
||||||
Self::Or(Box::new(l), Box::new(r))
|
|
||||||
}
|
|
||||||
Self::Not(ty) => Self::Not(Box::new(ty._replace(target, to))),
|
|
||||||
Self::Proj { lhs, rhs } => lhs._replace(target, to).proj(rhs),
|
Self::Proj { lhs, rhs } => lhs._replace(target, to).proj(rhs),
|
||||||
Self::ProjCall {
|
Self::ProjCall {
|
||||||
lhs,
|
lhs,
|
||||||
|
@ -2238,6 +2316,7 @@ impl Type {
|
||||||
let args = args.into_iter().map(|tp| tp.replace(target, to)).collect();
|
let args = args.into_iter().map(|tp| tp.replace(target, to)).collect();
|
||||||
lhs.replace(target, to).proj_call(attr_name, args)
|
lhs.replace(target, to).proj_call(attr_name, args)
|
||||||
}
|
}
|
||||||
|
Self::Structural(ty) => ty._replace(target, to).structuralize(),
|
||||||
other => other,
|
other => other,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2264,6 +2343,23 @@ impl Type {
|
||||||
Self::Subr(subr)
|
Self::Subr(subr)
|
||||||
}
|
}
|
||||||
Self::Proj { lhs, rhs } => lhs.normalize().proj(rhs),
|
Self::Proj { lhs, rhs } => lhs.normalize().proj(rhs),
|
||||||
|
Self::ProjCall {
|
||||||
|
lhs,
|
||||||
|
attr_name,
|
||||||
|
args,
|
||||||
|
} => {
|
||||||
|
let args = args.into_iter().map(|tp| tp.normalize()).collect();
|
||||||
|
lhs.normalize().proj_call(attr_name, args)
|
||||||
|
}
|
||||||
|
Self::Ref(t) => Self::Ref(Box::new(t.normalize())),
|
||||||
|
Self::RefMut { before, after } => Self::RefMut {
|
||||||
|
before: Box::new(before.normalize()),
|
||||||
|
after: after.map(|t| Box::new(t.normalize())),
|
||||||
|
},
|
||||||
|
Self::And(l, r) => l.normalize() & r.normalize(),
|
||||||
|
Self::Or(l, r) => l.normalize() | r.normalize(),
|
||||||
|
Self::Not(ty) => !ty.normalize(),
|
||||||
|
Self::Structural(ty) => ty.normalize().structuralize(),
|
||||||
other => other,
|
other => other,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,17 @@ use erg_common::dict::Dict;
|
||||||
use erg_common::set;
|
use erg_common::set;
|
||||||
use erg_common::set::Set;
|
use erg_common::set::Set;
|
||||||
use erg_common::traits::{LimitedDisplay, StructuralEq};
|
use erg_common::traits::{LimitedDisplay, StructuralEq};
|
||||||
|
use erg_common::vis::Field;
|
||||||
use erg_common::Str;
|
use erg_common::Str;
|
||||||
use erg_common::{dict, log};
|
use erg_common::{dict, log};
|
||||||
|
|
||||||
|
use erg_parser::ast::ConstLambda;
|
||||||
|
|
||||||
use super::constructors::int_interval;
|
use super::constructors::int_interval;
|
||||||
use super::free::{CanbeFree, Constraint, FreeKind, FreeTyParam, HasLevel, Level, GENERIC_LEVEL};
|
use super::free::{CanbeFree, Constraint, FreeKind, FreeTyParam, HasLevel, Level, GENERIC_LEVEL};
|
||||||
use super::value::ValueObj;
|
use super::value::ValueObj;
|
||||||
use super::Type;
|
use super::Type;
|
||||||
|
use super::{ConstSubr, ParamTy, UserConstSubr};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
|
@ -124,8 +128,65 @@ impl fmt::Display for IntervalOp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// type argument
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
/// This is an expression, not a evaluation result
|
pub struct TyParamLambda {
|
||||||
|
pub const_: ConstLambda,
|
||||||
|
pub nd_params: Vec<ParamTy>,
|
||||||
|
pub var_params: Option<ParamTy>,
|
||||||
|
pub d_params: Vec<ParamTy>,
|
||||||
|
pub body: Vec<TyParam>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for TyParamLambda {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.const_)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasLevel for TyParamLambda {
|
||||||
|
fn level(&self) -> Option<usize> {
|
||||||
|
self.body.iter().filter_map(|tp| tp.level()).min()
|
||||||
|
}
|
||||||
|
fn set_level(&self, lev: Level) {
|
||||||
|
for tp in self.body.iter() {
|
||||||
|
tp.set_level(lev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StructuralEq for TyParamLambda {
|
||||||
|
fn structural_eq(&self, other: &Self) -> bool {
|
||||||
|
self.body.len() == other.body.len()
|
||||||
|
&& self
|
||||||
|
.body
|
||||||
|
.iter()
|
||||||
|
.zip(other.body.iter())
|
||||||
|
.all(|(a, b)| a.structural_eq(b))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TyParamLambda {
|
||||||
|
pub const fn new(
|
||||||
|
lambda: ConstLambda,
|
||||||
|
nd_params: Vec<ParamTy>,
|
||||||
|
var_params: Option<ParamTy>,
|
||||||
|
d_params: Vec<ParamTy>,
|
||||||
|
body: Vec<TyParam>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
const_: lambda,
|
||||||
|
nd_params,
|
||||||
|
var_params,
|
||||||
|
d_params,
|
||||||
|
body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # type parameter
|
||||||
|
/// Unevaluated expressions that types can have inside
|
||||||
|
///
|
||||||
|
/// The evaluated one becomes `ValueObj`.
|
||||||
/// * Literal: 1, "aa", True, None, ... (don't use container literals, they can only hold literals)
|
/// * Literal: 1, "aa", True, None, ... (don't use container literals, they can only hold literals)
|
||||||
/// * Type: Int, Add(?R, ?O), ...
|
/// * Type: Int, Add(?R, ?O), ...
|
||||||
/// * Mono: I, N, ...
|
/// * Mono: I, N, ...
|
||||||
|
@ -146,6 +207,8 @@ pub enum TyParam {
|
||||||
Tuple(Vec<TyParam>),
|
Tuple(Vec<TyParam>),
|
||||||
Set(Set<TyParam>),
|
Set(Set<TyParam>),
|
||||||
Dict(Dict<TyParam, TyParam>),
|
Dict(Dict<TyParam, TyParam>),
|
||||||
|
Record(Dict<Field, TyParam>),
|
||||||
|
Lambda(TyParamLambda),
|
||||||
Mono(Str),
|
Mono(Str),
|
||||||
Proj {
|
Proj {
|
||||||
obj: Box<TyParam>,
|
obj: Box<TyParam>,
|
||||||
|
@ -177,7 +240,9 @@ impl PartialEq for TyParam {
|
||||||
(Self::Array(l), Self::Array(r)) => l == r,
|
(Self::Array(l), Self::Array(r)) => l == r,
|
||||||
(Self::Tuple(l), Self::Tuple(r)) => l == r,
|
(Self::Tuple(l), Self::Tuple(r)) => l == r,
|
||||||
(Self::Dict(l), Self::Dict(r)) => l == r,
|
(Self::Dict(l), Self::Dict(r)) => l == r,
|
||||||
|
(Self::Record(l), Self::Record(r)) => l == r,
|
||||||
(Self::Set(l), Self::Set(r)) => l == r,
|
(Self::Set(l), Self::Set(r)) => l == r,
|
||||||
|
(Self::Lambda(l), Self::Lambda(r)) => l == r,
|
||||||
(Self::Mono(l), Self::Mono(r)) => l == r,
|
(Self::Mono(l), Self::Mono(r)) => l == r,
|
||||||
(
|
(
|
||||||
Self::Proj { obj, attr },
|
Self::Proj { obj, attr },
|
||||||
|
@ -296,6 +361,8 @@ impl LimitedDisplay for TyParam {
|
||||||
write!(f, "}}")
|
write!(f, "}}")
|
||||||
}
|
}
|
||||||
Self::Dict(dict) => write!(f, "{dict}"),
|
Self::Dict(dict) => write!(f, "{dict}"),
|
||||||
|
Self::Record(rec) => write!(f, "{rec}"),
|
||||||
|
Self::Lambda(lambda) => write!(f, "{lambda}"),
|
||||||
Self::Tuple(tuple) => {
|
Self::Tuple(tuple) => {
|
||||||
write!(f, "(")?;
|
write!(f, "(")?;
|
||||||
for (i, t) in tuple.iter().enumerate() {
|
for (i, t) in tuple.iter().enumerate() {
|
||||||
|
@ -453,6 +520,23 @@ impl TryFrom<TyParam> for ValueObj {
|
||||||
}
|
}
|
||||||
Ok(ValueObj::Dict(vals))
|
Ok(ValueObj::Dict(vals))
|
||||||
}
|
}
|
||||||
|
TyParam::Record(rec) => {
|
||||||
|
let mut vals = dict! {};
|
||||||
|
for (k, v) in rec {
|
||||||
|
vals.insert(k, ValueObj::try_from(v)?);
|
||||||
|
}
|
||||||
|
Ok(ValueObj::Record(vals))
|
||||||
|
}
|
||||||
|
TyParam::Lambda(lambda) => {
|
||||||
|
// TODO: sig_t
|
||||||
|
let lambda = UserConstSubr::new(
|
||||||
|
"<lambda>".into(),
|
||||||
|
lambda.const_.sig.params,
|
||||||
|
lambda.const_.body,
|
||||||
|
Type::Never,
|
||||||
|
);
|
||||||
|
Ok(ValueObj::Subr(ConstSubr::User(lambda)))
|
||||||
|
}
|
||||||
TyParam::FreeVar(fv) if fv.is_linked() => ValueObj::try_from(fv.crack().clone()),
|
TyParam::FreeVar(fv) if fv.is_linked() => ValueObj::try_from(fv.crack().clone()),
|
||||||
TyParam::Type(t) => Ok(ValueObj::builtin_t(*t)),
|
TyParam::Type(t) => Ok(ValueObj::builtin_t(*t)),
|
||||||
TyParam::Value(v) => Ok(v),
|
TyParam::Value(v) => Ok(v),
|
||||||
|
@ -530,6 +614,11 @@ impl HasLevel for TyParam {
|
||||||
.min(v.level().unwrap_or(GENERIC_LEVEL))
|
.min(v.level().unwrap_or(GENERIC_LEVEL))
|
||||||
})
|
})
|
||||||
.min(),
|
.min(),
|
||||||
|
Self::Record(rec) => rec
|
||||||
|
.iter()
|
||||||
|
.map(|(_, v)| v.level().unwrap_or(GENERIC_LEVEL))
|
||||||
|
.min(),
|
||||||
|
Self::Lambda(lambda) => lambda.level(),
|
||||||
Self::Set(tps) => tps.iter().filter_map(|tp| tp.level()).min(),
|
Self::Set(tps) => tps.iter().filter_map(|tp| tp.level()).min(),
|
||||||
Self::Proj { obj, .. } => obj.level(),
|
Self::Proj { obj, .. } => obj.level(),
|
||||||
Self::App { args, .. } => args.iter().filter_map(|tp| tp.level()).min(),
|
Self::App { args, .. } => args.iter().filter_map(|tp| tp.level()).min(),
|
||||||
|
@ -549,6 +638,11 @@ impl HasLevel for TyParam {
|
||||||
v.set_level(level);
|
v.set_level(level);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Self::Record(rec) => {
|
||||||
|
for (_, v) in rec.iter() {
|
||||||
|
v.set_level(level);
|
||||||
|
}
|
||||||
|
}
|
||||||
Self::Array(tps) => {
|
Self::Array(tps) => {
|
||||||
for tp in tps {
|
for tp in tps {
|
||||||
tp.set_level(level);
|
tp.set_level(level);
|
||||||
|
@ -564,6 +658,7 @@ impl HasLevel for TyParam {
|
||||||
tp.set_level(level);
|
tp.set_level(level);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Self::Lambda(lambda) => lambda.set_level(level),
|
||||||
Self::UnaryOp { val, .. } => val.set_level(level),
|
Self::UnaryOp { val, .. } => val.set_level(level),
|
||||||
Self::BinOp { lhs, rhs, .. } => {
|
Self::BinOp { lhs, rhs, .. } => {
|
||||||
lhs.set_level(level);
|
lhs.set_level(level);
|
||||||
|
@ -600,6 +695,18 @@ impl StructuralEq for TyParam {
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
(Self::Record(l), Self::Record(r)) => {
|
||||||
|
for (l_field, l_val) in l.iter() {
|
||||||
|
if let Some((r_field, r_val)) = r.get_key_value(l_field) {
|
||||||
|
if l_field.vis != r_field.vis || !l_val.structural_eq(r_val) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
(Self::Set(l), Self::Set(r)) => {
|
(Self::Set(l), Self::Set(r)) => {
|
||||||
for l_val in l.iter() {
|
for l_val in l.iter() {
|
||||||
if r.get_by(l_val, |l, r| l.structural_eq(r)).is_none() {
|
if r.get_by(l_val, |l, r| l.structural_eq(r)).is_none() {
|
||||||
|
@ -608,6 +715,7 @@ impl StructuralEq for TyParam {
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
(Self::Lambda(l), Self::Lambda(r)) => l.structural_eq(r),
|
||||||
(
|
(
|
||||||
Self::Proj { obj, attr },
|
Self::Proj { obj, attr },
|
||||||
Self::Proj {
|
Self::Proj {
|
||||||
|
@ -663,13 +771,21 @@ impl TyParam {
|
||||||
Self::named_free_var(name.into(), crate::ty::free::GENERIC_LEVEL, constr)
|
Self::named_free_var(name.into(), crate::ty::free::GENERIC_LEVEL, constr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn proj<S: Into<Str>>(obj: TyParam, attr: S) -> Self {
|
pub fn proj<S: Into<Str>>(self, attr: S) -> Self {
|
||||||
Self::Proj {
|
Self::Proj {
|
||||||
obj: Box::new(obj),
|
obj: Box::new(self),
|
||||||
attr: attr.into(),
|
attr: attr.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn proj_call(self, attr_name: Str, args: Vec<TyParam>) -> Type {
|
||||||
|
Type::ProjCall {
|
||||||
|
lhs: Box::new(self),
|
||||||
|
attr_name,
|
||||||
|
args,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn free_var(level: usize, t: Type) -> Self {
|
pub fn free_var(level: usize, t: Type) -> Self {
|
||||||
let constraint = Constraint::new_type_of(t);
|
let constraint = Constraint::new_type_of(t);
|
||||||
Self::FreeVar(FreeTyParam::new_unbound(level, constraint))
|
Self::FreeVar(FreeTyParam::new_unbound(level, constraint))
|
||||||
|
@ -719,14 +835,6 @@ impl TyParam {
|
||||||
Self::Erased(Box::new(t))
|
Self::Erased(Box::new(t))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn proj_call(self, attr_name: Str, args: Vec<TyParam>) -> Type {
|
|
||||||
Type::ProjCall {
|
|
||||||
lhs: Box::new(self),
|
|
||||||
attr_name,
|
|
||||||
args,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if self: Ratio, Succ(self) => self+ε
|
// if self: Ratio, Succ(self) => self+ε
|
||||||
pub fn succ(self) -> Self {
|
pub fn succ(self) -> Self {
|
||||||
Self::app("Succ", vec![self])
|
Self::app("Succ", vec![self])
|
||||||
|
@ -813,6 +921,13 @@ impl TyParam {
|
||||||
Self::Dict(ts) => ts.iter().fold(set! {}, |acc, (k, v)| {
|
Self::Dict(ts) => ts.iter().fold(set! {}, |acc, (k, v)| {
|
||||||
acc.concat(k.qvars().concat(v.qvars()))
|
acc.concat(k.qvars().concat(v.qvars()))
|
||||||
}),
|
}),
|
||||||
|
Self::Record(rec) => rec
|
||||||
|
.iter()
|
||||||
|
.fold(set! {}, |acc, (_, v)| acc.concat(v.qvars())),
|
||||||
|
Self::Lambda(lambda) => lambda
|
||||||
|
.body
|
||||||
|
.iter()
|
||||||
|
.fold(set! {}, |acc, t| acc.concat(t.qvars())),
|
||||||
Self::UnaryOp { val, .. } => val.qvars(),
|
Self::UnaryOp { val, .. } => val.qvars(),
|
||||||
Self::BinOp { lhs, rhs, .. } => lhs.qvars().concat(rhs.qvars()),
|
Self::BinOp { lhs, rhs, .. } => lhs.qvars().concat(rhs.qvars()),
|
||||||
Self::App { args, .. } => args.iter().fold(set! {}, |acc, p| acc.concat(p.qvars())),
|
Self::App { args, .. } => args.iter().fold(set! {}, |acc, p| acc.concat(p.qvars())),
|
||||||
|
@ -833,9 +948,11 @@ impl TyParam {
|
||||||
}
|
}
|
||||||
Self::Type(t) => t.has_qvar(),
|
Self::Type(t) => t.has_qvar(),
|
||||||
Self::Proj { obj, .. } => obj.has_qvar(),
|
Self::Proj { obj, .. } => obj.has_qvar(),
|
||||||
Self::Array(ts) | Self::Tuple(ts) => ts.iter().any(|t| t.has_qvar()),
|
Self::Array(tps) | Self::Tuple(tps) => tps.iter().any(|tp| tp.has_qvar()),
|
||||||
Self::Set(ts) => ts.iter().any(|t| t.has_qvar()),
|
Self::Set(tps) => tps.iter().any(|tp| tp.has_qvar()),
|
||||||
Self::Dict(ts) => ts.iter().any(|(k, v)| k.has_qvar() || v.has_qvar()),
|
Self::Dict(tps) => tps.iter().any(|(k, v)| k.has_qvar() || v.has_qvar()),
|
||||||
|
Self::Record(rec) => rec.iter().any(|(_, tp)| tp.has_qvar()),
|
||||||
|
Self::Lambda(lambda) => lambda.body.iter().any(|tp| tp.has_qvar()),
|
||||||
Self::UnaryOp { val, .. } => val.has_qvar(),
|
Self::UnaryOp { val, .. } => val.has_qvar(),
|
||||||
Self::BinOp { lhs, rhs, .. } => lhs.has_qvar() || rhs.has_qvar(),
|
Self::BinOp { lhs, rhs, .. } => lhs.has_qvar() || rhs.has_qvar(),
|
||||||
Self::App { args, .. } => args.iter().any(|p| p.has_qvar()),
|
Self::App { args, .. } => args.iter().any(|p| p.has_qvar()),
|
||||||
|
@ -858,6 +975,8 @@ impl TyParam {
|
||||||
Self::Dict(ts) => ts
|
Self::Dict(ts) => ts
|
||||||
.iter()
|
.iter()
|
||||||
.any(|(k, v)| k.contains_var(name) || v.contains_var(name)),
|
.any(|(k, v)| k.contains_var(name) || v.contains_var(name)),
|
||||||
|
Self::Record(rec) => rec.iter().any(|(_, tp)| tp.contains_var(name)),
|
||||||
|
Self::Lambda(lambda) => lambda.body.iter().any(|tp| tp.contains_var(name)),
|
||||||
Self::UnaryOp { val, .. } => val.contains_var(name),
|
Self::UnaryOp { val, .. } => val.contains_var(name),
|
||||||
Self::BinOp { lhs, rhs, .. } => lhs.contains_var(name) || rhs.contains_var(name),
|
Self::BinOp { lhs, rhs, .. } => lhs.contains_var(name) || rhs.contains_var(name),
|
||||||
Self::App { args, .. } => args.iter().any(|p| p.contains_var(name)),
|
Self::App { args, .. } => args.iter().any(|p| p.contains_var(name)),
|
||||||
|
@ -885,6 +1004,8 @@ impl TyParam {
|
||||||
Self::Dict(kv) => kv
|
Self::Dict(kv) => kv
|
||||||
.iter()
|
.iter()
|
||||||
.any(|(k, v)| k.has_unbound_var() || v.has_unbound_var()),
|
.any(|(k, v)| k.has_unbound_var() || v.has_unbound_var()),
|
||||||
|
Self::Record(rec) => rec.iter().any(|(_, v)| v.has_unbound_var()),
|
||||||
|
Self::Lambda(lambda) => lambda.body.iter().any(|t| t.has_unbound_var()),
|
||||||
Self::UnaryOp { val, .. } => val.has_unbound_var(),
|
Self::UnaryOp { val, .. } => val.has_unbound_var(),
|
||||||
Self::BinOp { lhs, rhs, .. } => lhs.has_unbound_var() || rhs.has_unbound_var(),
|
Self::BinOp { lhs, rhs, .. } => lhs.has_unbound_var() || rhs.has_unbound_var(),
|
||||||
Self::App { args, .. } => args.iter().any(|p| p.has_unbound_var()),
|
Self::App { args, .. } => args.iter().any(|p| p.has_unbound_var()),
|
||||||
|
|
|
@ -164,6 +164,21 @@ impl IntersectionTypeObj {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct StructuralTypeObj {
|
||||||
|
pub t: Type,
|
||||||
|
pub base: Box<TypeObj>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StructuralTypeObj {
|
||||||
|
pub fn new(t: Type, base: TypeObj) -> Self {
|
||||||
|
Self {
|
||||||
|
t,
|
||||||
|
base: Box::new(base),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct PatchObj {
|
pub struct PatchObj {
|
||||||
pub t: Type,
|
pub t: Type,
|
||||||
|
@ -187,7 +202,7 @@ pub enum GenTypeObj {
|
||||||
Subclass(InheritedTypeObj),
|
Subclass(InheritedTypeObj),
|
||||||
Trait(TraitTypeObj),
|
Trait(TraitTypeObj),
|
||||||
Subtrait(SubsumedTypeObj),
|
Subtrait(SubsumedTypeObj),
|
||||||
StructuralTrait(TraitTypeObj),
|
Structural(StructuralTypeObj),
|
||||||
Union(UnionTypeObj),
|
Union(UnionTypeObj),
|
||||||
Intersection(IntersectionTypeObj),
|
Intersection(IntersectionTypeObj),
|
||||||
Patch(PatchObj),
|
Patch(PatchObj),
|
||||||
|
@ -238,13 +253,17 @@ impl GenTypeObj {
|
||||||
GenTypeObj::Intersection(IntersectionTypeObj::new(t, lhs, rhs))
|
GenTypeObj::Intersection(IntersectionTypeObj::new(t, lhs, rhs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn structural(t: Type, type_: TypeObj) -> Self {
|
||||||
|
GenTypeObj::Structural(StructuralTypeObj::new(t, type_))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn base_or_sup(&self) -> Option<&TypeObj> {
|
pub fn base_or_sup(&self) -> Option<&TypeObj> {
|
||||||
match self {
|
match self {
|
||||||
Self::Class(class) => class.base.as_ref().map(AsRef::as_ref),
|
Self::Class(class) => class.base.as_ref().map(AsRef::as_ref),
|
||||||
Self::Subclass(subclass) => Some(subclass.sup.as_ref()),
|
Self::Subclass(subclass) => Some(subclass.sup.as_ref()),
|
||||||
Self::Trait(trait_) => Some(trait_.requires.as_ref()),
|
Self::Trait(trait_) => Some(trait_.requires.as_ref()),
|
||||||
Self::Subtrait(subtrait) => Some(subtrait.sup.as_ref()),
|
Self::Subtrait(subtrait) => Some(subtrait.sup.as_ref()),
|
||||||
Self::StructuralTrait(trait_) => Some(trait_.requires.as_ref()),
|
Self::Structural(type_) => Some(type_.base.as_ref()),
|
||||||
Self::Patch(patch) => Some(patch.base.as_ref()),
|
Self::Patch(patch) => Some(patch.base.as_ref()),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
@ -281,8 +300,9 @@ impl GenTypeObj {
|
||||||
pub fn meta_type(&self) -> Type {
|
pub fn meta_type(&self) -> Type {
|
||||||
match self {
|
match self {
|
||||||
Self::Class(_) | Self::Subclass(_) => Type::ClassType,
|
Self::Class(_) | Self::Subclass(_) => Type::ClassType,
|
||||||
Self::Trait(_) | Self::Subtrait(_) | Self::StructuralTrait(_) => Type::TraitType,
|
Self::Trait(_) | Self::Subtrait(_) => Type::TraitType,
|
||||||
Self::Patch(_) => Type::Patch,
|
Self::Patch(_) => Type::Patch,
|
||||||
|
Self::Structural(_) => Type::Type,
|
||||||
_ => Type::Type,
|
_ => Type::Type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -293,7 +313,7 @@ impl GenTypeObj {
|
||||||
Self::Subclass(subclass) => &subclass.t,
|
Self::Subclass(subclass) => &subclass.t,
|
||||||
Self::Trait(trait_) => &trait_.t,
|
Self::Trait(trait_) => &trait_.t,
|
||||||
Self::Subtrait(subtrait) => &subtrait.t,
|
Self::Subtrait(subtrait) => &subtrait.t,
|
||||||
Self::StructuralTrait(trait_) => &trait_.t,
|
Self::Structural(struct_) => &struct_.t,
|
||||||
Self::Union(union_) => &union_.t,
|
Self::Union(union_) => &union_.t,
|
||||||
Self::Intersection(intersection) => &intersection.t,
|
Self::Intersection(intersection) => &intersection.t,
|
||||||
Self::Patch(patch) => &patch.t,
|
Self::Patch(patch) => &patch.t,
|
||||||
|
@ -306,7 +326,7 @@ impl GenTypeObj {
|
||||||
Self::Subclass(subclass) => &mut subclass.t,
|
Self::Subclass(subclass) => &mut subclass.t,
|
||||||
Self::Trait(trait_) => &mut trait_.t,
|
Self::Trait(trait_) => &mut trait_.t,
|
||||||
Self::Subtrait(subtrait) => &mut subtrait.t,
|
Self::Subtrait(subtrait) => &mut subtrait.t,
|
||||||
Self::StructuralTrait(trait_) => &mut trait_.t,
|
Self::Structural(struct_) => &mut struct_.t,
|
||||||
Self::Union(union_) => &mut union_.t,
|
Self::Union(union_) => &mut union_.t,
|
||||||
Self::Intersection(intersection) => &mut intersection.t,
|
Self::Intersection(intersection) => &mut intersection.t,
|
||||||
Self::Patch(patch) => &mut patch.t,
|
Self::Patch(patch) => &mut patch.t,
|
||||||
|
@ -319,7 +339,7 @@ impl GenTypeObj {
|
||||||
Self::Subclass(subclass) => subclass.t,
|
Self::Subclass(subclass) => subclass.t,
|
||||||
Self::Trait(trait_) => trait_.t,
|
Self::Trait(trait_) => trait_.t,
|
||||||
Self::Subtrait(subtrait) => subtrait.t,
|
Self::Subtrait(subtrait) => subtrait.t,
|
||||||
Self::StructuralTrait(trait_) => trait_.t,
|
Self::Structural(struct_) => struct_.t,
|
||||||
Self::Union(union_) => union_.t,
|
Self::Union(union_) => union_.t,
|
||||||
Self::Intersection(intersection) => intersection.t,
|
Self::Intersection(intersection) => intersection.t,
|
||||||
Self::Patch(patch) => patch.t,
|
Self::Patch(patch) => patch.t,
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::path::PathBuf;
|
||||||
|
|
||||||
use erg_common::error::Location;
|
use erg_common::error::Location;
|
||||||
use erg_common::set::Set;
|
use erg_common::set::Set;
|
||||||
use erg_common::vis::Visibility;
|
use erg_common::vis::{Field, Visibility};
|
||||||
use erg_common::Str;
|
use erg_common::Str;
|
||||||
use Visibility::*;
|
use Visibility::*;
|
||||||
|
|
||||||
|
@ -243,4 +243,23 @@ impl VarInfo {
|
||||||
};
|
};
|
||||||
Self::new(t, Immutable, Private, kind, None, None, None, def_loc)
|
Self::new(t, Immutable, Private, kind, None, None, None, def_loc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn instance_attr(field: Field, t: Type, impl_of: Option<Type>) -> Self {
|
||||||
|
let muty = if field.is_const() {
|
||||||
|
Mutability::Const
|
||||||
|
} else {
|
||||||
|
Mutability::Immutable
|
||||||
|
};
|
||||||
|
let kind = VarKind::Declared;
|
||||||
|
Self::new(
|
||||||
|
t,
|
||||||
|
muty,
|
||||||
|
field.vis,
|
||||||
|
kind,
|
||||||
|
None,
|
||||||
|
impl_of,
|
||||||
|
None,
|
||||||
|
AbsLocation::unknown(),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -884,6 +884,14 @@ impl Record {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_normal(l_brace: Token, r_brace: Token, attrs: RecordAttrs) -> Self {
|
||||||
|
Self::Normal(NormalRecord {
|
||||||
|
l_brace,
|
||||||
|
r_brace,
|
||||||
|
attrs,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn empty(l_brace: Token, r_brace: Token) -> Self {
|
pub fn empty(l_brace: Token, r_brace: Token) -> Self {
|
||||||
Self::Normal(NormalRecord {
|
Self::Normal(NormalRecord {
|
||||||
l_brace,
|
l_brace,
|
||||||
|
@ -1528,6 +1536,150 @@ impl ConstTuple {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct ConstBlock(Vec<ConstExpr>);
|
||||||
|
|
||||||
|
impl NestedDisplay for ConstBlock {
|
||||||
|
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
||||||
|
fmt_lines(self.0.iter(), f, _level)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_display_from_nested!(ConstBlock);
|
||||||
|
|
||||||
|
impl Locational for ConstBlock {
|
||||||
|
fn loc(&self) -> Location {
|
||||||
|
if self.0.is_empty() {
|
||||||
|
Location::Unknown
|
||||||
|
} else {
|
||||||
|
Location::concat(self.0.first().unwrap(), self.0.last().unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_stream!(ConstBlock, ConstExpr);
|
||||||
|
|
||||||
|
impl ConstBlock {
|
||||||
|
pub fn downcast(self) -> Block {
|
||||||
|
Block::new(self.0.into_iter().map(|e| e.downcast()).collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct ConstDefBody {
|
||||||
|
pub op: Token,
|
||||||
|
pub block: ConstBlock,
|
||||||
|
pub id: DefId,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_locational!(ConstDefBody, lossy op, block);
|
||||||
|
|
||||||
|
impl ConstDefBody {
|
||||||
|
pub const fn new(op: Token, block: ConstBlock, id: DefId) -> Self {
|
||||||
|
Self { op, block, id }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn downcast(self) -> DefBody {
|
||||||
|
DefBody::new(self.op, self.block.downcast(), self.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct ConstDef {
|
||||||
|
pub ident: ConstIdentifier,
|
||||||
|
pub body: ConstDefBody,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NestedDisplay for ConstDef {
|
||||||
|
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
||||||
|
write!(f, "{} = {}", self.ident, self.body.block)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_display_from_nested!(ConstDef);
|
||||||
|
impl_locational!(ConstDef, ident, body);
|
||||||
|
|
||||||
|
impl ConstDef {
|
||||||
|
pub const fn new(ident: ConstIdentifier, body: ConstDefBody) -> Self {
|
||||||
|
Self { ident, body }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn downcast(self) -> Def {
|
||||||
|
Def::new(Signature::new_var(self.ident), self.body.downcast())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct ConstLambda {
|
||||||
|
pub sig: Box<LambdaSignature>,
|
||||||
|
pub op: Token,
|
||||||
|
pub body: ConstBlock,
|
||||||
|
pub id: DefId,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NestedDisplay for ConstLambda {
|
||||||
|
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
||||||
|
write!(f, "({}) {} {}", self.sig, self.op.content, self.body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_display_from_nested!(ConstLambda);
|
||||||
|
impl_locational!(ConstLambda, sig, body);
|
||||||
|
|
||||||
|
impl ConstLambda {
|
||||||
|
pub fn new(sig: LambdaSignature, op: Token, body: ConstBlock, id: DefId) -> Self {
|
||||||
|
Self {
|
||||||
|
sig: Box::new(sig),
|
||||||
|
op,
|
||||||
|
body,
|
||||||
|
id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn downcast(self) -> Lambda {
|
||||||
|
Lambda::new(*self.sig, self.op, self.body.downcast(), self.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct ConstRecord {
|
||||||
|
pub l_brace: Token,
|
||||||
|
pub r_brace: Token,
|
||||||
|
pub attrs: Vec<ConstDef>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NestedDisplay for ConstRecord {
|
||||||
|
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result {
|
||||||
|
write!(f, "{{{}}}", fmt_vec_split_with(&self.attrs, "; "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Locational for ConstRecord {
|
||||||
|
fn loc(&self) -> Location {
|
||||||
|
Location::concat(&self.l_brace, &self.r_brace)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_display_from_nested!(ConstRecord);
|
||||||
|
|
||||||
|
impl ConstRecord {
|
||||||
|
pub const fn new(l_brace: Token, r_brace: Token, attrs: Vec<ConstDef>) -> Self {
|
||||||
|
Self {
|
||||||
|
l_brace,
|
||||||
|
r_brace,
|
||||||
|
attrs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn downcast(self) -> Record {
|
||||||
|
Record::Normal(NormalRecord::new(
|
||||||
|
self.l_brace,
|
||||||
|
self.r_brace,
|
||||||
|
self.attrs.into_iter().map(|d| d.downcast()).collect(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct ConstBinOp {
|
pub struct ConstBinOp {
|
||||||
pub op: Token,
|
pub op: Token,
|
||||||
|
@ -1633,13 +1785,16 @@ pub enum ConstExpr {
|
||||||
Set(ConstSet),
|
Set(ConstSet),
|
||||||
Dict(ConstDict),
|
Dict(ConstDict),
|
||||||
Tuple(ConstTuple),
|
Tuple(ConstTuple),
|
||||||
|
Record(ConstRecord),
|
||||||
|
Def(ConstDef),
|
||||||
|
Lambda(ConstLambda),
|
||||||
BinOp(ConstBinOp),
|
BinOp(ConstBinOp),
|
||||||
UnaryOp(ConstUnaryOp),
|
UnaryOp(ConstUnaryOp),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_nested_display_for_chunk_enum!(ConstExpr; Lit, Accessor, App, Array, Set, Dict, Tuple, BinOp, UnaryOp, Erased, Set);
|
impl_nested_display_for_chunk_enum!(ConstExpr; Lit, Accessor, App, Array, Set, Dict, Tuple, Record, BinOp, UnaryOp, Def, Lambda, Erased, Set);
|
||||||
impl_display_from_nested!(ConstExpr);
|
impl_display_from_nested!(ConstExpr);
|
||||||
impl_locational_for_enum!(ConstExpr; Lit, Accessor, App, Array, Set Dict, Tuple, BinOp, UnaryOp, Erased, Set);
|
impl_locational_for_enum!(ConstExpr; Lit, Accessor, App, Array, Set, Dict, Tuple, Record, BinOp, UnaryOp, Def, Lambda, Erased, Set);
|
||||||
|
|
||||||
impl ConstExpr {
|
impl ConstExpr {
|
||||||
pub fn need_to_be_closed(&self) -> bool {
|
pub fn need_to_be_closed(&self) -> bool {
|
||||||
|
|
|
@ -51,6 +51,12 @@ impl Desugarer {
|
||||||
module
|
module
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn desugar_simple_expr(expr: Expr) -> Expr {
|
||||||
|
let expr = Self::rec_desugar_shortened_record(expr);
|
||||||
|
let expr = Self::rec_desugar_lambda_pattern(&mut Desugarer {}, expr);
|
||||||
|
Self::rec_desugar_acc(expr)
|
||||||
|
}
|
||||||
|
|
||||||
fn desugar_all_chunks(module: Module, desugar: impl Fn(Expr) -> Expr) -> Module {
|
fn desugar_all_chunks(module: Module, desugar: impl Fn(Expr) -> Expr) -> Module {
|
||||||
module.into_iter().map(desugar).collect()
|
module.into_iter().map(desugar).collect()
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ use erg_common::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::ast::*;
|
use crate::ast::*;
|
||||||
|
use crate::desugar::Desugarer;
|
||||||
use crate::error::{ParseError, ParseErrors, ParseResult, ParserRunnerError, ParserRunnerErrors};
|
use crate::error::{ParseError, ParseErrors, ParseResult, ParserRunnerError, ParserRunnerErrors};
|
||||||
use crate::lex::Lexer;
|
use crate::lex::Lexer;
|
||||||
use crate::token::{Token, TokenCategory, TokenKind, TokenStream};
|
use crate::token::{Token, TokenCategory, TokenKind, TokenStream};
|
||||||
|
@ -1169,6 +1170,7 @@ impl Parser {
|
||||||
let lhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_)));
|
let lhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_)));
|
||||||
let t_spec_as_expr = self
|
let t_spec_as_expr = self
|
||||||
.try_reduce_expr(false, false, false, false)
|
.try_reduce_expr(false, false, false, false)
|
||||||
|
.map(Desugarer::desugar_simple_expr)
|
||||||
.map_err(|_| self.stack_dec(fn_name!()))?;
|
.map_err(|_| self.stack_dec(fn_name!()))?;
|
||||||
let t_spec = Self::expr_to_type_spec(t_spec_as_expr.clone())
|
let t_spec = Self::expr_to_type_spec(t_spec_as_expr.clone())
|
||||||
.map_err(|e| self.errs.push(e))?;
|
.map_err(|e| self.errs.push(e))?;
|
||||||
|
@ -1440,6 +1442,7 @@ impl Parser {
|
||||||
let lhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_)));
|
let lhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_)));
|
||||||
let t_spec_as_expr = self
|
let t_spec_as_expr = self
|
||||||
.try_reduce_expr(false, in_type_args, in_brace, false)
|
.try_reduce_expr(false, in_type_args, in_brace, false)
|
||||||
|
.map(Desugarer::desugar_simple_expr)
|
||||||
.map_err(|_| self.stack_dec(fn_name!()))?;
|
.map_err(|_| self.stack_dec(fn_name!()))?;
|
||||||
let t_spec = Self::expr_to_type_spec(t_spec_as_expr.clone())
|
let t_spec = Self::expr_to_type_spec(t_spec_as_expr.clone())
|
||||||
.map_err(|e| self.errs.push(e))?;
|
.map_err(|e| self.errs.push(e))?;
|
||||||
|
|
|
@ -109,10 +109,34 @@ impl Parser {
|
||||||
let args = ConstArgs::pos_only(const_pos_args, paren);
|
let args = ConstArgs::pos_only(const_pos_args, paren);
|
||||||
Ok(ConstExpr::App(ConstApp::new(acc, args)))
|
Ok(ConstExpr::App(ConstApp::new(acc, args)))
|
||||||
}
|
}
|
||||||
// TODO: App, Record,
|
Expr::Def(def) => Self::validate_const_def(def).map(ConstExpr::Def),
|
||||||
|
Expr::Lambda(lambda) => {
|
||||||
|
let body = Self::validate_const_block(lambda.body)?;
|
||||||
|
let lambda = ConstLambda::new(lambda.sig, lambda.op, body, lambda.id);
|
||||||
|
Ok(ConstExpr::Lambda(lambda))
|
||||||
|
}
|
||||||
|
Expr::Record(rec) => {
|
||||||
|
let rec = match rec {
|
||||||
|
Record::Normal(rec) => rec,
|
||||||
|
Record::Mixed(_) => unreachable!(),
|
||||||
|
};
|
||||||
|
let mut const_fields = vec![];
|
||||||
|
for attr in rec.attrs.into_iter() {
|
||||||
|
const_fields.push(Self::validate_const_def(attr)?);
|
||||||
|
}
|
||||||
|
Ok(ConstExpr::Record(ConstRecord::new(
|
||||||
|
rec.l_brace,
|
||||||
|
rec.r_brace,
|
||||||
|
const_fields,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
// TODO: Lambda, ...
|
||||||
other => Err(ParseError::syntax_error(
|
other => Err(ParseError::syntax_error(
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
other.loc(),
|
{
|
||||||
|
erg_common::log!(err "{other}");
|
||||||
|
other.loc()
|
||||||
|
},
|
||||||
switch_lang!(
|
switch_lang!(
|
||||||
"japanese" => "この式はコンパイル時計算できないため、型引数には使用できません",
|
"japanese" => "この式はコンパイル時計算できないため、型引数には使用できません",
|
||||||
"simplified_chinese" => "此表达式在编译时不可计算,因此不能用作类型参数",
|
"simplified_chinese" => "此表达式在编译时不可计算,因此不能用作类型参数",
|
||||||
|
@ -124,6 +148,21 @@ impl Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn validate_const_block(block: Block) -> Result<ConstBlock, ParseError> {
|
||||||
|
let mut const_block = vec![];
|
||||||
|
for expr in block.into_iter() {
|
||||||
|
let const_expr = Self::validate_const_expr(expr)?;
|
||||||
|
const_block.push(const_expr);
|
||||||
|
}
|
||||||
|
Ok(ConstBlock::new(const_block))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_const_def(def: Def) -> Result<ConstDef, ParseError> {
|
||||||
|
let block = Self::validate_const_block(def.body.block)?;
|
||||||
|
let body = ConstDefBody::new(def.body.op, block, def.body.id);
|
||||||
|
Ok(ConstDef::new(def.sig.ident().unwrap().clone(), body))
|
||||||
|
}
|
||||||
|
|
||||||
fn ident_to_type_spec(ident: Identifier) -> SimpleTypeSpec {
|
fn ident_to_type_spec(ident: Identifier) -> SimpleTypeSpec {
|
||||||
SimpleTypeSpec::new(ident, ConstArgs::empty())
|
SimpleTypeSpec::new(ident, ConstArgs::empty())
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,13 @@
|
||||||
|
|
||||||
## debug
|
## debug
|
||||||
|
|
||||||
Enter debug mode. As a result, the behavior inside Erg is sequentially displayed in the log.
|
Enter debug mode. As a result, the behavior inside Erg is sequentially displayed in the log. Also, enable `backtrace_on_stack_overflow`.
|
||||||
Independent of Rust's `debug_assertions` flag.
|
Independent of Rust's `debug_assertions` flag.
|
||||||
|
|
||||||
|
## backtrace
|
||||||
|
|
||||||
|
Enable only `backtrace_on_stack_overflow`.
|
||||||
|
|
||||||
## japanese
|
## japanese
|
||||||
|
|
||||||
Set the system language to Japanese.
|
Set the system language to Japanese.
|
||||||
|
|
|
@ -4,9 +4,13 @@
|
||||||
|
|
||||||
## debug
|
## debug
|
||||||
|
|
||||||
デバッグモードにする。これにより、Erg内部での挙動が逐次ログ表示される。
|
デバッグモードにする。これにより、Erg内部での挙動が逐次ログ表示される。また、`backtrace_on_stack_overflow`を有効化する。
|
||||||
Rustの`debug_assertions`フラグとは独立。
|
Rustの`debug_assertions`フラグとは独立。
|
||||||
|
|
||||||
|
## backtrace
|
||||||
|
|
||||||
|
`backtrace_on_stack_overflow`だけを有効化する。
|
||||||
|
|
||||||
## japanese
|
## japanese
|
||||||
|
|
||||||
システム言語を日本語にする。
|
システム言語を日本語にする。
|
||||||
|
|
31
examples/structural.er
Normal file
31
examples/structural.er
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
name n: Structural { .name = Str } = n.name
|
||||||
|
|
||||||
|
C = Class { .name = Str }
|
||||||
|
C.
|
||||||
|
new name = C::__new__ { .name = name }
|
||||||
|
D = Class { .name = Str; .id = Nat }
|
||||||
|
D.
|
||||||
|
new name, id = D::__new__ { .name = name; .id = id }
|
||||||
|
|
||||||
|
c = C.new "foo"
|
||||||
|
d = D.new "bar", 1
|
||||||
|
|
||||||
|
assert name(c) == "foo"
|
||||||
|
assert name(d) == "bar"
|
||||||
|
|
||||||
|
inner|T: Type| x: Structural { .inner = T } = x.inner
|
||||||
|
|
||||||
|
E = Class { .inner = Int }
|
||||||
|
E.
|
||||||
|
new inner = E::__new__ { .inner = inner }
|
||||||
|
__add__ self, other: E = E::__new__ { .inner = self.inner + other.inner }
|
||||||
|
|
||||||
|
e = E.new 1
|
||||||
|
|
||||||
|
assert inner(e) == 1
|
||||||
|
|
||||||
|
add|T: Type, U: Type, V: Type| x: Structural({ .__add__ = (self: T, other: U) -> V }), other: U =
|
||||||
|
x.__add__(other)
|
||||||
|
|
||||||
|
_ = add 1, 2
|
||||||
|
_ = add e, e
|
32
tests/should_err/structural.er
Normal file
32
tests/should_err/structural.er
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
name n: Structural { .name = Str } = n.name
|
||||||
|
|
||||||
|
C = Class()
|
||||||
|
D = Class { .name = Int; .id = Nat }
|
||||||
|
D.
|
||||||
|
__add__ self, _ = 1
|
||||||
|
new name, id = D::__new__ { .name = name; .id = id }
|
||||||
|
|
||||||
|
c = C.new()
|
||||||
|
d = D.new 1, 2
|
||||||
|
|
||||||
|
print! name(1) # ERR
|
||||||
|
print! name(c) # ERR
|
||||||
|
print! name(d) # ERR
|
||||||
|
|
||||||
|
inner|T: Type| x: Structural { .inner = T } = x.inner
|
||||||
|
|
||||||
|
E = Class { .inner = Int }
|
||||||
|
E.
|
||||||
|
new inner = E::__new__ { .inner = inner }
|
||||||
|
__add__ self, other: E = E::__new__ { .inner = self.inner + other.inner }
|
||||||
|
|
||||||
|
e = E.new 1
|
||||||
|
|
||||||
|
print! inner(1) # ERR
|
||||||
|
assert inner(e) == "a" # ERR
|
||||||
|
|
||||||
|
add|T: Type, U: Type, V: Type| x: Structural({ .__add__ = (self: T, other: U) -> V }), other: U =
|
||||||
|
x.__add__(other)
|
||||||
|
|
||||||
|
_ = add 1, "a" # ERR
|
||||||
|
_ = add e, 1 # ERR
|
|
@ -156,6 +156,11 @@ fn exec_return() -> Result<(), ()> {
|
||||||
expect_success("tests/should_ok/return.er")
|
expect_success("tests/should_ok/return.er")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exec_structural() -> Result<(), ()> {
|
||||||
|
expect_success("examples/structural.er")
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exec_subtyping() -> Result<(), ()> {
|
fn exec_subtyping() -> Result<(), ()> {
|
||||||
expect_success("tests/should_ok/subtyping.er")
|
expect_success("tests/should_ok/subtyping.er")
|
||||||
|
@ -246,6 +251,11 @@ fn exec_side_effect() -> Result<(), ()> {
|
||||||
expect_failure("examples/side_effect.er", 4)
|
expect_failure("examples/side_effect.er", 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exec_structural_err() -> Result<(), ()> {
|
||||||
|
expect_failure("tests/should_err/structural.er", 7)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exec_subtyping_err() -> Result<(), ()> {
|
fn exec_subtyping_err() -> Result<(), ()> {
|
||||||
expect_failure("tests/should_err/subtyping.er", 6)
|
expect_failure("tests/should_err/subtyping.er", 6)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue