feat: add ConstTypeAsc

This commit is contained in:
Shunsuke Shibayama 2023-02-23 20:11:50 +09:00
parent 1dbfb4b834
commit aaa259d6c0
4 changed files with 81 additions and 7 deletions

View file

@ -892,6 +892,28 @@ impl Context {
let val = self.instantiate_const_expr(&unary.expr, erased_idx, tmp_tv_cache)?;
Ok(TyParam::unary(op, val))
}
ast::ConstExpr::TypeAsc(tasc) => {
let tp = self.instantiate_const_expr(&tasc.expr, erased_idx, tmp_tv_cache)?;
let spec_t = self.instantiate_typespec(
&tasc.t_spec.t_spec,
None,
tmp_tv_cache,
RegistrationMode::Normal,
false,
)?;
if self.subtype_of(&self.get_tp_t(&tp)?, &spec_t, true) {
Ok(tp)
} else {
Err(TyCheckErrors::from(TyCheckError::subtyping_error(
self.cfg.input.clone(),
line!() as usize,
&self.get_tp_t(&tp)?,
&spec_t,
tasc.loc(),
self.caused_by(),
)))
}
}
other => type_feature_error!(
self,
other.loc(),

View file

@ -388,6 +388,22 @@ impl ASTLowerer {
Ok(hir::Dummy::new(dummy_))
}
fn fake_lower_type_asc(&self, tasc: ast::TypeAscription) -> LowerResult<hir::TypeAscription> {
let expr = self.fake_lower_expr(*tasc.expr)?;
let t_spec_as_expr = self.fake_lower_expr(*tasc.t_spec.t_spec_as_expr)?;
let mut dummy_tv_cache = TyVarCache::new(self.module.context.level, &self.module.context);
let spec_t = self.module.context.instantiate_typespec(
&tasc.t_spec.t_spec,
None,
&mut dummy_tv_cache,
RegistrationMode::Normal,
false,
)?;
let spec =
hir::TypeSpecWithOp::new(tasc.t_spec.op, tasc.t_spec.t_spec, t_spec_as_expr, spec_t);
Ok(hir::TypeAscription::new(expr, spec))
}
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)?)),
@ -401,6 +417,9 @@ impl ASTLowerer {
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)?)),
ast::Expr::TypeAscription(tasc) => {
Ok(hir::Expr::TypeAsc(self.fake_lower_type_asc(tasc)?))
}
other => Err(LowerErrors::from(LowerError::declare_error(
self.cfg().input.clone(),
line!() as usize,

View file

@ -1773,6 +1773,38 @@ impl ConstApp {
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ConstTypeAsc {
pub expr: Box<ConstExpr>,
pub t_spec: Box<TypeSpecWithOp>,
}
impl NestedDisplay for ConstTypeAsc {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
writeln!(f, "{}{}", self.expr, self.t_spec)
}
}
impl_display_from_nested!(ConstTypeAsc);
impl_locational!(ConstTypeAsc, expr, t_spec);
impl ConstTypeAsc {
pub fn new(expr: ConstExpr, t_spec: TypeSpecWithOp) -> Self {
Self {
expr: Box::new(expr),
t_spec: Box::new(t_spec),
}
}
pub fn is_instance_ascription(&self) -> bool {
self.t_spec.op.is(TokenKind::Colon)
}
pub fn is_subtype_ascription(&self) -> bool {
self.t_spec.op.is(TokenKind::SubtypeOf)
}
}
/// valid expression for an argument of polymorphic types
/// 多相型の実引数として有効な式
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
@ -1790,11 +1822,12 @@ pub enum ConstExpr {
Lambda(ConstLambda),
BinOp(ConstBinOp),
UnaryOp(ConstUnaryOp),
TypeAsc(ConstTypeAsc),
}
impl_nested_display_for_chunk_enum!(ConstExpr; Lit, Accessor, App, Array, Set, Dict, Tuple, Record, BinOp, UnaryOp, Def, Lambda, Erased, Set);
impl_nested_display_for_chunk_enum!(ConstExpr; Lit, Accessor, App, Array, Set, Dict, Tuple, Record, BinOp, UnaryOp, Def, Lambda, Erased, Set, TypeAsc);
impl_display_from_nested!(ConstExpr);
impl_locational_for_enum!(ConstExpr; Lit, Accessor, App, Array, Set, Dict, Tuple, Record, BinOp, UnaryOp, Def, Lambda, Erased, Set);
impl_locational_for_enum!(ConstExpr; Lit, Accessor, App, Array, Set, Dict, Tuple, Record, BinOp, UnaryOp, Def, Lambda, Erased, Set, TypeAsc);
impl ConstExpr {
pub fn need_to_be_closed(&self) -> bool {

View file

@ -130,13 +130,13 @@ impl Parser {
const_fields,
)))
}
// TODO: Lambda, ...
Expr::TypeAscription(tasc) => {
let expr = Self::validate_const_expr(*tasc.expr)?;
Ok(ConstExpr::TypeAsc(ConstTypeAsc::new(expr, tasc.t_spec)))
}
other => Err(ParseError::syntax_error(
line!() as usize,
{
erg_common::log!(err "{other}");
other.loc()
},
other.loc(),
switch_lang!(
"japanese" => "この式はコンパイル時計算できないため、型引数には使用できません",
"simplified_chinese" => "此表达式在编译时不可计算,因此不能用作类型参数",