mirror of
https://github.com/erg-lang/erg.git
synced 2025-08-03 18:29:00 +00:00
Add user-defined var-params function
This commit is contained in:
parent
4b08fd21a2
commit
23a7e2caf3
28 changed files with 526 additions and 211 deletions
|
@ -27,6 +27,7 @@ use crate::ty::typaram::{OpKind, TyParam};
|
|||
use crate::ty::value::{GenTypeObj, TypeObj, ValueObj};
|
||||
use crate::ty::{ConstSubr, HasType, Predicate, SubrKind, Type, UserConstSubr, ValueArgs};
|
||||
|
||||
use crate::context::instantiate::ParamKind;
|
||||
use crate::context::{ClassDefType, Context, ContextKind, RegistrationMode};
|
||||
use crate::error::{EvalError, EvalErrors, EvalResult, SingleEvalResult};
|
||||
|
||||
|
@ -451,19 +452,19 @@ impl Context {
|
|||
let pt = self.instantiate_param_ty(
|
||||
sig,
|
||||
None,
|
||||
None,
|
||||
&mut tmp_tv_cache,
|
||||
RegistrationMode::Normal,
|
||||
ParamKind::NonDefault,
|
||||
)?;
|
||||
non_default_params.push(pt);
|
||||
}
|
||||
let var_params = if let Some(p) = lambda.sig.params.var_args.as_ref() {
|
||||
let var_params = if let Some(p) = lambda.sig.params.var_params.as_ref() {
|
||||
let pt = self.instantiate_param_ty(
|
||||
p,
|
||||
None,
|
||||
None,
|
||||
&mut tmp_tv_cache,
|
||||
RegistrationMode::Normal,
|
||||
ParamKind::VarParams,
|
||||
)?;
|
||||
Some(pt)
|
||||
} else {
|
||||
|
@ -474,10 +475,10 @@ impl Context {
|
|||
let expr = self.eval_const_expr(&sig.default_val)?;
|
||||
let pt = self.instantiate_param_ty(
|
||||
&sig.sig,
|
||||
Some(expr.t()),
|
||||
None,
|
||||
&mut tmp_tv_cache,
|
||||
RegistrationMode::Normal,
|
||||
ParamKind::Default(expr.t()),
|
||||
)?;
|
||||
default_params.push(pt);
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ use crate::{feature_error, hir};
|
|||
use RegistrationMode::*;
|
||||
use Visibility::*;
|
||||
|
||||
use super::instantiate::ParamKind;
|
||||
use super::{ContextKind, MethodInfo};
|
||||
|
||||
impl Context {
|
||||
|
@ -274,6 +275,7 @@ impl Context {
|
|||
None,
|
||||
&mut dummy_tv_cache,
|
||||
Normal,
|
||||
ParamKind::NonDefault,
|
||||
)?;
|
||||
union_pat_t = self.union(&union_pat_t, &rhs);
|
||||
}
|
||||
|
|
|
@ -31,12 +31,38 @@ use crate::unreachable_error;
|
|||
use TyParamOrdering::*;
|
||||
use Type::*;
|
||||
|
||||
use crate::context::{Context, RegistrationMode};
|
||||
use crate::context::{Context, DefaultInfo, RegistrationMode};
|
||||
use crate::error::{TyCheckError, TyCheckErrors, TyCheckResult};
|
||||
use crate::hir;
|
||||
use crate::AccessKind;
|
||||
use RegistrationMode::*;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ParamKind {
|
||||
NonDefault,
|
||||
Default(Type),
|
||||
VarParams,
|
||||
KwParams,
|
||||
}
|
||||
|
||||
impl ParamKind {
|
||||
pub const fn is_var_params(&self) -> bool {
|
||||
matches!(self, ParamKind::VarParams)
|
||||
}
|
||||
pub const fn is_kw_params(&self) -> bool {
|
||||
matches!(self, ParamKind::KwParams)
|
||||
}
|
||||
pub const fn is_default(&self) -> bool {
|
||||
matches!(self, ParamKind::Default(_))
|
||||
}
|
||||
pub const fn default_info(&self) -> DefaultInfo {
|
||||
match self {
|
||||
ParamKind::Default(_) => DefaultInfo::WithDefault,
|
||||
_ => DefaultInfo::NonDefault,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Context for instantiating a quantified type
|
||||
/// For example, cloning each type variable of quantified type `?T -> ?T` would result in `?1 -> ?2`.
|
||||
/// To avoid this, an environment to store type variables is needed, which is `TyVarCache`.
|
||||
|
@ -252,7 +278,13 @@ impl Context {
|
|||
let opt_decl_t = opt_decl_sig_t
|
||||
.as_ref()
|
||||
.and_then(|subr| subr.non_default_params.get(n));
|
||||
match self.instantiate_param_ty(param, None, opt_decl_t, &mut tmp_tv_cache, mode) {
|
||||
match self.instantiate_param_ty(
|
||||
param,
|
||||
opt_decl_t,
|
||||
&mut tmp_tv_cache,
|
||||
mode,
|
||||
ParamKind::NonDefault,
|
||||
) {
|
||||
Ok(t) => non_defaults.push(t),
|
||||
Err(es) => {
|
||||
errs.extend(es);
|
||||
|
@ -260,16 +292,16 @@ impl Context {
|
|||
}
|
||||
}
|
||||
}
|
||||
let var_args = if let Some(var_args) = sig.params.var_args.as_ref() {
|
||||
let var_args = if let Some(var_args) = sig.params.var_params.as_ref() {
|
||||
let opt_decl_t = opt_decl_sig_t
|
||||
.as_ref()
|
||||
.and_then(|subr| subr.var_params.as_ref().map(|v| v.as_ref()));
|
||||
let pt = match self.instantiate_param_ty(
|
||||
var_args,
|
||||
None,
|
||||
opt_decl_t,
|
||||
&mut tmp_tv_cache,
|
||||
mode,
|
||||
ParamKind::VarParams,
|
||||
) {
|
||||
Ok(pt) => pt,
|
||||
Err(es) => {
|
||||
|
@ -288,10 +320,10 @@ impl Context {
|
|||
.and_then(|subr| subr.default_params.get(n));
|
||||
match self.instantiate_param_ty(
|
||||
&p.sig,
|
||||
Some(default_t),
|
||||
opt_decl_t,
|
||||
&mut tmp_tv_cache,
|
||||
mode,
|
||||
ParamKind::Default(default_t),
|
||||
) {
|
||||
Ok(t) => defaults.push(t),
|
||||
Err(es) => {
|
||||
|
@ -345,6 +377,7 @@ impl Context {
|
|||
opt_decl_t: Option<&ParamTy>,
|
||||
tmp_tv_cache: &mut TyVarCache,
|
||||
mode: RegistrationMode,
|
||||
kind: ParamKind,
|
||||
) -> TyCheckResult<Type> {
|
||||
let spec_t = if let Some(spec_with_op) = &sig.t_spec {
|
||||
self.instantiate_typespec(&spec_with_op.t_spec, opt_decl_t, tmp_tv_cache, mode, false)?
|
||||
|
@ -365,15 +398,28 @@ impl Context {
|
|||
}
|
||||
};
|
||||
if let Some(decl_pt) = opt_decl_t {
|
||||
self.sub_unify(
|
||||
decl_pt.typ(),
|
||||
&spec_t,
|
||||
sig.t_spec
|
||||
.as_ref()
|
||||
.map(|s| s.loc())
|
||||
.unwrap_or_else(|| sig.loc()),
|
||||
None,
|
||||
)?;
|
||||
if kind.is_var_params() {
|
||||
let spec_t = unknown_len_array_t(spec_t.clone());
|
||||
self.sub_unify(
|
||||
decl_pt.typ(),
|
||||
&spec_t,
|
||||
sig.t_spec
|
||||
.as_ref()
|
||||
.map(|s| s.loc())
|
||||
.unwrap_or_else(|| sig.loc()),
|
||||
None,
|
||||
)?;
|
||||
} else {
|
||||
self.sub_unify(
|
||||
decl_pt.typ(),
|
||||
&spec_t,
|
||||
sig.t_spec
|
||||
.as_ref()
|
||||
.map(|s| s.loc())
|
||||
.unwrap_or_else(|| sig.loc()),
|
||||
None,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
Ok(spec_t)
|
||||
}
|
||||
|
@ -381,17 +427,18 @@ impl Context {
|
|||
pub(crate) fn instantiate_param_ty(
|
||||
&self,
|
||||
sig: &NonDefaultParamSignature,
|
||||
opt_default_t: Option<Type>,
|
||||
opt_decl_t: Option<&ParamTy>,
|
||||
tmp_tv_cache: &mut TyVarCache,
|
||||
mode: RegistrationMode,
|
||||
kind: ParamKind,
|
||||
) -> TyCheckResult<ParamTy> {
|
||||
let t = self.instantiate_param_sig_t(sig, opt_decl_t, tmp_tv_cache, mode)?;
|
||||
match (sig.inspect(), opt_default_t) {
|
||||
(Some(name), Some(default_t)) => Ok(ParamTy::kw_default(name.clone(), t, default_t)),
|
||||
(Some(name), None) => Ok(ParamTy::kw(name.clone(), t)),
|
||||
(None, None) => Ok(ParamTy::anonymous(t)),
|
||||
_ => unreachable!(),
|
||||
let t = self.instantiate_param_sig_t(sig, opt_decl_t, tmp_tv_cache, mode, kind.clone())?;
|
||||
match (sig.inspect(), kind) {
|
||||
(Some(name), ParamKind::Default(default_t)) => {
|
||||
Ok(ParamTy::kw_default(name.clone(), t, default_t))
|
||||
}
|
||||
(Some(name), _) => Ok(ParamTy::kw(name.clone(), t)),
|
||||
(None, _) => Ok(ParamTy::anonymous(t)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -919,8 +966,8 @@ impl Context {
|
|||
let non_defaults = try_map_mut(subr.non_defaults.iter(), |p| {
|
||||
self.instantiate_func_param_spec(p, opt_decl_t, None, tmp_tv_ctx, mode)
|
||||
})?;
|
||||
let var_args = subr
|
||||
.var_args
|
||||
let var_params = subr
|
||||
.var_params
|
||||
.as_ref()
|
||||
.map(|p| {
|
||||
self.instantiate_func_param_spec(p, opt_decl_t, None, tmp_tv_ctx, mode)
|
||||
|
@ -947,7 +994,7 @@ impl Context {
|
|||
Ok(subr_t(
|
||||
SubrKind::from(subr.arrow.kind),
|
||||
non_defaults,
|
||||
var_args,
|
||||
var_params,
|
||||
defaults,
|
||||
return_t,
|
||||
))
|
||||
|
|
|
@ -17,7 +17,9 @@ use erg_common::{enum_unwrap, get_hash, log, set};
|
|||
use ast::{Decorator, DefId, Identifier, OperationKind, SimpleTypeSpec, VarName};
|
||||
use erg_parser::ast::{self, ConstIdentifier};
|
||||
|
||||
use crate::ty::constructors::{free_var, func, func0, func1, proc, ref_, ref_mut, v_enum};
|
||||
use crate::ty::constructors::{
|
||||
free_var, func, func0, func1, proc, ref_, ref_mut, unknown_len_array_t, v_enum,
|
||||
};
|
||||
use crate::ty::free::{Constraint, FreeKind, HasLevel};
|
||||
use crate::ty::value::{GenTypeObj, TypeObj, ValueObj};
|
||||
use crate::ty::{HasType, ParamTy, SubrType, Type};
|
||||
|
@ -37,7 +39,7 @@ use Mutability::*;
|
|||
use RegistrationMode::*;
|
||||
use Visibility::*;
|
||||
|
||||
use super::instantiate::TyVarCache;
|
||||
use super::instantiate::{ParamKind, TyVarCache};
|
||||
|
||||
const UBAR: &Str = &Str::ever("_");
|
||||
|
||||
|
@ -240,14 +242,15 @@ impl Context {
|
|||
fn assign_param(
|
||||
&mut self,
|
||||
sig: &ast::NonDefaultParamSignature,
|
||||
default_val_exists: bool,
|
||||
opt_decl_t: Option<&ParamTy>,
|
||||
kind: ParamKind,
|
||||
) -> TyCheckResult<()> {
|
||||
let vis = if cfg!(feature = "py_compatible") {
|
||||
Public
|
||||
} else {
|
||||
Private
|
||||
};
|
||||
let default = kind.default_info();
|
||||
match &sig.pat {
|
||||
// Literal patterns will be desugared to discard patterns
|
||||
ast::ParamPattern::Lit(_) => unreachable!(),
|
||||
|
@ -257,6 +260,7 @@ impl Context {
|
|||
opt_decl_t,
|
||||
&mut TyVarCache::new(self.level, self),
|
||||
Normal,
|
||||
kind,
|
||||
)?;
|
||||
let def_id = DefId(get_hash(&(&self.name, "_")));
|
||||
let kind = VarKind::parameter(def_id, DefaultInfo::NonDefault);
|
||||
|
@ -288,8 +292,13 @@ impl Context {
|
|||
} else {
|
||||
// ok, not defined
|
||||
let mut dummy_tv_cache = TyVarCache::new(self.level, self);
|
||||
let spec_t =
|
||||
self.instantiate_param_sig_t(sig, opt_decl_t, &mut dummy_tv_cache, Normal)?;
|
||||
let spec_t = self.instantiate_param_sig_t(
|
||||
sig,
|
||||
opt_decl_t,
|
||||
&mut dummy_tv_cache,
|
||||
Normal,
|
||||
kind,
|
||||
)?;
|
||||
if &name.inspect()[..] == "self" {
|
||||
if let Some(self_t) = self.rec_get_self_t() {
|
||||
self.sub_unify(&spec_t, &self_t, name.loc(), Some(name.inspect()))?;
|
||||
|
@ -297,11 +306,6 @@ impl Context {
|
|||
log!(err "self_t is None");
|
||||
}
|
||||
}
|
||||
let default = if default_val_exists {
|
||||
DefaultInfo::WithDefault
|
||||
} else {
|
||||
DefaultInfo::NonDefault
|
||||
};
|
||||
let def_id = DefId(get_hash(&(&self.name, name)));
|
||||
let kind = VarKind::parameter(def_id, default);
|
||||
let muty = Mutability::from(&name.inspect()[..]);
|
||||
|
@ -334,8 +338,13 @@ impl Context {
|
|||
} else {
|
||||
// ok, not defined
|
||||
let mut dummy_tv_cache = TyVarCache::new(self.level, self);
|
||||
let spec_t =
|
||||
self.instantiate_param_sig_t(sig, opt_decl_t, &mut dummy_tv_cache, Normal)?;
|
||||
let spec_t = self.instantiate_param_sig_t(
|
||||
sig,
|
||||
opt_decl_t,
|
||||
&mut dummy_tv_cache,
|
||||
Normal,
|
||||
kind,
|
||||
)?;
|
||||
if &name.inspect()[..] == "self" {
|
||||
if let Some(self_t) = self.rec_get_self_t() {
|
||||
self.sub_unify(&spec_t, &self_t, name.loc(), Some(name.inspect()))?;
|
||||
|
@ -344,11 +353,6 @@ impl Context {
|
|||
}
|
||||
}
|
||||
let spec_t = ref_(spec_t);
|
||||
let default = if default_val_exists {
|
||||
DefaultInfo::WithDefault
|
||||
} else {
|
||||
DefaultInfo::NonDefault
|
||||
};
|
||||
let kind = VarKind::parameter(DefId(get_hash(&(&self.name, name))), default);
|
||||
let vi = VarInfo::new(
|
||||
spec_t,
|
||||
|
@ -379,8 +383,13 @@ impl Context {
|
|||
} else {
|
||||
// ok, not defined
|
||||
let mut dummy_tv_cache = TyVarCache::new(self.level, self);
|
||||
let spec_t =
|
||||
self.instantiate_param_sig_t(sig, opt_decl_t, &mut dummy_tv_cache, Normal)?;
|
||||
let spec_t = self.instantiate_param_sig_t(
|
||||
sig,
|
||||
opt_decl_t,
|
||||
&mut dummy_tv_cache,
|
||||
Normal,
|
||||
kind,
|
||||
)?;
|
||||
if &name.inspect()[..] == "self" {
|
||||
if let Some(self_t) = self.rec_get_self_t() {
|
||||
self.sub_unify(&spec_t, &self_t, name.loc(), Some(name.inspect()))?;
|
||||
|
@ -389,11 +398,6 @@ impl Context {
|
|||
}
|
||||
}
|
||||
let spec_t = ref_mut(spec_t.clone(), Some(spec_t));
|
||||
let default = if default_val_exists {
|
||||
DefaultInfo::WithDefault
|
||||
} else {
|
||||
DefaultInfo::NonDefault
|
||||
};
|
||||
let kind = VarKind::parameter(DefId(get_hash(&(&self.name, name))), default);
|
||||
let vi = VarInfo::new(
|
||||
spec_t,
|
||||
|
@ -433,7 +437,18 @@ impl Context {
|
|||
.iter()
|
||||
.zip(decl_subr_t.non_default_params.iter())
|
||||
{
|
||||
if let Err(es) = self.assign_param(sig, false, Some(pt)) {
|
||||
if let Err(es) = self.assign_param(sig, Some(pt), ParamKind::NonDefault) {
|
||||
errs.extend(es);
|
||||
}
|
||||
}
|
||||
if let Some(var_params) = ¶ms.var_params {
|
||||
if let Some(pt) = &decl_subr_t.var_params {
|
||||
let pt = pt.clone().map_type(unknown_len_array_t);
|
||||
if let Err(es) = self.assign_param(var_params, Some(&pt), ParamKind::VarParams)
|
||||
{
|
||||
errs.extend(es);
|
||||
}
|
||||
} else if let Err(es) = self.assign_param(var_params, None, ParamKind::VarParams) {
|
||||
errs.extend(es);
|
||||
}
|
||||
}
|
||||
|
@ -442,18 +457,22 @@ impl Context {
|
|||
.iter()
|
||||
.zip(decl_subr_t.default_params.iter())
|
||||
{
|
||||
if let Err(es) = self.assign_param(&sig.sig, true, Some(pt)) {
|
||||
if let Err(es) =
|
||||
self.assign_param(&sig.sig, Some(pt), ParamKind::Default(sig.default_val.t()))
|
||||
{
|
||||
errs.extend(es);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for sig in params.non_defaults.iter() {
|
||||
if let Err(es) = self.assign_param(sig, false, None) {
|
||||
if let Err(es) = self.assign_param(sig, None, ParamKind::NonDefault) {
|
||||
errs.extend(es);
|
||||
}
|
||||
}
|
||||
for sig in params.defaults.iter() {
|
||||
if let Err(es) = self.assign_param(&sig.sig, true, None) {
|
||||
if let Err(es) =
|
||||
self.assign_param(&sig.sig, None, ParamKind::Default(sig.default_val.t()))
|
||||
{
|
||||
errs.extend(es);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue