chore: add ast::VarPattern::Phi

This commit is contained in:
Shunsuke Shibayama 2024-10-20 14:25:29 +09:00
parent 9c1e77ecd0
commit 01a5938c29
9 changed files with 121 additions and 26 deletions

View file

@ -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,

View file

@ -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)

View file

@ -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")));

View file

@ -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,

View file

@ -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(),

View file

@ -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();

View file

@ -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,12 +2308,26 @@ 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() {
self.module
.context
.union(existing_t.as_ref().unwrap_or(&Type::Never), found_body_t)
} else {
found_body_t.clone()
};
let vi = if no_reassign {
VarInfo {
t: found_body_t,
..existing_vi.unwrap_or_default()
}
} else {
match self.module.context.outer.as_mut().unwrap().assign_var_sig(
&sig, &sig,
found_body_t, &found_body_t,
body.id, body.id,
block.last(), block.last(),
None, None,
@ -2317,6 +2337,7 @@ impl<A: ASTBuildable> GenericASTLowerer<A> {
errors.extend(errs); errors.extend(errs);
VarInfo::ILLEGAL VarInfo::ILLEGAL
} }
}
}; };
let ident = hir::Identifier::new(ident, None, vi); let ident = hir::Identifier::new(ident, None, vi);
let t_spec = if let Some(ts) = sig.t_spec { let t_spec = if let Some(ts) = sig.t_spec {
@ -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,

View file

@ -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]

View file

@ -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));
} }