mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-29 20:34:44 +00:00
Implement type spec of projection and enum types
This commit is contained in:
parent
4eae5788ca
commit
47bedf67d8
14 changed files with 282 additions and 128 deletions
|
@ -113,6 +113,12 @@ impl Context {
|
||||||
return self.same_type_of(t, &other_t);
|
return self.same_type_of(t, &other_t);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
(TyParam::Value(ValueObj::Type(l)), TyParam::Type(r)) => {
|
||||||
|
return self.same_type_of(l.typ(), r.as_ref());
|
||||||
|
}
|
||||||
|
(TyParam::Type(l), TyParam::Value(ValueObj::Type(r))) => {
|
||||||
|
return self.same_type_of(l.as_ref(), r.typ());
|
||||||
|
}
|
||||||
(l, r) if l == r => {
|
(l, r) if l == r => {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -567,8 +573,9 @@ impl Context {
|
||||||
// ({I: Int | I >= 0} :> {I: Int | I >= 1}) == true,
|
// ({I: Int | I >= 0} :> {I: Int | I >= 1}) == true,
|
||||||
// ({I: Int | I >= 0} :> {N: Nat | N >= 1}) == true,
|
// ({I: Int | I >= 0} :> {N: Nat | N >= 1}) == true,
|
||||||
// ({I: Int | I > 1 or I < -1} :> {I: Int | I >= 0}) == false,
|
// ({I: Int | I > 1 or I < -1} :> {I: Int | I >= 0}) == false,
|
||||||
|
// {1, 2, 3} :> {1, } == true
|
||||||
(Refinement(l), Refinement(r)) => {
|
(Refinement(l), Refinement(r)) => {
|
||||||
if !self.supertype_of(&l.t, &r.t) {
|
if !self.supertype_of(&l.t, &r.t) && !self.supertype_of(&r.t, &l.t) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let mut r_preds_clone = r.preds.clone();
|
let mut r_preds_clone = r.preds.clone();
|
||||||
|
@ -777,6 +784,9 @@ impl Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn supertype_of_tp(&self, lp: &TyParam, rp: &TyParam, variance: Variance) -> bool {
|
fn supertype_of_tp(&self, lp: &TyParam, rp: &TyParam, variance: Variance) -> bool {
|
||||||
|
if lp == rp {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
match (lp, rp, variance) {
|
match (lp, rp, variance) {
|
||||||
(TyParam::FreeVar(fv), _, _) if fv.is_linked() => {
|
(TyParam::FreeVar(fv), _, _) if fv.is_linked() => {
|
||||||
self.supertype_of_tp(&fv.crack(), rp, variance)
|
self.supertype_of_tp(&fv.crack(), rp, variance)
|
||||||
|
|
|
@ -224,10 +224,13 @@ impl<'c> SubstContext<'c> {
|
||||||
Type::FreeVar(fv) => {
|
Type::FreeVar(fv) => {
|
||||||
if let Some(name) = fv.unbound_name() {
|
if let Some(name) = fv.unbound_name() {
|
||||||
if let Some(tp) = self.params.get(&name) {
|
if let Some(tp) = self.params.get(&name) {
|
||||||
if let TyParam::Type(t) = tp {
|
match Type::try_from(tp.clone()) {
|
||||||
self.ctx.sub_unify(param_t, t, Location::Unknown, None)?;
|
Ok(t) => {
|
||||||
} else {
|
self.ctx.sub_unify(param_t, &t, Location::Unknown, None)?;
|
||||||
panic!()
|
}
|
||||||
|
Err(_) => {
|
||||||
|
todo!("")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1254,6 +1257,13 @@ impl Context {
|
||||||
/// NOTE: lとrが型の場合はContextの方で判定する
|
/// NOTE: lとrが型の場合はContextの方で判定する
|
||||||
pub(crate) fn shallow_eq_tp(&self, lhs: &TyParam, rhs: &TyParam) -> bool {
|
pub(crate) fn shallow_eq_tp(&self, lhs: &TyParam, rhs: &TyParam) -> bool {
|
||||||
match (lhs, rhs) {
|
match (lhs, rhs) {
|
||||||
|
(TyParam::Type(l), _) if l.is_unbound_var() => {
|
||||||
|
self.subtype_of(&self.get_tp_t(rhs).unwrap(), &Type::Type)
|
||||||
|
}
|
||||||
|
(_, TyParam::Type(r)) if r.is_unbound_var() => {
|
||||||
|
let lhs = self.get_tp_t(lhs).unwrap();
|
||||||
|
self.subtype_of(&lhs, &Type::Type)
|
||||||
|
}
|
||||||
(TyParam::Type(l), TyParam::Type(r)) => l == r,
|
(TyParam::Type(l), TyParam::Type(r)) => l == r,
|
||||||
(TyParam::Value(l), TyParam::Value(r)) => l == r,
|
(TyParam::Value(l), TyParam::Value(r)) => l == r,
|
||||||
(TyParam::Erased(l), TyParam::Erased(r)) => l == r,
|
(TyParam::Erased(l), TyParam::Erased(r)) => l == r,
|
||||||
|
@ -1287,7 +1297,7 @@ impl Context {
|
||||||
(TyParam::Erased(t), _) => t.as_ref() == &self.get_tp_t(rhs).unwrap(),
|
(TyParam::Erased(t), _) => t.as_ref() == &self.get_tp_t(rhs).unwrap(),
|
||||||
(_, TyParam::Erased(t)) => t.as_ref() == &self.get_tp_t(lhs).unwrap(),
|
(_, TyParam::Erased(t)) => t.as_ref() == &self.get_tp_t(lhs).unwrap(),
|
||||||
(TyParam::MonoQVar(_), _) | (_, TyParam::MonoQVar(_)) => false,
|
(TyParam::MonoQVar(_), _) | (_, TyParam::MonoQVar(_)) => false,
|
||||||
(l, r) => todo!("l: {l}, r: {r}"),
|
(l, r) => todo!("l: {l:?}, r: {r:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ use ast::{
|
||||||
};
|
};
|
||||||
use erg_parser::ast;
|
use erg_parser::ast;
|
||||||
use erg_parser::token::TokenKind;
|
use erg_parser::token::TokenKind;
|
||||||
|
use erg_parser::Parser;
|
||||||
|
|
||||||
use crate::ty::constructors::*;
|
use crate::ty::constructors::*;
|
||||||
use crate::ty::free::{Constraint, Cyclicity, FreeTyVar};
|
use crate::ty::free::{Constraint, Cyclicity, FreeTyVar};
|
||||||
|
@ -29,7 +30,7 @@ use TyParamOrdering::*;
|
||||||
use Type::*;
|
use Type::*;
|
||||||
|
|
||||||
use crate::context::{Context, RegistrationMode};
|
use crate::context::{Context, RegistrationMode};
|
||||||
use crate::error::{SingleTyCheckResult, TyCheckError, TyCheckErrors, TyCheckResult};
|
use crate::error::{TyCheckError, TyCheckErrors, TyCheckResult};
|
||||||
use crate::hir;
|
use crate::hir;
|
||||||
use crate::AccessKind;
|
use crate::AccessKind;
|
||||||
use RegistrationMode::*;
|
use RegistrationMode::*;
|
||||||
|
@ -323,6 +324,7 @@ impl TyVarInstContext {
|
||||||
|
|
||||||
fn instantiate_qtp(&mut self, quantified: TyParam) -> TyParam {
|
fn instantiate_qtp(&mut self, quantified: TyParam) -> TyParam {
|
||||||
match quantified {
|
match quantified {
|
||||||
|
TyParam::FreeVar(fv) if fv.is_linked() => self.instantiate_qtp(fv.crack().clone()),
|
||||||
TyParam::MonoQVar(n) => {
|
TyParam::MonoQVar(n) => {
|
||||||
if let Some(t) = self.get_typaram(&n) {
|
if let Some(t) = self.get_typaram(&n) {
|
||||||
t.clone()
|
t.clone()
|
||||||
|
@ -453,13 +455,9 @@ impl TyVarInstContext {
|
||||||
|
|
||||||
pub(crate) fn get_tyvar(&self, name: &str) -> Option<&Type> {
|
pub(crate) fn get_tyvar(&self, name: &str) -> Option<&Type> {
|
||||||
self.tyvar_instances.get(name).or_else(|| {
|
self.tyvar_instances.get(name).or_else(|| {
|
||||||
self.typaram_instances.get(name).map(|t| {
|
self.typaram_instances
|
||||||
if let TyParam::Type(t) = t {
|
.get(name)
|
||||||
t.as_ref()
|
.map(|tp| <&Type>::try_from(tp).unwrap())
|
||||||
} else {
|
|
||||||
todo!("{t}")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -651,6 +649,14 @@ impl Context {
|
||||||
self.instantiate_simple_t(simple, opt_decl_t, tmp_tv_ctx, not_found_is_qvar)
|
self.instantiate_simple_t(simple, opt_decl_t, tmp_tv_ctx, not_found_is_qvar)
|
||||||
}
|
}
|
||||||
ast::PreDeclTypeSpec::Attr { namespace, t } => {
|
ast::PreDeclTypeSpec::Attr { namespace, t } => {
|
||||||
|
if let Ok(namespace) = Parser::validate_const_expr(namespace.as_ref().clone()) {
|
||||||
|
if let Ok(namespace) =
|
||||||
|
self.instantiate_const_expr_as_type(&namespace, None, tmp_tv_ctx)
|
||||||
|
{
|
||||||
|
let rhs = t.ident.inspect();
|
||||||
|
return Ok(proj(namespace, rhs));
|
||||||
|
}
|
||||||
|
}
|
||||||
let ctx = self.get_singular_ctx(namespace.as_ref(), &self.name)?;
|
let ctx = self.get_singular_ctx(namespace.as_ref(), &self.name)?;
|
||||||
if let Some((typ, _)) = ctx.rec_get_type(t.ident.inspect()) {
|
if let Some((typ, _)) = ctx.rec_get_type(t.ident.inspect()) {
|
||||||
// TODO: visibility check
|
// TODO: visibility check
|
||||||
|
@ -698,9 +704,9 @@ impl Context {
|
||||||
// TODO: kw
|
// TODO: kw
|
||||||
let mut args = simple.args.pos_args();
|
let mut args = simple.args.pos_args();
|
||||||
if let Some(first) = args.next() {
|
if let Some(first) = args.next() {
|
||||||
let t = self.instantiate_const_expr_as_type(&first.expr)?;
|
let t = self.instantiate_const_expr_as_type(&first.expr, None, tmp_tv_ctx)?;
|
||||||
let len = args.next().unwrap();
|
let len = args.next().unwrap();
|
||||||
let len = self.instantiate_const_expr(&len.expr)?;
|
let len = self.instantiate_const_expr(&len.expr, None, tmp_tv_ctx)?;
|
||||||
Ok(array_t(t, len))
|
Ok(array_t(t, len))
|
||||||
} else {
|
} else {
|
||||||
Ok(mono("GenericArray"))
|
Ok(mono("GenericArray"))
|
||||||
|
@ -709,14 +715,14 @@ impl Context {
|
||||||
"Ref" => {
|
"Ref" => {
|
||||||
let mut args = simple.args.pos_args();
|
let mut args = simple.args.pos_args();
|
||||||
let first = args.next().unwrap();
|
let first = args.next().unwrap();
|
||||||
let t = self.instantiate_const_expr_as_type(&first.expr)?;
|
let t = self.instantiate_const_expr_as_type(&first.expr, None, tmp_tv_ctx)?;
|
||||||
Ok(ref_(t))
|
Ok(ref_(t))
|
||||||
}
|
}
|
||||||
"RefMut" => {
|
"RefMut" => {
|
||||||
// TODO after
|
// TODO after
|
||||||
let mut args = simple.args.pos_args();
|
let mut args = simple.args.pos_args();
|
||||||
let first = args.next().unwrap();
|
let first = args.next().unwrap();
|
||||||
let t = self.instantiate_const_expr_as_type(&first.expr)?;
|
let t = self.instantiate_const_expr_as_type(&first.expr, None, tmp_tv_ctx)?;
|
||||||
Ok(ref_mut(t, None))
|
Ok(ref_mut(t, None))
|
||||||
}
|
}
|
||||||
other if simple.args.is_empty() => {
|
other if simple.args.is_empty() => {
|
||||||
|
@ -773,32 +779,16 @@ impl Context {
|
||||||
// FIXME: kw args
|
// FIXME: kw args
|
||||||
let mut new_params = vec![];
|
let mut new_params = vec![];
|
||||||
for (i, arg) in simple.args.pos_args().enumerate() {
|
for (i, arg) in simple.args.pos_args().enumerate() {
|
||||||
match &arg.expr {
|
let params = self.instantiate_const_expr(&arg.expr, Some((ctx, i)), tmp_tv_ctx);
|
||||||
ast::ConstExpr::Lit(lit) => {
|
let params = params.or_else(|e| {
|
||||||
new_params.push(TyParam::Value(self.eval_lit(lit)?));
|
if not_found_is_qvar {
|
||||||
}
|
// TODO:
|
||||||
ast::ConstExpr::Accessor(ast::ConstAccessor::Local(name)) => {
|
Ok(mono_q_tp(arg.expr.to_string()))
|
||||||
if &name.inspect()[..] == "_" {
|
|
||||||
new_params.push(TyParam::erased(ctx.params[i].1.t.clone()));
|
|
||||||
} else if let Some((typ, _)) = self.rec_get_type(name.inspect()) {
|
|
||||||
new_params.push(TyParam::t(typ.clone()));
|
|
||||||
} else if not_found_is_qvar {
|
|
||||||
new_params.push(mono_q_tp(name.inspect().clone()));
|
|
||||||
} else {
|
} else {
|
||||||
return Err(TyCheckErrors::from(TyCheckError::no_var_error(
|
Err(e)
|
||||||
self.cfg.input.clone(),
|
|
||||||
line!() as usize,
|
|
||||||
name.loc(),
|
|
||||||
self.caused_by(),
|
|
||||||
name.inspect(),
|
|
||||||
self.get_similar_name(name.inspect()),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
other => {
|
|
||||||
todo!("instantiating {other}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
})?;
|
||||||
|
new_params.push(params);
|
||||||
}
|
}
|
||||||
// FIXME: non-builtin
|
// FIXME: non-builtin
|
||||||
Ok(poly(Str::rc(other), new_params))
|
Ok(poly(Str::rc(other), new_params))
|
||||||
|
@ -806,15 +796,48 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn instantiate_const_expr(&self, expr: &ast::ConstExpr) -> TyCheckResult<TyParam> {
|
pub(crate) fn instantiate_const_expr(
|
||||||
|
&self,
|
||||||
|
expr: &ast::ConstExpr,
|
||||||
|
erased_idx: Option<(&Context, usize)>,
|
||||||
|
tmp_tv_ctx: Option<&TyVarInstContext>,
|
||||||
|
) -> TyCheckResult<TyParam> {
|
||||||
match expr {
|
match expr {
|
||||||
ast::ConstExpr::Lit(lit) => Ok(TyParam::Value(self.eval_lit(lit)?)),
|
ast::ConstExpr::Lit(lit) => Ok(TyParam::Value(self.eval_lit(lit)?)),
|
||||||
ast::ConstExpr::Accessor(ast::ConstAccessor::Local(name)) => {
|
ast::ConstExpr::Accessor(ast::ConstAccessor::Local(name)) => {
|
||||||
if &name.inspect()[..] == "_" {
|
if &name.inspect()[..] == "_" {
|
||||||
Ok(TyParam::erased(Type::Uninited))
|
let t = if let Some((ctx, i)) = erased_idx {
|
||||||
|
ctx.params[i].1.t.clone()
|
||||||
} else {
|
} else {
|
||||||
Ok(TyParam::Mono(name.inspect().clone()))
|
Type::Uninited
|
||||||
|
};
|
||||||
|
return Ok(TyParam::erased(t));
|
||||||
}
|
}
|
||||||
|
if let Some(tmp_tv_ctx) = tmp_tv_ctx {
|
||||||
|
if let Ok(tp) =
|
||||||
|
self.instantiate_tp(mono_q_tp(name.inspect()), tmp_tv_ctx, name.loc())
|
||||||
|
{
|
||||||
|
return Ok(tp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(tv_ctx) = &self.tv_ctx {
|
||||||
|
if let Some(t) = tv_ctx.get_qvar(mono_q(name.inspect())) {
|
||||||
|
return Ok(TyParam::t(t));
|
||||||
|
} else if let Some(tp) = tv_ctx.get_typaram(name.inspect()) {
|
||||||
|
return Ok(tp.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(value) = self.rec_get_const_obj(name.inspect()) {
|
||||||
|
return Ok(TyParam::Value(value.clone()));
|
||||||
|
}
|
||||||
|
Err(TyCheckErrors::from(TyCheckError::no_var_error(
|
||||||
|
self.cfg.input.clone(),
|
||||||
|
line!() as usize,
|
||||||
|
name.loc(),
|
||||||
|
self.caused_by(),
|
||||||
|
name.inspect(),
|
||||||
|
self.get_similar_name(name.inspect()),
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
|
@ -823,23 +846,13 @@ impl Context {
|
||||||
pub(crate) fn instantiate_const_expr_as_type(
|
pub(crate) fn instantiate_const_expr_as_type(
|
||||||
&self,
|
&self,
|
||||||
expr: &ast::ConstExpr,
|
expr: &ast::ConstExpr,
|
||||||
) -> SingleTyCheckResult<Type> {
|
erased_idx: Option<(&Context, usize)>,
|
||||||
match expr {
|
tmp_tv_ctx: Option<&TyVarInstContext>,
|
||||||
ast::ConstExpr::Accessor(ast::ConstAccessor::Local(name)) => {
|
) -> TyCheckResult<Type> {
|
||||||
if let Some((typ, _)) = self.rec_get_type(name.inspect()) {
|
match self.instantiate_const_expr(expr, erased_idx, tmp_tv_ctx)? {
|
||||||
Ok(typ.clone())
|
TyParam::Type(t) => Ok(*t),
|
||||||
} else {
|
TyParam::Value(ValueObj::Type(t)) => Ok(t.into_typ()),
|
||||||
Err(TyCheckError::no_var_error(
|
other => todo!("{other}"),
|
||||||
self.cfg.input.clone(),
|
|
||||||
line!() as usize,
|
|
||||||
name.loc(),
|
|
||||||
self.caused_by(),
|
|
||||||
name.inspect(),
|
|
||||||
self.get_similar_name(name.inspect()),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => todo!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -901,13 +914,13 @@ impl Context {
|
||||||
mode,
|
mode,
|
||||||
not_found_is_qvar,
|
not_found_is_qvar,
|
||||||
)?;
|
)?;
|
||||||
let mut len = self.instantiate_const_expr(&arr.len)?;
|
let mut len = self.instantiate_const_expr(&arr.len, None, tmp_tv_ctx)?;
|
||||||
if let TyParam::Erased(t) = &mut len {
|
if let TyParam::Erased(t) = &mut len {
|
||||||
*t.as_mut() = Type::Nat;
|
*t.as_mut() = Type::Nat;
|
||||||
}
|
}
|
||||||
Ok(array_t(elem_t, len))
|
Ok(array_t(elem_t, len))
|
||||||
}
|
}
|
||||||
TypeSpec::Set(set) => {
|
TypeSpec::SetWithLen(set) => {
|
||||||
let elem_t = self.instantiate_typespec(
|
let elem_t = self.instantiate_typespec(
|
||||||
&set.ty,
|
&set.ty,
|
||||||
opt_decl_t,
|
opt_decl_t,
|
||||||
|
@ -915,7 +928,7 @@ impl Context {
|
||||||
mode,
|
mode,
|
||||||
not_found_is_qvar,
|
not_found_is_qvar,
|
||||||
)?;
|
)?;
|
||||||
let mut len = self.instantiate_const_expr(&set.len)?;
|
let mut len = self.instantiate_const_expr(&set.len, None, tmp_tv_ctx)?;
|
||||||
if let TyParam::Erased(t) = &mut len {
|
if let TyParam::Erased(t) = &mut len {
|
||||||
*t.as_mut() = Type::Nat;
|
*t.as_mut() = Type::Nat;
|
||||||
}
|
}
|
||||||
|
@ -976,13 +989,12 @@ impl Context {
|
||||||
TypeSpec::Enum(set) => {
|
TypeSpec::Enum(set) => {
|
||||||
let mut new_set = set! {};
|
let mut new_set = set! {};
|
||||||
for arg in set.pos_args() {
|
for arg in set.pos_args() {
|
||||||
if let ast::ConstExpr::Lit(lit) = &arg.expr {
|
new_set.insert(self.instantiate_const_expr(&arg.expr, None, tmp_tv_ctx)?);
|
||||||
new_set.insert(self.eval_lit(lit)?);
|
|
||||||
} else {
|
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
}
|
let ty = new_set.iter().fold(Type::Never, |t, tp| {
|
||||||
Ok(v_enum(new_set))
|
self.union(&t, &self.get_tp_t(tp).unwrap())
|
||||||
|
});
|
||||||
|
Ok(tp_enum(ty, new_set))
|
||||||
}
|
}
|
||||||
TypeSpec::Interval { op, lhs, rhs } => {
|
TypeSpec::Interval { op, lhs, rhs } => {
|
||||||
let op = match op.kind {
|
let op = match op.kind {
|
||||||
|
@ -992,9 +1004,9 @@ impl Context {
|
||||||
TokenKind::Open => IntervalOp::Open,
|
TokenKind::Open => IntervalOp::Open,
|
||||||
_ => assume_unreachable!(),
|
_ => assume_unreachable!(),
|
||||||
};
|
};
|
||||||
let l = self.instantiate_const_expr(lhs)?;
|
let l = self.instantiate_const_expr(lhs, None, tmp_tv_ctx)?;
|
||||||
let l = self.eval_tp(&l)?;
|
let l = self.eval_tp(&l)?;
|
||||||
let r = self.instantiate_const_expr(rhs)?;
|
let r = self.instantiate_const_expr(rhs, None, tmp_tv_ctx)?;
|
||||||
let r = self.eval_tp(&r)?;
|
let r = self.eval_tp(&r)?;
|
||||||
if let Some(Greater) = self.try_cmp(&l, &r) {
|
if let Some(Greater) = self.try_cmp(&l, &r) {
|
||||||
panic!("{l}..{r} is not a valid interval type (should be lhs <= rhs)")
|
panic!("{l}..{r} is not a valid interval type (should be lhs <= rhs)")
|
||||||
|
@ -1106,20 +1118,16 @@ impl Context {
|
||||||
match quantified {
|
match quantified {
|
||||||
TyParam::MonoQVar(n) => {
|
TyParam::MonoQVar(n) => {
|
||||||
if let Some(tp) = tmp_tv_ctx.get_typaram(&n) {
|
if let Some(tp) = tmp_tv_ctx.get_typaram(&n) {
|
||||||
Ok(tp.clone())
|
return Ok(tp.clone());
|
||||||
} else if let Some(t) = tmp_tv_ctx.get_tyvar(&n) {
|
} else if let Some(t) = tmp_tv_ctx.get_tyvar(&n) {
|
||||||
Ok(TyParam::t(t.clone()))
|
return Ok(TyParam::t(t.clone()));
|
||||||
} else if let Some(tv_ctx) = &self.tv_ctx {
|
}
|
||||||
tv_ctx.get_qtp(TyParam::MonoQVar(n.clone())).ok_or_else(|| {
|
if let Some(tv_ctx) = &self.tv_ctx {
|
||||||
TyCheckErrors::from(TyCheckError::tyvar_not_defined_error(
|
if let Some(tp) = tv_ctx.get_qtp(TyParam::MonoQVar(n.clone())) {
|
||||||
self.cfg.input.clone(),
|
return Ok(tp);
|
||||||
line!() as usize,
|
}
|
||||||
&n,
|
}
|
||||||
loc,
|
if let Some(outer) = &self.outer {
|
||||||
AtomicStr::ever("?"),
|
|
||||||
))
|
|
||||||
})
|
|
||||||
} else if let Some(outer) = &self.outer {
|
|
||||||
outer.instantiate_tp(TyParam::MonoQVar(n), tmp_tv_ctx, loc)
|
outer.instantiate_tp(TyParam::MonoQVar(n), tmp_tv_ctx, loc)
|
||||||
} else {
|
} else {
|
||||||
Err(TyCheckErrors::from(TyCheckError::tyvar_not_defined_error(
|
Err(TyCheckErrors::from(TyCheckError::tyvar_not_defined_error(
|
||||||
|
@ -1131,6 +1139,38 @@ impl Context {
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
TyParam::Dict(dict) => {
|
||||||
|
let dict = dict
|
||||||
|
.into_iter()
|
||||||
|
.map(|(k, v)| {
|
||||||
|
let k = self.instantiate_tp(k, tmp_tv_ctx, loc)?;
|
||||||
|
let v = self.instantiate_tp(v, tmp_tv_ctx, loc)?;
|
||||||
|
Ok((k, v))
|
||||||
|
})
|
||||||
|
.collect::<TyCheckResult<_>>()?;
|
||||||
|
Ok(TyParam::Dict(dict))
|
||||||
|
}
|
||||||
|
TyParam::Array(arr) => {
|
||||||
|
let arr = arr
|
||||||
|
.into_iter()
|
||||||
|
.map(|v| self.instantiate_tp(v, tmp_tv_ctx, loc))
|
||||||
|
.collect::<TyCheckResult<_>>()?;
|
||||||
|
Ok(TyParam::Array(arr))
|
||||||
|
}
|
||||||
|
TyParam::Set(set) => {
|
||||||
|
let set = set
|
||||||
|
.into_iter()
|
||||||
|
.map(|v| self.instantiate_tp(v, tmp_tv_ctx, loc))
|
||||||
|
.collect::<TyCheckResult<_>>()?;
|
||||||
|
Ok(TyParam::Set(set))
|
||||||
|
}
|
||||||
|
TyParam::Tuple(tup) => {
|
||||||
|
let tup = tup
|
||||||
|
.into_iter()
|
||||||
|
.map(|v| self.instantiate_tp(v, tmp_tv_ctx, loc))
|
||||||
|
.collect::<TyCheckResult<_>>()?;
|
||||||
|
Ok(TyParam::Tuple(tup))
|
||||||
|
}
|
||||||
TyParam::UnaryOp { op, val } => {
|
TyParam::UnaryOp { op, val } => {
|
||||||
let res = self.instantiate_tp(*val, tmp_tv_ctx, loc)?;
|
let res = self.instantiate_tp(*val, tmp_tv_ctx, loc)?;
|
||||||
Ok(TyParam::unary(op, res))
|
Ok(TyParam::unary(op, res))
|
||||||
|
@ -1179,10 +1219,10 @@ impl Context {
|
||||||
match unbound {
|
match unbound {
|
||||||
MonoQVar(n) => {
|
MonoQVar(n) => {
|
||||||
if let Some(t) = tmp_tv_ctx.get_tyvar(&n) {
|
if let Some(t) = tmp_tv_ctx.get_tyvar(&n) {
|
||||||
Ok(t.clone())
|
return Ok(t.clone());
|
||||||
} else if let Some(tp) = tmp_tv_ctx.get_typaram(&n) {
|
} else if let Some(tp) = tmp_tv_ctx.get_typaram(&n) {
|
||||||
if let TyParam::Type(t) = tp {
|
if let TyParam::Type(t) = tp {
|
||||||
Ok(*t.clone())
|
return Ok(*t.clone());
|
||||||
} else {
|
} else {
|
||||||
todo!(
|
todo!(
|
||||||
"typaram_insts: {}\ntyvar_insts:{}\n{tp}",
|
"typaram_insts: {}\ntyvar_insts:{}\n{tp}",
|
||||||
|
@ -1190,17 +1230,12 @@ impl Context {
|
||||||
tmp_tv_ctx.tyvar_instances,
|
tmp_tv_ctx.tyvar_instances,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else if let Some(tv_ctx) = &self.tv_ctx {
|
}
|
||||||
tv_ctx.get_qvar(MonoQVar(n.clone())).ok_or_else(|| {
|
if let Some(tv_ctx) = &self.tv_ctx {
|
||||||
TyCheckErrors::from(TyCheckError::tyvar_not_defined_error(
|
if let Some(t) = tv_ctx.get_qvar(MonoQVar(n.clone())) {
|
||||||
self.cfg.input.clone(),
|
return Ok(t);
|
||||||
line!() as usize,
|
}
|
||||||
&n,
|
}
|
||||||
loc,
|
|
||||||
AtomicStr::ever("?"),
|
|
||||||
))
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Err(TyCheckErrors::from(TyCheckError::tyvar_not_defined_error(
|
Err(TyCheckErrors::from(TyCheckError::tyvar_not_defined_error(
|
||||||
self.cfg.input.clone(),
|
self.cfg.input.clone(),
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
|
@ -1209,7 +1244,6 @@ impl Context {
|
||||||
AtomicStr::ever("?"),
|
AtomicStr::ever("?"),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
PolyQVar { name, mut params } => {
|
PolyQVar { name, mut params } => {
|
||||||
for param in params.iter_mut() {
|
for param in params.iter_mut() {
|
||||||
*param = self.instantiate_tp(mem::take(param), tmp_tv_ctx, loc)?;
|
*param = self.instantiate_tp(mem::take(param), tmp_tv_ctx, loc)?;
|
||||||
|
|
|
@ -181,11 +181,10 @@ impl Context {
|
||||||
}
|
}
|
||||||
self.validate_var_sig_t(ident, sig.t_spec.as_ref(), body_t, Normal)?;
|
self.validate_var_sig_t(ident, sig.t_spec.as_ref(), body_t, Normal)?;
|
||||||
let muty = Mutability::from(&ident.inspect()[..]);
|
let muty = Mutability::from(&ident.inspect()[..]);
|
||||||
let generalized = self.generalize_t(body_t.clone());
|
|
||||||
self.decls.remove(ident.inspect());
|
self.decls.remove(ident.inspect());
|
||||||
let vis = ident.vis();
|
let vis = ident.vis();
|
||||||
let vi = VarInfo::new(
|
let vi = VarInfo::new(
|
||||||
generalized,
|
body_t.clone(),
|
||||||
muty,
|
muty,
|
||||||
vis,
|
vis,
|
||||||
VarKind::Defined(id),
|
VarKind::Defined(id),
|
||||||
|
|
|
@ -68,6 +68,7 @@ impl Context {
|
||||||
}
|
}
|
||||||
_ => assume_unreachable!(),
|
_ => assume_unreachable!(),
|
||||||
},
|
},
|
||||||
|
TyParam::FreeVar(_) => free,
|
||||||
other if other.has_no_unbound_var() => other,
|
other if other.has_no_unbound_var() => other,
|
||||||
other => todo!("{other}"),
|
other => todo!("{other}"),
|
||||||
}
|
}
|
||||||
|
@ -241,6 +242,15 @@ impl Context {
|
||||||
after,
|
after,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Refinement(refine) => {
|
||||||
|
let t = self.generalize_t_inner(*refine.t, variance, bounds, lazy_inits);
|
||||||
|
let preds = refine
|
||||||
|
.preds
|
||||||
|
.into_iter()
|
||||||
|
.map(|pred| self.generalize_pred(pred, variance, bounds, lazy_inits))
|
||||||
|
.collect();
|
||||||
|
refinement(refine.var, t, preds)
|
||||||
|
}
|
||||||
Poly { name, mut params } => {
|
Poly { name, mut params } => {
|
||||||
let params = params
|
let params = params
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
|
@ -314,6 +324,35 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn generalize_pred(
|
||||||
|
&self,
|
||||||
|
pred: Predicate,
|
||||||
|
variance: Variance,
|
||||||
|
bounds: &mut Set<TyBound>,
|
||||||
|
lazy_inits: &mut Set<Str>,
|
||||||
|
) -> Predicate {
|
||||||
|
match pred {
|
||||||
|
Predicate::Const(_) => pred,
|
||||||
|
Predicate::Equal { lhs, rhs } => {
|
||||||
|
let rhs = self.generalize_tp(rhs, variance, bounds, lazy_inits);
|
||||||
|
Predicate::eq(lhs, rhs)
|
||||||
|
}
|
||||||
|
Predicate::GreaterEqual { lhs, rhs } => {
|
||||||
|
let rhs = self.generalize_tp(rhs, variance, bounds, lazy_inits);
|
||||||
|
Predicate::ge(lhs, rhs)
|
||||||
|
}
|
||||||
|
Predicate::LessEqual { lhs, rhs } => {
|
||||||
|
let rhs = self.generalize_tp(rhs, variance, bounds, lazy_inits);
|
||||||
|
Predicate::le(lhs, rhs)
|
||||||
|
}
|
||||||
|
Predicate::NotEqual { lhs, rhs } => {
|
||||||
|
let rhs = self.generalize_tp(rhs, variance, bounds, lazy_inits);
|
||||||
|
Predicate::ne(lhs, rhs)
|
||||||
|
}
|
||||||
|
other => todo!("{other}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn deref_tp(
|
pub(crate) fn deref_tp(
|
||||||
&self,
|
&self,
|
||||||
tp: TyParam,
|
tp: TyParam,
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
|
.__import__: |S: Str|(name: {S}, globals := {Str: Obj}) -> Module S
|
||||||
|
.import_module: |S: Str|(name: {S}, package := Str or NoneType) -> Module S
|
||||||
.reload!: (GenericModule, ) => NoneType
|
.reload!: (GenericModule, ) => NoneType
|
||||||
|
|
|
@ -21,7 +21,7 @@ use erg_parser::Parser;
|
||||||
use crate::ty::constructors::{
|
use crate::ty::constructors::{
|
||||||
array_mut, array_t, free_var, func, mono, poly, proc, quant, set_mut, set_t, ty_tp,
|
array_mut, array_t, free_var, func, mono, poly, proc, quant, set_mut, set_t, ty_tp,
|
||||||
};
|
};
|
||||||
use crate::ty::free::Constraint;
|
use crate::ty::free::{Constraint, HasLevel};
|
||||||
use crate::ty::typaram::TyParam;
|
use crate::ty::typaram::TyParam;
|
||||||
use crate::ty::value::{GenTypeObj, TypeKind, TypeObj, ValueObj};
|
use crate::ty::value::{GenTypeObj, TypeKind, TypeObj, ValueObj};
|
||||||
use crate::ty::{HasType, ParamTy, Type};
|
use crate::ty::{HasType, ParamTy, Type};
|
||||||
|
@ -1595,6 +1595,8 @@ impl ASTLowerer {
|
||||||
RegistrationMode::Normal,
|
RegistrationMode::Normal,
|
||||||
false,
|
false,
|
||||||
)?;
|
)?;
|
||||||
|
t.lift();
|
||||||
|
let t = self.ctx.generalize_t(t);
|
||||||
if is_instance_ascription {
|
if is_instance_ascription {
|
||||||
self.declare_instance(&ident, &t, py_name)?;
|
self.declare_instance(&ident, &t, py_name)?;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -394,6 +394,9 @@ impl<T> Free<T> {
|
||||||
pub fn as_ptr(&self) -> *mut FreeKind<T> {
|
pub fn as_ptr(&self) -> *mut FreeKind<T> {
|
||||||
self.0.as_ptr()
|
self.0.as_ptr()
|
||||||
}
|
}
|
||||||
|
pub fn forced_as_ref(&self) -> &FreeKind<T> {
|
||||||
|
unsafe { self.as_ptr().as_ref() }.unwrap()
|
||||||
|
}
|
||||||
pub fn force_replace(&self, new: FreeKind<T>) {
|
pub fn force_replace(&self, new: FreeKind<T>) {
|
||||||
// prevent linking to self
|
// prevent linking to self
|
||||||
if addr_eq!(*self.borrow(), new) {
|
if addr_eq!(*self.borrow(), new) {
|
||||||
|
|
|
@ -482,6 +482,22 @@ impl TryFrom<TyParam> for Type {
|
||||||
match tp {
|
match tp {
|
||||||
TyParam::FreeVar(fv) if fv.is_linked() => Type::try_from(fv.crack().clone()),
|
TyParam::FreeVar(fv) if fv.is_linked() => Type::try_from(fv.crack().clone()),
|
||||||
TyParam::Type(t) => Ok(t.as_ref().clone()),
|
TyParam::Type(t) => Ok(t.as_ref().clone()),
|
||||||
|
TyParam::Value(v) => Type::try_from(v),
|
||||||
|
// TODO: Array, Dict, Set
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TryFrom<&'a TyParam> for &'a Type {
|
||||||
|
type Error = ();
|
||||||
|
fn try_from(tp: &'a TyParam) -> Result<&'a Type, ()> {
|
||||||
|
match tp {
|
||||||
|
TyParam::FreeVar(fv) if fv.is_linked() => {
|
||||||
|
<&'a Type>::try_from(fv.forced_as_ref().linked().unwrap())
|
||||||
|
}
|
||||||
|
TyParam::Type(t) => Ok(t.as_ref()),
|
||||||
|
TyParam::Value(v) => <&Type>::try_from(v),
|
||||||
// TODO: Array, Dict, Set
|
// TODO: Array, Dict, Set
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
|
|
|
@ -374,6 +374,33 @@ impl TryFrom<&ValueObj> for f64 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<ValueObj> for Type {
|
||||||
|
type Error = ();
|
||||||
|
fn try_from(val: ValueObj) -> Result<Type, ()> {
|
||||||
|
match val {
|
||||||
|
ValueObj::Type(t) => match t {
|
||||||
|
TypeObj::Builtin(t) => Ok(t),
|
||||||
|
TypeObj::Generated(gen) => Ok(gen.t),
|
||||||
|
},
|
||||||
|
ValueObj::Mut(v) => Type::try_from(v.borrow().clone()).map_err(|_| ()),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TryFrom<&'a ValueObj> for &'a Type {
|
||||||
|
type Error = ();
|
||||||
|
fn try_from(val: &'a ValueObj) -> Result<Self, ()> {
|
||||||
|
match val {
|
||||||
|
ValueObj::Type(t) => match t {
|
||||||
|
TypeObj::Builtin(t) => Ok(t),
|
||||||
|
TypeObj::Generated(gen) => Ok(&gen.t),
|
||||||
|
},
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl HasType for ValueObj {
|
impl HasType for ValueObj {
|
||||||
fn ref_t(&self) -> &Type {
|
fn ref_t(&self) -> &Type {
|
||||||
panic!("cannot get reference of the const")
|
panic!("cannot get reference of the const")
|
||||||
|
|
|
@ -1079,7 +1079,7 @@ pub struct ConstLocal {
|
||||||
|
|
||||||
impl NestedDisplay for ConstLocal {
|
impl NestedDisplay for ConstLocal {
|
||||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
||||||
write!(f, "{}", self.symbol)
|
write!(f, "{}", self.symbol.content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1514,7 +1514,7 @@ impl fmt::Display for SimpleTypeSpec {
|
||||||
if self.args.is_empty() {
|
if self.args.is_empty() {
|
||||||
write!(f, "{}", self.ident)
|
write!(f, "{}", self.ident)
|
||||||
} else {
|
} else {
|
||||||
write!(f, "{}{}", self.ident, self.args)
|
write!(f, "{}({})", self.ident, self.args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1728,20 +1728,20 @@ impl ArrayTypeSpec {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct SetTypeSpec {
|
pub struct SetWithLenTypeSpec {
|
||||||
pub ty: Box<TypeSpec>,
|
pub ty: Box<TypeSpec>,
|
||||||
pub len: ConstExpr,
|
pub len: ConstExpr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for SetTypeSpec {
|
impl fmt::Display for SetWithLenTypeSpec {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{{{}; {}}}", self.ty, self.len)
|
write!(f, "{{{}; {}}}", self.ty, self.len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_locational!(SetTypeSpec, ty, len);
|
impl_locational!(SetWithLenTypeSpec, ty, len);
|
||||||
|
|
||||||
impl SetTypeSpec {
|
impl SetWithLenTypeSpec {
|
||||||
pub fn new(ty: TypeSpec, len: ConstExpr) -> Self {
|
pub fn new(ty: TypeSpec, len: ConstExpr) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ty: Box::new(ty),
|
ty: Box::new(ty),
|
||||||
|
@ -1765,7 +1765,7 @@ pub enum TypeSpec {
|
||||||
PreDeclTy(PreDeclTypeSpec),
|
PreDeclTy(PreDeclTypeSpec),
|
||||||
/* Composite types */
|
/* Composite types */
|
||||||
Array(ArrayTypeSpec),
|
Array(ArrayTypeSpec),
|
||||||
Set(SetTypeSpec),
|
SetWithLen(SetWithLenTypeSpec),
|
||||||
Tuple(Vec<TypeSpec>),
|
Tuple(Vec<TypeSpec>),
|
||||||
Dict(Vec<(TypeSpec, TypeSpec)>),
|
Dict(Vec<(TypeSpec, TypeSpec)>),
|
||||||
Record(Vec<(Identifier, TypeSpec)>),
|
Record(Vec<(Identifier, TypeSpec)>),
|
||||||
|
@ -1795,7 +1795,7 @@ impl fmt::Display for TypeSpec {
|
||||||
Self::Not(lhs, rhs) => write!(f, "{lhs} not {rhs}"),
|
Self::Not(lhs, rhs) => write!(f, "{lhs} not {rhs}"),
|
||||||
Self::Or(lhs, rhs) => write!(f, "{lhs} or {rhs}"),
|
Self::Or(lhs, rhs) => write!(f, "{lhs} or {rhs}"),
|
||||||
Self::Array(arr) => write!(f, "{arr}"),
|
Self::Array(arr) => write!(f, "{arr}"),
|
||||||
Self::Set(set) => write!(f, "{set}"),
|
Self::SetWithLen(set) => write!(f, "{set}"),
|
||||||
Self::Tuple(tys) => write!(f, "({})", fmt_vec(tys)),
|
Self::Tuple(tys) => write!(f, "({})", fmt_vec(tys)),
|
||||||
Self::Dict(dict) => {
|
Self::Dict(dict) => {
|
||||||
write!(f, "{{")?;
|
write!(f, "{{")?;
|
||||||
|
@ -1827,7 +1827,7 @@ impl Locational for TypeSpec {
|
||||||
Location::concat(lhs.as_ref(), rhs.as_ref())
|
Location::concat(lhs.as_ref(), rhs.as_ref())
|
||||||
}
|
}
|
||||||
Self::Array(arr) => arr.loc(),
|
Self::Array(arr) => arr.loc(),
|
||||||
Self::Set(set) => set.loc(),
|
Self::SetWithLen(set) => set.loc(),
|
||||||
// TODO: ユニット
|
// TODO: ユニット
|
||||||
Self::Tuple(tys) => Location::concat(tys.first().unwrap(), tys.last().unwrap()),
|
Self::Tuple(tys) => Location::concat(tys.first().unwrap(), tys.last().unwrap()),
|
||||||
Self::Dict(dict) => Location::concat(&dict.first().unwrap().0, &dict.last().unwrap().1),
|
Self::Dict(dict) => Location::concat(&dict.first().unwrap().0, &dict.last().unwrap().1),
|
||||||
|
|
|
@ -2840,7 +2840,7 @@ impl 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.
|
||||||
impl Parser {
|
impl Parser {
|
||||||
fn validate_const_expr(expr: Expr) -> Result<ConstExpr, ParseError> {
|
pub fn validate_const_expr(expr: Expr) -> Result<ConstExpr, ParseError> {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::Lit(l) => Ok(ConstExpr::Lit(l)),
|
Expr::Lit(l) => Ok(ConstExpr::Lit(l)),
|
||||||
Expr::Accessor(Accessor::Ident(local)) => {
|
Expr::Accessor(Accessor::Ident(local)) => {
|
||||||
|
@ -3016,17 +3016,21 @@ impl Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_to_set_type_spec(set: Set) -> Result<SetTypeSpec, ParseError> {
|
fn set_to_set_type_spec(set: Set) -> Result<TypeSpec, ParseError> {
|
||||||
match set {
|
match set {
|
||||||
Set::Normal(arr) => {
|
Set::Normal(set) => {
|
||||||
// TODO: add hint
|
let mut elem_ts = vec![];
|
||||||
let err = ParseError::simple_syntax_error(line!() as usize, arr.loc());
|
let (elems, .., paren) = set.elems.deconstruct();
|
||||||
Err(err)
|
for elem in elems.into_iter() {
|
||||||
|
let const_expr = Self::validate_const_expr(elem.expr)?;
|
||||||
|
elem_ts.push(ConstPosArg::new(const_expr));
|
||||||
|
}
|
||||||
|
Ok(TypeSpec::Enum(ConstArgs::new(elem_ts, vec![], paren)))
|
||||||
}
|
}
|
||||||
Set::WithLength(set) => {
|
Set::WithLength(set) => {
|
||||||
let t_spec = Self::expr_to_type_spec(set.elem.expr)?;
|
let t_spec = Self::expr_to_type_spec(set.elem.expr)?;
|
||||||
let len = Self::validate_const_expr(*set.len)?;
|
let len = Self::validate_const_expr(*set.len)?;
|
||||||
Ok(SetTypeSpec::new(t_spec, len))
|
Ok(TypeSpec::SetWithLen(SetWithLenTypeSpec::new(t_spec, len)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3095,7 +3099,7 @@ impl Parser {
|
||||||
}
|
}
|
||||||
Expr::Set(set) => {
|
Expr::Set(set) => {
|
||||||
let set = Self::set_to_set_type_spec(set)?;
|
let set = Self::set_to_set_type_spec(set)?;
|
||||||
Ok(TypeSpec::Set(set))
|
Ok(set)
|
||||||
}
|
}
|
||||||
Expr::Dict(dict) => {
|
Expr::Dict(dict) => {
|
||||||
let dict = Self::dict_to_dict_type_spec(dict)?;
|
let dict = Self::dict_to_dict_type_spec(dict)?;
|
||||||
|
|
3
tests/advanced_type_spec.er
Normal file
3
tests/advanced_type_spec.er
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
x: {1, 2, 3} = 1
|
||||||
|
id|T: Type|(x: T): T = x
|
||||||
|
add|R: Type, A <: Add(R)|(x: A, y: R): A.Output = x + y
|
|
@ -13,6 +13,11 @@ fn exec_addition() -> Result<(), ()> {
|
||||||
expect_failure("tests/addition.er", 1)
|
expect_failure("tests/addition.er", 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exec_advanced_type_spec() -> Result<(), ()> {
|
||||||
|
expect_success("tests/advanced_type_spec.er")
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exec_assert_cast() -> Result<(), ()> {
|
fn exec_assert_cast() -> Result<(), ()> {
|
||||||
expect_success("examples/assert_cast.er")
|
expect_success("examples/assert_cast.er")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue