mirror of
https://github.com/erg-lang/erg.git
synced 2025-10-01 13:11:11 +00:00
Support: type checking for math and random module (Python built-in)
This commit is contained in:
parent
6fb8508b26
commit
e34f59451b
4 changed files with 242 additions and 85 deletions
|
@ -35,17 +35,18 @@ fn obj_name(obj: &Expr) -> Option<String> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_to_python_attr(class: &str, name: Str) -> Str {
|
fn convert_to_python_attr(class: &str, uniq_obj_name: Option<&str>, name: Str) -> Str {
|
||||||
match (class, &name[..]) {
|
match (class, uniq_obj_name, &name[..]) {
|
||||||
("Array!", "push!") => Str::ever("append"),
|
("Array!", _, "push!") => Str::ever("append"),
|
||||||
("Complex" | "Real"| "Int" | "Nat" | "Float", "Real") => Str::ever("real"),
|
("Complex" | "Real"| "Int" | "Nat" | "Float", _, "Real") => Str::ever("real"),
|
||||||
("Complex" | "Real"| "Int" | "Nat" | "Float", "Imag") => Str::ever("imag"),
|
("Complex" | "Real"| "Int" | "Nat" | "Float", _, "Imag") => Str::ever("imag"),
|
||||||
|
("Module", Some("random"), "randint!") => Str::ever("randint"),
|
||||||
_ => name,
|
_ => name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn escape_attr(class: &str, name: Str) -> Str {
|
fn escape_attr(class: &str, uniq_obj_name: Option<&str>, name: Str) -> Str {
|
||||||
let mut name = convert_to_python_attr(class, name).to_string();
|
let mut name = convert_to_python_attr(class, uniq_obj_name, name).to_string();
|
||||||
name = name.replace("!", "__erg_proc__");
|
name = name.replace("!", "__erg_proc__");
|
||||||
name = name.replace("$", "__erg_shared__");
|
name = name.replace("$", "__erg_shared__");
|
||||||
Str::rc(&name)
|
Str::rc(&name)
|
||||||
|
@ -285,7 +286,7 @@ impl CodeGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
// local_searchで見つからなかった変数を探索する
|
// local_searchで見つからなかった変数を探索する
|
||||||
fn deep_search(&mut self, name: &str) -> Option<StoreLoadKind> {
|
fn rec_search(&mut self, name: &str) -> Option<StoreLoadKind> {
|
||||||
// search_name()を実行した後なのでcur_blockはskipする
|
// search_name()を実行した後なのでcur_blockはskipする
|
||||||
for (nth_from_toplevel, block) in self.units.iter_mut().enumerate().rev().skip(1) {
|
for (nth_from_toplevel, block) in self.units.iter_mut().enumerate().rev().skip(1) {
|
||||||
let block_is_toplevel = nth_from_toplevel == 0;
|
let block_is_toplevel = nth_from_toplevel == 0;
|
||||||
|
@ -314,7 +315,7 @@ impl CodeGenerator {
|
||||||
fn register_name(&mut self, name: Str) -> Name {
|
fn register_name(&mut self, name: Str) -> Name {
|
||||||
let current_is_toplevel = self.cur_block() == self.toplevel_block();
|
let current_is_toplevel = self.cur_block() == self.toplevel_block();
|
||||||
let name = escape_name(name);
|
let name = escape_name(name);
|
||||||
match self.deep_search(&name) {
|
match self.rec_search(&name) {
|
||||||
Some(st @ (StoreLoadKind::Local | StoreLoadKind::Global)) => {
|
Some(st @ (StoreLoadKind::Local | StoreLoadKind::Global)) => {
|
||||||
self.mut_cur_block_codeobj().names.push(name);
|
self.mut_cur_block_codeobj().names.push(name);
|
||||||
Name::new(st, self.cur_block_codeobj().names.len() - 1)
|
Name::new(st, self.cur_block_codeobj().names.len() - 1)
|
||||||
|
@ -339,16 +340,16 @@ impl CodeGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_attr(&mut self, class: &str, name: Str) -> Name {
|
fn register_attr(&mut self, class: &str, uniq_obj_name: Option<&str>, name: Str) -> Name {
|
||||||
let name = Str::rc(name.split(".").last().unwrap());
|
let name = Str::rc(name.split(".").last().unwrap());
|
||||||
let name = escape_attr(class, name);
|
let name = escape_attr(class, uniq_obj_name, name);
|
||||||
self.mut_cur_block_codeobj().names.push(name);
|
self.mut_cur_block_codeobj().names.push(name);
|
||||||
Name::local(self.cur_block_codeobj().names.len() - 1)
|
Name::local(self.cur_block_codeobj().names.len() - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_method(&mut self, class: &str, name: Str) -> Name {
|
fn register_method(&mut self, class: &str, uniq_obj_name: Option<&str>, name: Str) -> Name {
|
||||||
let name = Str::rc(name.split(".").last().unwrap());
|
let name = Str::rc(name.split(".").last().unwrap());
|
||||||
let name = escape_attr(class, name);
|
let name = escape_attr(class, uniq_obj_name, name);
|
||||||
self.mut_cur_block_codeobj().names.push(name);
|
self.mut_cur_block_codeobj().names.push(name);
|
||||||
Name::local(self.cur_block_codeobj().names.len() - 1)
|
Name::local(self.cur_block_codeobj().names.len() - 1)
|
||||||
}
|
}
|
||||||
|
@ -369,9 +370,9 @@ impl CodeGenerator {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_load_attr_instr(&mut self, class: &str, name: Str) -> CompileResult<()> {
|
fn emit_load_attr_instr(&mut self, class: &str, uniq_obj_name: Option<&str>, name: Str) -> CompileResult<()> {
|
||||||
let name = self.local_search(&name, Attr).unwrap_or_else(|| {
|
let name = self.local_search(&name, Attr).unwrap_or_else(|| {
|
||||||
self.register_attr(class, name)
|
self.register_attr(class, uniq_obj_name, name)
|
||||||
});
|
});
|
||||||
let instr = match name.kind {
|
let instr = match name.kind {
|
||||||
StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST,
|
StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST,
|
||||||
|
@ -384,9 +385,9 @@ impl CodeGenerator {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_load_method_instr(&mut self, class: &str, name: Str) -> CompileResult<()> {
|
fn emit_load_method_instr(&mut self, class: &str, uniq_obj_name: Option<&str>, name: Str) -> CompileResult<()> {
|
||||||
let name = self.local_search(&name, Method).unwrap_or_else(|| {
|
let name = self.local_search(&name, Method).unwrap_or_else(|| {
|
||||||
self.register_method(class, name)
|
self.register_method(class, uniq_obj_name, name)
|
||||||
});
|
});
|
||||||
let instr = match name.kind {
|
let instr = match name.kind {
|
||||||
StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST,
|
StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST,
|
||||||
|
@ -765,8 +766,10 @@ impl CodeGenerator {
|
||||||
self.stack_dec_n((1 + 1 + argc + kwsc) - 1);
|
self.stack_dec_n((1 + 1 + argc + kwsc) - 1);
|
||||||
} else {
|
} else {
|
||||||
let class = Str::rc(obj.ref_t().name());
|
let class = Str::rc(obj.ref_t().name());
|
||||||
|
let uniq_obj_name = obj.__name__().map(Str::rc);
|
||||||
self.codegen_expr(obj);
|
self.codegen_expr(obj);
|
||||||
self.emit_load_method_instr(&class, name).unwrap_or_else(|err| {
|
self.emit_load_method_instr(&class, uniq_obj_name.as_ref().map(|s| &s[..]), name)
|
||||||
|
.unwrap_or_else(|err| {
|
||||||
self.errs.push(err);
|
self.errs.push(err);
|
||||||
});
|
});
|
||||||
let argc = args.len();
|
let argc = args.len();
|
||||||
|
@ -881,8 +884,10 @@ impl CodeGenerator {
|
||||||
}
|
}
|
||||||
Expr::Accessor(Accessor::Attr(a)) => {
|
Expr::Accessor(Accessor::Attr(a)) => {
|
||||||
let class = Str::rc(a.obj.ref_t().name());
|
let class = Str::rc(a.obj.ref_t().name());
|
||||||
|
let uniq_obj_name = a.obj.__name__().map(Str::rc);
|
||||||
self.codegen_expr(*a.obj);
|
self.codegen_expr(*a.obj);
|
||||||
self.emit_load_attr_instr(&class, a.name.content.clone()).unwrap_or_else(|err| {
|
self.emit_load_attr_instr(&class, uniq_obj_name.as_ref().map(|s| &s[..]), a.name.content.clone())
|
||||||
|
.unwrap_or_else(|err| {
|
||||||
self.errs.push(err);
|
self.errs.push(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use erg_common::Str;
|
||||||
use erg_common::ty::Constraint;
|
use erg_common::ty::Constraint;
|
||||||
use erg_common::ty::RefinementType;
|
use erg_common::ty::RefinementType;
|
||||||
use erg_common::ty::fresh_varname;
|
use erg_common::ty::fresh_varname;
|
||||||
use erg_common::{fn_name, get_hash, log, assume_unreachable, set, try_map, fmt_slice};
|
use erg_common::{fn_name, get_hash, log, assume_unreachable, set, try_map, fmt_slice, enum_unwrap};
|
||||||
use erg_common::dict::Dict;
|
use erg_common::dict::Dict;
|
||||||
use erg_common::set::Set;
|
use erg_common::set::Set;
|
||||||
use erg_common::error::{Location, ErrorCore};
|
use erg_common::error::{Location, ErrorCore};
|
||||||
|
@ -241,6 +241,7 @@ pub struct Context {
|
||||||
// stores user-defined type context
|
// stores user-defined type context
|
||||||
pub(crate) types: Dict<Type, Context>,
|
pub(crate) types: Dict<Type, Context>,
|
||||||
pub(crate) patches: Dict<VarName, Context>,
|
pub(crate) patches: Dict<VarName, Context>,
|
||||||
|
pub(crate) mods: Dict<VarName, Context>,
|
||||||
pub(crate) _nlocals: usize, // necessary for CodeObj.nlocals
|
pub(crate) _nlocals: usize, // necessary for CodeObj.nlocals
|
||||||
pub(crate) level: usize,
|
pub(crate) level: usize,
|
||||||
}
|
}
|
||||||
|
@ -264,6 +265,7 @@ impl fmt::Display for Context {
|
||||||
.field("eval", &self.eval)
|
.field("eval", &self.eval)
|
||||||
.field("types", &self.types)
|
.field("types", &self.types)
|
||||||
.field("patches", &self.patches)
|
.field("patches", &self.patches)
|
||||||
|
.field("mods", &self.mods)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -329,6 +331,7 @@ impl Context {
|
||||||
unnamed_params,
|
unnamed_params,
|
||||||
eval: Evaluator::default(),
|
eval: Evaluator::default(),
|
||||||
types: Dict::default(),
|
types: Dict::default(),
|
||||||
|
mods: Dict::default(),
|
||||||
patches: Dict::default(),
|
patches: Dict::default(),
|
||||||
_nlocals: 0,
|
_nlocals: 0,
|
||||||
level,
|
level,
|
||||||
|
@ -470,7 +473,7 @@ impl Context {
|
||||||
let muty = Mutability::from(&sig.inspect().unwrap()[..]);
|
let muty = Mutability::from(&sig.inspect().unwrap()[..]);
|
||||||
let (generalized, bounds) = self.generalize_t(body_t.clone());
|
let (generalized, bounds) = self.generalize_t(body_t.clone());
|
||||||
let generalized = if !bounds.is_empty() {
|
let generalized = if !bounds.is_empty() {
|
||||||
if self.deep_supertype_of(&Type::CallableCommon, &generalized) {
|
if self.rec_supertype_of(&Type::CallableCommon, &generalized) {
|
||||||
Type::quantified(generalized, bounds)
|
Type::quantified(generalized, bounds)
|
||||||
} else { panic!() }
|
} else { panic!() }
|
||||||
} else { generalized };
|
} else { generalized };
|
||||||
|
@ -627,7 +630,7 @@ impl Context {
|
||||||
sub_t.lift();
|
sub_t.lift();
|
||||||
let (generalized, bounds) = self.generalize_t(sub_t);
|
let (generalized, bounds) = self.generalize_t(sub_t);
|
||||||
let found_t = if !bounds.is_empty() {
|
let found_t = if !bounds.is_empty() {
|
||||||
if self.deep_supertype_of(&Type::CallableCommon, &generalized) {
|
if self.rec_supertype_of(&Type::CallableCommon, &generalized) {
|
||||||
Type::quantified(generalized, bounds)
|
Type::quantified(generalized, bounds)
|
||||||
} else { panic!() }
|
} else { panic!() }
|
||||||
} else { generalized };
|
} else { generalized };
|
||||||
|
@ -636,7 +639,7 @@ impl Context {
|
||||||
vi.t.lift();
|
vi.t.lift();
|
||||||
let (generalized, bounds) = self.generalize_t(vi.t.clone());
|
let (generalized, bounds) = self.generalize_t(vi.t.clone());
|
||||||
let generalized = if !bounds.is_empty() {
|
let generalized = if !bounds.is_empty() {
|
||||||
if self.deep_supertype_of(&Type::CallableCommon, &generalized) {
|
if self.rec_supertype_of(&Type::CallableCommon, &generalized) {
|
||||||
Type::quantified(generalized, bounds)
|
Type::quantified(generalized, bounds)
|
||||||
} else { panic!() }
|
} else { panic!() }
|
||||||
} else { generalized };
|
} else { generalized };
|
||||||
|
@ -645,7 +648,7 @@ impl Context {
|
||||||
self.decls.insert(name.clone(), vi);
|
self.decls.insert(name.clone(), vi);
|
||||||
}
|
}
|
||||||
if let Some(vi) = self.decls.remove(name) {
|
if let Some(vi) = self.decls.remove(name) {
|
||||||
if !self.deep_supertype_of(&vi.t, &found_t) {
|
if !self.rec_supertype_of(&vi.t, &found_t) {
|
||||||
return Err(TyCheckError::violate_decl_error(
|
return Err(TyCheckError::violate_decl_error(
|
||||||
sig.loc(),
|
sig.loc(),
|
||||||
self.caused_by(),
|
self.caused_by(),
|
||||||
|
@ -663,11 +666,38 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_subtype_bound(&mut self, sub: Type, sup: Type) {
|
pub(crate) fn import_mod(&mut self, var_name: &VarName, mod_name: &hir::Expr) -> TyCheckResult<()> {
|
||||||
|
match mod_name {
|
||||||
|
hir::Expr::Lit(lit) => {
|
||||||
|
if self.rec_subtype_of(&lit.data.class(), &Str) {
|
||||||
|
let name = enum_unwrap!(lit.data.clone(), ValueObj::Str);
|
||||||
|
match &name[..] {
|
||||||
|
"math" => { self.mods.insert(var_name.clone(), Self::init_py_math_mod()); },
|
||||||
|
"random" => { self.mods.insert(var_name.clone(), Self::init_py_random_mod()); },
|
||||||
|
other => todo!("importing {other}"),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(TyCheckError::type_mismatch_error(
|
||||||
|
mod_name.loc(),
|
||||||
|
self.caused_by(),
|
||||||
|
"import::name",
|
||||||
|
&Str,
|
||||||
|
mod_name.ref_t()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
return Err(TyCheckError::feature_error(mod_name.loc(), "non-literal importing", self.caused_by()))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn _push_subtype_bound(&mut self, sub: Type, sup: Type) {
|
||||||
self.bounds.push(TyBound::subtype(sub, sup));
|
self.bounds.push(TyBound::subtype(sub, sup));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_instance_bound(&mut self, name: Str, t: Type) {
|
pub(crate) fn _push_instance_bound(&mut self, name: Str, t: Type) {
|
||||||
self.bounds.push(TyBound::instance(name, t));
|
self.bounds.push(TyBound::instance(name, t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1005,7 +1035,7 @@ impl Context {
|
||||||
let mut passed_params = set!{};
|
let mut passed_params = set!{};
|
||||||
let params = subr.non_default_params.iter().chain(subr.default_params.iter());
|
let params = subr.non_default_params.iter().chain(subr.default_params.iter());
|
||||||
for (param_ty, pos_arg) in params.clone().zip(pos_args) {
|
for (param_ty, pos_arg) in params.clone().zip(pos_args) {
|
||||||
self.unify(¶m_ty.ty, pos_arg.expr.ref_t(), None, Some(pos_arg.loc())).map_err(|e| {
|
self.sub_unify(pos_arg.expr.ref_t(), ¶m_ty.ty, None, Some(pos_arg.loc())).map_err(|e| {
|
||||||
TyCheckError::type_mismatch_error(
|
TyCheckError::type_mismatch_error(
|
||||||
e.core.loc,
|
e.core.loc,
|
||||||
e.caused_by,
|
e.caused_by,
|
||||||
|
@ -1037,8 +1067,8 @@ impl Context {
|
||||||
param_ts
|
param_ts
|
||||||
};
|
};
|
||||||
for kw_arg in kw_args.iter() {
|
for kw_arg in kw_args.iter() {
|
||||||
if let Some(ty) = param_ts.get(kw_arg.keyword.inspect()) {
|
if let Some(param_ty) = param_ts.get(kw_arg.keyword.inspect()) {
|
||||||
self.unify(ty, kw_arg.expr.ref_t(), None, Some(kw_arg.loc()))?;
|
self.sub_unify(kw_arg.expr.ref_t(), param_ty, None, Some(kw_arg.loc()))?;
|
||||||
} else {
|
} else {
|
||||||
return Err(TyCheckError::unexpected_kw_arg_error(
|
return Err(TyCheckError::unexpected_kw_arg_error(
|
||||||
kw_arg.keyword.loc(),
|
kw_arg.keyword.loc(),
|
||||||
|
@ -1132,7 +1162,7 @@ impl Context {
|
||||||
|
|
||||||
/// allow_divergence = trueにすると、Num型変数と±Infの単一化を許す
|
/// allow_divergence = trueにすると、Num型変数と±Infの単一化を許す
|
||||||
pub(crate) fn unify_tp(&self, l: &TyParam, r: &TyParam, bounds: Option<&Set<TyBound>>, allow_divergence: bool) -> TyCheckResult<()> {
|
pub(crate) fn unify_tp(&self, l: &TyParam, r: &TyParam, bounds: Option<&Set<TyBound>>, allow_divergence: bool) -> TyCheckResult<()> {
|
||||||
if l.has_no_unbound_var() && r.has_no_unbound_var() && l.deep_eq(r) { return Ok(()) }
|
if l.has_no_unbound_var() && r.has_no_unbound_var() && l.rec_eq(r) { return Ok(()) }
|
||||||
match (l, r) {
|
match (l, r) {
|
||||||
(TyParam::Type(l), TyParam::Type(r)) =>
|
(TyParam::Type(l), TyParam::Type(r)) =>
|
||||||
self.unify(&l, &r, None, None),
|
self.unify(&l, &r, None, None),
|
||||||
|
@ -1155,7 +1185,7 @@ impl Context {
|
||||||
.unwrap().typ()
|
.unwrap().typ()
|
||||||
.unwrap().clone(); // fvを参照しないよいにcloneする(あとでborrow_mutするため)
|
.unwrap().clone(); // fvを参照しないよいにcloneする(あとでborrow_mutするため)
|
||||||
let tp_t = self.eval.get_tp_t(tp, bounds, &self)?;
|
let tp_t = self.eval.get_tp_t(tp, bounds, &self)?;
|
||||||
if self.deep_supertype_of(&fv_t, &tp_t) {
|
if self.rec_supertype_of(&fv_t, &tp_t) {
|
||||||
// 外部未連携型変数の場合、linkしないで制約を弱めるだけにする(see compiler/inference.md)
|
// 外部未連携型変数の場合、linkしないで制約を弱めるだけにする(see compiler/inference.md)
|
||||||
if fv.level() < Some(self.level) {
|
if fv.level() < Some(self.level) {
|
||||||
let new_constraint = Constraint::SubtypeOf(tp_t.clone());
|
let new_constraint = Constraint::SubtypeOf(tp_t.clone());
|
||||||
|
@ -1172,7 +1202,7 @@ impl Context {
|
||||||
&& (
|
&& (
|
||||||
self.eq_tp(&tp, &TyParam::value(Inf), None)
|
self.eq_tp(&tp, &TyParam::value(Inf), None)
|
||||||
|| self.eq_tp(&tp, &TyParam::value(NegInf), None)
|
|| self.eq_tp(&tp, &TyParam::value(NegInf), None)
|
||||||
) && self.deep_subtype_of(&fv_t, &Type::mono("Num")) {
|
) && self.rec_subtype_of(&fv_t, &Type::mono("Num")) {
|
||||||
fv.link(tp);
|
fv.link(tp);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
|
@ -1279,7 +1309,9 @@ impl Context {
|
||||||
/// So `unify(?T, Int); unify(?T, Bool)` will causes an error
|
/// So `unify(?T, Int); unify(?T, Bool)` will causes an error
|
||||||
/// To bypass the constraint, you need to specify `'T: Structural` in the type bounds
|
/// To bypass the constraint, you need to specify `'T: Structural` in the type bounds
|
||||||
pub(crate) fn unify(&self, lhs_t: &Type, rhs_t: &Type, lhs_loc: Option<Location>, rhs_loc: Option<Location>) -> TyCheckResult<()> {
|
pub(crate) fn unify(&self, lhs_t: &Type, rhs_t: &Type, lhs_loc: Option<Location>, rhs_loc: Option<Location>) -> TyCheckResult<()> {
|
||||||
if lhs_t.has_no_unbound_var() && rhs_t.has_no_unbound_var() && self.deep_supertype_of(lhs_t, rhs_t) { return Ok(()) }
|
if lhs_t.has_no_unbound_var()
|
||||||
|
&& rhs_t.has_no_unbound_var()
|
||||||
|
&& self.rec_supertype_of(lhs_t, rhs_t) { return Ok(()) }
|
||||||
match (lhs_t, rhs_t) {
|
match (lhs_t, rhs_t) {
|
||||||
// unify(?T[2], ?U[3]): ?U[3] => ?T[2]
|
// unify(?T[2], ?U[3]): ?U[3] => ?T[2]
|
||||||
// bind the higher level var to lower one
|
// bind the higher level var to lower one
|
||||||
|
@ -1302,7 +1334,7 @@ impl Context {
|
||||||
if let Some(sup) = constraint.super_type_mut() {
|
if let Some(sup) = constraint.super_type_mut() {
|
||||||
// 下のような場合は制約を弱化する
|
// 下のような場合は制約を弱化する
|
||||||
// unify(?T(<: Nat), Int): (?T(<: Int))
|
// unify(?T(<: Nat), Int): (?T(<: Int))
|
||||||
if self.deep_subtype_of(sup, t) {
|
if self.rec_subtype_of(sup, t) {
|
||||||
*sup = t.clone();
|
*sup = t.clone();
|
||||||
} else {
|
} else {
|
||||||
self.sub_unify(t, sup, rhs_loc, lhs_loc)?;
|
self.sub_unify(t, sup, rhs_loc, lhs_loc)?;
|
||||||
|
@ -1421,32 +1453,44 @@ impl Context {
|
||||||
/// sub_unify(Nat, Add(?R, ?O)): (?R => Nat, ?O => Nat)
|
/// sub_unify(Nat, Add(?R, ?O)): (?R => Nat, ?O => Nat)
|
||||||
/// sub_unify([?T; 0], Mutate): ()
|
/// sub_unify([?T; 0], Mutate): ()
|
||||||
/// ```
|
/// ```
|
||||||
fn sub_unify(&self, sub: &Type, sup: &Type, sub_loc: Option<Location>, sup_loc: Option<Location>) -> TyCheckResult<()> {
|
fn sub_unify(&self, maybe_sub: &Type, maybe_sup: &Type, sub_loc: Option<Location>, sup_loc: Option<Location>) -> TyCheckResult<()> {
|
||||||
if sub.has_no_unbound_var() && sup.has_no_unbound_var() { return Ok(()) }
|
if maybe_sub.has_no_unbound_var()
|
||||||
match (sub, sup) {
|
&& maybe_sup.has_no_unbound_var()
|
||||||
|
&& self.rec_subtype_of(maybe_sub, maybe_sup) { return Ok(()) }
|
||||||
|
if !self.rec_subtype_of(maybe_sub, maybe_sup) {
|
||||||
|
let loc = sub_loc.or(sup_loc).unwrap_or(Location::Unknown);
|
||||||
|
return Err(TyCheckError::type_mismatch_error(
|
||||||
|
loc,
|
||||||
|
self.caused_by(),
|
||||||
|
"<???>",
|
||||||
|
maybe_sup,
|
||||||
|
maybe_sub,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
match (maybe_sub, maybe_sup) {
|
||||||
(l @ Refinement(_), r @ Refinement(_)) => {
|
(l @ Refinement(_), r @ Refinement(_)) => {
|
||||||
return self.unify(l ,r, sub_loc, sup_loc)
|
return self.unify(l ,r, sub_loc, sup_loc)
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
let mut opt_smallest = None;
|
let mut opt_smallest = None;
|
||||||
for ctx in self.get_sorted_supertypes(sub) {
|
for ctx in self.get_sorted_supertypes(maybe_sub) {
|
||||||
let instances = ctx.super_classes.iter()
|
let instances = ctx.super_classes.iter()
|
||||||
.chain(ctx.super_traits.iter())
|
.chain(ctx.super_traits.iter())
|
||||||
.filter(|t| self.supertype_of(sup, t, None));
|
.filter(|t| self.supertype_of(maybe_sup, t, None));
|
||||||
// instanceが複数ある場合、経験的に最も小さい型を選ぶのが良い
|
// instanceが複数ある場合、経験的に最も小さい型を選ぶのが良い
|
||||||
// これでうまくいかない場合は型指定してもらう(REVIEW: もっと良い方法があるか?)
|
// これでうまくいかない場合は型指定してもらう(REVIEW: もっと良い方法があるか?)
|
||||||
if let Some(t) = self.smallest_ref_t(instances) {
|
if let Some(t) = self.smallest_ref_t(instances) {
|
||||||
opt_smallest = if let Some(small) = opt_smallest { self.min(small, t) } else { Some(t) };
|
opt_smallest = if let Some(small) = opt_smallest { self.min(small, t) } else { Some(t) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let glue_patch_and_types = self.deep_get_glue_patch_and_types();
|
let glue_patch_and_types = self.rec_get_glue_patch_and_types();
|
||||||
let patch_instances = glue_patch_and_types.iter()
|
let patch_instances = glue_patch_and_types.iter()
|
||||||
.filter_map(|(patch_name, l, r)| {
|
.filter_map(|(patch_name, l, r)| {
|
||||||
let patch = self.deep_get_patch(patch_name).unwrap();
|
let patch = self.rec_get_patch(patch_name).unwrap();
|
||||||
let bounds = patch.bounds();
|
let bounds = patch.bounds();
|
||||||
if self.supertype_of(l, sub, Some(&bounds))
|
if self.supertype_of(l, maybe_sub, Some(&bounds))
|
||||||
&& self.supertype_of(r, sup, Some(&bounds)) {
|
&& self.supertype_of(r, maybe_sup, Some(&bounds)) {
|
||||||
let tv_ctx = TyVarContext::new(self.level, bounds);
|
let tv_ctx = TyVarContext::new(self.level, bounds);
|
||||||
let (l, _) = Self::instantiate_t(l.clone(), tv_ctx.clone());
|
let (l, _) = Self::instantiate_t(l.clone(), tv_ctx.clone());
|
||||||
let (r, _) = Self::instantiate_t(r.clone(), tv_ctx);
|
let (r, _) = Self::instantiate_t(r.clone(), tv_ctx);
|
||||||
|
@ -1457,22 +1501,22 @@ impl Context {
|
||||||
match (opt_smallest, opt_smallest_pair) {
|
match (opt_smallest, opt_smallest_pair) {
|
||||||
(Some(smallest), Some((l, r))) => {
|
(Some(smallest), Some((l, r))) => {
|
||||||
if self.min(smallest, &r) == Some(&r) {
|
if self.min(smallest, &r) == Some(&r) {
|
||||||
self.unify(sub, &l, sub_loc, None)?;
|
self.unify(maybe_sub, &l, sub_loc, None)?;
|
||||||
self.unify(sup, &r, sup_loc, None)
|
self.unify(maybe_sup, &r, sup_loc, None)
|
||||||
} else {
|
} else {
|
||||||
self.unify(sup, smallest, sup_loc, None)
|
self.unify(maybe_sup, smallest, sup_loc, None)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(Some(smallest), None) => {
|
(Some(smallest), None) => {
|
||||||
self.unify(sup, smallest, sup_loc, None)
|
self.unify(maybe_sup, smallest, sup_loc, None)
|
||||||
},
|
},
|
||||||
(None, Some((l, r))) => {
|
(None, Some((l, r))) => {
|
||||||
self.unify(sub, &l, sub_loc, None)?;
|
self.unify(maybe_sub, &l, sub_loc, None)?;
|
||||||
self.unify(sup, &r, sup_loc, None)?;
|
self.unify(maybe_sup, &r, sup_loc, None)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
(None, None) => {
|
(None, None) => {
|
||||||
log!("{sub}, {sup}");
|
log!("{maybe_sub}, {maybe_sup}");
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1706,6 +1750,26 @@ impl Context {
|
||||||
self.impls.get(name).or_else(|| self.decls.get(name))
|
self.impls.get(name).or_else(|| self.decls.get(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_context(&self, obj: &hir::Expr, kind: Option<ContextKind>, namespace: &Str) -> TyCheckResult<&Context> {
|
||||||
|
match obj {
|
||||||
|
hir::Expr::Accessor(hir::Accessor::Local(name)) => {
|
||||||
|
if kind == Some(ContextKind::Module) {
|
||||||
|
if let Some(ctx) = self.rec_get_mod(name.inspect()) {
|
||||||
|
Ok(ctx)
|
||||||
|
} else {
|
||||||
|
Err(TyCheckError::no_var_error(
|
||||||
|
obj.loc(),
|
||||||
|
namespace.clone(),
|
||||||
|
name.inspect(),
|
||||||
|
self.get_similar_name(name.inspect()),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
} else { todo!() }
|
||||||
|
},
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_match_call_t(&self, pos_args: &[hir::PosArg], kw_args: &[hir::KwArg]) -> TyCheckResult<Type> {
|
fn get_match_call_t(&self, pos_args: &[hir::PosArg], kw_args: &[hir::KwArg]) -> TyCheckResult<Type> {
|
||||||
if !kw_args.is_empty() { todo!() }
|
if !kw_args.is_empty() { todo!() }
|
||||||
for pos_arg in pos_args.iter().skip(1) {
|
for pos_arg in pos_args.iter().skip(1) {
|
||||||
|
@ -1763,6 +1827,14 @@ impl Context {
|
||||||
Ok(t)
|
Ok(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_local_uniq_obj_name(&self, name: &Token) -> Option<Str> {
|
||||||
|
// TODO: types, functions, patches
|
||||||
|
if let Some(ctx) = self.rec_get_mod(name.inspect()) {
|
||||||
|
return Some(ctx.name.clone())
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn get_local_t(&self, name: &Token, namespace: &Str) -> TyCheckResult<Type> {
|
pub(crate) fn get_local_t(&self, name: &Token, namespace: &Str) -> TyCheckResult<Type> {
|
||||||
if let Some(vi) = self.impls.get(name.inspect())
|
if let Some(vi) = self.impls.get(name.inspect())
|
||||||
.or_else(|| self.decls.get(name.inspect())) {
|
.or_else(|| self.decls.get(name.inspect())) {
|
||||||
|
@ -1782,7 +1854,17 @@ impl Context {
|
||||||
|
|
||||||
pub(crate) fn get_attr_t(&self, obj: &hir::Expr, name: &Token, namespace: &Str) -> TyCheckResult<Type> {
|
pub(crate) fn get_attr_t(&self, obj: &hir::Expr, name: &Token, namespace: &Str) -> TyCheckResult<Type> {
|
||||||
let self_t = obj.t();
|
let self_t = obj.t();
|
||||||
if self_t == ASTOmitted { panic!() }
|
match self_t {
|
||||||
|
ASTOmitted => panic!(),
|
||||||
|
Type => todo!(),
|
||||||
|
Type::Record(_) => todo!(),
|
||||||
|
Module => {
|
||||||
|
let mod_ctx = self.get_context(obj, Some(ContextKind::Module), namespace)?;
|
||||||
|
let t = mod_ctx.get_local_t(name, namespace)?;
|
||||||
|
return Ok(t)
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
for ctx in self.get_sorted_supertypes(&self_t) {
|
for ctx in self.get_sorted_supertypes(&self_t) {
|
||||||
if let Ok(t) = ctx.get_local_t(name, namespace) {
|
if let Ok(t) = ctx.get_local_t(name, namespace) {
|
||||||
return Ok(t)
|
return Ok(t)
|
||||||
|
@ -1866,7 +1948,7 @@ impl Context {
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn deep_supertype_of(&self, lhs: &Type, rhs: &Type) -> bool {
|
pub(crate) fn rec_supertype_of(&self, lhs: &Type, rhs: &Type) -> bool {
|
||||||
if self.supertype_of(lhs, rhs, None) { return true }
|
if self.supertype_of(lhs, rhs, None) { return true }
|
||||||
for sup_rhs in self.get_sorted_supertypes(rhs) {
|
for sup_rhs in self.get_sorted_supertypes(rhs) {
|
||||||
let bounds = sup_rhs.bounds();
|
let bounds = sup_rhs.bounds();
|
||||||
|
@ -1874,23 +1956,23 @@ impl Context {
|
||||||
|| sup_rhs.super_traits.iter().any(|sup| self.supertype_of(lhs, sup, Some(&bounds))) { return true }
|
|| sup_rhs.super_traits.iter().any(|sup| self.supertype_of(lhs, sup, Some(&bounds))) { return true }
|
||||||
}
|
}
|
||||||
for (patch_name, sub, sup) in self.glue_patch_and_types.iter() {
|
for (patch_name, sub, sup) in self.glue_patch_and_types.iter() {
|
||||||
let patch = self.deep_get_patch(patch_name).unwrap();
|
let patch = self.rec_get_patch(patch_name).unwrap();
|
||||||
let bounds = patch.bounds();
|
let bounds = patch.bounds();
|
||||||
if self.supertype_of(sub, rhs, Some(&bounds))
|
if self.supertype_of(sub, rhs, Some(&bounds))
|
||||||
&& self.supertype_of(sup, lhs, Some(&bounds)) { return true }
|
&& self.supertype_of(sup, lhs, Some(&bounds)) { return true }
|
||||||
}
|
}
|
||||||
if let Some(outer) = &self.outer {
|
if let Some(outer) = &self.outer {
|
||||||
if outer.deep_supertype_of(lhs, rhs) { return true }
|
if outer.rec_supertype_of(lhs, rhs) { return true }
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn deep_subtype_of(&self, lhs: &Type, rhs: &Type) -> bool {
|
pub(crate) fn rec_subtype_of(&self, lhs: &Type, rhs: &Type) -> bool {
|
||||||
self.deep_supertype_of(rhs, lhs)
|
self.rec_supertype_of(rhs, lhs)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn _deep_same_type_of(&self, lhs: &Type, rhs: &Type) -> bool {
|
pub(crate) fn _rec_same_type_of(&self, lhs: &Type, rhs: &Type) -> bool {
|
||||||
self.deep_supertype_of(lhs, rhs) && self.deep_subtype_of(lhs, rhs)
|
self.rec_supertype_of(lhs, rhs) && self.rec_subtype_of(lhs, rhs)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eq_tp(&self, lhs: &TyParam, rhs: &TyParam, bounds: Option<&Set<TyBound>>) -> bool {
|
fn eq_tp(&self, lhs: &TyParam, rhs: &TyParam, bounds: Option<&Set<TyBound>>) -> bool {
|
||||||
|
@ -1946,7 +2028,7 @@ impl Context {
|
||||||
/// 単一化、評価等はここでは行わない、スーパータイプになる可能性があるかだけ判定する
|
/// 単一化、評価等はここでは行わない、スーパータイプになる可能性があるかだけ判定する
|
||||||
/// ので、lhsが(未連携)型変数の場合は単一化せずにtrueを返す
|
/// ので、lhsが(未連携)型変数の場合は単一化せずにtrueを返す
|
||||||
pub(crate) fn supertype_of(&self, lhs: &Type, rhs: &Type, bounds: Option<&Set<TyBound>>) -> bool {
|
pub(crate) fn supertype_of(&self, lhs: &Type, rhs: &Type, bounds: Option<&Set<TyBound>>) -> bool {
|
||||||
if lhs.deep_eq(rhs) { return true }
|
if lhs.rec_eq(rhs) { return true }
|
||||||
match (lhs, rhs) {
|
match (lhs, rhs) {
|
||||||
// FIXME: Obj/Neverはクラス、Top/Bottomは構造型
|
// FIXME: Obj/Neverはクラス、Top/Bottomは構造型
|
||||||
(Obj, _) | (_, Never) => true,
|
(Obj, _) | (_, Never) => true,
|
||||||
|
@ -2136,7 +2218,7 @@ impl Context {
|
||||||
) /* if v.is_unbound() */ => {
|
) /* if v.is_unbound() */ => {
|
||||||
let l_t = self.eval.get_tp_t(l, bounds, self).unwrap();
|
let l_t = self.eval.get_tp_t(l, bounds, self).unwrap();
|
||||||
let r_t = self.eval.get_tp_t(r, bounds, self).unwrap();
|
let r_t = self.eval.get_tp_t(r, bounds, self).unwrap();
|
||||||
if self.deep_supertype_of(&l_t, &r_t) || self.deep_subtype_of(&l_t, &r_t) {
|
if self.rec_supertype_of(&l_t, &r_t) || self.rec_subtype_of(&l_t, &r_t) {
|
||||||
Some(Any)
|
Some(Any)
|
||||||
} else { Some(NotEqual) }
|
} else { Some(NotEqual) }
|
||||||
},
|
},
|
||||||
|
@ -2212,7 +2294,7 @@ impl Context {
|
||||||
|
|
||||||
/// 和集合(A or B)を返す
|
/// 和集合(A or B)を返す
|
||||||
fn union(&self, lhs: &Type, rhs: &Type) -> Type {
|
fn union(&self, lhs: &Type, rhs: &Type) -> Type {
|
||||||
match (self.deep_supertype_of(lhs, rhs), self.deep_subtype_of(lhs, rhs)) {
|
match (self.rec_supertype_of(lhs, rhs), self.rec_subtype_of(lhs, rhs)) {
|
||||||
(true, true) => return lhs.clone(), // lhs = rhs
|
(true, true) => return lhs.clone(), // lhs = rhs
|
||||||
(true, false) => return lhs.clone(), // lhs :> rhs
|
(true, false) => return lhs.clone(), // lhs :> rhs
|
||||||
(false, true) => return rhs.clone(),
|
(false, true) => return rhs.clone(),
|
||||||
|
@ -2296,7 +2378,7 @@ impl Context {
|
||||||
// |I: Nat| <: |I: Int|
|
// |I: Nat| <: |I: Int|
|
||||||
(Constraint::SubtypeOf(lhs), Constraint::SubtypeOf(rhs))
|
(Constraint::SubtypeOf(lhs), Constraint::SubtypeOf(rhs))
|
||||||
| (Constraint::TypeOf(lhs), Constraint::TypeOf(rhs)) =>
|
| (Constraint::TypeOf(lhs), Constraint::TypeOf(rhs)) =>
|
||||||
self.deep_subtype_of(lhs, rhs),
|
self.rec_subtype_of(lhs, rhs),
|
||||||
(Constraint::SubtypeOf(_), Constraint::TypeOf(Type)) => true,
|
(Constraint::SubtypeOf(_), Constraint::TypeOf(Type)) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
@ -2364,8 +2446,8 @@ impl Context {
|
||||||
/// lhsとrhsが包含関係にあるとき小さいほうを返す
|
/// lhsとrhsが包含関係にあるとき小さいほうを返す
|
||||||
/// 関係なければNoneを返す
|
/// 関係なければNoneを返す
|
||||||
fn min<'t>(&self, lhs: &'t Type, rhs: &'t Type) -> Option<&'t Type> {
|
fn min<'t>(&self, lhs: &'t Type, rhs: &'t Type) -> Option<&'t Type> {
|
||||||
if self.deep_supertype_of(lhs, rhs) { Some(rhs) }
|
if self.rec_supertype_of(lhs, rhs) { Some(rhs) }
|
||||||
else if self.deep_subtype_of(lhs, rhs) { Some(rhs) }
|
else if self.rec_subtype_of(lhs, rhs) { Some(rhs) }
|
||||||
else { None }
|
else { None }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2475,23 +2557,23 @@ impl Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_sorted_supertypes<'a>(&'a self, t: &'a Type) -> impl Iterator<Item=&'a Context> {
|
pub(crate) fn get_sorted_supertypes<'a>(&'a self, t: &'a Type) -> impl Iterator<Item=&'a Context> {
|
||||||
let mut ctxs = self._deep_get_supertypes(t).collect::<Vec<_>>();
|
let mut ctxs = self._rec_get_supertypes(t).collect::<Vec<_>>();
|
||||||
ctxs.sort_by(|(lhs, _), (rhs, _)| self.cmp_t(lhs, rhs));
|
ctxs.sort_by(|(lhs, _), (rhs, _)| self.cmp_t(lhs, rhs));
|
||||||
ctxs.into_iter().map(|(_, ctx)| ctx)
|
ctxs.into_iter().map(|(_, ctx)| ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// this method is for `get_sorted_supertypes` only
|
/// this method is for `get_sorted_supertypes` only
|
||||||
fn _deep_get_supertypes<'a>(&'a self, t: &'a Type) -> impl Iterator<Item=(&'a Type, &'a Context)> {
|
fn _rec_get_supertypes<'a>(&'a self, t: &'a Type) -> impl Iterator<Item=(&'a Type, &'a Context)> {
|
||||||
let i = self._get_supertypes(t);
|
let i = self._get_supertypes(t);
|
||||||
if i.size_hint().1 == Some(0) {
|
if i.size_hint().1 == Some(0) {
|
||||||
if let Some(outer) = &self.outer {
|
if let Some(outer) = &self.outer {
|
||||||
return outer._deep_get_supertypes(t)
|
return outer._rec_get_supertypes(t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i
|
i
|
||||||
}
|
}
|
||||||
|
|
||||||
/// this method is for `deep_get_supertypes` only
|
/// this method is for `rec_get_supertypes` only
|
||||||
fn _get_supertypes<'a>(&'a self, t: &'a Type) -> impl Iterator<Item=(&'a Type, &'a Context)> {
|
fn _get_supertypes<'a>(&'a self, t: &'a Type) -> impl Iterator<Item=(&'a Type, &'a Context)> {
|
||||||
self.types.iter()
|
self.types.iter()
|
||||||
.filter_map(|(maybe_sup, ctx)| {
|
.filter_map(|(maybe_sup, ctx)| {
|
||||||
|
@ -2500,21 +2582,31 @@ impl Context {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deep_get_glue_patch_and_types(&self) -> Vec<(VarName, Type, Type)> {
|
fn rec_get_glue_patch_and_types(&self) -> Vec<(VarName, Type, Type)> {
|
||||||
if let Some(outer) = &self.outer {
|
if let Some(outer) = &self.outer {
|
||||||
[&self.glue_patch_and_types[..], &outer.deep_get_glue_patch_and_types()].concat()
|
[&self.glue_patch_and_types[..], &outer.rec_get_glue_patch_and_types()].concat()
|
||||||
} else {
|
} else {
|
||||||
self.glue_patch_and_types.clone()
|
self.glue_patch_and_types.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// this method is for `get_sorted_supertypes` only
|
fn rec_get_patch(&self, name: &VarName) -> Option<&Context> {
|
||||||
fn deep_get_patch(&self, name: &VarName) -> Option<&Context> {
|
|
||||||
if let Some(patch) = self.patches.get(name) {
|
if let Some(patch) = self.patches.get(name) {
|
||||||
return Some(patch)
|
return Some(patch)
|
||||||
} else {
|
} else {
|
||||||
if let Some(outer) = &self.outer {
|
if let Some(outer) = &self.outer {
|
||||||
return outer.deep_get_patch(name)
|
return outer.rec_get_patch(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rec_get_mod(&self, name: &str) -> Option<&Context> {
|
||||||
|
if let Some(mod_) = self.mods.get(name) {
|
||||||
|
return Some(mod_)
|
||||||
|
} else {
|
||||||
|
if let Some(outer) = &self.outer {
|
||||||
|
return outer.rec_get_mod(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
|
|
@ -211,15 +211,20 @@ impl Args {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Local {
|
pub struct Local {
|
||||||
pub name: Token,
|
pub name: Token,
|
||||||
|
/// オブジェクト自身の名前
|
||||||
|
__name__: Option<Str>,
|
||||||
t: Type,
|
t: Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Local {
|
impl fmt::Display for Local {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let __name__ = if let Some(__name__) = self.__name__() {
|
||||||
|
format!("(__name__ = {__name__})")
|
||||||
|
} else { "".to_string() };
|
||||||
if self.t != Type::ASTOmitted {
|
if self.t != Type::ASTOmitted {
|
||||||
write!(f, "{} (: {})", self.name.content, self.t)
|
write!(f, "{} (: {}){}", self.name.content, self.t, __name__)
|
||||||
} else {
|
} else {
|
||||||
write!(f, "{}", self.name.content)
|
write!(f, "{}{}", self.name.content, __name__)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,11 +242,13 @@ impl Locational for Local {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Local {
|
impl Local {
|
||||||
pub const fn new(name: Token, t: Type) -> Self { Self{ name, t } }
|
pub const fn new(name: Token, __name__: Option<Str>, t: Type) -> Self { Self{ name, __name__, t } }
|
||||||
|
|
||||||
// &strにするとクローンしたいときにアロケーションコストがかかるので&Strのままで
|
// &strにするとクローンしたいときにアロケーションコストがかかるので&Strのままで
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn inspect(&self) -> &Str { &self.name.content }
|
pub fn inspect(&self) -> &Str { &self.name.content }
|
||||||
|
|
||||||
|
pub const fn __name__(&self) -> Option<&Str> { self.__name__.as_ref() }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -312,7 +319,7 @@ impl NestedDisplay for Accessor {
|
||||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Local(name) => write!(f, "{}", name),
|
Self::Local(name) => write!(f, "{}", name),
|
||||||
Self::SelfDot(attr) => write!(f, "self.{}", attr),
|
Self::SelfDot(attr) => write!(f, ".{}", attr),
|
||||||
Self::Attr(attr) => write!(f, "{}", attr),
|
Self::Attr(attr) => write!(f, "{}", attr),
|
||||||
Self::Subscr(subscr) => write!(f, "{}", subscr),
|
Self::Subscr(subscr) => write!(f, "{}", subscr),
|
||||||
}
|
}
|
||||||
|
@ -336,9 +343,9 @@ impl HasType for Accessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Accessor {
|
impl Accessor {
|
||||||
pub const fn local(symbol: Token, t: Type) -> Self { Self::Local(Local::new(symbol, t)) }
|
pub const fn local(symbol: Token, t: Type) -> Self { Self::Local(Local::new(symbol, None, t)) }
|
||||||
|
|
||||||
pub const fn self_dot(name: Token, t: Type) -> Self { Self::SelfDot(Local::new(name, t)) }
|
pub const fn self_dot(name: Token, t: Type) -> Self { Self::SelfDot(Local::new(name, None, t)) }
|
||||||
|
|
||||||
pub fn attr(obj: Expr, name: Token, t: Type) -> Self {
|
pub fn attr(obj: Expr, name: Token, t: Type) -> Self {
|
||||||
Self::Attr(Attribute::new(obj, name, t))
|
Self::Attr(Attribute::new(obj, name, t))
|
||||||
|
@ -347,6 +354,23 @@ impl Accessor {
|
||||||
pub fn subscr(obj: Expr, index: Expr, t: Type) -> Self {
|
pub fn subscr(obj: Expr, index: Expr, t: Type) -> Self {
|
||||||
Self::Subscr(Subscript::new(obj, index, t))
|
Self::Subscr(Subscript::new(obj, index, t))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> Option<&Str> {
|
||||||
|
match self {
|
||||||
|
Self::Local(local)
|
||||||
|
| Self::SelfDot(local) => Some(local.inspect()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 参照するオブジェクト自体が持っている固有の名前
|
||||||
|
pub fn __name__(&self) -> Option<&str> {
|
||||||
|
match self {
|
||||||
|
Self::Local(local)
|
||||||
|
| Self::SelfDot(local) => local.__name__().map(|s| &s[..]),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -531,6 +555,12 @@ impl Call {
|
||||||
pub fn new(obj: Expr, args: Args, sig_t: Type) -> Self {
|
pub fn new(obj: Expr, args: Args, sig_t: Type) -> Self {
|
||||||
Self { obj: Box::new(obj), args, sig_t }
|
Self { obj: Box::new(obj), args, sig_t }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_import_call(&self) -> bool {
|
||||||
|
self.obj.get_name()
|
||||||
|
.map(|s| &s[..] == "import" || &s[..] == "pyimport")
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -792,6 +822,21 @@ impl Expr {
|
||||||
_other => None,
|
_other => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_name(&self) -> Option<&Str> {
|
||||||
|
match self {
|
||||||
|
Expr::Accessor(acc) => acc.name(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 参照するオブジェクト自体が持っている名前(e.g. Int.__name__ == Some("int"))
|
||||||
|
pub fn __name__(&self) -> Option<&str> {
|
||||||
|
match self {
|
||||||
|
Expr::Accessor(acc) => acc.__name__(),
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Toplevel grammar unit
|
/// Toplevel grammar unit
|
||||||
|
|
|
@ -95,10 +95,13 @@ impl ASTLowerer {
|
||||||
log!("[DEBUG] entered {}({acc})", fn_name!());
|
log!("[DEBUG] entered {}({acc})", fn_name!());
|
||||||
match acc {
|
match acc {
|
||||||
ast::Accessor::Local(n) => {
|
ast::Accessor::Local(n) => {
|
||||||
let t = if check {
|
let (t, __name__) = if check {
|
||||||
self.mod_ctx.get_local_t(&n.symbol, &self.mod_ctx.name)?
|
(
|
||||||
} else { Type::ASTOmitted };
|
self.mod_ctx.get_local_t(&n.symbol, &self.mod_ctx.name)?,
|
||||||
let acc = hir::Accessor::Local(hir::Local::new(n.symbol, t));
|
self.mod_ctx.get_local_uniq_obj_name(&n.symbol),
|
||||||
|
)
|
||||||
|
} else { (Type::ASTOmitted, None) };
|
||||||
|
let acc = hir::Accessor::Local(hir::Local::new(n.symbol, __name__, t));
|
||||||
Ok(acc)
|
Ok(acc)
|
||||||
}
|
}
|
||||||
ast::Accessor::Attr(a) => {
|
ast::Accessor::Attr(a) => {
|
||||||
|
@ -248,6 +251,18 @@ impl ASTLowerer {
|
||||||
let id = body.id;
|
let id = body.id;
|
||||||
// TODO: cover all VarPatterns
|
// TODO: cover all VarPatterns
|
||||||
self.mod_ctx.outer.as_mut().unwrap().assign_var(&sig, id, found_body_t)?;
|
self.mod_ctx.outer.as_mut().unwrap().assign_var(&sig, id, found_body_t)?;
|
||||||
|
match block.first().unwrap() {
|
||||||
|
hir::Expr::Call(call) => {
|
||||||
|
if let ast::VarPattern::VarName(name) = &sig.pat {
|
||||||
|
if call.is_import_call() {
|
||||||
|
self.mod_ctx.outer.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.import_mod(name, &call.args.pos_args().first().unwrap().expr)?;
|
||||||
|
}
|
||||||
|
} else { todo!() }
|
||||||
|
},
|
||||||
|
_other => {}
|
||||||
|
}
|
||||||
let sig = hir::VarSignature::new(sig.pat, found_body_t.clone());
|
let sig = hir::VarSignature::new(sig.pat, found_body_t.clone());
|
||||||
let body = hir::DefBody::new(body.op, block, body.id);
|
let body = hir::DefBody::new(body.op, block, body.id);
|
||||||
Ok(hir::Def::new(hir::Signature::Var(sig), body))
|
Ok(hir::Def::new(hir::Signature::Var(sig), body))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue