mirror of
https://github.com/erg-lang/erg.git
synced 2025-10-03 05:54:33 +00:00
chore: add ast::VarPattern::Phi
This commit is contained in:
parent
9c1e77ecd0
commit
01a5938c29
9 changed files with 121 additions and 26 deletions
|
@ -77,6 +77,14 @@ impl<T, E> Triple<T, E> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn or_else_triple(self, f: impl FnOnce() -> Triple<T, E>) -> Triple<T, E> {
|
||||||
|
match self {
|
||||||
|
Triple::None => f(),
|
||||||
|
Triple::Ok(ok) => Triple::Ok(ok),
|
||||||
|
Triple::Err(err) => Triple::Err(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn unwrap_or(self, default: T) -> T {
|
pub fn unwrap_or(self, default: T) -> T {
|
||||||
match self {
|
match self {
|
||||||
Triple::None => default,
|
Triple::None => default,
|
||||||
|
|
|
@ -445,6 +445,23 @@ impl Context {
|
||||||
&& var_params_judge
|
&& var_params_judge
|
||||||
&& default_check() // contravariant
|
&& default_check() // contravariant
|
||||||
}
|
}
|
||||||
|
// {Int} <: Obj -> Int
|
||||||
|
(Subr(_) | Quantified(_), Refinement(refine))
|
||||||
|
if rhs.singleton_value().is_some() && self.subtype_of(&refine.t, &ClassType) =>
|
||||||
|
{
|
||||||
|
let Ok(typ) = self.convert_tp_into_type(rhs.singleton_value().unwrap().clone())
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let Some(ctx) = self.get_nominal_type_ctx(&typ) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
if let Some((_, __call__)) = ctx.get_class_attr("__call__") {
|
||||||
|
self.supertype_of(lhs, &__call__.t)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
// ?T(<: Int) :> ?U(:> Nat)
|
// ?T(<: Int) :> ?U(:> Nat)
|
||||||
// ?T(<: Int) :> ?U(:> Int)
|
// ?T(<: Int) :> ?U(:> Int)
|
||||||
// ?T(<: Nat) !:> ?U(:> Int) (if the upper bound of LHS is smaller than the lower bound of RHS, LHS cannot not be a supertype)
|
// ?T(<: Nat) !:> ?U(:> Int) (if the upper bound of LHS is smaller than the lower bound of RHS, LHS cannot not be a supertype)
|
||||||
|
|
|
@ -60,7 +60,7 @@ impl Context {
|
||||||
)
|
)
|
||||||
.quantify();
|
.quantify();
|
||||||
let t_proc_ret = if PYTHON_MODE { Obj } else { NoneType };
|
let t_proc_ret = if PYTHON_MODE { Obj } else { NoneType };
|
||||||
let t_for = nd_proc(
|
let t_for = proc(
|
||||||
vec![
|
vec![
|
||||||
kw("iterable", poly("Iterable", vec![ty_tp(T.clone())])),
|
kw("iterable", poly("Iterable", vec![ty_tp(T.clone())])),
|
||||||
kw(
|
kw(
|
||||||
|
@ -69,6 +69,8 @@ impl Context {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
None,
|
None,
|
||||||
|
vec![kw("else!", nd_proc(vec![], None, t_proc_ret.clone()))],
|
||||||
|
None,
|
||||||
NoneType,
|
NoneType,
|
||||||
)
|
)
|
||||||
.quantify();
|
.quantify();
|
||||||
|
@ -90,12 +92,14 @@ impl Context {
|
||||||
// not Bool! type because `cond` may be the result of evaluation of a mutable object's method returns Bool.
|
// not Bool! type because `cond` may be the result of evaluation of a mutable object's method returns Bool.
|
||||||
nd_proc(vec![], None, Bool)
|
nd_proc(vec![], None, Bool)
|
||||||
};
|
};
|
||||||
let t_while = nd_proc(
|
let t_while = proc(
|
||||||
vec![
|
vec![
|
||||||
kw("cond!", t_cond),
|
kw("cond!", t_cond),
|
||||||
kw("proc!", nd_proc(vec![], None, t_proc_ret)),
|
kw("proc!", nd_proc(vec![], None, t_proc_ret.clone())),
|
||||||
],
|
],
|
||||||
None,
|
None,
|
||||||
|
vec![kw("else!", nd_proc(vec![], None, t_proc_ret.clone()))],
|
||||||
|
None,
|
||||||
NoneType,
|
NoneType,
|
||||||
);
|
);
|
||||||
let P = mono_q("P", subtypeof(mono("PathLike")));
|
let P = mono_q("P", subtypeof(mono("PathLike")));
|
||||||
|
|
|
@ -750,6 +750,27 @@ impl Context {
|
||||||
Triple::None
|
Triple::None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn rec_get_param_or_decl_info(&self, name: &str) -> Option<VarInfo> {
|
||||||
|
if let Some(vi) = self
|
||||||
|
.params
|
||||||
|
.iter()
|
||||||
|
.find(|(var_name, _)| var_name.as_ref().is_some_and(|n| n.inspect() == name))
|
||||||
|
.map(|(_, vi)| vi)
|
||||||
|
.or_else(|| self.decls.get(name))
|
||||||
|
{
|
||||||
|
return Some(vi.clone());
|
||||||
|
}
|
||||||
|
for method_ctx in self.methods_list.iter() {
|
||||||
|
if let Some(vi) = method_ctx.rec_get_param_or_decl_info(name) {
|
||||||
|
return Some(vi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(parent) = self.get_outer_scope().or_else(|| self.get_builtins()) {
|
||||||
|
return parent.rec_get_param_or_decl_info(name);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn get_attr_info(
|
pub(crate) fn get_attr_info(
|
||||||
&self,
|
&self,
|
||||||
obj: &hir::Expr,
|
obj: &hir::Expr,
|
||||||
|
|
|
@ -130,7 +130,7 @@ impl Context {
|
||||||
let mut errs = TyCheckErrors::empty();
|
let mut errs = TyCheckErrors::empty();
|
||||||
let muty = Mutability::from(&sig.inspect().unwrap_or(UBAR)[..]);
|
let muty = Mutability::from(&sig.inspect().unwrap_or(UBAR)[..]);
|
||||||
let ident = match &sig.pat {
|
let ident = match &sig.pat {
|
||||||
ast::VarPattern::Ident(ident) => ident,
|
ast::VarPattern::Ident(ident) | ast::VarPattern::Phi(ident) => ident,
|
||||||
ast::VarPattern::Discard(_) | ast::VarPattern::Glob(_) => {
|
ast::VarPattern::Discard(_) | ast::VarPattern::Glob(_) => {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
@ -287,7 +287,7 @@ impl Context {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let ident = match &sig.pat {
|
let ident = match &sig.pat {
|
||||||
ast::VarPattern::Ident(ident) => ident,
|
ast::VarPattern::Ident(ident) | ast::VarPattern::Phi(ident) => ident,
|
||||||
ast::VarPattern::Discard(_) => {
|
ast::VarPattern::Discard(_) => {
|
||||||
return Ok(VarInfo {
|
return Ok(VarInfo {
|
||||||
t: body_t.clone(),
|
t: body_t.clone(),
|
||||||
|
|
|
@ -1874,6 +1874,8 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
|
||||||
}
|
}
|
||||||
self.sub_unify_pred(&sub.pred, &supe.pred)?;
|
self.sub_unify_pred(&sub.pred, &supe.pred)?;
|
||||||
}
|
}
|
||||||
|
// {Int} <: Obj -> Int
|
||||||
|
(Refinement(_), Subr(_) | Quantified(_)) if maybe_sub.singleton_value().is_some() => {}
|
||||||
// {I: Int | I >= 1} <: Nat == {I: Int | I >= 0}
|
// {I: Int | I >= 1} <: Nat == {I: Int | I >= 0}
|
||||||
(Refinement(_), sup) => {
|
(Refinement(_), sup) => {
|
||||||
let sup = sup.clone().into_refinement();
|
let sup = sup.clone().into_refinement();
|
||||||
|
|
|
@ -2253,6 +2253,11 @@ impl<A: ASTBuildable> GenericASTLowerer<A> {
|
||||||
errors.extend(errs);
|
errors.extend(errs);
|
||||||
}
|
}
|
||||||
let outer = self.module.context.outer.as_ref().unwrap();
|
let outer = self.module.context.outer.as_ref().unwrap();
|
||||||
|
let existing_vi = sig
|
||||||
|
.ident()
|
||||||
|
.and_then(|ident| outer.get_current_scope_var(&ident.name))
|
||||||
|
.cloned();
|
||||||
|
let existing_t = existing_vi.as_ref().map(|vi| vi.t.clone());
|
||||||
let expect_body_t = sig
|
let expect_body_t = sig
|
||||||
.t_spec
|
.t_spec
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -2269,14 +2274,14 @@ impl<A: ASTBuildable> GenericASTLowerer<A> {
|
||||||
})
|
})
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
sig.ident()
|
sig.ident()
|
||||||
.and_then(|ident| outer.get_current_scope_var(&ident.name))
|
.and_then(|ident| outer.rec_get_param_or_decl_info(ident.inspect()))
|
||||||
.map(|vi| vi.t.clone())
|
.map(|vi| vi.t.clone())
|
||||||
});
|
});
|
||||||
match self.lower_block(body.block, expect_body.or(expect_body_t.as_ref())) {
|
match self.lower_block(body.block, expect_body.or(expect_body_t.as_ref())) {
|
||||||
Ok(block) => {
|
Ok(block) => {
|
||||||
let found_body_t = block.ref_t();
|
let found_body_t = block.ref_t();
|
||||||
let ident = match &sig.pat {
|
let ident = match &sig.pat {
|
||||||
ast::VarPattern::Ident(ident) => ident.clone(),
|
ast::VarPattern::Ident(ident) | ast::VarPattern::Phi(ident) => ident.clone(),
|
||||||
ast::VarPattern::Discard(token) => {
|
ast::VarPattern::Discard(token) => {
|
||||||
ast::Identifier::private_from_token(token.clone())
|
ast::Identifier::private_from_token(token.clone())
|
||||||
}
|
}
|
||||||
|
@ -2291,6 +2296,7 @@ impl<A: ASTBuildable> GenericASTLowerer<A> {
|
||||||
.map_err(|errs| (None, errors.concat(errs)));
|
.map_err(|errs| (None, errors.concat(errs)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let mut no_reassign = false;
|
||||||
if let Some(expect_body_t) = expect_body_t {
|
if let Some(expect_body_t) = expect_body_t {
|
||||||
// TODO: expect_body_t is smaller for constants
|
// TODO: expect_body_t is smaller for constants
|
||||||
// TODO: 定数の場合、expect_body_tのほうが小さくなってしまう
|
// TODO: 定数の場合、expect_body_tのほうが小さくなってしまう
|
||||||
|
@ -2302,20 +2308,35 @@ impl<A: ASTBuildable> GenericASTLowerer<A> {
|
||||||
found_body_t,
|
found_body_t,
|
||||||
) {
|
) {
|
||||||
errors.push(e);
|
errors.push(e);
|
||||||
|
no_reassign = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let vi = match self.module.context.outer.as_mut().unwrap().assign_var_sig(
|
let found_body_t = if sig.is_phi() {
|
||||||
&sig,
|
self.module
|
||||||
found_body_t,
|
.context
|
||||||
body.id,
|
.union(existing_t.as_ref().unwrap_or(&Type::Never), found_body_t)
|
||||||
block.last(),
|
} else {
|
||||||
None,
|
found_body_t.clone()
|
||||||
) {
|
};
|
||||||
Ok(vi) => vi,
|
let vi = if no_reassign {
|
||||||
Err(errs) => {
|
VarInfo {
|
||||||
errors.extend(errs);
|
t: found_body_t,
|
||||||
VarInfo::ILLEGAL
|
..existing_vi.unwrap_or_default()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match self.module.context.outer.as_mut().unwrap().assign_var_sig(
|
||||||
|
&sig,
|
||||||
|
&found_body_t,
|
||||||
|
body.id,
|
||||||
|
block.last(),
|
||||||
|
None,
|
||||||
|
) {
|
||||||
|
Ok(vi) => vi,
|
||||||
|
Err(errs) => {
|
||||||
|
errors.extend(errs);
|
||||||
|
VarInfo::ILLEGAL
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let ident = hir::Identifier::new(ident, None, vi);
|
let ident = hir::Identifier::new(ident, None, vi);
|
||||||
|
@ -2351,7 +2372,7 @@ impl<A: ASTBuildable> GenericASTLowerer<A> {
|
||||||
errors.extend(errs);
|
errors.extend(errs);
|
||||||
let found_body_t = block.ref_t();
|
let found_body_t = block.ref_t();
|
||||||
let ident = match &sig.pat {
|
let ident = match &sig.pat {
|
||||||
ast::VarPattern::Ident(ident) => ident.clone(),
|
ast::VarPattern::Ident(ident) | ast::VarPattern::Phi(ident) => ident.clone(),
|
||||||
ast::VarPattern::Discard(token) => {
|
ast::VarPattern::Discard(token) => {
|
||||||
ast::Identifier::private_from_token(token.clone())
|
ast::Identifier::private_from_token(token.clone())
|
||||||
}
|
}
|
||||||
|
@ -2366,9 +2387,16 @@ impl<A: ASTBuildable> GenericASTLowerer<A> {
|
||||||
.map_err(|errs| (None, errors.concat(errs)));
|
.map_err(|errs| (None, errors.concat(errs)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let found_body_t = if sig.is_phi() {
|
||||||
|
self.module
|
||||||
|
.context
|
||||||
|
.union(existing_t.as_ref().unwrap_or(&Type::Never), found_body_t)
|
||||||
|
} else {
|
||||||
|
found_body_t.clone()
|
||||||
|
};
|
||||||
if let Err(errs) = self.module.context.outer.as_mut().unwrap().assign_var_sig(
|
if let Err(errs) = self.module.context.outer.as_mut().unwrap().assign_var_sig(
|
||||||
&sig,
|
&sig,
|
||||||
found_body_t,
|
&found_body_t,
|
||||||
ast::DefId(0),
|
ast::DefId(0),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -4723,6 +4723,10 @@ pub enum VarPattern {
|
||||||
Discard(Token),
|
Discard(Token),
|
||||||
Glob(Token),
|
Glob(Token),
|
||||||
Ident(Identifier),
|
Ident(Identifier),
|
||||||
|
/// Used when a different value is assigned in a branch other than `Ident`.
|
||||||
|
/// (e.g. the else variable when a variable is defined with Python if-else)
|
||||||
|
/// Not used in Erg mode at this time
|
||||||
|
Phi(Identifier),
|
||||||
/// e.g. `[x, y, z]` of `[x, y, z] = [1, 2, 3]`
|
/// e.g. `[x, y, z]` of `[x, y, z] = [1, 2, 3]`
|
||||||
List(VarListPattern),
|
List(VarListPattern),
|
||||||
/// e.g. `(x, y, z)` of `(x, y, z) = (1, 2, 3)`
|
/// e.g. `(x, y, z)` of `(x, y, z) = (1, 2, 3)`
|
||||||
|
@ -4739,6 +4743,7 @@ impl NestedDisplay for VarPattern {
|
||||||
Self::Discard(_) => write!(f, "_"),
|
Self::Discard(_) => write!(f, "_"),
|
||||||
Self::Glob(_) => write!(f, "*"),
|
Self::Glob(_) => write!(f, "*"),
|
||||||
Self::Ident(ident) => write!(f, "{ident}"),
|
Self::Ident(ident) => write!(f, "{ident}"),
|
||||||
|
Self::Phi(ident) => write!(f, "(phi){ident}"),
|
||||||
Self::List(l) => write!(f, "{l}"),
|
Self::List(l) => write!(f, "{l}"),
|
||||||
Self::Tuple(t) => write!(f, "{t}"),
|
Self::Tuple(t) => write!(f, "{t}"),
|
||||||
Self::Record(r) => write!(f, "{r}"),
|
Self::Record(r) => write!(f, "{r}"),
|
||||||
|
@ -4748,9 +4753,9 @@ impl NestedDisplay for VarPattern {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_display_from_nested!(VarPattern);
|
impl_display_from_nested!(VarPattern);
|
||||||
impl_locational_for_enum!(VarPattern; Discard, Glob, Ident, List, Tuple, Record, DataPack);
|
impl_locational_for_enum!(VarPattern; Discard, Glob, Ident, Phi, List, Tuple, Record, DataPack);
|
||||||
impl_into_py_for_enum!(VarPattern; Discard, Glob, Ident, List, Tuple, Record, DataPack);
|
impl_into_py_for_enum!(VarPattern; Discard, Glob, Ident, Phi, List, Tuple, Record, DataPack);
|
||||||
impl_from_py_for_enum!(VarPattern; Discard(Token), Glob(Token), Ident(Identifier), List(VarListPattern), Tuple(VarTuplePattern), Record(VarRecordPattern), DataPack(VarDataPackPattern));
|
impl_from_py_for_enum!(VarPattern; Discard(Token), Glob(Token), Ident(Identifier), Phi(Identifier), List(VarListPattern), Tuple(VarTuplePattern), Record(VarRecordPattern), DataPack(VarDataPackPattern));
|
||||||
|
|
||||||
impl VarPattern {
|
impl VarPattern {
|
||||||
pub const fn inspect(&self) -> Option<&Str> {
|
pub const fn inspect(&self) -> Option<&Str> {
|
||||||
|
@ -4900,10 +4905,14 @@ impl VarSignature {
|
||||||
|
|
||||||
pub fn ident(&self) -> Option<&Identifier> {
|
pub fn ident(&self) -> Option<&Identifier> {
|
||||||
match &self.pat {
|
match &self.pat {
|
||||||
VarPattern::Ident(ident) => Some(ident),
|
VarPattern::Ident(ident) | VarPattern::Phi(ident) => Some(ident),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_phi(&self) -> bool {
|
||||||
|
matches!(self.pat, VarPattern::Phi(_))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
|
|
|
@ -763,7 +763,10 @@ impl Desugarer {
|
||||||
self.desugar_nested_var_pattern(new, rhs, &buf_name, BufIndex::Record(lhs));
|
self.desugar_nested_var_pattern(new, rhs, &buf_name, BufIndex::Record(lhs));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VarPattern::Ident(_) | VarPattern::Discard(_) | VarPattern::Glob(_) => {
|
VarPattern::Ident(_)
|
||||||
|
| VarPattern::Phi(_)
|
||||||
|
| VarPattern::Discard(_)
|
||||||
|
| VarPattern::Glob(_) => {
|
||||||
if let VarPattern::Ident(ident) = v.pat {
|
if let VarPattern::Ident(ident) = v.pat {
|
||||||
v.pat = VarPattern::Ident(Self::desugar_ident(ident));
|
v.pat = VarPattern::Ident(Self::desugar_ident(ident));
|
||||||
}
|
}
|
||||||
|
@ -966,7 +969,10 @@ impl Desugarer {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VarPattern::Ident(_) | VarPattern::Discard(_) | VarPattern::Glob(_) => {
|
VarPattern::Ident(_)
|
||||||
|
| VarPattern::Phi(_)
|
||||||
|
| VarPattern::Discard(_)
|
||||||
|
| VarPattern::Glob(_) => {
|
||||||
let def = Def::new(Signature::Var(sig.clone()), body);
|
let def = Def::new(Signature::Var(sig.clone()), body);
|
||||||
new_module.push(Expr::Def(def));
|
new_module.push(Expr::Def(def));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue