Implement type spec of projection and enum types

This commit is contained in:
Shunsuke Shibayama 2022-10-22 14:01:48 +09:00
parent 4eae5788ca
commit 47bedf67d8
14 changed files with 282 additions and 128 deletions

View file

@ -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)

View file

@ -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:?}"),
} }
} }
} }

View file

@ -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)?;

View file

@ -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),

View file

@ -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,

View file

@ -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

View file

@ -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 {

View file

@ -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) {

View file

@ -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(()),
} }

View file

@ -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")

View file

@ -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),

View file

@ -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)?;

View 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

View file

@ -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")