mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-28 04:09:05 +00:00
feat: polymorphic type class members
This commit is contained in:
parent
f65e3acaf3
commit
e3b479ebf7
12 changed files with 247 additions and 48 deletions
|
@ -303,8 +303,28 @@ impl Context {
|
||||||
|
|
||||||
fn call(&self, subr: ConstSubr, args: ValueArgs, loc: Location) -> EvalResult<ValueObj> {
|
fn call(&self, subr: ConstSubr, args: ValueArgs, loc: Location) -> EvalResult<ValueObj> {
|
||||||
match subr {
|
match subr {
|
||||||
ConstSubr::User(_user) => {
|
ConstSubr::User(user) => {
|
||||||
feature_error!(self, loc, "calling user-defined subroutines").map_err(Into::into)
|
// HACK: should avoid cloning
|
||||||
|
let mut subr_ctx = Context::instant(
|
||||||
|
user.name.clone(),
|
||||||
|
self.cfg.clone(),
|
||||||
|
2,
|
||||||
|
self.shared.clone(),
|
||||||
|
self.clone(),
|
||||||
|
);
|
||||||
|
// TODO: var_args
|
||||||
|
for (arg, sig) in args
|
||||||
|
.pos_args
|
||||||
|
.into_iter()
|
||||||
|
.zip(user.params.non_defaults.iter())
|
||||||
|
{
|
||||||
|
let name = VarName::from_str(sig.inspect().unwrap().clone());
|
||||||
|
subr_ctx.consts.insert(name, arg);
|
||||||
|
}
|
||||||
|
for (name, arg) in args.kw_args.into_iter() {
|
||||||
|
subr_ctx.consts.insert(VarName::from_str(name), arg);
|
||||||
|
}
|
||||||
|
subr_ctx.eval_const_block(&user.block())
|
||||||
}
|
}
|
||||||
ConstSubr::Builtin(builtin) => builtin.call(args, self).map_err(|mut e| {
|
ConstSubr::Builtin(builtin) => builtin.call(args, self).map_err(|mut e| {
|
||||||
if e.0.loc.is_unknown() {
|
if e.0.loc.is_unknown() {
|
||||||
|
@ -316,6 +336,16 @@ impl Context {
|
||||||
self.caused_by(),
|
self.caused_by(),
|
||||||
))
|
))
|
||||||
}),
|
}),
|
||||||
|
ConstSubr::Gen(gen) => gen.call(args, self).map_err(|mut e| {
|
||||||
|
if e.0.loc.is_unknown() {
|
||||||
|
e.0.loc = loc;
|
||||||
|
}
|
||||||
|
EvalErrors::from(EvalError::new(
|
||||||
|
*e.0,
|
||||||
|
self.cfg.input.clone(),
|
||||||
|
self.caused_by(),
|
||||||
|
))
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,9 @@ impl Generalizer {
|
||||||
fn generalize_tp(&mut self, free: TyParam, uninit: bool) -> TyParam {
|
fn generalize_tp(&mut self, free: TyParam, uninit: bool) -> TyParam {
|
||||||
match free {
|
match free {
|
||||||
TyParam::Type(t) => TyParam::t(self.generalize_t(*t, uninit)),
|
TyParam::Type(t) => TyParam::t(self.generalize_t(*t, uninit)),
|
||||||
|
TyParam::Value(ValueObj::Type(t)) => {
|
||||||
|
TyParam::t(self.generalize_t(t.into_typ(), uninit))
|
||||||
|
}
|
||||||
TyParam::FreeVar(fv) if fv.is_generalized() => TyParam::FreeVar(fv),
|
TyParam::FreeVar(fv) if fv.is_generalized() => TyParam::FreeVar(fv),
|
||||||
TyParam::FreeVar(fv) if fv.is_linked() => {
|
TyParam::FreeVar(fv) if fv.is_linked() => {
|
||||||
self.generalize_tp(fv.crack().clone(), uninit)
|
self.generalize_tp(fv.crack().clone(), uninit)
|
||||||
|
@ -122,7 +125,7 @@ impl Generalizer {
|
||||||
TyParam::unary(op, val)
|
TyParam::unary(op, val)
|
||||||
}
|
}
|
||||||
other if other.has_no_unbound_var() => other,
|
other if other.has_no_unbound_var() => other,
|
||||||
other => todo!("{other}"),
|
other => todo!("{other:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1181,7 +1181,7 @@ impl Context {
|
||||||
);
|
);
|
||||||
/* Array */
|
/* Array */
|
||||||
let mut array_ =
|
let mut array_ =
|
||||||
Self::builtin_poly_class(ARRAY, vec![PS::t_nd(TY_T), PS::named_nd(TY_N, Nat)], 10);
|
Self::builtin_poly_class(ARRAY, vec![PS::t_nd(TY_T), PS::default(TY_N, Nat)], 10);
|
||||||
array_.register_superclass(mono(GENERIC_ARRAY), &generic_array);
|
array_.register_superclass(mono(GENERIC_ARRAY), &generic_array);
|
||||||
array_
|
array_
|
||||||
.register_marker_trait(self, poly(OUTPUT, vec![ty_tp(T.clone())]))
|
.register_marker_trait(self, poly(OUTPUT, vec![ty_tp(T.clone())]))
|
||||||
|
|
|
@ -33,7 +33,9 @@ use crate::module::SharedCompilerResource;
|
||||||
use crate::ty::constructors::*;
|
use crate::ty::constructors::*;
|
||||||
use crate::ty::free::Constraint;
|
use crate::ty::free::Constraint;
|
||||||
use crate::ty::value::ValueObj;
|
use crate::ty::value::ValueObj;
|
||||||
use crate::ty::{BuiltinConstSubr, ConstSubr, ParamTy, Predicate, TyParam, Type, Visibility};
|
use crate::ty::{
|
||||||
|
BuiltinConstSubr, ConstSubr, GenConstSubr, ParamTy, Predicate, TyParam, Type, Visibility,
|
||||||
|
};
|
||||||
use crate::varinfo::{AbsLocation, Mutability, VarInfo, VarKind};
|
use crate::varinfo::{AbsLocation, Mutability, VarInfo, VarKind};
|
||||||
use Mutability::*;
|
use Mutability::*;
|
||||||
use ParamSpec as PS;
|
use ParamSpec as PS;
|
||||||
|
@ -780,23 +782,48 @@ impl Context {
|
||||||
muty: Mutability,
|
muty: Mutability,
|
||||||
py_name: Option<&'static str>,
|
py_name: Option<&'static str>,
|
||||||
) {
|
) {
|
||||||
// FIXME: panic
|
|
||||||
if let Some((_, root_ctx)) = self.poly_types.get_mut(&t.local_name()) {
|
if let Some((_, root_ctx)) = self.poly_types.get_mut(&t.local_name()) {
|
||||||
root_ctx.methods_list.push((ClassDefType::Simple(t), ctx));
|
root_ctx.methods_list.push((ClassDefType::Simple(t), ctx));
|
||||||
} else {
|
} else {
|
||||||
let val = match ctx.kind {
|
let ret_val = match ctx.kind {
|
||||||
ContextKind::Class => ValueObj::builtin_class(t.clone()),
|
ContextKind::Class => ValueObj::builtin_class(t.clone()),
|
||||||
ContextKind::Trait => ValueObj::builtin_trait(t.clone()),
|
ContextKind::Trait => ValueObj::builtin_trait(t.clone()),
|
||||||
_ => ValueObj::builtin_type(t.clone()),
|
_ => ValueObj::builtin_type(t.clone()),
|
||||||
};
|
};
|
||||||
|
let qual_name = t.qual_name();
|
||||||
let name = VarName::from_str(t.local_name());
|
let name = VarName::from_str(t.local_name());
|
||||||
// e.g Array!: |T, N|(_: {T}, _: {N}) -> {Array!(T, N)}
|
// e.g Array!: |T, N|(_: {T}, _:= {N}) -> {Array!(T, N)}
|
||||||
let params = t
|
let nd_params = ctx
|
||||||
.typarams()
|
.params_spec
|
||||||
|
.iter()
|
||||||
|
.filter_map(|ps| (!ps.has_default()).then_some(ParamTy::from(ps)))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let num_nd = nd_params.len();
|
||||||
|
let d_params = ctx
|
||||||
|
.params_spec
|
||||||
|
.iter()
|
||||||
|
.filter_map(|ps| ps.has_default().then_some(ParamTy::from(ps)))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let num_d = d_params.len();
|
||||||
|
let meta_t =
|
||||||
|
func(nd_params, None, d_params.clone(), v_enum(set! { ret_val })).quantify();
|
||||||
|
let subr = move |args, _ctx: &Context| {
|
||||||
|
let passed = Vec::<TyParam>::from(args);
|
||||||
|
let lack = num_nd + num_d - passed.len();
|
||||||
|
let erased = d_params
|
||||||
|
.clone()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|tp| ParamTy::Pos(tp_enum(self.get_tp_t(&tp).unwrap_or(Obj), set! { tp })))
|
.take(lack)
|
||||||
.collect();
|
.map(|pt| TyParam::erased(pt.typ().clone()));
|
||||||
let meta_t = func(params, None, vec![], v_enum(set! { val.clone() })).quantify();
|
let params = passed.into_iter().chain(erased).collect::<Vec<_>>();
|
||||||
|
Ok(ValueObj::builtin_type(poly(qual_name.clone(), params)))
|
||||||
|
};
|
||||||
|
let subr = ConstSubr::Gen(GenConstSubr::new(
|
||||||
|
t.local_name(),
|
||||||
|
subr,
|
||||||
|
meta_t.clone(),
|
||||||
|
Some(t.clone()),
|
||||||
|
));
|
||||||
if ERG_MODE {
|
if ERG_MODE {
|
||||||
self.locals.insert(
|
self.locals.insert(
|
||||||
name.clone(),
|
name.clone(),
|
||||||
|
@ -812,7 +839,7 @@ impl Context {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
self.consts.insert(name.clone(), val);
|
self.consts.insert(name.clone(), ValueObj::Subr(subr));
|
||||||
self.register_methods(&t, &ctx);
|
self.register_methods(&t, &ctx);
|
||||||
self.poly_types.insert(name, (t, ctx));
|
self.poly_types.insert(name, (t, ctx));
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,8 @@ use Type::*;
|
||||||
use crate::context::instantiate_spec::ConstTemplate;
|
use crate::context::instantiate_spec::ConstTemplate;
|
||||||
use crate::context::{Context, RegistrationMode, TraitImpl, TyVarCache, Variance};
|
use crate::context::{Context, RegistrationMode, TraitImpl, TyVarCache, Variance};
|
||||||
use crate::error::{
|
use crate::error::{
|
||||||
binop_to_dname, readable_name, unaryop_to_dname, SingleTyCheckResult, TyCheckError,
|
binop_to_dname, ordinal_num, readable_name, unaryop_to_dname, SingleTyCheckResult,
|
||||||
TyCheckErrors, TyCheckResult,
|
TyCheckError, TyCheckErrors, TyCheckResult,
|
||||||
};
|
};
|
||||||
use crate::varinfo::{AbsLocation, Mutability, VarInfo, VarKind};
|
use crate::varinfo::{AbsLocation, Mutability, VarInfo, VarKind};
|
||||||
use crate::{feature_error, hir};
|
use crate::{feature_error, hir};
|
||||||
|
@ -1486,7 +1486,12 @@ impl Context {
|
||||||
let missing_params = subr
|
let missing_params = subr
|
||||||
.non_default_params
|
.non_default_params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|pt| pt.name().cloned().unwrap_or(Str::ever("_")))
|
.enumerate()
|
||||||
|
.map(|(i, pt)| {
|
||||||
|
pt.name().cloned().unwrap_or_else(|| {
|
||||||
|
Str::from(format!("({} param)", ordinal_num(i + 1)))
|
||||||
|
})
|
||||||
|
})
|
||||||
.filter(|pt| !passed_params.contains(pt))
|
.filter(|pt| !passed_params.contains(pt))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
if !missing_params.is_empty() {
|
if !missing_params.is_empty() {
|
||||||
|
@ -1666,6 +1671,8 @@ impl Context {
|
||||||
} else {
|
} else {
|
||||||
passed_params.insert(name.clone());
|
passed_params.insert(name.clone());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
passed_params.insert(Str::from(format!("({} param)", ordinal_num(nth))));
|
||||||
}
|
}
|
||||||
self.sub_unify(arg_t, param_t, arg, param.name())
|
self.sub_unify(arg_t, param_t, arg, param.name())
|
||||||
.map_err(|errs| {
|
.map_err(|errs| {
|
||||||
|
|
|
@ -42,6 +42,7 @@ use crate::module::{
|
||||||
};
|
};
|
||||||
use crate::ty::value::ValueObj;
|
use crate::ty::value::ValueObj;
|
||||||
use crate::ty::GuardType;
|
use crate::ty::GuardType;
|
||||||
|
use crate::ty::ParamTy;
|
||||||
use crate::ty::{Predicate, Type, Visibility, VisibilityModifier};
|
use crate::ty::{Predicate, Type, Visibility, VisibilityModifier};
|
||||||
use crate::varinfo::{AbsLocation, Mutability, VarInfo, VarKind};
|
use crate::varinfo::{AbsLocation, Mutability, VarInfo, VarKind};
|
||||||
use Type::*;
|
use Type::*;
|
||||||
|
@ -233,6 +234,16 @@ impl ParamSpec {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn default<S: Into<Str>>(name: S, t: Type) -> Self {
|
||||||
|
Self::new(
|
||||||
|
Some(name),
|
||||||
|
t,
|
||||||
|
false,
|
||||||
|
DefaultInfo::WithDefault,
|
||||||
|
AbsLocation::unknown(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn t<S: Into<Str>>(name: S, is_var_params: bool, default: DefaultInfo) -> Self {
|
pub fn t<S: Into<Str>>(name: S, is_var_params: bool, default: DefaultInfo) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
Some(name),
|
Some(name),
|
||||||
|
@ -252,6 +263,20 @@ impl ParamSpec {
|
||||||
AbsLocation::unknown(),
|
AbsLocation::unknown(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn has_default(&self) -> bool {
|
||||||
|
self.default_info.has_default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&ParamSpec> for ParamTy {
|
||||||
|
fn from(param: &ParamSpec) -> Self {
|
||||||
|
if let Some(name) = ¶m.name {
|
||||||
|
ParamTy::kw(name.clone(), param.t.clone())
|
||||||
|
} else {
|
||||||
|
ParamTy::Pos(param.t.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
@ -434,6 +459,7 @@ pub struct Context {
|
||||||
/// => locals: {"x": T, "y": T}
|
/// => locals: {"x": T, "y": T}
|
||||||
/// TODO: impl params desugaring and replace to `Dict`
|
/// TODO: impl params desugaring and replace to `Dict`
|
||||||
pub(crate) params: Vec<(Option<VarName>, VarInfo)>,
|
pub(crate) params: Vec<(Option<VarName>, VarInfo)>,
|
||||||
|
pub(crate) params_spec: Vec<ParamSpec>,
|
||||||
pub(crate) locals: Dict<VarName, VarInfo>,
|
pub(crate) locals: Dict<VarName, VarInfo>,
|
||||||
pub(crate) consts: Dict<VarName, ValueObj>,
|
pub(crate) consts: Dict<VarName, ValueObj>,
|
||||||
// {"Nat": ctx, "Int": ctx, ...}
|
// {"Nat": ctx, "Int": ctx, ...}
|
||||||
|
@ -589,7 +615,7 @@ impl Context {
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut params_ = Vec::new();
|
let mut params_ = Vec::new();
|
||||||
for param in params.into_iter() {
|
for param in params.clone().into_iter() {
|
||||||
let id = DefId(get_hash(&(&name, ¶m)));
|
let id = DefId(get_hash(&(&name, ¶m)));
|
||||||
if let Some(name) = param.name {
|
if let Some(name) = param.name {
|
||||||
let kind = VarKind::parameter(id, param.is_var_params, param.default_info);
|
let kind = VarKind::parameter(id, param.is_var_params, param.default_info);
|
||||||
|
@ -635,6 +661,7 @@ impl Context {
|
||||||
method_to_classes: Dict::default(),
|
method_to_classes: Dict::default(),
|
||||||
method_impl_patches: Dict::default(),
|
method_impl_patches: Dict::default(),
|
||||||
params: params_,
|
params: params_,
|
||||||
|
params_spec: params,
|
||||||
decls: Dict::default(),
|
decls: Dict::default(),
|
||||||
future_defined_locals: Dict::default(),
|
future_defined_locals: Dict::default(),
|
||||||
deleted_locals: Dict::default(),
|
deleted_locals: Dict::default(),
|
||||||
|
|
|
@ -1,24 +1,25 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use erg_common::dict::Dict;
|
use erg_common::dict::Dict;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use erg_common::log;
|
use erg_common::log;
|
||||||
use erg_common::Str;
|
use erg_common::Str;
|
||||||
|
|
||||||
use erg_parser::ast::{ConstBlock, Params};
|
use erg_parser::ast::{Block, ConstBlock, Params};
|
||||||
|
|
||||||
use super::constructors::subr_t;
|
use super::constructors::subr_t;
|
||||||
use super::value::{EvalValueResult, ValueObj};
|
use super::value::{EvalValueResult, ValueObj};
|
||||||
use super::{Predicate, Type};
|
use super::{Predicate, TyParam, Type};
|
||||||
|
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct UserConstSubr {
|
pub struct UserConstSubr {
|
||||||
name: Str,
|
pub name: Str,
|
||||||
params: Params,
|
pub(crate) params: Params,
|
||||||
block: ConstBlock,
|
pub(crate) block: ConstBlock,
|
||||||
sig_t: Type,
|
pub(crate) sig_t: Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserConstSubr {
|
impl UserConstSubr {
|
||||||
|
@ -30,6 +31,10 @@ impl UserConstSubr {
|
||||||
sig_t,
|
sig_t,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn block(self) -> Block {
|
||||||
|
self.block.downgrade()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
@ -38,6 +43,13 @@ pub struct ValueArgs {
|
||||||
pub kw_args: Dict<Str, ValueObj>,
|
pub kw_args: Dict<Str, ValueObj>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ValueArgs> for Vec<TyParam> {
|
||||||
|
fn from(args: ValueArgs) -> Self {
|
||||||
|
// TODO: kw_args
|
||||||
|
args.pos_args.into_iter().map(TyParam::Value).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ValueArgs {
|
impl ValueArgs {
|
||||||
pub const fn new(pos_args: Vec<ValueObj>, kw_args: Dict<Str, ValueObj>) -> Self {
|
pub const fn new(pos_args: Vec<ValueObj>, kw_args: Dict<Str, ValueObj>) -> Self {
|
||||||
ValueArgs { pos_args, kw_args }
|
ValueArgs { pos_args, kw_args }
|
||||||
|
@ -54,7 +66,7 @@ impl ValueArgs {
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct BuiltinConstSubr {
|
pub struct BuiltinConstSubr {
|
||||||
name: &'static str,
|
name: Str,
|
||||||
subr: fn(ValueArgs, &Context) -> EvalValueResult<ValueObj>,
|
subr: fn(ValueArgs, &Context) -> EvalValueResult<ValueObj>,
|
||||||
sig_t: Type,
|
sig_t: Type,
|
||||||
as_type: Option<Type>,
|
as_type: Option<Type>,
|
||||||
|
@ -91,14 +103,14 @@ impl fmt::Display for BuiltinConstSubr {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuiltinConstSubr {
|
impl BuiltinConstSubr {
|
||||||
pub const fn new(
|
pub fn new<S: Into<Str>>(
|
||||||
name: &'static str,
|
name: S,
|
||||||
subr: fn(ValueArgs, &Context) -> EvalValueResult<ValueObj>,
|
subr: fn(ValueArgs, &Context) -> EvalValueResult<ValueObj>,
|
||||||
sig_t: Type,
|
sig_t: Type,
|
||||||
as_type: Option<Type>,
|
as_type: Option<Type>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name: name.into(),
|
||||||
subr,
|
subr,
|
||||||
sig_t,
|
sig_t,
|
||||||
as_type,
|
as_type,
|
||||||
|
@ -110,10 +122,73 @@ impl BuiltinConstSubr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct GenConstSubr {
|
||||||
|
name: Str,
|
||||||
|
subr: Arc<dyn Fn(ValueArgs, &Context) -> EvalValueResult<ValueObj>>,
|
||||||
|
sig_t: Type,
|
||||||
|
as_type: Option<Type>,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for GenConstSubr {}
|
||||||
|
unsafe impl Sync for GenConstSubr {}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for GenConstSubr {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("BuiltinConstSubr")
|
||||||
|
.field("name", &self.name)
|
||||||
|
.field("sig_t", &self.sig_t)
|
||||||
|
.field("as_type", &self.as_type)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for GenConstSubr {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.name == other.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for GenConstSubr {}
|
||||||
|
|
||||||
|
impl std::hash::Hash for GenConstSubr {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
self.name.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for GenConstSubr {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "<const subroutine '{}'>", self.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GenConstSubr {
|
||||||
|
pub fn new<S: Into<Str>>(
|
||||||
|
name: S,
|
||||||
|
subr: impl Fn(ValueArgs, &Context) -> EvalValueResult<ValueObj> + 'static,
|
||||||
|
sig_t: Type,
|
||||||
|
as_type: Option<Type>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.into(),
|
||||||
|
subr: Arc::new(subr),
|
||||||
|
sig_t,
|
||||||
|
as_type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call(&self, args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
|
||||||
|
(self.subr)(args, ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum ConstSubr {
|
pub enum ConstSubr {
|
||||||
User(UserConstSubr),
|
User(UserConstSubr),
|
||||||
Builtin(BuiltinConstSubr),
|
Builtin(BuiltinConstSubr),
|
||||||
|
Gen(GenConstSubr),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ConstSubr {
|
impl fmt::Display for ConstSubr {
|
||||||
|
@ -123,6 +198,7 @@ impl fmt::Display for ConstSubr {
|
||||||
write!(f, "<user-defined const subroutine '{}'>", subr.name)
|
write!(f, "<user-defined const subroutine '{}'>", subr.name)
|
||||||
}
|
}
|
||||||
ConstSubr::Builtin(subr) => write!(f, "{subr}"),
|
ConstSubr::Builtin(subr) => write!(f, "{subr}"),
|
||||||
|
ConstSubr::Gen(subr) => write!(f, "{subr}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,10 +208,10 @@ impl ConstSubr {
|
||||||
match self {
|
match self {
|
||||||
ConstSubr::User(user) => &user.sig_t,
|
ConstSubr::User(user) => &user.sig_t,
|
||||||
ConstSubr::Builtin(builtin) => &builtin.sig_t,
|
ConstSubr::Builtin(builtin) => &builtin.sig_t,
|
||||||
|
ConstSubr::Gen(gen) => &gen.sig_t,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ConstSubr{sig_t: Int -> {Int}, ..}.as_type() == Int -> Int
|
|
||||||
pub fn as_type(&self, ctx: &Context) -> Option<Type> {
|
pub fn as_type(&self, ctx: &Context) -> Option<Type> {
|
||||||
match self {
|
match self {
|
||||||
ConstSubr::User(user) => {
|
ConstSubr::User(user) => {
|
||||||
|
@ -170,6 +246,7 @@ impl ConstSubr {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
ConstSubr::Builtin(builtin) => builtin.as_type.clone(),
|
ConstSubr::Builtin(builtin) => builtin.as_type.clone(),
|
||||||
|
ConstSubr::Gen(gen) => gen.as_type.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -375,22 +375,7 @@ impl Hash for TypeObj {
|
||||||
|
|
||||||
impl fmt::Display for TypeObj {
|
impl fmt::Display for TypeObj {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
self.limited_fmt(f, 10)
|
||||||
TypeObj::Builtin { t, .. } => {
|
|
||||||
if cfg!(feature = "debug") {
|
|
||||||
write!(f, "<type {t}>")
|
|
||||||
} else {
|
|
||||||
write!(f, "{t}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TypeObj::Generated(t) => {
|
|
||||||
if cfg!(feature = "debug") {
|
|
||||||
write!(f, "<user type {t}>")
|
|
||||||
} else {
|
|
||||||
write!(f, "{t}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,7 +386,7 @@ impl LimitedDisplay for TypeObj {
|
||||||
if cfg!(feature = "debug") {
|
if cfg!(feature = "debug") {
|
||||||
write!(f, "<type ")?;
|
write!(f, "<type ")?;
|
||||||
t.limited_fmt(f, limit - 1)?;
|
t.limited_fmt(f, limit - 1)?;
|
||||||
write!(f, "{t}>")
|
write!(f, ">")
|
||||||
} else {
|
} else {
|
||||||
t.limited_fmt(f, limit - 1)
|
t.limited_fmt(f, limit - 1)
|
||||||
}
|
}
|
||||||
|
@ -410,7 +395,7 @@ impl LimitedDisplay for TypeObj {
|
||||||
if cfg!(feature = "debug") {
|
if cfg!(feature = "debug") {
|
||||||
write!(f, "<user type ")?;
|
write!(f, "<user type ")?;
|
||||||
t.limited_fmt(f, limit - 1)?;
|
t.limited_fmt(f, limit - 1)?;
|
||||||
write!(f, "{t}>")
|
write!(f, ">")
|
||||||
} else {
|
} else {
|
||||||
t.limited_fmt(f, limit - 1)
|
t.limited_fmt(f, limit - 1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -312,6 +312,24 @@ impl VarInfo {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn d_parameter(t: Type, def_loc: AbsLocation, namespace: Str) -> Self {
|
||||||
|
let kind = VarKind::Parameter {
|
||||||
|
def_id: DefId(0),
|
||||||
|
var: false,
|
||||||
|
default: DefaultInfo::WithDefault,
|
||||||
|
};
|
||||||
|
Self::new(
|
||||||
|
t,
|
||||||
|
Immutable,
|
||||||
|
Visibility::private(namespace),
|
||||||
|
kind,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
def_loc,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn instance_attr(field: Field, t: Type, impl_of: Option<Type>, namespace: Str) -> Self {
|
pub fn instance_attr(field: Field, t: Type, impl_of: Option<Type>, namespace: Str) -> Self {
|
||||||
let muty = if field.is_const() {
|
let muty = if field.is_const() {
|
||||||
Mutability::Const
|
Mutability::Const
|
||||||
|
|
12
tests/should_err/array_member.er
Normal file
12
tests/should_err/array_member.er
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
C = Class { .a = Array(Int) }
|
||||||
|
_ = C.new { .a = [1] } # OK
|
||||||
|
_ = C.new { .a = ["a"] } # ERR
|
||||||
|
|
||||||
|
D = Class { .a = Array(Int, 1) }
|
||||||
|
_ = D.new { .a = [1] } # OK
|
||||||
|
d = D.new { .a = [1, 2] } # OK
|
||||||
|
assert d.a[0] == "a" # ERR
|
||||||
|
|
||||||
|
E = Class { .a = Array(Int, 2) }
|
||||||
|
_ = E.new { .a = [1, 2] } # OK
|
||||||
|
_ = E.new { .a = [1] } # ERR
|
3
tests/should_ok/array_member.er
Normal file
3
tests/should_ok/array_member.er
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
D = Class { .a = Array(Int, 1) }
|
||||||
|
d = D.new { .a = [1] }
|
||||||
|
assert d.a[0] == 1
|
|
@ -17,6 +17,11 @@ fn exec_array() -> Result<(), ()> {
|
||||||
expect_success("tests/should_ok/array.er", 0)
|
expect_success("tests/should_ok/array.er", 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exec_array_member() -> Result<(), ()> {
|
||||||
|
expect_success("tests/should_ok/array_member.er", 0)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exec_class() -> Result<(), ()> {
|
fn exec_class() -> Result<(), ()> {
|
||||||
expect_success("examples/class.er", 0)
|
expect_success("examples/class.er", 0)
|
||||||
|
@ -308,6 +313,11 @@ fn exec_array_err() -> Result<(), ()> {
|
||||||
expect_failure("examples/array.er", 0, 1)
|
expect_failure("examples/array.er", 0, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exec_array_member_err() -> Result<(), ()> {
|
||||||
|
expect_failure("tests/should_err/array_member.er", 0, 3)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exec_as() -> Result<(), ()> {
|
fn exec_as() -> Result<(), ()> {
|
||||||
expect_failure("tests/should_err/as.er", 0, 6)
|
expect_failure("tests/should_err/as.er", 0, 6)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue