mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-28 04:09:05 +00:00
feat: introduce bidirectional type checking
This commit is contained in:
parent
5f8d744e47
commit
75b5b68831
13 changed files with 501 additions and 135 deletions
|
@ -94,7 +94,7 @@ impl HIRDiff {
|
||||||
ASTDiff::Deletion(idx) => Some(Self::Deletion(idx)),
|
ASTDiff::Deletion(idx) => Some(Self::Deletion(idx)),
|
||||||
ASTDiff::Addition(idx, expr) => {
|
ASTDiff::Addition(idx, expr) => {
|
||||||
let expr = lowerer
|
let expr = lowerer
|
||||||
.lower_chunk(expr)
|
.lower_chunk(expr, None)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
crate::_log!("err: {err}");
|
crate::_log!("err: {err}");
|
||||||
})
|
})
|
||||||
|
@ -111,7 +111,7 @@ impl HIRDiff {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let expr = lowerer
|
let expr = lowerer
|
||||||
.lower_chunk(expr)
|
.lower_chunk(expr, None)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
crate::_log!("err: {err}");
|
crate::_log!("err: {err}");
|
||||||
})
|
})
|
||||||
|
|
|
@ -1022,6 +1022,12 @@ impl Locational for () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Locational, const N: usize> Locational for [T; N] {
|
||||||
|
fn loc(&self) -> Location {
|
||||||
|
Location::stream(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! impl_locational_for_enum {
|
macro_rules! impl_locational_for_enum {
|
||||||
($Enum: ident; $($Variant: ident $(,)?)*) => {
|
($Enum: ident; $($Variant: ident $(,)?)*) => {
|
||||||
|
|
|
@ -20,7 +20,7 @@ use erg_parser::desugar::Desugarer;
|
||||||
use erg_parser::token::{Token, TokenKind};
|
use erg_parser::token::{Token, TokenKind};
|
||||||
|
|
||||||
use crate::ty::constructors::{
|
use crate::ty::constructors::{
|
||||||
array_t, dict_t, mono, mono_q, named_free_var, poly, proj, proj_call, ref_, ref_mut,
|
array_t, bounded, dict_t, mono, mono_q, named_free_var, poly, proj, proj_call, ref_, ref_mut,
|
||||||
refinement, set_t, subr_t, subtypeof, tp_enum, tuple_t, v_enum,
|
refinement, set_t, subr_t, subtypeof, tp_enum, tuple_t, v_enum,
|
||||||
};
|
};
|
||||||
use crate::ty::free::{Constraint, HasLevel};
|
use crate::ty::free::{Constraint, HasLevel};
|
||||||
|
@ -1668,8 +1668,8 @@ impl Context {
|
||||||
if let Some(fv) = lhs.as_free() {
|
if let Some(fv) = lhs.as_free() {
|
||||||
let (sub, sup) = fv.get_subsup().unwrap();
|
let (sub, sup) = fv.get_subsup().unwrap();
|
||||||
if self.is_trait(&sup) && !self.trait_impl_exists(&sub, &sup) {
|
if self.is_trait(&sup) && !self.trait_impl_exists(&sub, &sup) {
|
||||||
// link to `Never` to prevent double errors from being reported
|
// link to `Never..Obj` to prevent double errors from being reported
|
||||||
lhs.destructive_link(&Never);
|
lhs.destructive_link(&bounded(Never, Type::Obj));
|
||||||
let sub = if cfg!(feature = "debug") {
|
let sub = if cfg!(feature = "debug") {
|
||||||
sub
|
sub
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -897,6 +897,36 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn search_callee_info_without_args(
|
||||||
|
&self,
|
||||||
|
obj: &hir::Expr,
|
||||||
|
attr_name: &Option<Identifier>,
|
||||||
|
input: &Input,
|
||||||
|
namespace: &Context,
|
||||||
|
) -> SingleTyCheckResult<VarInfo> {
|
||||||
|
if obj.ref_t() == Type::FAILURE {
|
||||||
|
// (...Obj) -> Failure
|
||||||
|
return Ok(VarInfo {
|
||||||
|
t: Type::Subr(SubrType::new(
|
||||||
|
SubrKind::Func,
|
||||||
|
vec![],
|
||||||
|
Some(ParamTy::Pos(ref_(Obj))),
|
||||||
|
vec![],
|
||||||
|
Failure,
|
||||||
|
)),
|
||||||
|
..VarInfo::default()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if let Some(attr_name) = attr_name.as_ref() {
|
||||||
|
self.search_method_info_without_args(obj, attr_name, input, namespace)
|
||||||
|
} else {
|
||||||
|
Ok(VarInfo {
|
||||||
|
t: obj.t(),
|
||||||
|
..VarInfo::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn resolve_overload(
|
fn resolve_overload(
|
||||||
&self,
|
&self,
|
||||||
obj: &hir::Expr,
|
obj: &hir::Expr,
|
||||||
|
@ -1155,6 +1185,150 @@ impl Context {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn search_method_info_without_args(
|
||||||
|
&self,
|
||||||
|
obj: &hir::Expr,
|
||||||
|
attr_name: &Identifier,
|
||||||
|
input: &Input,
|
||||||
|
namespace: &Context,
|
||||||
|
) -> SingleTyCheckResult<VarInfo> {
|
||||||
|
match self.get_attr_info_from_attributive(obj.ref_t(), attr_name) {
|
||||||
|
Triple::Ok(vi) => {
|
||||||
|
return Ok(vi);
|
||||||
|
}
|
||||||
|
Triple::Err(e) => {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
for ctx in self
|
||||||
|
.get_nominal_super_type_ctxs(obj.ref_t())
|
||||||
|
.ok_or_else(|| {
|
||||||
|
TyCheckError::type_not_found(
|
||||||
|
self.cfg.input.clone(),
|
||||||
|
line!() as usize,
|
||||||
|
obj.loc(),
|
||||||
|
self.caused_by(),
|
||||||
|
obj.ref_t(),
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
{
|
||||||
|
if let Some(vi) = ctx
|
||||||
|
.locals
|
||||||
|
.get(attr_name.inspect())
|
||||||
|
.or_else(|| ctx.decls.get(attr_name.inspect()))
|
||||||
|
{
|
||||||
|
self.validate_visibility(attr_name, vi, input, namespace)?;
|
||||||
|
return Ok(vi.clone());
|
||||||
|
}
|
||||||
|
for (_, methods_ctx) in ctx.methods_list.iter() {
|
||||||
|
if let Some(vi) = methods_ctx
|
||||||
|
.locals
|
||||||
|
.get(attr_name.inspect())
|
||||||
|
.or_else(|| methods_ctx.decls.get(attr_name.inspect()))
|
||||||
|
{
|
||||||
|
self.validate_visibility(attr_name, vi, input, namespace)?;
|
||||||
|
return Ok(vi.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(ctx) = self.get_same_name_context(&ctx.name) {
|
||||||
|
match ctx.rec_get_var_info(attr_name, AccessKind::BoundAttr, input, namespace) {
|
||||||
|
Triple::Ok(t) => {
|
||||||
|
return Ok(t);
|
||||||
|
}
|
||||||
|
Triple::Err(e) => {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
Triple::None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Ok(singular_ctxs) = self.get_singular_ctxs_by_hir_expr(obj, namespace) {
|
||||||
|
for ctx in singular_ctxs {
|
||||||
|
if let Some(vi) = ctx
|
||||||
|
.locals
|
||||||
|
.get(attr_name.inspect())
|
||||||
|
.or_else(|| ctx.decls.get(attr_name.inspect()))
|
||||||
|
{
|
||||||
|
self.validate_visibility(attr_name, vi, input, namespace)?;
|
||||||
|
return Ok(vi.clone());
|
||||||
|
}
|
||||||
|
for (_, method_ctx) in ctx.methods_list.iter() {
|
||||||
|
if let Some(vi) = method_ctx
|
||||||
|
.locals
|
||||||
|
.get(attr_name.inspect())
|
||||||
|
.or_else(|| method_ctx.decls.get(attr_name.inspect()))
|
||||||
|
{
|
||||||
|
self.validate_visibility(attr_name, vi, input, namespace)?;
|
||||||
|
return Ok(vi.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Err(TyCheckError::singular_no_attr_error(
|
||||||
|
self.cfg.input.clone(),
|
||||||
|
line!() as usize,
|
||||||
|
attr_name.loc(),
|
||||||
|
namespace.name.to_string(),
|
||||||
|
obj.qual_name().as_deref().unwrap_or("?"),
|
||||||
|
obj.ref_t(),
|
||||||
|
attr_name.inspect(),
|
||||||
|
self.get_similar_attr_from_singular(obj, attr_name.inspect()),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
match self.get_attr_type_by_name(obj, attr_name) {
|
||||||
|
Triple::Ok(method) => {
|
||||||
|
let def_t = self.instantiate_def_type(&method.definition_type).unwrap();
|
||||||
|
self.sub_unify(obj.ref_t(), &def_t, obj, None)
|
||||||
|
// HACK: change this func's return type to TyCheckResult<Type>
|
||||||
|
.map_err(|mut errs| errs.remove(0))?;
|
||||||
|
return Ok(method.method_info.clone());
|
||||||
|
}
|
||||||
|
Triple::Err(err) => {
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
for patch in self.find_patches_of(obj.ref_t()) {
|
||||||
|
if let Some(vi) = patch
|
||||||
|
.locals
|
||||||
|
.get(attr_name.inspect())
|
||||||
|
.or_else(|| patch.decls.get(attr_name.inspect()))
|
||||||
|
{
|
||||||
|
self.validate_visibility(attr_name, vi, input, namespace)?;
|
||||||
|
return Ok(vi.clone());
|
||||||
|
}
|
||||||
|
for (_, methods_ctx) in patch.methods_list.iter() {
|
||||||
|
if let Some(vi) = methods_ctx
|
||||||
|
.locals
|
||||||
|
.get(attr_name.inspect())
|
||||||
|
.or_else(|| methods_ctx.decls.get(attr_name.inspect()))
|
||||||
|
{
|
||||||
|
self.validate_visibility(attr_name, vi, input, namespace)?;
|
||||||
|
return Ok(vi.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let coerced = self
|
||||||
|
.coerce(obj.t(), &())
|
||||||
|
.map_err(|mut errs| errs.remove(0))?;
|
||||||
|
if &coerced != obj.ref_t() {
|
||||||
|
let hash = get_hash(obj.ref_t());
|
||||||
|
obj.ref_t().destructive_coerce();
|
||||||
|
if get_hash(obj.ref_t()) != hash {
|
||||||
|
return self.search_method_info_without_args(obj, attr_name, input, namespace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(TyCheckError::no_attr_error(
|
||||||
|
self.cfg.input.clone(),
|
||||||
|
line!() as usize,
|
||||||
|
attr_name.loc(),
|
||||||
|
namespace.name.to_string(),
|
||||||
|
obj.ref_t(),
|
||||||
|
attr_name.inspect(),
|
||||||
|
self.get_similar_attr(obj.ref_t(), attr_name.inspect()),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
fn validate_visibility(
|
fn validate_visibility(
|
||||||
&self,
|
&self,
|
||||||
ident: &Identifier,
|
ident: &Identifier,
|
||||||
|
@ -1930,6 +2104,37 @@ impl Context {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_call_t_without_args(
|
||||||
|
&self,
|
||||||
|
obj: &hir::Expr,
|
||||||
|
attr_name: &Option<Identifier>,
|
||||||
|
input: &Input,
|
||||||
|
namespace: &Context,
|
||||||
|
) -> Result<VarInfo, (Option<VarInfo>, TyCheckErrors)> {
|
||||||
|
let found = self
|
||||||
|
.search_callee_info_without_args(obj, attr_name, input, namespace)
|
||||||
|
.map_err(|err| (None, TyCheckErrors::from(err)))?;
|
||||||
|
log!(
|
||||||
|
"Found:\ncallee: {obj}{}\nfound: {found}",
|
||||||
|
fmt_option!(pre ".", attr_name.as_ref().map(|ident| &ident.name))
|
||||||
|
);
|
||||||
|
let instance = self
|
||||||
|
.instantiate(found.t.clone(), obj)
|
||||||
|
.map_err(|errs| (Some(found.clone()), errs))?;
|
||||||
|
log!("Instantiated:\ninstance: {instance}");
|
||||||
|
debug_assert!(
|
||||||
|
!instance.is_quantified_subr(),
|
||||||
|
"{instance} is quantified subr"
|
||||||
|
);
|
||||||
|
log!(info "Substituted:\ninstance: {instance}");
|
||||||
|
debug_assert!(instance.has_no_qvar(), "{instance} has qvar");
|
||||||
|
let res = VarInfo {
|
||||||
|
t: instance,
|
||||||
|
..found
|
||||||
|
};
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn get_call_t(
|
pub(crate) fn get_call_t(
|
||||||
&self,
|
&self,
|
||||||
obj: &hir::Expr,
|
obj: &hir::Expr,
|
||||||
|
|
|
@ -848,9 +848,7 @@ impl Context {
|
||||||
}
|
}
|
||||||
// HACK: {op: |T|(T -> T) | op == F} => ?T -> ?T
|
// HACK: {op: |T|(T -> T) | op == F} => ?T -> ?T
|
||||||
Refinement(refine) if refine.t.is_quantified_subr() => {
|
Refinement(refine) if refine.t.is_quantified_subr() => {
|
||||||
let quant = enum_unwrap!(*refine.t, Type::Quantified);
|
let t = self.instantiate(*refine.t, callee)?;
|
||||||
let mut tmp_tv_cache = TyVarCache::new(self.level, self);
|
|
||||||
let t = self.instantiate_t_inner(*quant, &mut tmp_tv_cache, callee)?;
|
|
||||||
match &t {
|
match &t {
|
||||||
Type::Subr(subr) => {
|
Type::Subr(subr) => {
|
||||||
if let Some(self_t) = subr.self_t() {
|
if let Some(self_t) = subr.self_t() {
|
||||||
|
|
|
@ -665,26 +665,23 @@ impl Context {
|
||||||
pub(crate) fn assign_params(
|
pub(crate) fn assign_params(
|
||||||
&mut self,
|
&mut self,
|
||||||
params: &mut hir::Params,
|
params: &mut hir::Params,
|
||||||
opt_decl_subr_t: Option<SubrType>,
|
expect: Option<SubrType>,
|
||||||
) -> TyCheckResult<()> {
|
) -> TyCheckResult<()> {
|
||||||
let mut errs = TyCheckErrors::empty();
|
let mut errs = TyCheckErrors::empty();
|
||||||
if let Some(decl_subr_t) = opt_decl_subr_t {
|
if let Some(subr_t) = expect {
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(params.non_defaults.len(), subr_t.non_default_params.len());
|
||||||
params.non_defaults.len(),
|
debug_assert_eq!(params.defaults.len(), subr_t.default_params.len());
|
||||||
decl_subr_t.non_default_params.len()
|
|
||||||
);
|
|
||||||
debug_assert_eq!(params.defaults.len(), decl_subr_t.default_params.len());
|
|
||||||
for (non_default, pt) in params
|
for (non_default, pt) in params
|
||||||
.non_defaults
|
.non_defaults
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.zip(decl_subr_t.non_default_params.iter())
|
.zip(subr_t.non_default_params.iter())
|
||||||
{
|
{
|
||||||
if let Err(es) = self.assign_param(non_default, Some(pt), ParamKind::NonDefault) {
|
if let Err(es) = self.assign_param(non_default, Some(pt), ParamKind::NonDefault) {
|
||||||
errs.extend(es);
|
errs.extend(es);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(var_params) = &mut params.var_params {
|
if let Some(var_params) = &mut params.var_params {
|
||||||
if let Some(pt) = &decl_subr_t.var_params {
|
if let Some(pt) = &subr_t.var_params {
|
||||||
let pt = pt.clone().map_type(unknown_len_array_t);
|
let pt = pt.clone().map_type(unknown_len_array_t);
|
||||||
if let Err(es) = self.assign_param(var_params, Some(&pt), ParamKind::VarParams)
|
if let Err(es) = self.assign_param(var_params, Some(&pt), ParamKind::VarParams)
|
||||||
{
|
{
|
||||||
|
@ -694,11 +691,7 @@ impl Context {
|
||||||
errs.extend(es);
|
errs.extend(es);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (default, pt) in params
|
for (default, pt) in params.defaults.iter_mut().zip(subr_t.default_params.iter()) {
|
||||||
.defaults
|
|
||||||
.iter_mut()
|
|
||||||
.zip(decl_subr_t.default_params.iter())
|
|
||||||
{
|
|
||||||
if let Err(es) = self.assign_param(
|
if let Err(es) = self.assign_param(
|
||||||
&mut default.sig,
|
&mut default.sig,
|
||||||
Some(pt),
|
Some(pt),
|
||||||
|
|
|
@ -716,6 +716,7 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
|
||||||
// ?T(<: Add(?T))
|
// ?T(<: Add(?T))
|
||||||
// ?U(:> {1, 2}, <: Add(?U)) ==> {1, 2}
|
// ?U(:> {1, 2}, <: Add(?U)) ==> {1, 2}
|
||||||
sup_fv.dummy_link();
|
sup_fv.dummy_link();
|
||||||
|
sub_fv.dummy_link();
|
||||||
if lsub.qual_name() == rsub.qual_name() {
|
if lsub.qual_name() == rsub.qual_name() {
|
||||||
for (lps, rps) in lsub.typarams().iter().zip(rsub.typarams().iter()) {
|
for (lps, rps) in lsub.typarams().iter().zip(rsub.typarams().iter()) {
|
||||||
self.sub_unify_tp(lps, rps, None, false).map_err(|errs| {
|
self.sub_unify_tp(lps, rps, None, false).map_err(|errs| {
|
||||||
|
@ -735,6 +736,7 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sup_fv.undo();
|
sup_fv.undo();
|
||||||
|
sub_fv.undo();
|
||||||
let intersec = self.ctx.intersection(&lsup, &rsup);
|
let intersec = self.ctx.intersection(&lsup, &rsup);
|
||||||
if intersec == Type::Never {
|
if intersec == Type::Never {
|
||||||
return Err(TyCheckErrors::from(TyCheckError::subtyping_error(
|
return Err(TyCheckErrors::from(TyCheckError::subtyping_error(
|
||||||
|
@ -765,7 +767,9 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
|
||||||
}
|
}
|
||||||
// e.g. intersec == Int, rsup == Add(?T)
|
// e.g. intersec == Int, rsup == Add(?T)
|
||||||
// => ?T(:> Int)
|
// => ?T(:> Int)
|
||||||
|
if !(intersec.is_recursive() && rsup.is_recursive()) {
|
||||||
self.sub_unify(&intersec, &rsup)?;
|
self.sub_unify(&intersec, &rsup)?;
|
||||||
|
}
|
||||||
self.sub_unify(&rsub, &union)?;
|
self.sub_unify(&rsub, &union)?;
|
||||||
// self.sub_unify(&intersec, &lsup, loc, param_name)?;
|
// self.sub_unify(&intersec, &lsup, loc, param_name)?;
|
||||||
// self.sub_unify(&lsub, &union, loc, param_name)?;
|
// self.sub_unify(&lsub, &union, loc, param_name)?;
|
||||||
|
|
|
@ -155,6 +155,19 @@ impl ASTLowerer {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fake_lower_literal(&self, lit: ast::Literal) -> LowerResult<hir::Literal> {
|
||||||
|
let loc = lit.loc();
|
||||||
|
let lit = hir::Literal::try_from(lit.token).map_err(|_| {
|
||||||
|
LowerError::invalid_literal(
|
||||||
|
self.cfg.input.clone(),
|
||||||
|
line!() as usize,
|
||||||
|
loc,
|
||||||
|
self.module.context.caused_by(),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
Ok(lit)
|
||||||
|
}
|
||||||
|
|
||||||
fn fake_lower_acc(&self, acc: ast::Accessor) -> LowerResult<hir::Accessor> {
|
fn fake_lower_acc(&self, acc: ast::Accessor) -> LowerResult<hir::Accessor> {
|
||||||
// TypeApp is lowered in `fake_lower_expr`
|
// TypeApp is lowered in `fake_lower_expr`
|
||||||
match acc {
|
match acc {
|
||||||
|
@ -501,7 +514,7 @@ impl ASTLowerer {
|
||||||
|
|
||||||
pub(crate) fn fake_lower_expr(&self, expr: ast::Expr) -> LowerResult<hir::Expr> {
|
pub(crate) fn fake_lower_expr(&self, expr: ast::Expr) -> LowerResult<hir::Expr> {
|
||||||
match expr {
|
match expr {
|
||||||
ast::Expr::Literal(lit) => Ok(hir::Expr::Literal(self.lower_literal(lit)?)),
|
ast::Expr::Literal(lit) => Ok(hir::Expr::Literal(self.fake_lower_literal(lit)?)),
|
||||||
ast::Expr::BinOp(binop) => Ok(hir::Expr::BinOp(self.fake_lower_binop(binop)?)),
|
ast::Expr::BinOp(binop) => Ok(hir::Expr::BinOp(self.fake_lower_binop(binop)?)),
|
||||||
ast::Expr::UnaryOp(unop) => Ok(hir::Expr::UnaryOp(self.fake_lower_unaryop(unop)?)),
|
ast::Expr::UnaryOp(unop) => Ok(hir::Expr::UnaryOp(self.fake_lower_unaryop(unop)?)),
|
||||||
ast::Expr::Array(arr) => Ok(hir::Expr::Array(self.fake_lower_array(arr)?)),
|
ast::Expr::Array(arr) => Ok(hir::Expr::Array(self.fake_lower_array(arr)?)),
|
||||||
|
@ -857,9 +870,11 @@ impl ASTLowerer {
|
||||||
log!(info "entered {}", fn_name!());
|
log!(info "entered {}", fn_name!());
|
||||||
match expr {
|
match expr {
|
||||||
ast::Expr::Literal(lit) if lit.is_doc_comment() => {
|
ast::Expr::Literal(lit) if lit.is_doc_comment() => {
|
||||||
Ok(hir::Expr::Literal(self.lower_literal(lit)?))
|
Ok(hir::Expr::Literal(self.lower_literal(lit, None)?))
|
||||||
|
}
|
||||||
|
ast::Expr::Accessor(acc) if allow_acc => {
|
||||||
|
Ok(hir::Expr::Accessor(self.lower_acc(acc, None)?))
|
||||||
}
|
}
|
||||||
ast::Expr::Accessor(acc) if allow_acc => Ok(hir::Expr::Accessor(self.lower_acc(acc)?)),
|
|
||||||
ast::Expr::Def(def) => Ok(hir::Expr::Def(self.declare_def(def)?)),
|
ast::Expr::Def(def) => Ok(hir::Expr::Def(self.declare_def(def)?)),
|
||||||
ast::Expr::TypeAscription(tasc) => Ok(hir::Expr::TypeAsc(self.declare_ident(tasc)?)),
|
ast::Expr::TypeAscription(tasc) => Ok(hir::Expr::TypeAsc(self.declare_ident(tasc)?)),
|
||||||
ast::Expr::Call(call)
|
ast::Expr::Call(call)
|
||||||
|
@ -868,7 +883,7 @@ impl ASTLowerer {
|
||||||
.map(|op| op.is_import())
|
.map(|op| op.is_import())
|
||||||
.unwrap_or(false) =>
|
.unwrap_or(false) =>
|
||||||
{
|
{
|
||||||
Ok(hir::Expr::Call(self.lower_call(call)?))
|
Ok(hir::Expr::Call(self.lower_call(call, None)?))
|
||||||
}
|
}
|
||||||
other => Err(LowerErrors::from(LowerError::declare_error(
|
other => Err(LowerErrors::from(LowerError::declare_error(
|
||||||
self.cfg().input.clone(),
|
self.cfg().input.clone(),
|
||||||
|
|
|
@ -260,7 +260,7 @@ impl ASTLowerer {
|
||||||
self.errs.extend(errs);
|
self.errs.extend(errs);
|
||||||
}
|
}
|
||||||
for chunk in ast.module.into_iter() {
|
for chunk in ast.module.into_iter() {
|
||||||
match self.lower_chunk(chunk) {
|
match self.lower_chunk(chunk, None) {
|
||||||
Ok(chunk) => {
|
Ok(chunk) => {
|
||||||
module.push(chunk);
|
module.push(chunk);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,9 @@ use crate::ty::constructors::{
|
||||||
use crate::ty::free::Constraint;
|
use crate::ty::free::Constraint;
|
||||||
use crate::ty::typaram::TyParam;
|
use crate::ty::typaram::TyParam;
|
||||||
use crate::ty::value::{GenTypeObj, TypeObj, ValueObj};
|
use crate::ty::value::{GenTypeObj, TypeObj, ValueObj};
|
||||||
use crate::ty::{CastTarget, GuardType, HasType, ParamTy, Predicate, Type, VisibilityModifier};
|
use crate::ty::{
|
||||||
|
CastTarget, GuardType, HasType, ParamTy, Predicate, SubrType, Type, VisibilityModifier,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::context::{
|
use crate::context::{
|
||||||
ClassDefType, Context, ContextKind, ContextProvider, ControlKind, ModuleContext,
|
ClassDefType, Context, ContextKind, ContextProvider, ControlKind, ModuleContext,
|
||||||
|
@ -223,7 +225,11 @@ impl ASTLowerer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ASTLowerer {
|
impl ASTLowerer {
|
||||||
pub(crate) fn lower_literal(&self, lit: ast::Literal) -> LowerResult<hir::Literal> {
|
pub(crate) fn lower_literal(
|
||||||
|
&mut self,
|
||||||
|
lit: ast::Literal,
|
||||||
|
expect: Option<&Type>,
|
||||||
|
) -> LowerResult<hir::Literal> {
|
||||||
let loc = lit.loc();
|
let loc = lit.loc();
|
||||||
let lit = hir::Literal::try_from(lit.token).map_err(|_| {
|
let lit = hir::Literal::try_from(lit.token).map_err(|_| {
|
||||||
LowerError::invalid_literal(
|
LowerError::invalid_literal(
|
||||||
|
@ -233,16 +239,23 @@ impl ASTLowerer {
|
||||||
self.module.context.caused_by(),
|
self.module.context.caused_by(),
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
if let Some(expect) = expect {
|
||||||
|
if let Err(_errs) = self.module.context.sub_unify(&lit.t(), expect, &loc, None) {
|
||||||
|
// self.errs.extend(errs);
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(lit)
|
Ok(lit)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_array(&mut self, array: ast::Array) -> LowerResult<hir::Array> {
|
fn lower_array(&mut self, array: ast::Array, expect: Option<&Type>) -> LowerResult<hir::Array> {
|
||||||
log!(info "entered {}({array})", fn_name!());
|
log!(info "entered {}({array})", fn_name!());
|
||||||
match array {
|
match array {
|
||||||
ast::Array::Normal(arr) => Ok(hir::Array::Normal(self.lower_normal_array(arr)?)),
|
ast::Array::Normal(arr) => {
|
||||||
ast::Array::WithLength(arr) => {
|
Ok(hir::Array::Normal(self.lower_normal_array(arr, expect)?))
|
||||||
Ok(hir::Array::WithLength(self.lower_array_with_length(arr)?))
|
|
||||||
}
|
}
|
||||||
|
ast::Array::WithLength(arr) => Ok(hir::Array::WithLength(
|
||||||
|
self.lower_array_with_length(arr, expect)?,
|
||||||
|
)),
|
||||||
other => feature_error!(
|
other => feature_error!(
|
||||||
LowerErrors,
|
LowerErrors,
|
||||||
LowerError,
|
LowerError,
|
||||||
|
@ -278,14 +291,18 @@ impl ASTLowerer {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_normal_array(&mut self, array: ast::NormalArray) -> LowerResult<hir::NormalArray> {
|
fn lower_normal_array(
|
||||||
|
&mut self,
|
||||||
|
array: ast::NormalArray,
|
||||||
|
_expect: Option<&Type>,
|
||||||
|
) -> LowerResult<hir::NormalArray> {
|
||||||
log!(info "entered {}({array})", fn_name!());
|
log!(info "entered {}({array})", fn_name!());
|
||||||
let mut new_array = vec![];
|
let mut new_array = vec![];
|
||||||
let eval_result = self.module.context.eval_const_normal_array(&array);
|
let eval_result = self.module.context.eval_const_normal_array(&array);
|
||||||
let (elems, ..) = array.elems.deconstruct();
|
let (elems, ..) = array.elems.deconstruct();
|
||||||
let mut union = Type::Never;
|
let mut union = Type::Never;
|
||||||
for elem in elems.into_iter() {
|
for elem in elems.into_iter() {
|
||||||
let elem = self.lower_expr(elem.expr)?;
|
let elem = self.lower_expr(elem.expr, None)?;
|
||||||
let union_ = self.module.context.union(&union, elem.ref_t());
|
let union_ = self.module.context.union(&union, elem.ref_t());
|
||||||
if let Some((l, r)) = union_.union_pair() {
|
if let Some((l, r)) = union_.union_pair() {
|
||||||
match (l.is_unbound_var(), r.is_unbound_var()) {
|
match (l.is_unbound_var(), r.is_unbound_var()) {
|
||||||
|
@ -335,11 +352,12 @@ impl ASTLowerer {
|
||||||
fn lower_array_with_length(
|
fn lower_array_with_length(
|
||||||
&mut self,
|
&mut self,
|
||||||
array: ast::ArrayWithLength,
|
array: ast::ArrayWithLength,
|
||||||
|
_expect: Option<&Type>,
|
||||||
) -> LowerResult<hir::ArrayWithLength> {
|
) -> LowerResult<hir::ArrayWithLength> {
|
||||||
log!(info "entered {}({array})", fn_name!());
|
log!(info "entered {}({array})", fn_name!());
|
||||||
let elem = self.lower_expr(array.elem.expr)?;
|
let elem = self.lower_expr(array.elem.expr, None)?;
|
||||||
let array_t = self.gen_array_with_length_type(&elem, &array.len);
|
let array_t = self.gen_array_with_length_type(&elem, &array.len);
|
||||||
let len = self.lower_expr(*array.len)?;
|
let len = self.lower_expr(*array.len, None)?;
|
||||||
let hir_array = hir::ArrayWithLength::new(array.l_sqbr, array.r_sqbr, array_t, elem, len);
|
let hir_array = hir::ArrayWithLength::new(array.l_sqbr, array.r_sqbr, array_t, elem, len);
|
||||||
Ok(hir_array)
|
Ok(hir_array)
|
||||||
}
|
}
|
||||||
|
@ -354,35 +372,49 @@ impl ASTLowerer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_tuple(&mut self, tuple: ast::Tuple) -> LowerResult<hir::Tuple> {
|
fn lower_tuple(&mut self, tuple: ast::Tuple, expect: Option<&Type>) -> LowerResult<hir::Tuple> {
|
||||||
log!(info "entered {}({tuple})", fn_name!());
|
log!(info "entered {}({tuple})", fn_name!());
|
||||||
match tuple {
|
match tuple {
|
||||||
ast::Tuple::Normal(tup) => Ok(hir::Tuple::Normal(self.lower_normal_tuple(tup)?)),
|
ast::Tuple::Normal(tup) => {
|
||||||
|
Ok(hir::Tuple::Normal(self.lower_normal_tuple(tup, expect)?))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_normal_tuple(&mut self, tuple: ast::NormalTuple) -> LowerResult<hir::NormalTuple> {
|
fn lower_normal_tuple(
|
||||||
|
&mut self,
|
||||||
|
tuple: ast::NormalTuple,
|
||||||
|
_expect: Option<&Type>,
|
||||||
|
) -> LowerResult<hir::NormalTuple> {
|
||||||
log!(info "entered {}({tuple})", fn_name!());
|
log!(info "entered {}({tuple})", fn_name!());
|
||||||
let mut new_tuple = vec![];
|
let mut new_tuple = vec![];
|
||||||
let (elems, .., paren) = tuple.elems.deconstruct();
|
let (elems, .., paren) = tuple.elems.deconstruct();
|
||||||
for elem in elems {
|
for elem in elems {
|
||||||
let elem = self.lower_expr(elem.expr)?;
|
let elem = self.lower_expr(elem.expr, None)?;
|
||||||
new_tuple.push(elem);
|
new_tuple.push(elem);
|
||||||
}
|
}
|
||||||
Ok(hir::NormalTuple::new(hir::Args::values(new_tuple, paren)))
|
Ok(hir::NormalTuple::new(hir::Args::values(new_tuple, paren)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_record(&mut self, record: ast::Record) -> LowerResult<hir::Record> {
|
fn lower_record(
|
||||||
|
&mut self,
|
||||||
|
record: ast::Record,
|
||||||
|
expect: Option<&Type>,
|
||||||
|
) -> LowerResult<hir::Record> {
|
||||||
log!(info "entered {}({record})", fn_name!());
|
log!(info "entered {}({record})", fn_name!());
|
||||||
match record {
|
match record {
|
||||||
ast::Record::Normal(rec) => self.lower_normal_record(rec),
|
ast::Record::Normal(rec) => self.lower_normal_record(rec, expect),
|
||||||
ast::Record::Mixed(mixed) => {
|
ast::Record::Mixed(mixed) => {
|
||||||
self.lower_normal_record(Desugarer::desugar_shortened_record_inner(mixed))
|
self.lower_normal_record(Desugarer::desugar_shortened_record_inner(mixed), None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_normal_record(&mut self, record: ast::NormalRecord) -> LowerResult<hir::Record> {
|
fn lower_normal_record(
|
||||||
|
&mut self,
|
||||||
|
record: ast::NormalRecord,
|
||||||
|
_expect: Option<&Type>,
|
||||||
|
) -> LowerResult<hir::Record> {
|
||||||
log!(info "entered {}({record})", fn_name!());
|
log!(info "entered {}({record})", fn_name!());
|
||||||
let mut hir_record =
|
let mut hir_record =
|
||||||
hir::Record::new(record.l_brace, record.r_brace, hir::RecordAttrs::empty());
|
hir::Record::new(record.l_brace, record.r_brace, hir::RecordAttrs::empty());
|
||||||
|
@ -411,11 +443,13 @@ impl ASTLowerer {
|
||||||
Ok(hir_record)
|
Ok(hir_record)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_set(&mut self, set: ast::Set) -> LowerResult<hir::Set> {
|
fn lower_set(&mut self, set: ast::Set, expect: Option<&Type>) -> LowerResult<hir::Set> {
|
||||||
log!(info "enter {}({set})", fn_name!());
|
log!(info "enter {}({set})", fn_name!());
|
||||||
match set {
|
match set {
|
||||||
ast::Set::Normal(set) => Ok(hir::Set::Normal(self.lower_normal_set(set)?)),
|
ast::Set::Normal(set) => Ok(hir::Set::Normal(self.lower_normal_set(set, expect)?)),
|
||||||
ast::Set::WithLength(set) => Ok(hir::Set::WithLength(self.lower_set_with_length(set)?)),
|
ast::Set::WithLength(set) => Ok(hir::Set::WithLength(
|
||||||
|
self.lower_set_with_length(set, expect)?,
|
||||||
|
)),
|
||||||
ast::Set::Comprehension(set) => feature_error!(
|
ast::Set::Comprehension(set) => feature_error!(
|
||||||
LowerErrors,
|
LowerErrors,
|
||||||
LowerError,
|
LowerError,
|
||||||
|
@ -426,13 +460,17 @@ impl ASTLowerer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_normal_set(&mut self, set: ast::NormalSet) -> LowerResult<hir::NormalSet> {
|
fn lower_normal_set(
|
||||||
|
&mut self,
|
||||||
|
set: ast::NormalSet,
|
||||||
|
_expect: Option<&Type>,
|
||||||
|
) -> LowerResult<hir::NormalSet> {
|
||||||
log!(info "entered {}({set})", fn_name!());
|
log!(info "entered {}({set})", fn_name!());
|
||||||
let (elems, ..) = set.elems.deconstruct();
|
let (elems, ..) = set.elems.deconstruct();
|
||||||
let mut union = Type::Never;
|
let mut union = Type::Never;
|
||||||
let mut new_set = vec![];
|
let mut new_set = vec![];
|
||||||
for elem in elems {
|
for elem in elems {
|
||||||
let elem = self.lower_expr(elem.expr)?;
|
let elem = self.lower_expr(elem.expr, None)?;
|
||||||
union = self.module.context.union(&union, elem.ref_t());
|
union = self.module.context.union(&union, elem.ref_t());
|
||||||
if ERG_MODE && union.is_union_type() {
|
if ERG_MODE && union.is_union_type() {
|
||||||
return Err(LowerErrors::from(LowerError::syntax_error(
|
return Err(LowerErrors::from(LowerError::syntax_error(
|
||||||
|
@ -504,11 +542,12 @@ impl ASTLowerer {
|
||||||
fn lower_set_with_length(
|
fn lower_set_with_length(
|
||||||
&mut self,
|
&mut self,
|
||||||
set: ast::SetWithLength,
|
set: ast::SetWithLength,
|
||||||
|
_expect: Option<&Type>,
|
||||||
) -> LowerResult<hir::SetWithLength> {
|
) -> LowerResult<hir::SetWithLength> {
|
||||||
log!("entered {}({set})", fn_name!());
|
log!("entered {}({set})", fn_name!());
|
||||||
let elem = self.lower_expr(set.elem.expr)?;
|
let elem = self.lower_expr(set.elem.expr, None)?;
|
||||||
let set_t = self.gen_set_with_length_type(&elem, &set.len);
|
let set_t = self.gen_set_with_length_type(&elem, &set.len);
|
||||||
let len = self.lower_expr(*set.len)?;
|
let len = self.lower_expr(*set.len, None)?;
|
||||||
let hir_set = hir::SetWithLength::new(set.l_brace, set.r_brace, set_t, elem, len);
|
let hir_set = hir::SetWithLength::new(set.l_brace, set.r_brace, set_t, elem, len);
|
||||||
Ok(hir_set)
|
Ok(hir_set)
|
||||||
}
|
}
|
||||||
|
@ -528,10 +567,10 @@ impl ASTLowerer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_dict(&mut self, dict: ast::Dict) -> LowerResult<hir::Dict> {
|
fn lower_dict(&mut self, dict: ast::Dict, expect: Option<&Type>) -> LowerResult<hir::Dict> {
|
||||||
log!(info "enter {}({dict})", fn_name!());
|
log!(info "enter {}({dict})", fn_name!());
|
||||||
match dict {
|
match dict {
|
||||||
ast::Dict::Normal(set) => Ok(hir::Dict::Normal(self.lower_normal_dict(set)?)),
|
ast::Dict::Normal(set) => Ok(hir::Dict::Normal(self.lower_normal_dict(set, expect)?)),
|
||||||
other => feature_error!(
|
other => feature_error!(
|
||||||
LowerErrors,
|
LowerErrors,
|
||||||
LowerError,
|
LowerError,
|
||||||
|
@ -539,17 +578,21 @@ impl ASTLowerer {
|
||||||
other.loc(),
|
other.loc(),
|
||||||
"dict comprehension"
|
"dict comprehension"
|
||||||
),
|
),
|
||||||
// ast::Dict::WithLength(set) => Ok(hir::Dict::WithLength(self.lower_dict_with_length(set)?)),
|
// ast::Dict::WithLength(set) => Ok(hir::Dict::WithLength(self.lower_dict_with_length(set, expect)?)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_normal_dict(&mut self, dict: ast::NormalDict) -> LowerResult<hir::NormalDict> {
|
fn lower_normal_dict(
|
||||||
|
&mut self,
|
||||||
|
dict: ast::NormalDict,
|
||||||
|
_expect: Option<&Type>,
|
||||||
|
) -> LowerResult<hir::NormalDict> {
|
||||||
log!(info "enter {}({dict})", fn_name!());
|
log!(info "enter {}({dict})", fn_name!());
|
||||||
let mut union = dict! {};
|
let mut union = dict! {};
|
||||||
let mut new_kvs = vec![];
|
let mut new_kvs = vec![];
|
||||||
for kv in dict.kvs {
|
for kv in dict.kvs {
|
||||||
let key = self.lower_expr(kv.key)?;
|
let key = self.lower_expr(kv.key, None)?;
|
||||||
let value = self.lower_expr(kv.value)?;
|
let value = self.lower_expr(kv.value, None)?;
|
||||||
if let Some(popped_val_t) = union.insert(key.t(), value.t()) {
|
if let Some(popped_val_t) = union.insert(key.t(), value.t()) {
|
||||||
if PYTHON_MODE {
|
if PYTHON_MODE {
|
||||||
let val_t = union.get_mut(key.ref_t()).unwrap();
|
let val_t = union.get_mut(key.ref_t()).unwrap();
|
||||||
|
@ -627,16 +670,20 @@ impl ASTLowerer {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn lower_acc(&mut self, acc: ast::Accessor) -> LowerResult<hir::Accessor> {
|
pub(crate) fn lower_acc(
|
||||||
|
&mut self,
|
||||||
|
acc: ast::Accessor,
|
||||||
|
expect: Option<&Type>,
|
||||||
|
) -> LowerResult<hir::Accessor> {
|
||||||
log!(info "entered {}({acc})", fn_name!());
|
log!(info "entered {}({acc})", fn_name!());
|
||||||
match acc {
|
match acc {
|
||||||
ast::Accessor::Ident(ident) => {
|
ast::Accessor::Ident(ident) => {
|
||||||
let ident = self.lower_ident(ident)?;
|
let ident = self.lower_ident(ident, expect)?;
|
||||||
let acc = hir::Accessor::Ident(ident);
|
let acc = hir::Accessor::Ident(ident);
|
||||||
Ok(acc)
|
Ok(acc)
|
||||||
}
|
}
|
||||||
ast::Accessor::Attr(attr) => {
|
ast::Accessor::Attr(attr) => {
|
||||||
let obj = self.lower_expr(*attr.obj)?;
|
let obj = self.lower_expr(*attr.obj, None)?;
|
||||||
let vi = match self.module.context.get_attr_info(
|
let vi = match self.module.context.get_attr_info(
|
||||||
&obj,
|
&obj,
|
||||||
&attr.ident,
|
&attr.ident,
|
||||||
|
@ -686,7 +733,11 @@ impl ASTLowerer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_ident(&mut self, ident: ast::Identifier) -> LowerResult<hir::Identifier> {
|
fn lower_ident(
|
||||||
|
&mut self,
|
||||||
|
ident: ast::Identifier,
|
||||||
|
expect: Option<&Type>,
|
||||||
|
) -> LowerResult<hir::Identifier> {
|
||||||
// `match` is a special form, typing is magic
|
// `match` is a special form, typing is magic
|
||||||
let (vi, __name__) = if ident.vis.is_private()
|
let (vi, __name__) = if ident.vis.is_private()
|
||||||
&& (&ident.inspect()[..] == "match" || &ident.inspect()[..] == "match!")
|
&& (&ident.inspect()[..] == "match" || &ident.inspect()[..] == "match!")
|
||||||
|
@ -739,6 +790,15 @@ impl ASTLowerer {
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
self.inc_ref(ident.inspect(), &vi, &ident.name);
|
self.inc_ref(ident.inspect(), &vi, &ident.name);
|
||||||
|
if let Some(expect) = expect {
|
||||||
|
if let Err(_errs) = self
|
||||||
|
.module
|
||||||
|
.context
|
||||||
|
.sub_unify(&vi.t, expect, &ident.loc(), None)
|
||||||
|
{
|
||||||
|
// self.errs.extend(errs);
|
||||||
|
}
|
||||||
|
}
|
||||||
let ident = hir::Identifier::new(ident, __name__, vi);
|
let ident = hir::Identifier::new(ident, __name__, vi);
|
||||||
Ok(ident)
|
Ok(ident)
|
||||||
}
|
}
|
||||||
|
@ -805,18 +865,18 @@ impl ASTLowerer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_bin(&mut self, bin: ast::BinOp) -> hir::BinOp {
|
fn lower_bin(&mut self, bin: ast::BinOp, expect: Option<&Type>) -> hir::BinOp {
|
||||||
log!(info "entered {}({bin})", fn_name!());
|
log!(info "entered {}({bin})", fn_name!());
|
||||||
let mut args = bin.args.into_iter();
|
let mut args = bin.args.into_iter();
|
||||||
let lhs = *args.next().unwrap();
|
let lhs = *args.next().unwrap();
|
||||||
let rhs = *args.next().unwrap();
|
let rhs = *args.next().unwrap();
|
||||||
let guard = self.get_guard_type(&bin.op, &lhs, &rhs);
|
let guard = self.get_guard_type(&bin.op, &lhs, &rhs);
|
||||||
let lhs = self.lower_expr(lhs).unwrap_or_else(|errs| {
|
let lhs = self.lower_expr(lhs, None).unwrap_or_else(|errs| {
|
||||||
self.errs.extend(errs);
|
self.errs.extend(errs);
|
||||||
hir::Expr::Dummy(hir::Dummy::new(vec![]))
|
hir::Expr::Dummy(hir::Dummy::new(vec![]))
|
||||||
});
|
});
|
||||||
let lhs = hir::PosArg::new(lhs);
|
let lhs = hir::PosArg::new(lhs);
|
||||||
let rhs = self.lower_expr(rhs).unwrap_or_else(|errs| {
|
let rhs = self.lower_expr(rhs, None).unwrap_or_else(|errs| {
|
||||||
self.errs.extend(errs);
|
self.errs.extend(errs);
|
||||||
hir::Expr::Dummy(hir::Dummy::new(vec![]))
|
hir::Expr::Dummy(hir::Dummy::new(vec![]))
|
||||||
});
|
});
|
||||||
|
@ -845,23 +905,32 @@ impl ASTLowerer {
|
||||||
*return_t = guard;
|
*return_t = guard;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(expect) = expect {
|
||||||
|
if let Err(_errs) =
|
||||||
|
self.module
|
||||||
|
.context
|
||||||
|
.sub_unify(vi.t.return_t().unwrap(), expect, &args, None)
|
||||||
|
{
|
||||||
|
// self.errs.extend(errs);
|
||||||
|
}
|
||||||
|
}
|
||||||
let mut args = args.into_iter();
|
let mut args = args.into_iter();
|
||||||
let lhs = args.next().unwrap().expr;
|
let lhs = args.next().unwrap().expr;
|
||||||
let rhs = args.next().unwrap().expr;
|
let rhs = args.next().unwrap().expr;
|
||||||
hir::BinOp::new(bin.op, lhs, rhs, vi)
|
hir::BinOp::new(bin.op, lhs, rhs, vi)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_unary(&mut self, unary: ast::UnaryOp) -> hir::UnaryOp {
|
fn lower_unary(&mut self, unary: ast::UnaryOp, expect: Option<&Type>) -> hir::UnaryOp {
|
||||||
log!(info "entered {}({unary})", fn_name!());
|
log!(info "entered {}({unary})", fn_name!());
|
||||||
let mut args = unary.args.into_iter();
|
let mut args = unary.args.into_iter();
|
||||||
let arg = self
|
let arg = self
|
||||||
.lower_expr(*args.next().unwrap())
|
.lower_expr(*args.next().unwrap(), None)
|
||||||
.unwrap_or_else(|errs| {
|
.unwrap_or_else(|errs| {
|
||||||
self.errs.extend(errs);
|
self.errs.extend(errs);
|
||||||
hir::Expr::Dummy(hir::Dummy::new(vec![]))
|
hir::Expr::Dummy(hir::Dummy::new(vec![]))
|
||||||
});
|
});
|
||||||
let args = [hir::PosArg::new(arg)];
|
let args = [hir::PosArg::new(arg)];
|
||||||
let t = self
|
let vi = self
|
||||||
.module
|
.module
|
||||||
.context
|
.context
|
||||||
.get_unaryop_t(&unary.op, &args, &self.cfg.input, &self.module.context)
|
.get_unaryop_t(&unary.op, &args, &self.cfg.input, &self.module.context)
|
||||||
|
@ -869,12 +938,26 @@ impl ASTLowerer {
|
||||||
self.errs.extend(errs);
|
self.errs.extend(errs);
|
||||||
VarInfo::ILLEGAL
|
VarInfo::ILLEGAL
|
||||||
});
|
});
|
||||||
|
if let Some(expect) = expect {
|
||||||
|
if let Err(_errs) =
|
||||||
|
self.module
|
||||||
|
.context
|
||||||
|
.sub_unify(vi.t.return_t().unwrap(), expect, &args, None)
|
||||||
|
{
|
||||||
|
// self.errs.extend(errs);
|
||||||
|
}
|
||||||
|
}
|
||||||
let mut args = args.into_iter();
|
let mut args = args.into_iter();
|
||||||
let expr = args.next().unwrap().expr;
|
let expr = args.next().unwrap().expr;
|
||||||
hir::UnaryOp::new(unary.op, expr, t)
|
hir::UnaryOp::new(unary.op, expr, vi)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_args(&mut self, args: ast::Args, errs: &mut LowerErrors) -> hir::Args {
|
fn lower_args(
|
||||||
|
&mut self,
|
||||||
|
args: ast::Args,
|
||||||
|
expect: Option<&SubrType>,
|
||||||
|
errs: &mut LowerErrors,
|
||||||
|
) -> hir::Args {
|
||||||
let (pos_args, var_args, kw_args, paren) = args.deconstruct();
|
let (pos_args, var_args, kw_args, paren) = args.deconstruct();
|
||||||
let mut hir_args = hir::Args::new(
|
let mut hir_args = hir::Args::new(
|
||||||
Vec::with_capacity(pos_args.len()),
|
Vec::with_capacity(pos_args.len()),
|
||||||
|
@ -882,8 +965,14 @@ impl ASTLowerer {
|
||||||
Vec::with_capacity(kw_args.len()),
|
Vec::with_capacity(kw_args.len()),
|
||||||
paren,
|
paren,
|
||||||
);
|
);
|
||||||
for (nth, arg) in pos_args.into_iter().enumerate() {
|
let pos_params = expect
|
||||||
match self.lower_expr(arg.expr) {
|
.as_ref()
|
||||||
|
.map(|subr| subr.pos_params().map(|p| Some(p.typ())))
|
||||||
|
.map_or(vec![None; pos_args.len()], |params| {
|
||||||
|
params.take(pos_args.len()).collect()
|
||||||
|
});
|
||||||
|
for (nth, (arg, param)) in pos_args.into_iter().zip(pos_params).enumerate() {
|
||||||
|
match self.lower_expr(arg.expr, param) {
|
||||||
Ok(expr) => {
|
Ok(expr) => {
|
||||||
if let Some(kind) = self.module.context.control_kind() {
|
if let Some(kind) = self.module.context.control_kind() {
|
||||||
self.push_guard(nth, kind, expr.ref_t());
|
self.push_guard(nth, kind, expr.ref_t());
|
||||||
|
@ -897,7 +986,7 @@ impl ASTLowerer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(var_args) = var_args {
|
if let Some(var_args) = var_args {
|
||||||
match self.lower_expr(var_args.expr) {
|
match self.lower_expr(var_args.expr, None) {
|
||||||
Ok(expr) => hir_args.var_args = Some(Box::new(hir::PosArg::new(expr))),
|
Ok(expr) => hir_args.var_args = Some(Box::new(hir::PosArg::new(expr))),
|
||||||
Err(es) => {
|
Err(es) => {
|
||||||
errs.extend(es);
|
errs.extend(es);
|
||||||
|
@ -907,7 +996,7 @@ impl ASTLowerer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for arg in kw_args.into_iter() {
|
for arg in kw_args.into_iter() {
|
||||||
match self.lower_expr(arg.expr) {
|
match self.lower_expr(arg.expr, None) {
|
||||||
Ok(expr) => hir_args.push_kw(hir::KwArg::new(arg.keyword, expr)),
|
Ok(expr) => hir_args.push_kw(hir::KwArg::new(arg.keyword, expr)),
|
||||||
Err(es) => {
|
Err(es) => {
|
||||||
errs.extend(es);
|
errs.extend(es);
|
||||||
|
@ -947,7 +1036,11 @@ impl ASTLowerer {
|
||||||
|
|
||||||
/// returning `Ok(call)` does not mean the call is valid, just means it is syntactically valid
|
/// returning `Ok(call)` does not mean the call is valid, just means it is syntactically valid
|
||||||
/// `ASTLowerer` is designed to cause as little information loss in HIR as possible
|
/// `ASTLowerer` is designed to cause as little information loss in HIR as possible
|
||||||
pub(crate) fn lower_call(&mut self, call: ast::Call) -> LowerResult<hir::Call> {
|
pub(crate) fn lower_call(
|
||||||
|
&mut self,
|
||||||
|
call: ast::Call,
|
||||||
|
_expect: Option<&Type>,
|
||||||
|
) -> LowerResult<hir::Call> {
|
||||||
log!(info "entered {}({}{}(...))", fn_name!(), call.obj, fmt_option!(call.attr_name));
|
log!(info "entered {}({}{}(...))", fn_name!(), call.obj, fmt_option!(call.attr_name));
|
||||||
if let (Some(name), None) = (call.obj.get_name(), &call.attr_name) {
|
if let (Some(name), None) = (call.obj.get_name(), &call.attr_name) {
|
||||||
self.module.context.higher_order_caller.push(name.clone());
|
self.module.context.higher_order_caller.push(name.clone());
|
||||||
|
@ -968,8 +1061,7 @@ impl ASTLowerer {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let hir_args = self.lower_args(call.args, &mut errs);
|
let mut obj = match self.lower_expr(*call.obj, None) {
|
||||||
let mut obj = match self.lower_expr(*call.obj) {
|
|
||||||
Ok(obj) => obj,
|
Ok(obj) => obj,
|
||||||
Err(es) => {
|
Err(es) => {
|
||||||
self.module.context.higher_order_caller.pop();
|
self.module.context.higher_order_caller.pop();
|
||||||
|
@ -977,6 +1069,17 @@ impl ASTLowerer {
|
||||||
return Err(errs);
|
return Err(errs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let opt_vi = self.module.context.get_call_t_without_args(
|
||||||
|
&obj,
|
||||||
|
&call.attr_name,
|
||||||
|
&self.cfg.input,
|
||||||
|
&self.module.context,
|
||||||
|
);
|
||||||
|
let expect_subr = opt_vi
|
||||||
|
.as_ref()
|
||||||
|
.ok()
|
||||||
|
.and_then(|vi| <&SubrType>::try_from(&vi.t).ok());
|
||||||
|
let hir_args = self.lower_args(call.args, expect_subr, &mut errs);
|
||||||
let mut vi = match self.module.context.get_call_t(
|
let mut vi = match self.module.context.get_call_t(
|
||||||
&obj,
|
&obj,
|
||||||
&call.attr_name,
|
&call.attr_name,
|
||||||
|
@ -1023,6 +1126,11 @@ impl ASTLowerer {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let mut call = hir::Call::new(obj, attr_name, hir_args);
|
let mut call = hir::Call::new(obj, attr_name, hir_args);
|
||||||
|
/*if let Some((found, expect)) = call.signature_t().and_then(|sig| sig.return_t()).zip(expect) {
|
||||||
|
if let Err(errs) = self.module.context.sub_unify(found, expect, &call, None) {
|
||||||
|
self.errs.extend(errs);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
self.module.context.higher_order_caller.pop();
|
self.module.context.higher_order_caller.pop();
|
||||||
if errs.is_empty() {
|
if errs.is_empty() {
|
||||||
self.exec_additional_op(&mut call)?;
|
self.exec_additional_op(&mut call)?;
|
||||||
|
@ -1088,10 +1196,14 @@ impl ASTLowerer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_pack(&mut self, pack: ast::DataPack) -> LowerResult<hir::Call> {
|
fn lower_pack(
|
||||||
|
&mut self,
|
||||||
|
pack: ast::DataPack,
|
||||||
|
_expect: Option<&Type>,
|
||||||
|
) -> LowerResult<hir::Call> {
|
||||||
log!(info "entered {}({pack})", fn_name!());
|
log!(info "entered {}({pack})", fn_name!());
|
||||||
let class = self.lower_expr(*pack.class)?;
|
let class = self.lower_expr(*pack.class, None)?;
|
||||||
let args = self.lower_record(pack.args)?;
|
let args = self.lower_record(pack.args, None)?;
|
||||||
let args = vec![hir::PosArg::new(hir::Expr::Record(args))];
|
let args = vec![hir::PosArg::new(hir::Expr::Record(args))];
|
||||||
let attr_name = ast::Identifier::new(
|
let attr_name = ast::Identifier::new(
|
||||||
VisModifierSpec::Public(Token::new(
|
VisModifierSpec::Public(Token::new(
|
||||||
|
@ -1172,7 +1284,7 @@ impl ASTLowerer {
|
||||||
};
|
};
|
||||||
let mut hir_defaults = vec![];
|
let mut hir_defaults = vec![];
|
||||||
for default in params.defaults.into_iter() {
|
for default in params.defaults.into_iter() {
|
||||||
match self.lower_expr(default.default_val) {
|
match self.lower_expr(default.default_val, None) {
|
||||||
Ok(default_val) => {
|
Ok(default_val) => {
|
||||||
let sig = self.lower_non_default_param(default.sig)?;
|
let sig = self.lower_non_default_param(default.sig)?;
|
||||||
hir_defaults.push(hir::DefaultParamSignature::new(sig, default_val));
|
hir_defaults.push(hir::DefaultParamSignature::new(sig, default_val));
|
||||||
|
@ -1193,7 +1305,12 @@ impl ASTLowerer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_lambda(&mut self, lambda: ast::Lambda) -> LowerResult<hir::Lambda> {
|
fn lower_lambda(
|
||||||
|
&mut self,
|
||||||
|
lambda: ast::Lambda,
|
||||||
|
expect: Option<&Type>,
|
||||||
|
) -> LowerResult<hir::Lambda> {
|
||||||
|
let expect = expect.and_then(|t| <&SubrType>::try_from(t).ok());
|
||||||
log!(info "entered {}({lambda})", fn_name!());
|
log!(info "entered {}({lambda})", fn_name!());
|
||||||
let in_statement = PYTHON_MODE
|
let in_statement = PYTHON_MODE
|
||||||
&& self
|
&& self
|
||||||
|
@ -1224,7 +1341,11 @@ impl ASTLowerer {
|
||||||
}
|
}
|
||||||
errs
|
errs
|
||||||
})?;
|
})?;
|
||||||
if let Err(errs) = self.module.context.assign_params(&mut params, None) {
|
if let Err(errs) = self
|
||||||
|
.module
|
||||||
|
.context
|
||||||
|
.assign_params(&mut params, expect.cloned())
|
||||||
|
{
|
||||||
self.errs.extend(errs);
|
self.errs.extend(errs);
|
||||||
}
|
}
|
||||||
let overwritten = {
|
let overwritten = {
|
||||||
|
@ -1244,7 +1365,7 @@ impl ASTLowerer {
|
||||||
if let Err(errs) = self.module.context.register_const(&lambda.body) {
|
if let Err(errs) = self.module.context.register_const(&lambda.body) {
|
||||||
self.errs.extend(errs);
|
self.errs.extend(errs);
|
||||||
}
|
}
|
||||||
let body = self.lower_block(lambda.body).map_err(|errs| {
|
let body = self.lower_block(lambda.body, None).map_err(|errs| {
|
||||||
if !in_statement {
|
if !in_statement {
|
||||||
self.pop_append_errs();
|
self.pop_append_errs();
|
||||||
}
|
}
|
||||||
|
@ -1467,7 +1588,7 @@ impl ASTLowerer {
|
||||||
if let Err(errs) = self.module.context.register_const(&body.block) {
|
if let Err(errs) = self.module.context.register_const(&body.block) {
|
||||||
self.errs.extend(errs);
|
self.errs.extend(errs);
|
||||||
}
|
}
|
||||||
match self.lower_block(body.block) {
|
match self.lower_block(body.block, None) {
|
||||||
Ok(block) => {
|
Ok(block) => {
|
||||||
let found_body_t = block.ref_t();
|
let found_body_t = block.ref_t();
|
||||||
let outer = self.module.context.outer.as_ref().unwrap();
|
let outer = self.module.context.outer.as_ref().unwrap();
|
||||||
|
@ -1565,7 +1686,7 @@ impl ASTLowerer {
|
||||||
if let Err(errs) = self.module.context.register_const(&body.block) {
|
if let Err(errs) = self.module.context.register_const(&body.block) {
|
||||||
self.errs.extend(errs);
|
self.errs.extend(errs);
|
||||||
}
|
}
|
||||||
match self.lower_block(body.block) {
|
match self.lower_block(body.block, None) {
|
||||||
Ok(block) => {
|
Ok(block) => {
|
||||||
let found_body_t = self.module.context.squash_tyvar(block.t());
|
let found_body_t = self.module.context.squash_tyvar(block.t());
|
||||||
let vi = match self.module.context.outer.as_mut().unwrap().assign_subr(
|
let vi = match self.module.context.outer.as_mut().unwrap().assign_subr(
|
||||||
|
@ -1636,7 +1757,7 @@ impl ASTLowerer {
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.fake_subr_assign(&sig.ident, &sig.decorators, Type::Failure)?;
|
.fake_subr_assign(&sig.ident, &sig.decorators, Type::Failure)?;
|
||||||
let block = self.lower_block(body.block)?;
|
let block = self.lower_block(body.block, None)?;
|
||||||
let ident = hir::Identifier::bare(sig.ident);
|
let ident = hir::Identifier::bare(sig.ident);
|
||||||
let ret_t_spec = if let Some(ts) = sig.return_t_spec {
|
let ret_t_spec = if let Some(ts) = sig.return_t_spec {
|
||||||
let spec_t = self.module.context.instantiate_typespec(&ts.t_spec)?;
|
let spec_t = self.module.context.instantiate_typespec(&ts.t_spec)?;
|
||||||
|
@ -1729,7 +1850,7 @@ impl ASTLowerer {
|
||||||
self.errs.extend(errs);
|
self.errs.extend(errs);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ast::ClassAttr::Decl(decl) => match self.lower_type_asc(decl) {
|
ast::ClassAttr::Decl(decl) => match self.lower_type_asc(decl, None) {
|
||||||
Ok(decl) => {
|
Ok(decl) => {
|
||||||
hir_methods.push(hir::Expr::TypeAsc(decl));
|
hir_methods.push(hir::Expr::TypeAsc(decl));
|
||||||
}
|
}
|
||||||
|
@ -1737,7 +1858,7 @@ impl ASTLowerer {
|
||||||
self.errs.extend(errs);
|
self.errs.extend(errs);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ast::ClassAttr::Doc(doc) => match self.lower_literal(doc) {
|
ast::ClassAttr::Doc(doc) => match self.lower_literal(doc, None) {
|
||||||
Ok(doc) => {
|
Ok(doc) => {
|
||||||
hir_methods.push(hir::Expr::Literal(doc));
|
hir_methods.push(hir::Expr::Literal(doc));
|
||||||
}
|
}
|
||||||
|
@ -1936,7 +2057,7 @@ impl ASTLowerer {
|
||||||
self.errs.extend(errs);
|
self.errs.extend(errs);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ast::ClassAttr::Decl(decl) => match self.lower_type_asc(decl) {
|
ast::ClassAttr::Decl(decl) => match self.lower_type_asc(decl, None) {
|
||||||
Ok(decl) => {
|
Ok(decl) => {
|
||||||
hir_methods.push(hir::Expr::TypeAsc(decl));
|
hir_methods.push(hir::Expr::TypeAsc(decl));
|
||||||
}
|
}
|
||||||
|
@ -1944,7 +2065,7 @@ impl ASTLowerer {
|
||||||
self.errs.extend(errs);
|
self.errs.extend(errs);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ast::ClassAttr::Doc(doc) => match self.lower_literal(doc) {
|
ast::ClassAttr::Doc(doc) => match self.lower_literal(doc, None) {
|
||||||
Ok(doc) => {
|
Ok(doc) => {
|
||||||
hir_methods.push(hir::Expr::Literal(doc));
|
hir_methods.push(hir::Expr::Literal(doc));
|
||||||
}
|
}
|
||||||
|
@ -1964,8 +2085,8 @@ impl ASTLowerer {
|
||||||
|
|
||||||
fn lower_redef(&mut self, redef: ast::ReDef) -> LowerResult<hir::ReDef> {
|
fn lower_redef(&mut self, redef: ast::ReDef) -> LowerResult<hir::ReDef> {
|
||||||
log!(info "entered {}({redef})", fn_name!());
|
log!(info "entered {}({redef})", fn_name!());
|
||||||
let mut attr = self.lower_acc(redef.attr)?;
|
let mut attr = self.lower_acc(redef.attr, None)?;
|
||||||
let expr = self.lower_expr(*redef.expr)?;
|
let expr = self.lower_expr(*redef.expr, None)?;
|
||||||
if let Err(err) =
|
if let Err(err) =
|
||||||
self.var_result_t_check(&attr, &Str::from(attr.show()), attr.ref_t(), expr.ref_t())
|
self.var_result_t_check(&attr, &Str::from(attr.show()), attr.ref_t(), expr.ref_t())
|
||||||
{
|
{
|
||||||
|
@ -2302,14 +2423,18 @@ impl ASTLowerer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_type_asc(&mut self, tasc: ast::TypeAscription) -> LowerResult<hir::TypeAscription> {
|
fn lower_type_asc(
|
||||||
|
&mut self,
|
||||||
|
tasc: ast::TypeAscription,
|
||||||
|
expect: Option<&Type>,
|
||||||
|
) -> LowerResult<hir::TypeAscription> {
|
||||||
log!(info "entered {}({tasc})", fn_name!());
|
log!(info "entered {}({tasc})", fn_name!());
|
||||||
let kind = tasc.kind();
|
let kind = tasc.kind();
|
||||||
let spec_t = self
|
let spec_t = self
|
||||||
.module
|
.module
|
||||||
.context
|
.context
|
||||||
.instantiate_typespec(&tasc.t_spec.t_spec)?;
|
.instantiate_typespec(&tasc.t_spec.t_spec)?;
|
||||||
let expr = self.lower_expr(*tasc.expr)?;
|
let expr = self.lower_expr(*tasc.expr, expect)?;
|
||||||
match kind {
|
match kind {
|
||||||
AscriptionKind::TypeOf | AscriptionKind::AsCast => {
|
AscriptionKind::TypeOf | AscriptionKind::AsCast => {
|
||||||
self.module.context.sub_unify(
|
self.module.context.sub_unify(
|
||||||
|
@ -2438,25 +2563,27 @@ impl ASTLowerer {
|
||||||
|
|
||||||
// Call.obj == Accessor cannot be type inferred by itself (it can only be inferred with arguments)
|
// Call.obj == Accessor cannot be type inferred by itself (it can only be inferred with arguments)
|
||||||
// so turn off type checking (check=false)
|
// so turn off type checking (check=false)
|
||||||
fn lower_expr(&mut self, expr: ast::Expr) -> LowerResult<hir::Expr> {
|
fn lower_expr(&mut self, expr: ast::Expr, expect: Option<&Type>) -> LowerResult<hir::Expr> {
|
||||||
log!(info "entered {}", fn_name!());
|
log!(info "entered {}", fn_name!());
|
||||||
let casted = self.module.context.get_casted_type(&expr);
|
let casted = self.module.context.get_casted_type(&expr);
|
||||||
let mut expr = match expr {
|
let mut expr = match expr {
|
||||||
ast::Expr::Literal(lit) => hir::Expr::Literal(self.lower_literal(lit)?),
|
ast::Expr::Literal(lit) => hir::Expr::Literal(self.lower_literal(lit, expect)?),
|
||||||
ast::Expr::Array(arr) => hir::Expr::Array(self.lower_array(arr)?),
|
ast::Expr::Array(arr) => hir::Expr::Array(self.lower_array(arr, expect)?),
|
||||||
ast::Expr::Tuple(tup) => hir::Expr::Tuple(self.lower_tuple(tup)?),
|
ast::Expr::Tuple(tup) => hir::Expr::Tuple(self.lower_tuple(tup, expect)?),
|
||||||
ast::Expr::Record(rec) => hir::Expr::Record(self.lower_record(rec)?),
|
ast::Expr::Record(rec) => hir::Expr::Record(self.lower_record(rec, expect)?),
|
||||||
ast::Expr::Set(set) => hir::Expr::Set(self.lower_set(set)?),
|
ast::Expr::Set(set) => hir::Expr::Set(self.lower_set(set, expect)?),
|
||||||
ast::Expr::Dict(dict) => hir::Expr::Dict(self.lower_dict(dict)?),
|
ast::Expr::Dict(dict) => hir::Expr::Dict(self.lower_dict(dict, expect)?),
|
||||||
ast::Expr::Accessor(acc) => hir::Expr::Accessor(self.lower_acc(acc)?),
|
ast::Expr::Accessor(acc) => hir::Expr::Accessor(self.lower_acc(acc, expect)?),
|
||||||
ast::Expr::BinOp(bin) => hir::Expr::BinOp(self.lower_bin(bin)),
|
ast::Expr::BinOp(bin) => hir::Expr::BinOp(self.lower_bin(bin, expect)),
|
||||||
ast::Expr::UnaryOp(unary) => hir::Expr::UnaryOp(self.lower_unary(unary)),
|
ast::Expr::UnaryOp(unary) => hir::Expr::UnaryOp(self.lower_unary(unary, expect)),
|
||||||
ast::Expr::Call(call) => hir::Expr::Call(self.lower_call(call)?),
|
ast::Expr::Call(call) => hir::Expr::Call(self.lower_call(call, expect)?),
|
||||||
ast::Expr::DataPack(pack) => hir::Expr::Call(self.lower_pack(pack)?),
|
ast::Expr::DataPack(pack) => hir::Expr::Call(self.lower_pack(pack, expect)?),
|
||||||
ast::Expr::Lambda(lambda) => hir::Expr::Lambda(self.lower_lambda(lambda)?),
|
ast::Expr::Lambda(lambda) => hir::Expr::Lambda(self.lower_lambda(lambda, expect)?),
|
||||||
ast::Expr::TypeAscription(tasc) => hir::Expr::TypeAsc(self.lower_type_asc(tasc)?),
|
ast::Expr::TypeAscription(tasc) => {
|
||||||
|
hir::Expr::TypeAsc(self.lower_type_asc(tasc, expect)?)
|
||||||
|
}
|
||||||
// Checking is also performed for expressions in Dummy. However, it has no meaning in code generation
|
// Checking is also performed for expressions in Dummy. However, it has no meaning in code generation
|
||||||
ast::Expr::Dummy(dummy) => hir::Expr::Dummy(self.lower_dummy(dummy)?),
|
ast::Expr::Dummy(dummy) => hir::Expr::Dummy(self.lower_dummy(dummy, expect)?),
|
||||||
other => {
|
other => {
|
||||||
log!(err "unreachable: {other}");
|
log!(err "unreachable: {other}");
|
||||||
return unreachable_error!(LowerErrors, LowerError, self.module.context);
|
return unreachable_error!(LowerErrors, LowerError, self.module.context);
|
||||||
|
@ -2475,7 +2602,11 @@ impl ASTLowerer {
|
||||||
/// The meaning of TypeAscription changes between chunk and expr.
|
/// The meaning of TypeAscription changes between chunk and expr.
|
||||||
/// For example, `x: Int`, as expr, is `x` itself,
|
/// For example, `x: Int`, as expr, is `x` itself,
|
||||||
/// but as chunk, it declares that `x` is of type `Int`, and is valid even before `x` is defined.
|
/// but as chunk, it declares that `x` is of type `Int`, and is valid even before `x` is defined.
|
||||||
pub fn lower_chunk(&mut self, chunk: ast::Expr) -> LowerResult<hir::Expr> {
|
pub fn lower_chunk(
|
||||||
|
&mut self,
|
||||||
|
chunk: ast::Expr,
|
||||||
|
expect: Option<&Type>,
|
||||||
|
) -> LowerResult<hir::Expr> {
|
||||||
log!(info "entered {}", fn_name!());
|
log!(info "entered {}", fn_name!());
|
||||||
match chunk {
|
match chunk {
|
||||||
ast::Expr::Def(def) => Ok(hir::Expr::Def(self.lower_def(def)?)),
|
ast::Expr::Def(def) => Ok(hir::Expr::Def(self.lower_def(def)?)),
|
||||||
|
@ -2483,15 +2614,21 @@ impl ASTLowerer {
|
||||||
ast::Expr::PatchDef(defs) => Ok(hir::Expr::PatchDef(self.lower_patch_def(defs)?)),
|
ast::Expr::PatchDef(defs) => Ok(hir::Expr::PatchDef(self.lower_patch_def(defs)?)),
|
||||||
ast::Expr::ReDef(redef) => Ok(hir::Expr::ReDef(self.lower_redef(redef)?)),
|
ast::Expr::ReDef(redef) => Ok(hir::Expr::ReDef(self.lower_redef(redef)?)),
|
||||||
ast::Expr::TypeAscription(tasc) => Ok(hir::Expr::TypeAsc(self.lower_decl(tasc)?)),
|
ast::Expr::TypeAscription(tasc) => Ok(hir::Expr::TypeAsc(self.lower_decl(tasc)?)),
|
||||||
other => self.lower_expr(other),
|
other => self.lower_expr(other, expect),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_block(&mut self, ast_block: ast::Block) -> LowerResult<hir::Block> {
|
fn lower_block(
|
||||||
|
&mut self,
|
||||||
|
ast_block: ast::Block,
|
||||||
|
expect: Option<&Type>,
|
||||||
|
) -> LowerResult<hir::Block> {
|
||||||
log!(info "entered {}", fn_name!());
|
log!(info "entered {}", fn_name!());
|
||||||
let mut hir_block = Vec::with_capacity(ast_block.len());
|
let mut hir_block = Vec::with_capacity(ast_block.len());
|
||||||
for chunk in ast_block.into_iter() {
|
let last = ast_block.len() - 1;
|
||||||
let chunk = match self.lower_chunk(chunk) {
|
for (i, chunk) in ast_block.into_iter().enumerate() {
|
||||||
|
let expect = if i == last { expect } else { None };
|
||||||
|
let chunk = match self.lower_chunk(chunk, expect) {
|
||||||
Ok(chunk) => chunk,
|
Ok(chunk) => chunk,
|
||||||
Err(errs) => {
|
Err(errs) => {
|
||||||
self.errs.extend(errs);
|
self.errs.extend(errs);
|
||||||
|
@ -2503,11 +2640,17 @@ impl ASTLowerer {
|
||||||
Ok(hir::Block::new(hir_block))
|
Ok(hir::Block::new(hir_block))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_dummy(&mut self, ast_dummy: ast::Dummy) -> LowerResult<hir::Dummy> {
|
fn lower_dummy(
|
||||||
|
&mut self,
|
||||||
|
ast_dummy: ast::Dummy,
|
||||||
|
expect: Option<&Type>,
|
||||||
|
) -> LowerResult<hir::Dummy> {
|
||||||
log!(info "entered {}", fn_name!());
|
log!(info "entered {}", fn_name!());
|
||||||
let mut hir_dummy = Vec::with_capacity(ast_dummy.len());
|
let mut hir_dummy = Vec::with_capacity(ast_dummy.len());
|
||||||
for chunk in ast_dummy.into_iter() {
|
let last = ast_dummy.len() - 1;
|
||||||
let chunk = self.lower_chunk(chunk)?;
|
for (i, chunk) in ast_dummy.into_iter().enumerate() {
|
||||||
|
let expect = if i == last { expect } else { None };
|
||||||
|
let chunk = self.lower_chunk(chunk, expect)?;
|
||||||
hir_dummy.push(chunk);
|
hir_dummy.push(chunk);
|
||||||
}
|
}
|
||||||
Ok(hir::Dummy::new(hir_dummy))
|
Ok(hir::Dummy::new(hir_dummy))
|
||||||
|
@ -2562,7 +2705,7 @@ impl ASTLowerer {
|
||||||
self.errs.extend(errs);
|
self.errs.extend(errs);
|
||||||
}
|
}
|
||||||
for chunk in ast.module.into_iter() {
|
for chunk in ast.module.into_iter() {
|
||||||
match self.lower_chunk(chunk) {
|
match self.lower_chunk(chunk, None) {
|
||||||
Ok(chunk) => {
|
Ok(chunk) => {
|
||||||
module.push(chunk);
|
module.push(chunk);
|
||||||
}
|
}
|
||||||
|
|
|
@ -556,6 +556,21 @@ impl SubrType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// WARN: This is an infinite iterator
|
||||||
|
///
|
||||||
|
/// `self` is not included
|
||||||
|
pub fn pos_params(&self) -> impl Iterator<Item = &ParamTy> + Clone {
|
||||||
|
let non_defaults = self
|
||||||
|
.non_default_params
|
||||||
|
.iter()
|
||||||
|
.filter(|pt| !pt.name().is_some_and(|n| &n[..] == "self"));
|
||||||
|
if let Some(var_params) = self.var_params.as_ref() {
|
||||||
|
non_defaults.chain(std::iter::repeat(var_params.as_ref()))
|
||||||
|
} else {
|
||||||
|
non_defaults.chain(std::iter::repeat(&ParamTy::Pos(Type::Failure)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn param_names(&self) -> impl Iterator<Item = &str> + Clone {
|
pub fn param_names(&self) -> impl Iterator<Item = &str> + Clone {
|
||||||
self.non_default_params
|
self.non_default_params
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -2388,19 +2403,6 @@ impl Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn union_types(&self) -> Vec<Type> {
|
|
||||||
match self {
|
|
||||||
Self::FreeVar(fv) if fv.is_linked() => fv.crack().union_types(),
|
|
||||||
Self::Refinement(refine) => refine.t.union_types(),
|
|
||||||
Self::Or(t1, t2) => {
|
|
||||||
let mut types = t1.union_types();
|
|
||||||
types.extend(t2.union_types());
|
|
||||||
types
|
|
||||||
}
|
|
||||||
_ => vec![self.clone()],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// assert!((A or B).contains_union(B))
|
/// assert!((A or B).contains_union(B))
|
||||||
pub fn contains_union(&self, typ: &Type) -> bool {
|
pub fn contains_union(&self, typ: &Type) -> bool {
|
||||||
match self {
|
match self {
|
||||||
|
|
|
@ -16,7 +16,7 @@ assert l == [1, 2]
|
||||||
l.extend! [3, 4]
|
l.extend! [3, 4]
|
||||||
assert l == [1, 2, 3, 4]
|
assert l == [1, 2, 3, 4]
|
||||||
|
|
||||||
l.update_nth! 0, (x: Nat) -> x + 2
|
l.update_nth! 0, x -> x + 2
|
||||||
assert l == [3, 2, 3, 4]
|
assert l == [3, 2, 3, 4]
|
||||||
|
|
||||||
l.sort!()
|
l.sort!()
|
||||||
|
|
|
@ -14,4 +14,4 @@ v2 = ![1, 1, 1]
|
||||||
v2.update!((x: [{1}; _]) -> x + [1])
|
v2.update!((x: [{1}; _]) -> x + [1])
|
||||||
|
|
||||||
v3 as Array!(Int, _) = ![1, 2, 3]
|
v3 as Array!(Int, _) = ![1, 2, 3]
|
||||||
v3.update!((x: [Int; _]) -> x + [1] as [Int; _])
|
v3.update!(x -> x + [1])
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue