fix(compiler): runtime type matching system

This commit is contained in:
Shunsuke Shibayama 2023-02-12 01:34:12 +09:00
parent 92614ce8d2
commit af0fff8226
25 changed files with 793 additions and 429 deletions

View file

@ -480,8 +480,40 @@ impl<'a> HIRVisitor<'a> {
None None
} }
fn get_sig_info(&self, sig: &Signature, token: &Token) -> Option<VarInfo> {
match sig {
Signature::Var(var) => {
self.return_var_info_if_same(&var.ident, var.ident.name.token(), token)
}
Signature::Subr(subr) => self
.return_var_info_if_same(&subr.ident, subr.ident.name.token(), token)
.or_else(|| self.get_params_info(&subr.params, token)),
}
}
fn get_params_info(&self, params: &Params, token: &Token) -> Option<VarInfo> {
for param in params.non_defaults.iter() {
if param.raw.pat.loc() == token.loc() {
return Some(param.vi.clone());
}
}
if let Some(var) = &params.var_params {
if var.raw.pat.loc() == token.loc() {
return Some(var.vi.clone());
}
}
for param in params.defaults.iter() {
if param.sig.raw.pat.loc() == token.loc() {
return Some(param.sig.vi.clone());
} else if let Some(vi) = self.get_expr_info(&param.default_val, token) {
return Some(vi);
}
}
None
}
fn get_def_info(&self, def: &Def, token: &Token) -> Option<VarInfo> { fn get_def_info(&self, def: &Def, token: &Token) -> Option<VarInfo> {
self.return_var_info_if_same(def.sig.ident(), def.sig.ident().name.token(), token) self.get_sig_info(&def.sig, token)
.or_else(|| self.get_block_info(&def.body.block, token)) .or_else(|| self.get_block_info(&def.body.block, token))
} }
@ -490,13 +522,7 @@ impl<'a> HIRVisitor<'a> {
.require_or_sup .require_or_sup
.as_ref() .as_ref()
.and_then(|req_sup| self.get_expr_info(req_sup, token)) .and_then(|req_sup| self.get_expr_info(req_sup, token))
.or_else(|| { .or_else(|| self.get_sig_info(&class_def.sig, token))
self.return_var_info_if_same(
class_def.sig.ident(),
class_def.sig.ident().name.token(),
token,
)
})
.or_else(|| self.get_block_info(&class_def.methods, token)) .or_else(|| self.get_block_info(&class_def.methods, token))
} }

View file

@ -113,7 +113,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
return result; return result;
}; };
for (nd_param, nd_t) in subr.params.non_defaults.iter().zip(nd_ts) { for (nd_param, nd_t) in subr.params.non_defaults.iter().zip(nd_ts) {
if nd_param.t_spec.is_some() { if nd_param.raw.t_spec.is_some() {
continue; continue;
} }
let hint = type_anot( let hint = type_anot(
@ -125,7 +125,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
result.push(hint); result.push(hint);
} }
for (d_param, d_t) in subr.params.defaults.iter().zip(d_ts) { for (d_param, d_t) in subr.params.defaults.iter().zip(d_ts) {
if d_param.sig.t_spec.is_some() { if d_param.sig.raw.t_spec.is_some() {
continue; continue;
} }
let hint = type_anot( let hint = type_anot(
@ -185,7 +185,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
return result; return result;
}; };
for (nd_param, nd_t) in lambda.params.non_defaults.iter().zip(nd_ts) { for (nd_param, nd_t) in lambda.params.non_defaults.iter().zip(nd_ts) {
if nd_param.t_spec.is_some() { if nd_param.raw.t_spec.is_some() {
continue; continue;
} }
let hint = type_anot( let hint = type_anot(
@ -197,7 +197,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
result.push(hint); result.push(hint);
} }
for (d_param, d_t) in lambda.params.defaults.iter().zip(d_ts) { for (d_param, d_t) in lambda.params.defaults.iter().zip(d_ts) {
if d_param.sig.t_spec.is_some() { if d_param.sig.raw.t_spec.is_some() {
continue; continue;
} }
let hint = type_anot( let hint = type_anot(

View file

@ -25,9 +25,7 @@ use erg_common::{
use erg_parser::ast::{DefId, DefKind}; use erg_parser::ast::{DefId, DefKind};
use CommonOpcode::*; use CommonOpcode::*;
use erg_parser::ast::PreDeclTypeSpec; use erg_parser::ast::{ParamPattern, VarName};
use erg_parser::ast::TypeSpec;
use erg_parser::ast::{NonDefaultParamSignature, ParamPattern, VarName};
use erg_parser::token::DOT; use erg_parser::token::DOT;
use erg_parser::token::EQUAL; use erg_parser::token::EQUAL;
use erg_parser::token::{Token, TokenKind}; use erg_parser::token::{Token, TokenKind};
@ -36,11 +34,12 @@ use crate::compile::{AccessKind, Name, StoreLoadKind};
use crate::error::CompileError; use crate::error::CompileError;
use crate::hir::{ use crate::hir::{
Accessor, Args, Array, BinOp, Block, Call, ClassDef, Def, DefBody, Expr, Identifier, Lambda, Accessor, Args, Array, BinOp, Block, Call, ClassDef, Def, DefBody, Expr, Identifier, Lambda,
Literal, Params, PatchDef, PosArg, ReDef, Record, Signature, SubrSignature, Tuple, UnaryOp, Literal, NonDefaultParamSignature, Params, PatchDef, PosArg, ReDef, Record, Signature,
VarSignature, HIR, SubrSignature, Tuple, UnaryOp, VarSignature, HIR,
}; };
use crate::ty::value::ValueObj; use crate::ty::value::ValueObj;
use crate::ty::{HasType, Type, TypeCode, TypePair}; use crate::ty::{HasType, Type, TypeCode, TypePair};
use crate::varinfo::VarInfo;
use erg_common::fresh::fresh_varname; use erg_common::fresh::fresh_varname;
use AccessKind::*; use AccessKind::*;
use Type::*; use Type::*;
@ -1850,46 +1849,9 @@ impl PyCodeGenerator {
) -> Vec<usize> { ) -> Vec<usize> {
log!(info "entered {}", fn_name!()); log!(info "entered {}", fn_name!());
let mut pop_jump_points = vec![]; let mut pop_jump_points = vec![];
if let Some(t_spec) = param.t_spec.map(|spec| spec.t_spec) { if let Some(t_spec) = param.t_spec_as_expr {
// If it's the last arm, there's no need to inspect it // If it's the last arm, there's no need to inspect it
if !is_last_arm { if !is_last_arm {
if self.py_version.minor >= Some(11) {
self.emit_match_guard_311(t_spec, &mut pop_jump_points);
} else {
self.emit_match_guard_310(t_spec, &mut pop_jump_points);
}
}
}
match param.pat {
ParamPattern::VarName(name) => {
let ident = Identifier::bare(None, name);
self.emit_store_instr(ident, AccessKind::Name);
}
ParamPattern::Discard(_) => {
self.emit_pop_top();
}
_other => unreachable!(),
}
pop_jump_points
}
fn emit_match_guard_311(&mut self, t_spec: TypeSpec, pop_jump_points: &mut Vec<usize>) {
log!(info "entered {} ({t_spec})", fn_name!());
match t_spec {
TypeSpec::Enum(enum_t) => {
let elems = ValueObj::vec_from_const_args(enum_t);
self.emit_load_const(elems);
self.write_instr(CONTAINS_OP);
self.write_arg(0);
self.stack_dec();
pop_jump_points.push(self.lasti());
// in 3.11, POP_JUMP_IF_FALSE is replaced with POP_JUMP_FORWARD_IF_FALSE
// but the numbers are the same, only the way the jumping points are calculated is different.
self.write_instr(Opcode310::POP_JUMP_IF_FALSE); // jump to the next case
self.write_arg(0);
// self.stack_dec();
}
TypeSpec::PreDeclTy(PreDeclTypeSpec::Simple(simple)) if simple.args.is_empty() => {
// arg null // arg null
// ↓ SWAP 1 // ↓ SWAP 1
// null arg // null arg
@ -1906,15 +1868,7 @@ impl PyCodeGenerator {
} }
self.emit_load_name_instr(Identifier::private("#in_operator")); self.emit_load_name_instr(Identifier::private("#in_operator"));
self.rot2(); self.rot2();
// TODO: DOT/not self.emit_expr(t_spec);
let mut typ = Identifier::bare(Some(DOT), simple.ident.name);
// TODO:
typ.vi.py_name = match &typ.name.inspect()[..] {
"Int" => Some("int".into()),
"Float" => Some("float".into()),
_ => None,
};
self.emit_load_name_instr(typ);
self.emit_precall_and_call(2); self.emit_precall_and_call(2);
self.stack_dec(); self.stack_dec();
pop_jump_points.push(self.lasti()); pop_jump_points.push(self.lasti());
@ -1924,127 +1878,18 @@ impl PyCodeGenerator {
self.write_arg(0); self.write_arg(0);
self.stack_dec(); self.stack_dec();
} }
// _: (Int, Str)
TypeSpec::Tuple(tup) => {
let len = tup.tys.len();
for (i, t_spec) in tup.tys.into_iter().enumerate() {
if i != 0 && i != len - 1 {
self.dup_top();
} }
self.emit_load_const(i); match param.raw.pat {
self.write_instr(Opcode311::BINARY_SUBSCR); ParamPattern::VarName(name) => {
self.write_arg(0); let ident = Identifier::bare(None, name);
self.stack_dec(); self.emit_store_instr(ident, AccessKind::Name);
self.emit_match_guard_311(t_spec, pop_jump_points);
} }
ParamPattern::Discard(_) => {
self.emit_pop_top();
} }
// TODO: consider ordering (e.g. both [1, 2] and [2, 1] is type of [{1, 2}; 2]) _other => unreachable!(),
TypeSpec::Array(arr) => {
let ValueObj::Nat(len) = ValueObj::from_const_expr(arr.len) else { todo!() };
for i in 0..=(len - 1) {
if i != 0 && i != len - 1 {
self.dup_top();
}
self.emit_load_const(i);
self.write_instr(Opcode311::BINARY_SUBSCR);
self.write_arg(0);
self.stack_dec();
self.emit_match_guard_311(*arr.ty.clone(), pop_jump_points);
}
}
/*TypeSpec::Interval { op, lhs, rhs } => {
let binop = BinOp::new(op, lhs.downcast(), rhs.downcast(), VarInfo::default());
self.emit_binop(binop);
}*/
// TODO:
TypeSpec::Infer(_) => unreachable!(),
// TODO:
other => log!(err "{other}"),
}
}
fn emit_match_guard_310(&mut self, t_spec: TypeSpec, pop_jump_points: &mut Vec<usize>) {
log!(info "entered {} ({t_spec})", fn_name!());
match t_spec {
TypeSpec::Enum(enum_t) => {
let elems = ValueObj::vec_from_const_args(enum_t);
self.emit_load_const(elems);
self.write_instr(Opcode310::CONTAINS_OP);
self.write_arg(0);
self.stack_dec();
pop_jump_points.push(self.lasti());
// in 3.11, POP_JUMP_IF_FALSE is replaced with POP_JUMP_FORWARD_IF_FALSE
// but the numbers are the same, only the way the jumping points are calculated is different.
self.write_instr(Opcode310::POP_JUMP_IF_FALSE); // jump to the next case
self.write_arg(0);
// self.stack_dec();
}
TypeSpec::PreDeclTy(PreDeclTypeSpec::Simple(simple)) if simple.args.is_empty() => {
// arg
// ↓ LOAD_NAME(in_operator)
// arg in_operator
// ↓ ROT 2
// in_operator arg
// ↓ LOAD_NAME(typ)
// in_operator arg typ
self.emit_load_name_instr(Identifier::private("#in_operator"));
self.rot2();
// TODO: DOT/not
let mut typ = Identifier::bare(Some(DOT), simple.ident.name);
// TODO:
typ.vi.py_name = match &typ.name.inspect()[..] {
"Int" => Some("int".into()),
"Float" => Some("float".into()),
_ => None,
};
self.emit_load_name_instr(typ);
self.write_instr(Opcode310::CALL_FUNCTION);
self.write_arg(2);
self.stack_dec();
pop_jump_points.push(self.lasti());
// in 3.11, POP_JUMP_IF_FALSE is replaced with POP_JUMP_FORWARD_IF_FALSE
// but the numbers are the same, only the way the jumping points are calculated is different.
self.write_instr(Opcode310::POP_JUMP_IF_FALSE); // jump to the next case
self.write_arg(0);
self.stack_dec();
}
// _: (Int, Str)
TypeSpec::Tuple(tup) => {
let len = tup.tys.len();
for (i, t_spec) in tup.tys.into_iter().enumerate() {
if i != 0 && i != len - 1 {
self.dup_top();
}
self.emit_load_const(i);
self.write_instr(Opcode310::BINARY_SUBSCR);
self.write_arg(0);
self.stack_dec();
self.emit_match_guard_310(t_spec, pop_jump_points);
}
}
// TODO: consider ordering (e.g. both [1, 2] and [2, 1] is type of [{1, 2}; 2])
TypeSpec::Array(arr) => {
let ValueObj::Nat(len) = ValueObj::from_const_expr(arr.len) else { todo!() };
for i in 0..=(len - 1) {
if i != 0 && i != len - 1 {
self.dup_top();
}
self.emit_load_const(i);
self.write_instr(Opcode310::BINARY_SUBSCR);
self.write_arg(0);
self.stack_dec();
self.emit_match_guard_310(*arr.ty.clone(), pop_jump_points);
}
}
/*TypeSpec::Interval { op, lhs, rhs } => {
let binop = BinOp::new(op, lhs.downcast(), rhs.downcast(), VarInfo::default());
self.emit_binop(binop);
}*/
// TODO:
TypeSpec::Infer(_) => unreachable!(),
// TODO:
other => log!(err "{other}"),
} }
pop_jump_points
} }
fn emit_with_instr_311(&mut self, mut args: Args) { fn emit_with_instr_311(&mut self, mut args: Args) {
@ -2878,14 +2723,23 @@ impl PyCodeGenerator {
let mut ident = Identifier::public_with_line(DOT, Str::ever("__init__"), line); let mut ident = Identifier::public_with_line(DOT, Str::ever("__init__"), line);
ident.vi.t = __new__.clone(); ident.vi.t = __new__.clone();
let self_param = VarName::from_str_and_line(Str::ever("self"), line); let self_param = VarName::from_str_and_line(Str::ever("self"), line);
let self_param = NonDefaultParamSignature::new(ParamPattern::VarName(self_param), None); let vi = VarInfo::parameter(
__new__.return_t().unwrap().clone(),
ident.vi.def_loc.clone(),
);
let raw =
erg_parser::ast::NonDefaultParamSignature::new(ParamPattern::VarName(self_param), None);
let self_param = NonDefaultParamSignature::new(raw, vi, None);
let (param_name, params) = if let Some(new_first_param) = new_first_param { let (param_name, params) = if let Some(new_first_param) = new_first_param {
let param_name = new_first_param let param_name = new_first_param
.name() .name()
.map(|s| s.to_string()) .map(|s| s.to_string())
.unwrap_or_else(fresh_varname); .unwrap_or_else(fresh_varname);
let param = VarName::from_str_and_line(Str::from(param_name.clone()), line); let param = VarName::from_str_and_line(Str::from(param_name.clone()), line);
let param = NonDefaultParamSignature::new(ParamPattern::VarName(param), None); let raw =
erg_parser::ast::NonDefaultParamSignature::new(ParamPattern::VarName(param), None);
let vi = VarInfo::parameter(new_first_param.typ().clone(), ident.vi.def_loc.clone());
let param = NonDefaultParamSignature::new(raw, vi, None);
let params = Params::new(vec![self_param, param], None, vec![], None); let params = Params::new(vec![self_param, param], None, vec![], None);
(param_name, params) (param_name, params)
} else { } else {
@ -2965,7 +2819,10 @@ impl PyCodeGenerator {
.map(|s| s.to_string()) .map(|s| s.to_string())
.unwrap_or_else(fresh_varname); .unwrap_or_else(fresh_varname);
let param = VarName::from_str_and_line(Str::from(param_name.clone()), line); let param = VarName::from_str_and_line(Str::from(param_name.clone()), line);
let param = NonDefaultParamSignature::new(ParamPattern::VarName(param), None); let vi = VarInfo::parameter(new_first_param.typ().clone(), ident.vi.def_loc.clone());
let raw =
erg_parser::ast::NonDefaultParamSignature::new(ParamPattern::VarName(param), None);
let param = NonDefaultParamSignature::new(raw, vi, None);
let params = Params::new(vec![param], None, vec![], None); let params = Params::new(vec![param], None, vec![], None);
let sig = SubrSignature::new(ident, params, sig.t_spec().cloned()); let sig = SubrSignature::new(ident, params, sig.t_spec().cloned());
let arg = PosArg::new(Expr::Accessor(Accessor::private_with_line( let arg = PosArg::new(Expr::Accessor(Accessor::private_with_line(

View file

@ -761,6 +761,26 @@ impl Context {
self.methods_list = methods_list; self.methods_list = methods_list;
} }
fn resolve_params_t(&self, params: &mut hir::Params) -> TyCheckResult<()> {
for param in params.non_defaults.iter_mut() {
param.vi.t =
self.deref_tyvar(mem::take(&mut param.vi.t), Contravariant, param.loc())?;
}
if let Some(var_params) = &mut params.var_params {
var_params.vi.t = self.deref_tyvar(
mem::take(&mut var_params.vi.t),
Contravariant,
var_params.loc(),
)?;
}
for param in params.defaults.iter_mut() {
param.sig.vi.t =
self.deref_tyvar(mem::take(&mut param.sig.vi.t), Contravariant, param.loc())?;
self.resolve_expr_t(&mut param.default_val)?;
}
Ok(())
}
fn resolve_expr_t(&self, expr: &mut hir::Expr) -> TyCheckResult<()> { fn resolve_expr_t(&self, expr: &mut hir::Expr) -> TyCheckResult<()> {
match expr { match expr {
hir::Expr::Lit(_) => Ok(()), hir::Expr::Lit(_) => Ok(()),
@ -898,6 +918,9 @@ impl Context {
hir::Expr::Def(def) => { hir::Expr::Def(def) => {
*def.sig.ref_mut_t() = *def.sig.ref_mut_t() =
self.deref_tyvar(mem::take(def.sig.ref_mut_t()), Covariant, def.sig.loc())?; self.deref_tyvar(mem::take(def.sig.ref_mut_t()), Covariant, def.sig.loc())?;
if let Some(params) = def.sig.params_mut() {
self.resolve_params_t(params)?;
}
for chunk in def.body.block.iter_mut() { for chunk in def.body.block.iter_mut() {
self.resolve_expr_t(chunk)?; self.resolve_expr_t(chunk)?;
} }
@ -905,6 +928,7 @@ impl Context {
} }
hir::Expr::Lambda(lambda) => { hir::Expr::Lambda(lambda) => {
lambda.t = self.deref_tyvar(mem::take(&mut lambda.t), Covariant, lambda.loc())?; lambda.t = self.deref_tyvar(mem::take(&mut lambda.t), Covariant, lambda.loc())?;
self.resolve_params_t(&mut lambda.params)?;
for chunk in lambda.body.iter_mut() { for chunk in lambda.body.iter_mut() {
self.resolve_expr_t(chunk)?; self.resolve_expr_t(chunk)?;
} }

View file

@ -271,7 +271,7 @@ impl Context {
} }
let mut dummy_tv_cache = TyVarCache::new(self.level, self); let mut dummy_tv_cache = TyVarCache::new(self.level, self);
let rhs = self.instantiate_param_sig_t( let rhs = self.instantiate_param_sig_t(
&lambda.params.non_defaults[0], &lambda.params.non_defaults[0].raw,
None, None,
&mut dummy_tv_cache, &mut dummy_tv_cache,
Normal, Normal,

View file

@ -379,8 +379,14 @@ impl Context {
mode: RegistrationMode, mode: RegistrationMode,
kind: ParamKind, kind: ParamKind,
) -> TyCheckResult<Type> { ) -> TyCheckResult<Type> {
let spec_t = if let Some(spec_with_op) = &sig.t_spec { let spec_t = if let Some(t_spec_with_op) = &sig.t_spec {
self.instantiate_typespec(&spec_with_op.t_spec, opt_decl_t, tmp_tv_cache, mode, false)? self.instantiate_typespec(
&t_spec_with_op.t_spec,
opt_decl_t,
tmp_tv_cache,
mode,
false,
)?
} else { } else {
match &sig.pat { match &sig.pat {
ast::ParamPattern::Lit(lit) => v_enum(set![self.eval_lit(lit)?]), ast::ParamPattern::Lit(lit) => v_enum(set![self.eval_lit(lit)?]),

View file

@ -242,10 +242,11 @@ impl Context {
Ok(vi) Ok(vi)
} }
/// TODO: sig should be immutable
/// 宣言が既にある場合、opt_decl_tに宣言の型を渡す /// 宣言が既にある場合、opt_decl_tに宣言の型を渡す
fn assign_param( fn assign_param(
&mut self, &mut self,
sig: &ast::NonDefaultParamSignature, sig: &mut hir::NonDefaultParamSignature,
opt_decl_t: Option<&ParamTy>, opt_decl_t: Option<&ParamTy>,
kind: ParamKind, kind: ParamKind,
) -> TyCheckResult<()> { ) -> TyCheckResult<()> {
@ -256,12 +257,12 @@ impl Context {
}; };
let default = kind.default_info(); let default = kind.default_info();
let is_var_params = kind.is_var_params(); let is_var_params = kind.is_var_params();
match &sig.pat { match &sig.raw.pat {
// Literal patterns will be desugared to discard patterns // Literal patterns will be desugared to discard patterns
ast::ParamPattern::Lit(_) => unreachable!(), ast::ParamPattern::Lit(_) => unreachable!(),
ast::ParamPattern::Discard(token) => { ast::ParamPattern::Discard(token) => {
let spec_t = self.instantiate_param_sig_t( let spec_t = self.instantiate_param_sig_t(
sig, &sig.raw,
opt_decl_t, opt_decl_t,
&mut TyVarCache::new(self.level, self), &mut TyVarCache::new(self.level, self),
Normal, Normal,
@ -279,6 +280,7 @@ impl Context {
None, None,
self.absolutize(token.loc()), self.absolutize(token.loc()),
); );
sig.vi = vi.clone();
self.params.push((Some(VarName::from_static("_")), vi)); self.params.push((Some(VarName::from_static("_")), vi));
Ok(()) Ok(())
} }
@ -298,7 +300,7 @@ impl Context {
// ok, not defined // ok, not defined
let mut dummy_tv_cache = TyVarCache::new(self.level, self); let mut dummy_tv_cache = TyVarCache::new(self.level, self);
let spec_t = self.instantiate_param_sig_t( let spec_t = self.instantiate_param_sig_t(
sig, &sig.raw,
opt_decl_t, opt_decl_t,
&mut dummy_tv_cache, &mut dummy_tv_cache,
Normal, Normal,
@ -332,6 +334,7 @@ impl Context {
if let Some(shared) = self.shared() { if let Some(shared) = self.shared() {
shared.index.register(&vi); shared.index.register(&vi);
} }
sig.vi = vi.clone();
self.params.push((Some(name.clone()), vi)); self.params.push((Some(name.clone()), vi));
Ok(()) Ok(())
} }
@ -352,7 +355,7 @@ impl Context {
// ok, not defined // ok, not defined
let mut dummy_tv_cache = TyVarCache::new(self.level, self); let mut dummy_tv_cache = TyVarCache::new(self.level, self);
let spec_t = self.instantiate_param_sig_t( let spec_t = self.instantiate_param_sig_t(
sig, &sig.raw,
opt_decl_t, opt_decl_t,
&mut dummy_tv_cache, &mut dummy_tv_cache,
Normal, Normal,
@ -377,6 +380,7 @@ impl Context {
None, None,
self.absolutize(name.loc()), self.absolutize(name.loc()),
); );
sig.vi = vi.clone();
self.params.push((Some(name.clone()), vi)); self.params.push((Some(name.clone()), vi));
Ok(()) Ok(())
} }
@ -397,7 +401,7 @@ impl Context {
// ok, not defined // ok, not defined
let mut dummy_tv_cache = TyVarCache::new(self.level, self); let mut dummy_tv_cache = TyVarCache::new(self.level, self);
let spec_t = self.instantiate_param_sig_t( let spec_t = self.instantiate_param_sig_t(
sig, &sig.raw,
opt_decl_t, opt_decl_t,
&mut dummy_tv_cache, &mut dummy_tv_cache,
Normal, Normal,
@ -422,6 +426,7 @@ impl Context {
None, None,
self.absolutize(name.loc()), self.absolutize(name.loc()),
); );
sig.vi = vi.clone();
self.params.push((Some(name.clone()), vi)); self.params.push((Some(name.clone()), vi));
Ok(()) Ok(())
} }
@ -435,7 +440,7 @@ impl Context {
pub(crate) fn assign_params( pub(crate) fn assign_params(
&mut self, &mut self,
params: &hir::Params, params: &mut hir::Params,
opt_decl_subr_t: Option<SubrType>, opt_decl_subr_t: Option<SubrType>,
) -> TyCheckResult<()> { ) -> TyCheckResult<()> {
let mut errs = TyCheckErrors::empty(); let mut errs = TyCheckErrors::empty();
@ -445,16 +450,16 @@ impl Context {
decl_subr_t.non_default_params.len() decl_subr_t.non_default_params.len()
); );
debug_assert_eq!(params.defaults.len(), decl_subr_t.default_params.len()); debug_assert_eq!(params.defaults.len(), decl_subr_t.default_params.len());
for (sig, pt) in params for (non_default, pt) in params
.non_defaults .non_defaults
.iter() .iter_mut()
.zip(decl_subr_t.non_default_params.iter()) .zip(decl_subr_t.non_default_params.iter())
{ {
if let Err(es) = self.assign_param(sig, 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) = &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) = &decl_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)
@ -465,27 +470,31 @@ impl Context {
errs.extend(es); errs.extend(es);
} }
} }
for (sig, pt) in params for (default, pt) in params
.defaults .defaults
.iter() .iter_mut()
.zip(decl_subr_t.default_params.iter()) .zip(decl_subr_t.default_params.iter())
{ {
if let Err(es) = if let Err(es) = self.assign_param(
self.assign_param(&sig.sig, Some(pt), ParamKind::Default(sig.default_val.t())) &mut default.sig,
{ Some(pt),
ParamKind::Default(default.default_val.t()),
) {
errs.extend(es); errs.extend(es);
} }
} }
} else { } else {
for sig in params.non_defaults.iter() { for non_default in params.non_defaults.iter_mut() {
if let Err(es) = self.assign_param(sig, None, ParamKind::NonDefault) { if let Err(es) = self.assign_param(non_default, None, ParamKind::NonDefault) {
errs.extend(es); errs.extend(es);
} }
} }
for sig in params.defaults.iter() { for default in params.defaults.iter_mut() {
if let Err(es) = if let Err(es) = self.assign_param(
self.assign_param(&sig.sig, None, ParamKind::Default(sig.default_val.t())) &mut default.sig,
{ None,
ParamKind::Default(default.default_val.t()),
) {
errs.extend(es); errs.extend(es);
} }
} }

View file

@ -11,6 +11,7 @@ use crate::ty::free::HasLevel;
use crate::ty::value::{GenTypeObj, TypeObj}; use crate::ty::value::{GenTypeObj, TypeObj};
use crate::ty::{HasType, Type}; use crate::ty::{HasType, Type};
use crate::compile::AccessKind;
use crate::context::RegistrationMode; use crate::context::RegistrationMode;
use crate::error::{LowerError, LowerErrors, LowerResult}; use crate::error::{LowerError, LowerErrors, LowerResult};
use crate::hir; use crate::hir;
@ -119,16 +120,28 @@ impl ASTLowerer {
res res
} }
fn fake_lower_obj(&self, obj: ast::Expr) -> LowerResult<hir::Expr> { fn fake_lower_acc(&self, acc: ast::Accessor) -> LowerResult<hir::Accessor> {
match obj { match acc {
ast::Expr::Accessor(ast::Accessor::Ident(ident)) => { ast::Accessor::Ident(ident) => {
let acc = hir::Accessor::Ident(hir::Identifier::bare(ident.dot, ident.name)); // to resolve `py_name`
Ok(hir::Expr::Accessor(acc)) let vi = self
.module
.context
.rec_get_var_info(
&ident,
AccessKind::Name,
self.input(),
&self.module.context.name,
)
.unwrap_or(VarInfo::default());
let ident = hir::Identifier::new(ident.dot, ident.name, None, vi);
let acc = hir::Accessor::Ident(ident);
Ok(acc)
} }
ast::Expr::Accessor(ast::Accessor::Attr(attr)) => { ast::Accessor::Attr(attr) => {
let obj = self.fake_lower_obj(*attr.obj)?; let obj = self.fake_lower_expr(*attr.obj)?;
let ident = hir::Identifier::bare(attr.ident.dot, attr.ident.name); let ident = hir::Identifier::bare(attr.ident.dot, attr.ident.name);
Ok(obj.attr_expr(ident)) Ok(obj.attr(ident))
} }
other => Err(LowerErrors::from(LowerError::declare_error( other => Err(LowerErrors::from(LowerError::declare_error(
self.cfg().input.clone(), self.cfg().input.clone(),
@ -139,6 +152,270 @@ impl ASTLowerer {
} }
} }
fn fake_lower_args(&self, args: ast::Args) -> LowerResult<hir::Args> {
let (pos_args_, var_args_, kw_args_, paren) = args.deconstruct();
let mut pos_args = vec![];
for arg in pos_args_.into_iter() {
let arg = self.fake_lower_expr(arg.expr)?;
pos_args.push(hir::PosArg::new(arg));
}
let var_args = match var_args_ {
Some(var_args) => {
let var_args = self.fake_lower_expr(var_args.expr)?;
Some(hir::PosArg::new(var_args))
}
None => None,
};
let mut kw_args = vec![];
for kw_arg in kw_args_.into_iter() {
let expr = self.fake_lower_expr(kw_arg.expr)?;
kw_args.push(hir::KwArg::new(kw_arg.keyword, expr));
}
let args = hir::Args::new(pos_args, var_args, kw_args, paren);
Ok(args)
}
fn fake_lower_call(&self, call: ast::Call) -> LowerResult<hir::Call> {
let obj = self.fake_lower_expr(*call.obj)?;
let attr_name = call
.attr_name
.map(|ident| hir::Identifier::bare(ident.dot, ident.name));
let args = self.fake_lower_args(call.args)?;
Ok(hir::Call::new(obj, attr_name, args))
}
fn fake_lower_binop(&self, binop: ast::BinOp) -> LowerResult<hir::BinOp> {
let mut args = binop.args.into_iter();
let lhs = self.fake_lower_expr(*args.next().unwrap())?;
let rhs = self.fake_lower_expr(*args.next().unwrap())?;
Ok(hir::BinOp::new(binop.op, lhs, rhs, VarInfo::default()))
}
fn fake_lower_array(&self, arr: ast::Array) -> LowerResult<hir::Array> {
match arr {
ast::Array::WithLength(arr) => {
let len = self.fake_lower_expr(*arr.len)?;
let elem = self.fake_lower_expr(arr.elem.expr)?;
Ok(hir::Array::WithLength(hir::ArrayWithLength::new(
arr.l_sqbr,
arr.r_sqbr,
Type::Failure,
len,
elem,
)))
}
ast::Array::Normal(arr) => {
let mut elems = Vec::new();
let (elems_, ..) = arr.elems.deconstruct();
for elem in elems_.into_iter() {
let elem = self.fake_lower_expr(elem.expr)?;
elems.push(hir::PosArg::new(elem));
}
let elems = hir::Args::new(elems, None, vec![], None);
Ok(hir::Array::Normal(hir::NormalArray::new(
arr.l_sqbr,
arr.r_sqbr,
Type::Failure,
elems,
)))
}
other => Err(LowerErrors::from(LowerError::declare_error(
self.cfg().input.clone(),
line!() as usize,
other.loc(),
self.module.context.caused_by(),
))),
}
}
fn fake_lower_tuple(&self, tup: ast::Tuple) -> LowerResult<hir::Tuple> {
match tup {
ast::Tuple::Normal(tup) => {
let mut elems = Vec::new();
let (elems_, _, _, paren) = tup.elems.deconstruct();
for elem in elems_.into_iter() {
let elem = self.fake_lower_expr(elem.expr)?;
elems.push(hir::PosArg::new(elem));
}
let elems = hir::Args::new(elems, None, vec![], paren);
Ok(hir::Tuple::Normal(hir::NormalTuple::new(elems)))
}
}
}
fn fake_lower_signature(&self, sig: ast::Signature) -> LowerResult<hir::Signature> {
match sig {
ast::Signature::Var(var) => {
let ident = var.ident().unwrap().clone();
let ident = hir::Identifier::bare(ident.dot, ident.name);
let sig = hir::VarSignature::new(ident, var.t_spec);
Ok(hir::Signature::Var(sig))
}
ast::Signature::Subr(subr) => {
let ident = hir::Identifier::bare(subr.ident.dot, subr.ident.name);
let params = self.fake_lower_params(subr.params)?;
let sig = hir::SubrSignature::new(ident, params, subr.return_t_spec);
Ok(hir::Signature::Subr(sig))
}
}
}
fn fake_lower_def(&self, def: ast::Def) -> LowerResult<hir::Def> {
let sig = self.fake_lower_signature(def.sig)?;
let block = self.fake_lower_block(def.body.block)?;
let body = hir::DefBody::new(def.body.op, block, def.body.id);
Ok(hir::Def::new(sig, body))
}
fn fake_lower_record(&self, rec: ast::Record) -> LowerResult<hir::Record> {
match rec {
ast::Record::Normal(rec) => {
let mut elems = Vec::new();
for elem in rec.attrs.into_iter() {
let elem = self.fake_lower_def(elem)?;
elems.push(elem);
}
let attrs = hir::RecordAttrs::new(elems);
Ok(hir::Record::new(rec.l_brace, rec.r_brace, attrs))
}
other => Err(LowerErrors::from(LowerError::declare_error(
self.cfg().input.clone(),
line!() as usize,
other.loc(),
self.module.context.caused_by(),
))),
}
}
fn fake_lower_set(&self, set: ast::Set) -> LowerResult<hir::Set> {
match set {
ast::Set::Normal(set) => {
let mut elems = Vec::new();
let (elems_, ..) = set.elems.deconstruct();
for elem in elems_.into_iter() {
let elem = self.fake_lower_expr(elem.expr)?;
elems.push(hir::PosArg::new(elem));
}
let elems = hir::Args::new(elems, None, vec![], None);
Ok(hir::Set::Normal(hir::NormalSet::new(
set.l_brace,
set.r_brace,
Type::Failure,
elems,
)))
}
other => Err(LowerErrors::from(LowerError::declare_error(
self.cfg().input.clone(),
line!() as usize,
other.loc(),
self.module.context.caused_by(),
))),
}
}
fn fake_lower_dict(&self, dict: ast::Dict) -> LowerResult<hir::Dict> {
match dict {
ast::Dict::Normal(dict) => {
let mut kvs = Vec::new();
for elem in dict.kvs.into_iter() {
let key = self.fake_lower_expr(elem.key)?;
let val = self.fake_lower_expr(elem.value)?;
kvs.push(hir::KeyValue::new(key, val));
}
let tys = erg_common::dict::Dict::new();
Ok(hir::Dict::Normal(hir::NormalDict::new(
dict.l_brace,
dict.r_brace,
tys,
kvs,
)))
}
other => Err(LowerErrors::from(LowerError::declare_error(
self.cfg().input.clone(),
line!() as usize,
other.loc(),
self.module.context.caused_by(),
))),
}
}
fn fake_lower_params(&self, params: ast::Params) -> LowerResult<hir::Params> {
let (non_defaults_, var_params_, defaults_, parens) = params.deconstruct();
let mut non_defaults = vec![];
for non_default_ in non_defaults_.into_iter() {
let non_default =
hir::NonDefaultParamSignature::new(non_default_, VarInfo::default(), None);
non_defaults.push(non_default);
}
let var_args = var_params_.map(|var_args| {
Box::new(hir::NonDefaultParamSignature::new(
*var_args,
VarInfo::default(),
None,
))
});
let mut defaults = vec![];
for default_ in defaults_.into_iter() {
let default_val = self.fake_lower_expr(default_.default_val)?;
let sig = hir::NonDefaultParamSignature::new(default_.sig, VarInfo::default(), None);
let default = hir::DefaultParamSignature::new(sig, default_val);
defaults.push(default);
}
Ok(hir::Params::new(non_defaults, var_args, defaults, parens))
}
fn fake_lower_block(&self, block: ast::Block) -> LowerResult<hir::Block> {
let mut chunks = vec![];
for chunk in block.into_iter() {
let chunk = self.fake_lower_expr(chunk)?;
chunks.push(chunk);
}
Ok(hir::Block::new(chunks))
}
fn fake_lower_lambda(&self, lambda: ast::Lambda) -> LowerResult<hir::Lambda> {
let params = self.fake_lower_params(lambda.sig.params)?;
let body = self.fake_lower_block(lambda.body)?;
Ok(hir::Lambda::new(
lambda.id.0,
params,
lambda.op,
body,
Type::Failure,
))
}
fn fake_lower_dummy(&self, dummy: ast::Dummy) -> LowerResult<hir::Dummy> {
let mut dummy_ = vec![];
for elem in dummy.into_iter() {
let elem = self.fake_lower_expr(elem)?;
dummy_.push(elem);
}
Ok(hir::Dummy::new(dummy_))
}
pub(crate) fn fake_lower_expr(&self, expr: ast::Expr) -> LowerResult<hir::Expr> {
match expr {
ast::Expr::Literal(lit) => Ok(hir::Expr::Lit(self.lower_literal(lit)?)),
ast::Expr::BinOp(binop) => Ok(hir::Expr::BinOp(self.fake_lower_binop(binop)?)),
ast::Expr::Array(arr) => Ok(hir::Expr::Array(self.fake_lower_array(arr)?)),
ast::Expr::Tuple(tup) => Ok(hir::Expr::Tuple(self.fake_lower_tuple(tup)?)),
ast::Expr::Record(rec) => Ok(hir::Expr::Record(self.fake_lower_record(rec)?)),
ast::Expr::Set(set) => Ok(hir::Expr::Set(self.fake_lower_set(set)?)),
ast::Expr::Dict(dict) => Ok(hir::Expr::Dict(self.fake_lower_dict(dict)?)),
ast::Expr::Accessor(acc) => Ok(hir::Expr::Accessor(self.fake_lower_acc(acc)?)),
ast::Expr::Call(call) => Ok(hir::Expr::Call(self.fake_lower_call(call)?)),
ast::Expr::Lambda(lambda) => Ok(hir::Expr::Lambda(self.fake_lower_lambda(lambda)?)),
ast::Expr::Dummy(dummy) => Ok(hir::Expr::Dummy(self.fake_lower_dummy(dummy)?)),
other => Err(LowerErrors::from(LowerError::declare_error(
self.cfg().input.clone(),
line!() as usize,
other.loc(),
self.module.context.caused_by(),
))),
}
}
fn declare_ident(&mut self, tasc: ast::TypeAscription) -> LowerResult<hir::TypeAscription> { fn declare_ident(&mut self, tasc: ast::TypeAscription) -> LowerResult<hir::TypeAscription> {
log!(info "entered {}({})", fn_name!(), tasc); log!(info "entered {}({})", fn_name!(), tasc);
let is_instance_ascription = tasc.is_instance_ascription(); let is_instance_ascription = tasc.is_instance_ascription();
@ -150,7 +427,7 @@ impl ASTLowerer {
} }
let py_name = Str::rc(ident.inspect().trim_end_matches('!')); let py_name = Str::rc(ident.inspect().trim_end_matches('!'));
let t = self.module.context.instantiate_typespec( let t = self.module.context.instantiate_typespec(
&tasc.t_spec, &tasc.t_spec.t_spec,
None, None,
&mut dummy_tv_cache, &mut dummy_tv_cache,
RegistrationMode::Normal, RegistrationMode::Normal,
@ -177,7 +454,10 @@ impl ASTLowerer {
self.module.context.absolutize(ident.loc()), self.module.context.absolutize(ident.loc()),
); );
let ident = hir::Identifier::new(ident.dot, ident.name, None, vi); let ident = hir::Identifier::new(ident.dot, ident.name, None, vi);
Ok(hir::Expr::Accessor(hir::Accessor::Ident(ident)).type_asc(tasc.t_spec)) let t_spec_expr = self.fake_lower_expr(*tasc.t_spec.t_spec_as_expr)?;
let t_spec =
hir::TypeSpecWithOp::new(tasc.t_spec.op, tasc.t_spec.t_spec, t_spec_expr);
Ok(hir::Expr::Accessor(hir::Accessor::Ident(ident)).type_asc(t_spec))
} }
ast::Expr::Accessor(ast::Accessor::Attr(mut attr)) => { ast::Expr::Accessor(ast::Accessor::Attr(mut attr)) => {
if cfg!(feature = "py_compatible") { if cfg!(feature = "py_compatible") {
@ -185,7 +465,7 @@ impl ASTLowerer {
} }
let py_name = Str::rc(attr.ident.inspect().trim_end_matches('!')); let py_name = Str::rc(attr.ident.inspect().trim_end_matches('!'));
let t = self.module.context.instantiate_typespec( let t = self.module.context.instantiate_typespec(
&tasc.t_spec, &tasc.t_spec.t_spec,
None, None,
&mut dummy_tv_cache, &mut dummy_tv_cache,
RegistrationMode::Normal, RegistrationMode::Normal,
@ -202,7 +482,7 @@ impl ASTLowerer {
ast::DefId(0), ast::DefId(0),
Some(py_name), Some(py_name),
)?; )?;
let obj = self.fake_lower_obj(*attr.obj)?; let obj = self.fake_lower_expr(*attr.obj)?;
let muty = Mutability::from(&attr.ident.inspect()[..]); let muty = Mutability::from(&attr.ident.inspect()[..]);
let vis = attr.ident.vis(); let vis = attr.ident.vis();
let py_name = Str::rc(attr.ident.inspect().trim_end_matches('!')); let py_name = Str::rc(attr.ident.inspect().trim_end_matches('!'));
@ -218,7 +498,10 @@ impl ASTLowerer {
); );
let ident = hir::Identifier::new(attr.ident.dot, attr.ident.name, None, vi); let ident = hir::Identifier::new(attr.ident.dot, attr.ident.name, None, vi);
let attr = obj.attr_expr(ident); let attr = obj.attr_expr(ident);
Ok(attr.type_asc(tasc.t_spec)) let t_spec_expr = self.fake_lower_expr(*tasc.t_spec.t_spec_as_expr)?;
let t_spec =
hir::TypeSpecWithOp::new(tasc.t_spec.op, tasc.t_spec.t_spec, t_spec_expr);
Ok(attr.type_asc(t_spec))
} }
other => Err(LowerErrors::from(LowerError::declare_error( other => Err(LowerErrors::from(LowerError::declare_error(
self.cfg().input.clone(), self.cfg().input.clone(),

View file

@ -250,7 +250,7 @@ impl SideEffectChecker {
self.errs.push(EffectError::proc_assign_error( self.errs.push(EffectError::proc_assign_error(
self.cfg.input.clone(), self.cfg.input.clone(),
line!() as usize, line!() as usize,
nd_param.pat.loc(), nd_param.raw.pat.loc(),
self.full_path(), self.full_path(),
)); ));
} }
@ -260,7 +260,7 @@ impl SideEffectChecker {
self.errs.push(EffectError::proc_assign_error( self.errs.push(EffectError::proc_assign_error(
self.cfg.input.clone(), self.cfg.input.clone(),
line!() as usize, line!() as usize,
var_arg.pat.loc(), var_arg.raw.pat.loc(),
self.full_path(), self.full_path(),
)); ));
} }
@ -270,7 +270,7 @@ impl SideEffectChecker {
self.errs.push(EffectError::proc_assign_error( self.errs.push(EffectError::proc_assign_error(
self.cfg.input.clone(), self.cfg.input.clone(),
line!() as usize, line!() as usize,
d_param.sig.pat.loc(), d_param.sig.raw.pat.loc(),
self.full_path(), self.full_path(),
)); ));
} }

View file

@ -14,9 +14,8 @@ use erg_common::{
impl_nested_display_for_enum, impl_no_type_display_for_enum, impl_stream, impl_nested_display_for_enum, impl_no_type_display_for_enum, impl_stream,
}; };
use erg_parser::ast::{ use erg_parser::ast;
fmt_lines, DefId, DefKind, NonDefaultParamSignature, OperationKind, TypeSpec, VarName, use erg_parser::ast::{fmt_lines, DefId, DefKind, OperationKind, TypeSpec, VarName};
};
use erg_parser::token::{Token, TokenKind, DOT}; use erg_parser::token::{Token, TokenKind, DOT};
use crate::ty::constructors::{array_t, dict_t, set_t, tuple_t}; use crate::ty::constructors::{array_t, dict_t, set_t, tuple_t};
@ -1593,6 +1592,50 @@ impl VarSignature {
} }
} }
/// Once the default_value is set to Some, all subsequent values must be Some
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct NonDefaultParamSignature {
pub raw: ast::NonDefaultParamSignature,
pub vi: VarInfo,
pub t_spec_as_expr: Option<Expr>,
}
impl NestedDisplay for NonDefaultParamSignature {
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result {
write!(f, "{}", self.raw)
}
}
impl_display_from_nested!(NonDefaultParamSignature);
impl Locational for NonDefaultParamSignature {
fn loc(&self) -> Location {
self.raw.loc()
}
}
impl NonDefaultParamSignature {
pub const fn new(
sig: ast::NonDefaultParamSignature,
vi: VarInfo,
t_spec_as_expr: Option<Expr>,
) -> Self {
Self {
raw: sig,
vi,
t_spec_as_expr,
}
}
pub const fn inspect(&self) -> Option<&Str> {
self.raw.pat.inspect()
}
pub const fn name(&self) -> Option<&VarName> {
self.raw.pat.name()
}
}
/// Once the default_value is set to Some, all subsequent values must be Some /// Once the default_value is set to Some, all subsequent values must be Some
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct DefaultParamSignature { pub struct DefaultParamSignature {
@ -1626,7 +1669,7 @@ impl DefaultParamSignature {
} }
pub const fn inspect(&self) -> Option<&Str> { pub const fn inspect(&self) -> Option<&Str> {
self.sig.pat.inspect() self.sig.inspect()
} }
pub const fn name(&self) -> Option<&VarName> { pub const fn name(&self) -> Option<&VarName> {
@ -1930,6 +1973,13 @@ impl Signature {
Self::Subr(s) => s.return_t_spec.as_ref(), Self::Subr(s) => s.return_t_spec.as_ref(),
} }
} }
pub fn params_mut(&mut self) -> Option<&mut Params> {
match self {
Self::Var(_) => None,
Self::Subr(s) => Some(&mut s.params),
}
}
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -2259,21 +2309,47 @@ impl ReDef {
} }
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct TypeSpecWithOp {
pub op: Token,
pub t_spec: TypeSpec,
pub t_spec_as_expr: Box<Expr>,
}
impl NestedDisplay for TypeSpecWithOp {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
write!(f, "{} {}", self.op.content, self.t_spec)
}
}
impl_display_from_nested!(TypeSpecWithOp);
impl_locational!(TypeSpecWithOp, lossy op, t_spec);
impl TypeSpecWithOp {
pub fn new(op: Token, t_spec: TypeSpec, t_spec_as_expr: Expr) -> Self {
Self {
op,
t_spec,
t_spec_as_expr: Box::new(t_spec_as_expr),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct TypeAscription { pub struct TypeAscription {
pub expr: Box<Expr>, pub expr: Box<Expr>,
pub spec: TypeSpec, pub spec: TypeSpecWithOp,
} }
impl NestedDisplay for TypeAscription { impl NestedDisplay for TypeAscription {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result { fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
writeln!(f, "{}: {}", self.expr, self.spec) writeln!(f, "{}{}", self.expr, self.spec)
} }
} }
impl NoTypeDisplay for TypeAscription { impl NoTypeDisplay for TypeAscription {
fn to_string_notype(&self) -> String { fn to_string_notype(&self) -> String {
format!("{}: {}", self.expr.to_string_notype(), self.spec) format!("{}{}", self.expr.to_string_notype(), self.spec)
} }
} }
@ -2300,7 +2376,7 @@ impl HasType for TypeAscription {
} }
impl TypeAscription { impl TypeAscription {
pub fn new(expr: Expr, spec: TypeSpec) -> Self { pub fn new(expr: Expr, spec: TypeSpecWithOp) -> Self {
Self { Self {
expr: Box::new(expr), expr: Box::new(expr),
spec, spec,
@ -2412,11 +2488,11 @@ impl Expr {
Self::Accessor(self.attr(ident)) Self::Accessor(self.attr(ident))
} }
pub fn type_asc(self, t_spec: TypeSpec) -> TypeAscription { pub fn type_asc(self, t_spec: TypeSpecWithOp) -> TypeAscription {
TypeAscription::new(self, t_spec) TypeAscription::new(self, t_spec)
} }
pub fn type_asc_expr(self, t_spec: TypeSpec) -> Self { pub fn type_asc_expr(self, t_spec: TypeSpecWithOp) -> Self {
Self::TypeAsc(self.type_asc(t_spec)) Self::TypeAsc(self.type_asc(t_spec))
} }
} }

View file

@ -28,6 +28,8 @@ class BoolMut(NatMut):
self.value = b self.value = b
def __repr__(self): def __repr__(self):
return self.value.__repr__() return self.value.__repr__()
def __hash__(self):
return self.value.__hash__()
def __eq__(self, other): def __eq__(self, other):
if isinstance(other, bool): if isinstance(other, bool):
return self.value == other return self.value == other

View file

@ -41,6 +41,8 @@ class FloatMut(): # inherits Float
self.value = Float(i) self.value = Float(i)
def __repr__(self): def __repr__(self):
return self.value.__repr__() return self.value.__repr__()
def __hash__(self):
return self.value.__hash__()
def __deref__(self): def __deref__(self):
return self.value return self.value
def __eq__(self, other): def __eq__(self, other):

View file

@ -1,24 +1,24 @@
from _erg_result import is_ok from _erg_result import is_ok
from _erg_range import Range from _erg_range import Range
def in_operator(x, y): def in_operator(elem, y):
if type(y) == type: if type(y) == type:
if isinstance(x, y): if isinstance(elem, y):
return True return True
elif is_ok(y.try_new(x)): elif is_ok(y.try_new(elem)):
return True return True
# TODO: trait check # TODO: trait check
return False return False
elif (issubclass(type(y), list) or issubclass(type(y), set)) \ elif issubclass(type(y), list) \
and (type(y[0]) == type or issubclass(type(y[0]), Range)): and (type(y[0]) == type or issubclass(type(y[0]), Range)):
# FIXME: # FIXME:
type_check = in_operator(x[0], y[0]) type_check = in_operator(elem[0], y[0])
len_check = len(x) == len(y) len_check = len(elem) == len(y)
return type_check and len_check return type_check and len_check
elif issubclass(type(y), dict) and issubclass(type(next(iter(y.keys()))), type): elif issubclass(type(y), dict) and issubclass(type(next(iter(y.keys()))), type):
# TODO: # TODO:
type_check = True # in_operator(x[next(iter(x.keys()))], next(iter(y.keys()))) type_check = True # in_operator(x[next(iter(x.keys()))], next(iter(y.keys())))
len_check = len(x) >= len(y) len_check = len(elem) >= len(y)
return type_check and len_check return type_check and len_check
else: else:
return x in y return elem in y

View file

@ -45,6 +45,8 @@ class IntMut(): # inherits Int
self.value = Int(i) self.value = Int(i)
def __repr__(self): def __repr__(self):
return self.value.__repr__() return self.value.__repr__()
def __hash__(self):
return self.value.__hash__()
def __eq__(self, other): def __eq__(self, other):
if isinstance(other, Int): if isinstance(other, Int):
return self.value == other return self.value == other

View file

@ -33,6 +33,8 @@ class NatMut(IntMut): # and Nat
self.value = n self.value = n
def __repr__(self): def __repr__(self):
return self.value.__repr__() return self.value.__repr__()
def __hash__(self):
return self.value.__hash__()
def __eq__(self, other): def __eq__(self, other):
if isinstance(other, int): if isinstance(other, int):
return self.value == other return self.value == other

View file

@ -37,6 +37,8 @@ class StrMut(): # Inherits Str
self.value = s self.value = s
def __repr__(self): def __repr__(self):
return self.value.__repr__() return self.value.__repr__()
def __hash__(self):
return self.value.__hash__()
def __eq__(self, other): def __eq__(self, other):
if isinstance(other, Str): if isinstance(other, Str):
return self.value == other return self.value == other

View file

@ -701,38 +701,8 @@ impl ASTLowerer {
Ok(hir::UnaryOp::new(unary.op, expr, t)) Ok(hir::UnaryOp::new(unary.op, expr, t))
} }
pub(crate) fn lower_call(&mut self, call: ast::Call) -> LowerResult<hir::Call> { fn lower_args(&mut self, args: ast::Args, errs: &mut LowerErrors) -> hir::Args {
log!(info "entered {}({}{}(...))", fn_name!(), call.obj, fmt_option!(call.attr_name)); let (pos_args, var_args, kw_args, paren) = args.deconstruct();
if let Some(name) = call.obj.get_name() {
self.module.context.higher_order_caller.push(name.clone());
}
let mut errs = LowerErrors::empty();
let opt_cast_to = if call.is_assert_cast() {
if let Some(typ) = call.assert_cast_target_type() {
Some(Parser::expr_to_type_spec(typ.clone()).map_err(|e| {
self.module.context.higher_order_caller.pop();
let e = LowerError::new(
e.into(),
self.input().clone(),
self.module.context.caused_by(),
);
LowerErrors::from(e)
})?)
} else {
self.module.context.higher_order_caller.pop();
return Err(LowerErrors::from(LowerError::syntax_error(
self.input().clone(),
line!() as usize,
call.args.loc(),
self.module.context.caused_by(),
"invalid assert casting type".to_owned(),
None,
)));
}
} else {
None
};
let (pos_args, var_args, kw_args, paren) = call.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()),
None, None,
@ -770,6 +740,41 @@ impl ASTLowerer {
} }
} }
} }
hir_args
}
pub(crate) fn lower_call(&mut self, call: ast::Call) -> LowerResult<hir::Call> {
log!(info "entered {}({}{}(...))", fn_name!(), call.obj, fmt_option!(call.attr_name));
if let Some(name) = call.obj.get_name() {
self.module.context.higher_order_caller.push(name.clone());
}
let mut errs = LowerErrors::empty();
let opt_cast_to = if call.is_assert_cast() {
if let Some(typ) = call.assert_cast_target_type() {
Some(Parser::expr_to_type_spec(typ.clone()).map_err(|e| {
self.module.context.higher_order_caller.pop();
let e = LowerError::new(
e.into(),
self.input().clone(),
self.module.context.caused_by(),
);
LowerErrors::from(e)
})?)
} else {
self.module.context.higher_order_caller.pop();
return Err(LowerErrors::from(LowerError::syntax_error(
self.input().clone(),
line!() as usize,
call.args.loc(),
self.module.context.caused_by(),
"invalid assert casting type".to_owned(),
None,
)));
}
} else {
None
};
let hir_args = self.lower_args(call.args, &mut errs);
let mut obj = match self.lower_expr(*call.obj) { let mut obj = match self.lower_expr(*call.obj) {
Ok(obj) => obj, Ok(obj) => obj,
Err(es) => { Err(es) => {
@ -895,14 +900,59 @@ impl ASTLowerer {
Ok(hir::Call::new(class, Some(attr_name), args)) Ok(hir::Call::new(class, Some(attr_name), args))
} }
fn lower_non_default_param(
&mut self,
non_default: ast::NonDefaultParamSignature,
) -> LowerResult<hir::NonDefaultParamSignature> {
let t_spec_as_expr = non_default
.t_spec
.as_ref()
.map(|t_spec_op| self.fake_lower_expr(*t_spec_op.t_spec_as_expr.clone()))
.transpose()?;
// TODO: define here (not assign_params)
let vi = VarInfo::default();
let sig = hir::NonDefaultParamSignature::new(non_default, vi, t_spec_as_expr);
Ok(sig)
}
fn lower_type_spec_with_op(
&mut self,
type_spec_with_op: ast::TypeSpecWithOp,
) -> LowerResult<hir::TypeSpecWithOp> {
let expr = self.fake_lower_expr(*type_spec_with_op.t_spec_as_expr)?;
Ok(hir::TypeSpecWithOp::new(
type_spec_with_op.op,
type_spec_with_op.t_spec,
expr,
))
}
fn lower_params(&mut self, params: ast::Params) -> LowerResult<hir::Params> { fn lower_params(&mut self, params: ast::Params) -> LowerResult<hir::Params> {
log!(info "entered {}({})", fn_name!(), params); log!(info "entered {}({})", fn_name!(), params);
let mut errs = LowerErrors::empty(); let mut errs = LowerErrors::empty();
let mut hir_non_defaults = vec![];
for non_default in params.non_defaults.into_iter() {
match self.lower_non_default_param(non_default) {
Ok(sig) => hir_non_defaults.push(sig),
Err(es) => errs.extend(es),
}
}
let hir_var_params = match params.var_params {
Some(var_params) => match self.lower_non_default_param(*var_params) {
Ok(sig) => Some(Box::new(sig)),
Err(es) => {
errs.extend(es);
None
}
},
None => None,
};
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) {
Ok(default_val) => { Ok(default_val) => {
hir_defaults.push(hir::DefaultParamSignature::new(default.sig, default_val)); let sig = self.lower_non_default_param(default.sig)?;
hir_defaults.push(hir::DefaultParamSignature::new(sig, default_val));
} }
Err(es) => errs.extend(es), Err(es) => errs.extend(es),
} }
@ -911,8 +961,8 @@ impl ASTLowerer {
Err(errs) Err(errs)
} else { } else {
let hir_params = hir::Params::new( let hir_params = hir::Params::new(
params.non_defaults, hir_non_defaults,
params.var_params, hir_var_params,
hir_defaults, hir_defaults,
params.parens, params.parens,
); );
@ -949,13 +999,13 @@ impl ASTLowerer {
.context .context
.grow(&name, kind, Private, Some(tv_cache)); .grow(&name, kind, Private, Some(tv_cache));
} }
let params = self.lower_params(lambda.sig.params).map_err(|errs| { let mut params = self.lower_params(lambda.sig.params).map_err(|errs| {
if !in_statement { if !in_statement {
self.pop_append_errs(); self.pop_append_errs();
} }
errs errs
})?; })?;
if let Err(errs) = self.module.context.assign_params(&params, None) { if let Err(errs) = self.module.context.assign_params(&mut params, None) {
self.errs.extend(errs); self.errs.extend(errs);
} }
if let Err(errs) = self.module.context.preregister(&lambda.body) { if let Err(errs) = self.module.context.preregister(&lambda.body) {
@ -1011,12 +1061,12 @@ impl ASTLowerer {
} else { } else {
self.pop_append_errs(); self.pop_append_errs();
} }
let t = if is_procedural { let ty = if is_procedural {
proc(non_default_params, None, default_params, body.t()) proc(non_default_params, None, default_params, body.t())
} else { } else {
func(non_default_params, None, default_params, body.t()) func(non_default_params, None, default_params, body.t())
}; };
let t = if t.has_qvar() { t.quantify() } else { t }; let t = if ty.has_qvar() { ty.quantify() } else { ty };
Ok(hir::Lambda::new(id, params, lambda.op, body, t)) Ok(hir::Lambda::new(id, params, lambda.op, body, t))
} }
@ -1184,8 +1234,8 @@ impl ASTLowerer {
.unwrap_or(Type::Failure); .unwrap_or(Type::Failure);
match registered_t { match registered_t {
Type::Subr(subr_t) => { Type::Subr(subr_t) => {
let params = self.lower_params(sig.params.clone())?; let mut params = self.lower_params(sig.params.clone())?;
if let Err(errs) = self.module.context.assign_params(&params, Some(subr_t)) { if let Err(errs) = self.module.context.assign_params(&mut params, Some(subr_t)) {
self.errs.extend(errs); self.errs.extend(errs);
} }
if let Err(errs) = self.module.context.preregister(&body.block) { if let Err(errs) = self.module.context.preregister(&body.block) {
@ -1241,8 +1291,8 @@ impl ASTLowerer {
} }
} }
Type::Failure => { Type::Failure => {
let params = self.lower_params(sig.params)?; let mut params = self.lower_params(sig.params)?;
if let Err(errs) = self.module.context.assign_params(&params, None) { if let Err(errs) = self.module.context.assign_params(&mut params, None) {
self.errs.extend(errs); self.errs.extend(errs);
} }
if let Err(errs) = self.module.context.preregister(&body.block) { if let Err(errs) = self.module.context.preregister(&body.block) {
@ -1276,7 +1326,7 @@ impl ASTLowerer {
// TODO: check `tasc.op` // TODO: check `tasc.op`
ast::Expr::TypeAscription(tasc) => ( ast::Expr::TypeAscription(tasc) => (
self.module.context.instantiate_typespec( self.module.context.instantiate_typespec(
&tasc.t_spec, &tasc.t_spec.t_spec,
None, None,
&mut dummy_tv_cache, &mut dummy_tv_cache,
RegistrationMode::Normal, RegistrationMode::Normal,
@ -1891,7 +1941,7 @@ impl ASTLowerer {
let is_instance_ascription = tasc.is_instance_ascription(); let is_instance_ascription = tasc.is_instance_ascription();
let mut dummy_tv_cache = TyVarCache::new(self.module.context.level, &self.module.context); let mut dummy_tv_cache = TyVarCache::new(self.module.context.level, &self.module.context);
let spec_t = self.module.context.instantiate_typespec( let spec_t = self.module.context.instantiate_typespec(
&tasc.t_spec, &tasc.t_spec.t_spec,
None, None,
&mut dummy_tv_cache, &mut dummy_tv_cache,
RegistrationMode::Normal, RegistrationMode::Normal,
@ -1926,7 +1976,8 @@ impl ASTLowerer {
))); )));
} }
} }
Ok(expr.type_asc(tasc.t_spec)) let t_spec = self.lower_type_spec_with_op(tasc.t_spec)?;
Ok(expr.type_asc(t_spec))
} }
fn lower_decl(&mut self, tasc: ast::TypeAscription) -> LowerResult<hir::TypeAscription> { fn lower_decl(&mut self, tasc: ast::TypeAscription) -> LowerResult<hir::TypeAscription> {
@ -1934,7 +1985,7 @@ impl ASTLowerer {
let is_instance_ascription = tasc.is_instance_ascription(); let is_instance_ascription = tasc.is_instance_ascription();
let mut dummy_tv_cache = TyVarCache::new(self.module.context.level, &self.module.context); let mut dummy_tv_cache = TyVarCache::new(self.module.context.level, &self.module.context);
let spec_t = self.module.context.instantiate_typespec( let spec_t = self.module.context.instantiate_typespec(
&tasc.t_spec, &tasc.t_spec.t_spec,
None, None,
&mut dummy_tv_cache, &mut dummy_tv_cache,
RegistrationMode::Normal, RegistrationMode::Normal,
@ -2005,7 +2056,8 @@ impl ASTLowerer {
.map(|ctx| ctx.name.clone()); .map(|ctx| ctx.name.clone());
let ident = hir::Identifier::new(ident.dot, ident.name, qual_name, ident_vi); let ident = hir::Identifier::new(ident.dot, ident.name, qual_name, ident_vi);
let expr = hir::Expr::Accessor(hir::Accessor::Ident(ident)); let expr = hir::Expr::Accessor(hir::Accessor::Ident(ident));
Ok(expr.type_asc(tasc.t_spec)) let t_spec = self.lower_type_spec_with_op(tasc.t_spec)?;
Ok(expr.type_asc(t_spec))
} }
// 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)

View file

@ -112,17 +112,17 @@ impl OwnershipChecker {
if let Signature::Subr(subr) = &def.sig { if let Signature::Subr(subr) = &def.sig {
let (nd_params, var_params, d_params, _) = subr.params.ref_deconstruct(); let (nd_params, var_params, d_params, _) = subr.params.ref_deconstruct();
for param in nd_params { for param in nd_params {
if let ParamPattern::VarName(name) = &param.pat { if let ParamPattern::VarName(name) = &param.raw.pat {
self.define_param(name); self.define_param(name);
} }
} }
if let Some(var) = var_params { if let Some(var) = var_params {
if let ParamPattern::VarName(name) = &var.pat { if let ParamPattern::VarName(name) = &var.raw.pat {
self.define_param(name); self.define_param(name);
} }
} }
for param in d_params { for param in d_params {
if let ParamPattern::VarName(name) = &param.sig.pat { if let ParamPattern::VarName(name) = &param.sig.raw.pat {
self.define_param(name); self.define_param(name);
} }
} }

View file

@ -616,8 +616,8 @@ impl ScriptGenerator {
let mut code = "for ".to_string(); let mut code = "for ".to_string();
let iter = call.args.remove(0); let iter = call.args.remove(0);
let Expr::Lambda(block) = call.args.remove(0) else { todo!() }; let Expr::Lambda(block) = call.args.remove(0) else { todo!() };
let sig = block.params.non_defaults.get(0).unwrap(); let non_default = block.params.non_defaults.get(0).unwrap();
let ParamPattern::VarName(param) = &sig.pat else { todo!() }; let ParamPattern::VarName(param) = &non_default.raw.pat else { todo!() };
code += &format!("{}__ ", &param.token().content); code += &format!("{}__ ", &param.token().content);
code += &format!("in {}:\n", self.transpile_expr(iter)); code += &format!("in {}:\n", self.transpile_expr(iter));
code += &self.transpile_block(block.body, Discard); code += &self.transpile_block(block.body, Discard);
@ -703,14 +703,14 @@ impl ScriptGenerator {
self.level += 1; self.level += 1;
code += &" ".repeat(self.level); code += &" ".repeat(self.level);
let target = arm.params.non_defaults.get(0).unwrap(); let target = arm.params.non_defaults.get(0).unwrap();
match &target.pat { match &target.raw.pat {
ParamPattern::VarName(param) => { ParamPattern::VarName(param) => {
code += &format!("case {}__:\n", &param.token().content); code += &format!("case {}__:\n", &param.token().content);
code += &self.transpile_block(arm.body, StoreTmp(tmp.clone())); code += &self.transpile_block(arm.body, StoreTmp(tmp.clone()));
self.level -= 1; self.level -= 1;
} }
ParamPattern::Discard(_) => { ParamPattern::Discard(_) => {
match target.t_spec.as_ref().map(|t| &t.t_spec) { match target.raw.t_spec.as_ref().map(|t| &t.t_spec) {
Some(TypeSpec::Enum(enum_t)) => { Some(TypeSpec::Enum(enum_t)) => {
let values = ValueObj::vec_from_const_args(enum_t.clone()); let values = ValueObj::vec_from_const_args(enum_t.clone());
if values.len() == 1 { if values.len() == 1 {
@ -799,7 +799,7 @@ impl ScriptGenerator {
fn transpile_params(&mut self, params: Params) -> String { fn transpile_params(&mut self, params: Params) -> String {
let mut code = String::new(); let mut code = String::new();
for non_default in params.non_defaults { for non_default in params.non_defaults {
match non_default.pat { match non_default.raw.pat {
ParamPattern::VarName(param) => { ParamPattern::VarName(param) => {
code += &format!("{}__,", param.into_token().content); code += &format!("{}__,", param.into_token().content);
} }
@ -811,7 +811,7 @@ impl ScriptGenerator {
} }
} }
for default in params.defaults { for default in params.defaults {
let ParamPattern::VarName(param) = default.sig.pat else { todo!() }; let ParamPattern::VarName(param) = default.sig.raw.pat else { todo!() };
code += &format!( code += &format!(
"{}__ = {},", "{}__ = {},",
param.into_token().content, param.into_token().content,

View file

@ -218,4 +218,12 @@ impl VarInfo {
_ => false, _ => false,
} }
} }
pub fn parameter(t: Type, def_loc: AbsLocation) -> Self {
let kind = VarKind::Parameter {
def_id: DefId(0),
default: DefaultInfo::NonDefault,
};
Self::new(t, Immutable, Private, kind, None, None, None, def_loc)
}
} }

View file

@ -1210,12 +1210,15 @@ impl Locational for Block {
impl_stream!(Block, Expr); impl_stream!(Block, Expr);
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Dummy(Vec<Expr>); pub struct Dummy {
pub loc: Option<Location>,
exprs: Vec<Expr>,
}
impl NestedDisplay for Dummy { impl NestedDisplay for Dummy {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result { fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
writeln!(f, "Dummy:")?; writeln!(f, "Dummy:")?;
fmt_lines(self.0.iter(), f, level) fmt_lines(self.exprs.iter(), f, level)
} }
} }
@ -1223,15 +1226,23 @@ impl_display_from_nested!(Dummy);
impl Locational for Dummy { impl Locational for Dummy {
fn loc(&self) -> Location { fn loc(&self) -> Location {
if self.0.is_empty() { if self.loc.is_some() {
self.loc.unwrap_or(Location::Unknown)
} else if self.exprs.is_empty() {
Location::Unknown Location::Unknown
} else { } else {
Location::concat(self.0.first().unwrap(), self.0.last().unwrap()) Location::concat(self.exprs.first().unwrap(), self.exprs.last().unwrap())
} }
} }
} }
impl_stream!(Dummy, Expr); impl_stream!(Dummy, Expr, exprs);
impl Dummy {
pub const fn new(loc: Option<Location>, exprs: Vec<Expr>) -> Self {
Self { loc, exprs }
}
}
pub type ConstIdentifier = Identifier; pub type ConstIdentifier = Identifier;
@ -2218,6 +2229,7 @@ impl TypeSpec {
pub struct TypeSpecWithOp { pub struct TypeSpecWithOp {
pub op: Token, pub op: Token,
pub t_spec: TypeSpec, pub t_spec: TypeSpec,
pub t_spec_as_expr: Box<Expr>,
} }
impl NestedDisplay for TypeSpecWithOp { impl NestedDisplay for TypeSpecWithOp {
@ -2230,8 +2242,12 @@ impl_display_from_nested!(TypeSpecWithOp);
impl_locational!(TypeSpecWithOp, lossy op, t_spec); impl_locational!(TypeSpecWithOp, lossy op, t_spec);
impl TypeSpecWithOp { impl TypeSpecWithOp {
pub const fn new(op: Token, t_spec: TypeSpec) -> Self { pub fn new(op: Token, t_spec: TypeSpec, t_spec_as_expr: Expr) -> Self {
Self { op, t_spec } Self {
op,
t_spec,
t_spec_as_expr: Box::new(t_spec_as_expr),
}
} }
} }
@ -3447,13 +3463,12 @@ impl Signature {
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct TypeAscription { pub struct TypeAscription {
pub expr: Box<Expr>, pub expr: Box<Expr>,
pub op: Token, pub t_spec: TypeSpecWithOp,
pub t_spec: TypeSpec,
} }
impl NestedDisplay for TypeAscription { impl NestedDisplay for TypeAscription {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result { fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
writeln!(f, "{}{} {}", self.expr, self.op.content, self.t_spec) writeln!(f, "{}{}", self.expr, self.t_spec)
} }
} }
@ -3461,20 +3476,19 @@ impl_display_from_nested!(TypeAscription);
impl_locational!(TypeAscription, expr, t_spec); impl_locational!(TypeAscription, expr, t_spec);
impl TypeAscription { impl TypeAscription {
pub fn new(expr: Expr, op: Token, t_spec: TypeSpec) -> Self { pub fn new(expr: Expr, t_spec: TypeSpecWithOp) -> Self {
Self { Self {
expr: Box::new(expr), expr: Box::new(expr),
op,
t_spec, t_spec,
} }
} }
pub fn is_instance_ascription(&self) -> bool { pub fn is_instance_ascription(&self) -> bool {
self.op.is(TokenKind::Colon) self.t_spec.op.is(TokenKind::Colon)
} }
pub fn is_subtype_ascription(&self) -> bool { pub fn is_subtype_ascription(&self) -> bool {
self.op.is(TokenKind::SubtypeOf) self.t_spec.op.is(TokenKind::SubtypeOf)
} }
} }
@ -3826,12 +3840,16 @@ impl Expr {
Self::Call(self.call(args)) Self::Call(self.call(args))
} }
pub fn type_asc(self, op: Token, t_spec: TypeSpec) -> TypeAscription { pub fn type_asc(self, t_spec: TypeSpecWithOp) -> TypeAscription {
TypeAscription::new(self, op, t_spec) TypeAscription::new(self, t_spec)
} }
pub fn type_asc_expr(self, op: Token, t_spec: TypeSpec) -> Self { pub fn type_asc_expr(self, t_spec: TypeSpecWithOp) -> Self {
Self::TypeAscription(self.type_asc(op, t_spec)) Self::TypeAscription(self.type_asc(t_spec))
}
pub fn dummy(loc: Location) -> Self {
Self::Dummy(Dummy::new(Some(loc), vec![]))
} }
} }

View file

@ -236,7 +236,7 @@ impl Parser {
.map_err(|_| self.stack_dec(fn_name!()))?; .map_err(|_| self.stack_dec(fn_name!()))?;
let sig = match sig { let sig = match sig {
Signature::Var(var) => { Signature::Var(var) => {
let var = VarSignature::new(var.pat, Some(tasc.t_spec)); let var = VarSignature::new(var.pat, Some(tasc.t_spec.t_spec));
Signature::Var(var) Signature::Var(var)
} }
Signature::Subr(subr) => { Signature::Subr(subr) => {
@ -245,7 +245,7 @@ impl Parser {
subr.ident, subr.ident,
subr.bounds, subr.bounds,
subr.params, subr.params,
Some(tasc.t_spec), Some(tasc.t_spec.t_spec),
); );
Signature::Subr(subr) Signature::Subr(subr)
} }
@ -334,8 +334,7 @@ impl Parser {
.unwrap_or_else(|| todo!()) .unwrap_or_else(|| todo!())
.pat; .pat;
let lhs = option_enum_unwrap!(lhs, VarPattern::Ident).unwrap_or_else(|| todo!()); let lhs = option_enum_unwrap!(lhs, VarPattern::Ident).unwrap_or_else(|| todo!());
let spec_with_op = TypeSpecWithOp::new(tasc.op, tasc.t_spec); let bound = TypeBoundSpec::non_default(lhs.name.into_token(), tasc.t_spec);
let bound = TypeBoundSpec::non_default(lhs.name.into_token(), spec_with_op);
Ok(bound) Ok(bound)
} }
other => { other => {
@ -598,8 +597,7 @@ impl Parser {
let param = self let param = self
.convert_rhs_to_param(*tasc.expr, allow_self) .convert_rhs_to_param(*tasc.expr, allow_self)
.map_err(|_| self.stack_dec(fn_name!()))?; .map_err(|_| self.stack_dec(fn_name!()))?;
let t_spec = TypeSpecWithOp::new(tasc.op, tasc.t_spec); let param = NonDefaultParamSignature::new(param.pat, Some(tasc.t_spec));
let param = NonDefaultParamSignature::new(param.pat, Some(t_spec));
debug_exit_info!(self); debug_exit_info!(self);
Ok(param) Ok(param)
} }

View file

@ -270,7 +270,10 @@ impl Desugarer {
} }
Expr::TypeAscription(tasc) => { Expr::TypeAscription(tasc) => {
let expr = desugar(*tasc.expr); let expr = desugar(*tasc.expr);
expr.type_asc_expr(tasc.op, tasc.t_spec) let t_spec_as_expr = desugar(*tasc.t_spec.t_spec_as_expr);
let t_spec =
TypeSpecWithOp::new(tasc.t_spec.op, tasc.t_spec.t_spec, t_spec_as_expr);
expr.type_asc_expr(t_spec)
} }
Expr::Methods(method_defs) => { Expr::Methods(method_defs) => {
let mut new_attrs = vec![]; let mut new_attrs = vec![];
@ -286,7 +289,13 @@ impl Desugarer {
} }
ClassAttr::Decl(decl) => { ClassAttr::Decl(decl) => {
let expr = desugar(*decl.expr); let expr = desugar(*decl.expr);
new_attrs.push(ClassAttr::Decl(expr.type_asc(decl.op, decl.t_spec))); let t_spec_as_expr = desugar(*decl.t_spec.t_spec_as_expr);
let t_spec = TypeSpecWithOp::new(
decl.t_spec.op,
decl.t_spec.t_spec,
t_spec_as_expr,
);
new_attrs.push(ClassAttr::Decl(expr.type_asc(t_spec)));
} }
ClassAttr::Doc(doc) => { ClassAttr::Doc(doc) => {
new_attrs.push(ClassAttr::Doc(doc)); new_attrs.push(ClassAttr::Doc(doc));
@ -298,11 +307,12 @@ impl Desugarer {
} }
Expr::Accessor(acc) => Expr::Accessor(Self::perform_desugar_acc(desugar, acc)), Expr::Accessor(acc) => Expr::Accessor(Self::perform_desugar_acc(desugar, acc)),
Expr::Dummy(exprs) => { Expr::Dummy(exprs) => {
let loc = exprs.loc;
let mut chunks = vec![]; let mut chunks = vec![];
for chunk in exprs.into_iter() { for chunk in exprs.into_iter() {
chunks.push(desugar(chunk)); chunks.push(desugar(chunk));
} }
Expr::Dummy(Dummy::new(chunks)) Expr::Dummy(Dummy::new(loc, chunks))
} }
} }
} }
@ -773,7 +783,22 @@ impl Desugarer {
l.ln_begin().unwrap(), l.ln_begin().unwrap(),
l.col_begin().unwrap(), l.col_begin().unwrap(),
)); ));
param.t_spec = Some(TypeSpecWithOp::new(COLON, TypeSpec::enum_t_spec(vec![lit]))); let l_brace = Token {
content: "{".into(),
kind: TokenKind::LBrace,
..lit.token
};
let r_brace = Token {
content: "}".into(),
kind: TokenKind::RBrace,
..lit.token
};
let t_spec = TypeSpec::enum_t_spec(vec![lit.clone()]);
let args = Args::pos_only(vec![PosArg::new(Expr::Literal(lit))], None);
let set = astSet::Normal(NormalSet::new(l_brace, r_brace, args));
let t_spec_as_expr = Expr::Set(set);
let t_spec = TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr);
param.t_spec = Some(t_spec);
} }
ParamPattern::Tuple(tup) => { ParamPattern::Tuple(tup) => {
let (buf_name, buf_param) = self.gen_buf_nd_param(line); let (buf_name, buf_param) = self.gen_buf_nd_param(line);
@ -797,7 +822,8 @@ impl Desugarer {
} }
if param.t_spec.is_none() { if param.t_spec.is_none() {
let t_spec = TypeSpec::Tuple(TupleTypeSpec::new(tup.elems.parens.clone(), tys)); let t_spec = TypeSpec::Tuple(TupleTypeSpec::new(tup.elems.parens.clone(), tys));
param.t_spec = Some(TypeSpecWithOp::new(COLON, t_spec)); let t_spec_as_expr = Expr::dummy(t_spec.loc());
param.t_spec = Some(TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr));
} }
param.pat = buf_param; param.pat = buf_param;
} }
@ -817,9 +843,11 @@ impl Desugarer {
let len = Literal::new(Token::new(TokenKind::NatLit, len.to_string(), line, 0)); let len = Literal::new(Token::new(TokenKind::NatLit, len.to_string(), line, 0));
let infer = Token::new(TokenKind::Try, "?", line, 0); let infer = Token::new(TokenKind::Try, "?", line, 0);
let t_spec = ArrayTypeSpec::new(TypeSpec::Infer(infer), ConstExpr::Lit(len)); let t_spec = ArrayTypeSpec::new(TypeSpec::Infer(infer), ConstExpr::Lit(len));
let t_spec_as_expr = Expr::dummy(t_spec.loc());
param.t_spec = Some(TypeSpecWithOp::new( param.t_spec = Some(TypeSpecWithOp::new(
Token::dummy(TokenKind::Colon, ":"), Token::dummy(TokenKind::Colon, ":"),
TypeSpec::Array(t_spec), TypeSpec::Array(t_spec),
t_spec_as_expr,
)); ));
} }
param.pat = buf_param; param.pat = buf_param;
@ -848,7 +876,9 @@ impl Desugarer {
.clone(), .clone(),
)); ));
} }
param.t_spec = Some(TypeSpecWithOp::new(COLON, TypeSpec::Record(tys))); let t_spec = TypeSpec::Record(tys);
let t_spec_as_expr = Expr::dummy(t_spec.loc());
param.t_spec = Some(TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr));
} }
param.pat = buf_param; param.pat = buf_param;
} }
@ -937,7 +967,8 @@ impl Desugarer {
} }
if sig.t_spec.is_none() { if sig.t_spec.is_none() {
let t_spec = TypeSpec::Tuple(TupleTypeSpec::new(tup.elems.parens.clone(), tys)); let t_spec = TypeSpec::Tuple(TupleTypeSpec::new(tup.elems.parens.clone(), tys));
sig.t_spec = Some(TypeSpecWithOp::new(COLON, t_spec)); let t_spec_as_expr = Expr::dummy(t_spec.loc());
sig.t_spec = Some(TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr));
} }
sig.pat = buf_sig; sig.pat = buf_sig;
insertion_idx insertion_idx
@ -968,8 +999,31 @@ impl Desugarer {
let len = arr.elems.non_defaults.len(); let len = arr.elems.non_defaults.len();
let len = Literal::new(Token::new(TokenKind::NatLit, len.to_string(), line, 0)); let len = Literal::new(Token::new(TokenKind::NatLit, len.to_string(), line, 0));
let infer = Token::new(TokenKind::Try, "?", line, 0); let infer = Token::new(TokenKind::Try, "?", line, 0);
let t_spec = ArrayTypeSpec::new(TypeSpec::Infer(infer), ConstExpr::Lit(len)); let t_spec =
sig.t_spec = Some(TypeSpecWithOp::new(COLON, TypeSpec::Array(t_spec))); ArrayTypeSpec::new(TypeSpec::Infer(infer), ConstExpr::Lit(len.clone()));
let l_sqbr = Token {
content: "[".into(),
kind: TokenKind::LSqBr,
..len.token
};
let r_sqbr = Token {
content: "]".into(),
kind: TokenKind::RSqBr,
..len.token
};
let elem = Expr::local("Obj", l_sqbr.lineno, l_sqbr.col_begin);
let array = Array::WithLength(ArrayWithLength::new(
l_sqbr,
r_sqbr,
PosArg::new(elem),
Expr::Literal(len),
));
let t_spec_as_expr = Expr::Array(array);
sig.t_spec = Some(TypeSpecWithOp::new(
COLON,
TypeSpec::Array(t_spec),
t_spec_as_expr,
));
} }
sig.pat = buf_sig; sig.pat = buf_sig;
insertion_idx insertion_idx
@ -1007,7 +1061,9 @@ impl Desugarer {
)); ));
} }
if sig.t_spec.is_none() { if sig.t_spec.is_none() {
sig.t_spec = Some(TypeSpecWithOp::new(COLON, TypeSpec::Record(tys))); let t_spec = TypeSpec::Record(tys);
let t_spec_as_expr = Expr::dummy(t_spec.loc());
sig.t_spec = Some(TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr));
} }
sig.pat = buf_sig; sig.pat = buf_sig;
insertion_idx insertion_idx
@ -1047,7 +1103,21 @@ impl Desugarer {
l.ln_begin().unwrap(), l.ln_begin().unwrap(),
l.col_begin().unwrap(), l.col_begin().unwrap(),
)); ));
sig.t_spec = Some(TypeSpecWithOp::new(COLON, TypeSpec::enum_t_spec(vec![lit]))); let l_brace = Token {
content: "{".into(),
kind: TokenKind::LBrace,
..lit.token
};
let r_brace = Token {
content: "}".into(),
kind: TokenKind::RBrace,
..lit.token
};
let t_spec = TypeSpec::enum_t_spec(vec![lit.clone()]);
let args = Args::pos_only(vec![PosArg::new(Expr::Literal(lit))], None);
let set = astSet::Normal(NormalSet::new(l_brace, r_brace, args));
let t_spec_as_expr = Expr::Set(set);
sig.t_spec = Some(TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr));
insertion_idx insertion_idx
} }
_ => insertion_idx, _ => insertion_idx,

View file

@ -716,10 +716,10 @@ impl Parser {
Args::new(vec![], Some(pos_args), vec![], None) Args::new(vec![], Some(pos_args), vec![], None)
} }
PosOrKwArg::Pos(PosArg { PosOrKwArg::Pos(PosArg {
expr: Expr::TypeAscription(TypeAscription { expr, op, t_spec }), expr: Expr::TypeAscription(TypeAscription { expr, t_spec }),
}) if matches!(expr.as_ref(), Expr::UnaryOp(unary) if unary.op.is(PreStar)) => { }) if matches!(expr.as_ref(), Expr::UnaryOp(unary) if unary.op.is(PreStar)) => {
let Expr::UnaryOp(unary) = *expr else { unreachable!() }; let Expr::UnaryOp(unary) = *expr else { unreachable!() };
let var_args = PosArg::new(unary.deconstruct().1.type_asc_expr(op, t_spec)); let var_args = PosArg::new(unary.deconstruct().1.type_asc_expr(t_spec));
Args::new(vec![], Some(var_args), vec![], None) Args::new(vec![], Some(var_args), vec![], None)
} }
PosOrKwArg::Pos(arg) => Args::pos_only(vec![arg], None), PosOrKwArg::Pos(arg) => Args::pos_only(vec![arg], None),
@ -786,12 +786,12 @@ impl Parser {
args.set_var_args(PosArg::new(unary.deconstruct().1)); args.set_var_args(PosArg::new(unary.deconstruct().1));
} }
PosOrKwArg::Pos(PosArg { PosOrKwArg::Pos(PosArg {
expr: Expr::TypeAscription(TypeAscription { expr, op, t_spec }), expr: Expr::TypeAscription(TypeAscription { expr, t_spec }),
}) if matches!(expr.as_ref(), Expr::UnaryOp(unary) if unary.op.is(PreStar)) => }) if matches!(expr.as_ref(), Expr::UnaryOp(unary) if unary.op.is(PreStar)) =>
{ {
let Expr::UnaryOp(unary) = *expr else { unreachable!() }; let Expr::UnaryOp(unary) = *expr else { unreachable!() };
args.set_var_args(PosArg::new( args.set_var_args(PosArg::new(
unary.deconstruct().1.type_asc_expr(op, t_spec), unary.deconstruct().1.type_asc_expr(t_spec),
)); ));
} }
PosOrKwArg::Pos(arg) => { PosOrKwArg::Pos(arg) => {
@ -908,8 +908,7 @@ impl Parser {
Expr::Accessor(Accessor::Ident(n)) => (n.name.into_token(), None), Expr::Accessor(Accessor::Ident(n)) => (n.name.into_token(), None),
Expr::TypeAscription(tasc) => { Expr::TypeAscription(tasc) => {
if let Expr::Accessor(Accessor::Ident(n)) = *tasc.expr { if let Expr::Accessor(Accessor::Ident(n)) = *tasc.expr {
let t_spec = TypeSpecWithOp::new(tasc.op, tasc.t_spec); (n.name.into_token(), Some(tasc.t_spec))
(n.name.into_token(), Some(t_spec))
} else { } else {
let err = ParseError::simple_syntax_error(0, tasc.loc()); let err = ParseError::simple_syntax_error(0, tasc.loc());
self.errs.push(err); self.errs.push(err);
@ -1165,11 +1164,13 @@ impl Parser {
} }
let op = self.lpop(); let op = self.lpop();
let lhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_))); let lhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_)));
let t_spec = self let t_spec_as_expr = self
.try_reduce_expr(false, false, false, false) .try_reduce_expr(false, false, false, false)
.map_err(|_| self.stack_dec(fn_name!()))?; .map_err(|_| self.stack_dec(fn_name!()))?;
let t_spec = Self::expr_to_type_spec(t_spec).map_err(|e| self.errs.push(e))?; let t_spec = Self::expr_to_type_spec(t_spec_as_expr.clone())
let expr = lhs.type_asc_expr(op, t_spec); .map_err(|e| self.errs.push(e))?;
let t_spec_op = TypeSpecWithOp::new(op, t_spec, t_spec_as_expr);
let expr = lhs.type_asc_expr(t_spec_op);
stack.push(ExprOrOp::Expr(expr)); stack.push(ExprOrOp::Expr(expr));
} }
Some(op) if op.category_is(TC::BinOp) => { Some(op) if op.category_is(TC::BinOp) => {
@ -1434,11 +1435,13 @@ impl Parser {
} }
let op = self.lpop(); let op = self.lpop();
let lhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_))); let lhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_)));
let t_spec = self let t_spec_as_expr = self
.try_reduce_expr(false, in_type_args, in_brace, false) .try_reduce_expr(false, in_type_args, in_brace, false)
.map_err(|_| self.stack_dec(fn_name!()))?; .map_err(|_| self.stack_dec(fn_name!()))?;
let t_spec = Self::expr_to_type_spec(t_spec).map_err(|e| self.errs.push(e))?; let t_spec = Self::expr_to_type_spec(t_spec_as_expr.clone())
let expr = lhs.type_asc_expr(op, t_spec); .map_err(|e| self.errs.push(e))?;
let t_spec_op = TypeSpecWithOp::new(op, t_spec, t_spec_as_expr);
let expr = lhs.type_asc_expr(t_spec_op);
stack.push(ExprOrOp::Expr(expr)); stack.push(ExprOrOp::Expr(expr));
} }
Some(op) if op.category_is(TC::BinOp) => { Some(op) if op.category_is(TC::BinOp) => {
@ -1596,10 +1599,7 @@ impl Parser {
Expr::Accessor(Accessor::Ident(ident)) => (ident.name.into_token(), None), Expr::Accessor(Accessor::Ident(ident)) => (ident.name.into_token(), None),
Expr::TypeAscription(tasc) => { Expr::TypeAscription(tasc) => {
if let Expr::Accessor(Accessor::Ident(ident)) = *tasc.expr { if let Expr::Accessor(Accessor::Ident(ident)) = *tasc.expr {
( (ident.name.into_token(), Some(tasc.t_spec))
ident.name.into_token(),
Some(TypeSpecWithOp::new(tasc.op, tasc.t_spec)),
)
} else { } else {
let err = ParseError::simple_syntax_error(line!() as usize, tasc.loc()); let err = ParseError::simple_syntax_error(line!() as usize, tasc.loc());
self.errs.push(err); self.errs.push(err);
@ -2367,11 +2367,11 @@ impl Parser {
Args::new(vec![], var_args, vec![], None) Args::new(vec![], var_args, vec![], None)
} }
PosOrKwArg::Pos(PosArg { PosOrKwArg::Pos(PosArg {
expr: Expr::TypeAscription(TypeAscription { expr, op, t_spec }), expr: Expr::TypeAscription(TypeAscription { expr, t_spec }),
}) if matches!(expr.as_ref(), Expr::UnaryOp(unary) if unary.op.is(PreStar)) => { }) if matches!(expr.as_ref(), Expr::UnaryOp(unary) if unary.op.is(PreStar)) => {
let Expr::UnaryOp(unary) = *expr else { unreachable!() }; let Expr::UnaryOp(unary) = *expr else { unreachable!() };
let expr = unary.deconstruct().1; let expr = unary.deconstruct().1;
let var_args = Some(PosArg::new(expr.type_asc_expr(op, t_spec))); let var_args = Some(PosArg::new(expr.type_asc_expr(t_spec)));
Args::new(vec![], var_args, vec![], None) Args::new(vec![], var_args, vec![], None)
} }
PosOrKwArg::Pos(pos) => Args::pos_only(vec![pos], None), PosOrKwArg::Pos(pos) => Args::pos_only(vec![pos], None),
@ -2402,11 +2402,11 @@ impl Parser {
Expr::UnaryOp(unary) if unary.op.is(PreStar) => { Expr::UnaryOp(unary) if unary.op.is(PreStar) => {
args.set_var_args(PosArg::new(unary.deconstruct().1)); args.set_var_args(PosArg::new(unary.deconstruct().1));
} }
Expr::TypeAscription(TypeAscription { expr, op, t_spec }) if matches!(expr.as_ref(), Expr::UnaryOp(unary) if unary.op.is(PreStar)) => Expr::TypeAscription(TypeAscription { expr, t_spec }) if matches!(expr.as_ref(), Expr::UnaryOp(unary) if unary.op.is(PreStar)) =>
{ {
let Expr::UnaryOp(unary) = *expr else { unreachable!() }; let Expr::UnaryOp(unary) = *expr else { unreachable!() };
let expr = unary.deconstruct().1; let expr = unary.deconstruct().1;
args.set_var_args(PosArg::new(expr.type_asc_expr(op, t_spec))); args.set_var_args(PosArg::new(expr.type_asc_expr(t_spec)));
} }
Expr::Tuple(Tuple::Normal(tup)) if tup.elems.paren.is_none() => { Expr::Tuple(Tuple::Normal(tup)) if tup.elems.paren.is_none() => {
args.extend_pos(tup.elems.into_iters().0); args.extend_pos(tup.elems.into_iters().0);

View file

@ -3,7 +3,7 @@ use erg_common::traits::{Locational, Stream};
use crate::ast::*; use crate::ast::*;
use crate::error::ParseError; use crate::error::ParseError;
use crate::token::{Token, TokenKind}; use crate::token::TokenKind;
use crate::Parser; use crate::Parser;
// The APIs defined below are also used by `ASTLowerer` to interpret expressions as types. // The APIs defined below are also used by `ASTLowerer` to interpret expressions as types.
@ -412,77 +412,4 @@ impl Parser {
} }
} }
} }
fn simple_type_spec_to_ident(simple: SimpleTypeSpec) -> Result<Identifier, ParseError> {
Ok(simple.ident)
}
fn simple_type_spec_to_call(simple: SimpleTypeSpec) -> Result<Call, ParseError> {
let (pos_args_, var_args_, kw_args_, paren) = simple.args.deconstruct();
let pos_args = pos_args_
.into_iter()
.map(|arg| PosArg::new(arg.expr.downcast()))
.collect::<Vec<_>>();
let var_args = var_args_.map(|arg| PosArg::new(arg.expr.downcast()));
let kw_args = kw_args_
.into_iter()
.map(|arg| KwArg::new(arg.keyword, None, arg.expr.downcast()))
.collect::<Vec<_>>();
let args = Args::new(pos_args, var_args, kw_args, paren);
let call = Call::new(simple.ident.into(), None, args);
Ok(call)
}
fn predecl_type_spec_to_expr(predecl: PreDeclTypeSpec) -> Result<Expr, ParseError> {
match predecl {
PreDeclTypeSpec::Simple(simple) if simple.args.is_empty() => {
Ok(Self::simple_type_spec_to_ident(simple)?.into())
}
PreDeclTypeSpec::Simple(simple) => Ok(Self::simple_type_spec_to_call(simple)?.into()),
PreDeclTypeSpec::Attr { namespace, t } => {
let ident = Self::simple_type_spec_to_ident(t)?;
Ok(namespace.attr_expr(ident))
}
other => Err(ParseError::feature_error(
line!() as usize,
other.loc(),
"compound predecl type spec to call conversion",
)),
}
}
pub fn type_spec_to_expr(t_spec: TypeSpec) -> Result<Expr, ParseError> {
match t_spec {
TypeSpec::PreDeclTy(predecl) => Self::predecl_type_spec_to_expr(predecl),
TypeSpec::Or(lhs, rhs) => {
let lhs = Self::type_spec_to_expr(*lhs)?;
let rhs = Self::type_spec_to_expr(*rhs)?;
let op = Token::new(
TokenKind::OrOp,
"or",
lhs.ln_begin().unwrap(),
lhs.col_end().unwrap(),
);
let bin = BinOp::new(op, lhs, rhs);
Ok(Expr::BinOp(bin))
}
TypeSpec::And(lhs, rhs) => {
let lhs = Self::type_spec_to_expr(*lhs)?;
let rhs = Self::type_spec_to_expr(*rhs)?;
let op = Token::new(
TokenKind::AndOp,
"and",
lhs.ln_begin().unwrap(),
lhs.col_end().unwrap(),
);
let bin = BinOp::new(op, lhs, rhs);
Ok(Expr::BinOp(bin))
}
other => Err(ParseError::feature_error(
line!() as usize,
other.loc(),
"compound type spec to expr conversion",
)),
}
}
} }