mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-29 20:34:44 +00:00
3501 lines
104 KiB
Rust
3501 lines
104 KiB
Rust
//! defines `Type` (type kind).
|
|
//!
|
|
//! Type(コンパイラ等で使われる「型」を表現する)を定義する
|
|
use std::cell::{Ref, RefMut};
|
|
use std::cmp::Ordering;
|
|
use std::fmt;
|
|
use std::mem;
|
|
use std::ops::{Add, Div, Mul, Neg, Range, RangeInclusive, Sub};
|
|
|
|
use crate::codeobj::CodeObj;
|
|
use crate::dict::Dict;
|
|
use crate::rccell::RcCell;
|
|
use crate::set::Set;
|
|
use crate::traits::{HasType, LimitedDisplay};
|
|
use crate::value::ValueObj::{Inf, NegInf};
|
|
use crate::value::{Field, ValueObj};
|
|
use crate::{enum_unwrap, fmt_set_split_with, fmt_vec, set, Str};
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
#[repr(u8)]
|
|
pub enum OpKind {
|
|
Add,
|
|
Sub,
|
|
Mul,
|
|
Div,
|
|
Pow,
|
|
Mod,
|
|
Pos,
|
|
Neg,
|
|
Invert,
|
|
Gt,
|
|
Lt,
|
|
Ge,
|
|
Le,
|
|
Eq,
|
|
Ne,
|
|
And,
|
|
Or,
|
|
BitAnd,
|
|
BitOr,
|
|
BitXor,
|
|
Shl,
|
|
Shr,
|
|
Mutate,
|
|
}
|
|
|
|
impl fmt::Display for OpKind {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
Self::Add => write!(f, "+"),
|
|
Self::Sub => write!(f, "-"),
|
|
Self::Mul => write!(f, "*"),
|
|
Self::Div => write!(f, "/"),
|
|
Self::Pow => write!(f, "**"),
|
|
Self::Mod => write!(f, "%"),
|
|
Self::Pos => write!(f, "+"),
|
|
Self::Neg => write!(f, "-"),
|
|
Self::Invert => write!(f, "~"),
|
|
Self::Gt => write!(f, ">"),
|
|
Self::Lt => write!(f, "<"),
|
|
Self::Ge => write!(f, ">="),
|
|
Self::Le => write!(f, "<="),
|
|
Self::Eq => write!(f, "=="),
|
|
Self::Ne => write!(f, "!="),
|
|
Self::And => write!(f, "and"),
|
|
Self::Or => write!(f, "or"),
|
|
Self::BitAnd => write!(f, "&&"),
|
|
Self::BitOr => write!(f, "||"),
|
|
Self::BitXor => write!(f, "^^"),
|
|
Self::Shl => write!(f, "<<"),
|
|
Self::Shr => write!(f, ">>"),
|
|
Self::Mutate => write!(f, "!"),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub type Level = usize;
|
|
pub type Id = usize;
|
|
|
|
thread_local! {
|
|
static UNBOUND_ID: RcCell<usize> = RcCell::new(0);
|
|
static REFINEMENT_VAR_ID: RcCell<usize> = RcCell::new(0);
|
|
}
|
|
|
|
pub fn fresh_varname() -> String {
|
|
REFINEMENT_VAR_ID.with(|id| {
|
|
*id.borrow_mut() += 1;
|
|
let i = *id.borrow();
|
|
format!("%v{i}")
|
|
})
|
|
}
|
|
|
|
pub fn fresh_param_name() -> String {
|
|
REFINEMENT_VAR_ID.with(|id| {
|
|
*id.borrow_mut() += 1;
|
|
let i = *id.borrow();
|
|
format!("%p{i}")
|
|
})
|
|
}
|
|
|
|
pub trait HasLevel {
|
|
fn level(&self) -> Option<Level>;
|
|
fn update_level(&self, level: Level);
|
|
fn lift(&self);
|
|
}
|
|
|
|
// REVIEW: TyBoundと微妙に役割が被っている
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub enum Constraint {
|
|
// : Type --> (:> Never, <: Obj)
|
|
// :> Sub --> (:> Sub, <: Obj)
|
|
// <: Sup --> (:> Never, <: Sup)
|
|
/// :> Sub, <: Sup
|
|
Sandwiched {
|
|
sub: Type,
|
|
sup: Type,
|
|
},
|
|
// : Int, ...
|
|
TypeOf(Type),
|
|
Uninited,
|
|
}
|
|
|
|
impl fmt::Display for Constraint {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
Self::Sandwiched { sub, sup } => {
|
|
match (sub.rec_eq(&Type::Never), sup.rec_eq(&Type::Obj)) {
|
|
(true, true) => write!(f, ": Type (:> Never, <: Obj)"),
|
|
(true, false) => write!(f, "<: {sup}"),
|
|
(false, true) => write!(f, ":> {sub}"),
|
|
(false, false) => write!(f, ":> {sub}, <: {sup}"),
|
|
}
|
|
}
|
|
Self::TypeOf(t) => write!(f, ": {t}"),
|
|
Self::Uninited => write!(f, "<uninited>"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Constraint {
|
|
pub fn limited_fmt(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
|
|
if level == 0 {
|
|
return write!(f, "...");
|
|
}
|
|
match self {
|
|
Self::Sandwiched { sub, sup } => {
|
|
match (sub.rec_eq(&Type::Never), sup.rec_eq(&Type::Obj)) {
|
|
(true, true) => write!(f, ": Type (:> Never, <: Obj)"),
|
|
(true, false) => write!(f, "<: {sup}"),
|
|
(false, true) => write!(f, ":> {sub}"),
|
|
(false, false) => write!(f, ":> {sub}, <: {sup}"),
|
|
}
|
|
}
|
|
Self::TypeOf(t) => write!(f, ": {t}"),
|
|
Self::Uninited => write!(f, "<uninited>"),
|
|
}
|
|
}
|
|
|
|
pub const fn sandwiched(sub: Type, sup: Type) -> Self {
|
|
Self::Sandwiched { sub, sup }
|
|
}
|
|
|
|
pub fn type_of(t: Type) -> Self {
|
|
if t.rec_eq(&Type::Type) {
|
|
Self::sandwiched(Type::Never, Type::Obj)
|
|
} else {
|
|
Self::TypeOf(t)
|
|
}
|
|
}
|
|
|
|
pub const fn subtype_of(sup: Type) -> Self {
|
|
Self::sandwiched(Type::Never, sup)
|
|
}
|
|
|
|
pub const fn supertype_of(sub: Type) -> Self {
|
|
Self::sandwiched(sub, Type::Obj)
|
|
}
|
|
|
|
pub const fn is_uninited(&self) -> bool {
|
|
matches!(self, Self::Uninited)
|
|
}
|
|
|
|
pub fn typ(&self) -> Option<&Type> {
|
|
match self {
|
|
Self::TypeOf(ty) => Some(ty),
|
|
Self::Sandwiched {
|
|
sub: Type::Never,
|
|
sup: Type::Obj,
|
|
} => Some(&Type::Type),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn sub_type(&self) -> Option<&Type> {
|
|
match self {
|
|
Self::Sandwiched { sub, .. } => Some(sub),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn super_type(&self) -> Option<&Type> {
|
|
match self {
|
|
Self::Sandwiched { sup, .. } => Some(sup),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn sub_sup_type(&self) -> Option<(&Type, &Type)> {
|
|
match self {
|
|
Self::Sandwiched { sub, sup } => Some((sub, sup)),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn super_type_mut(&mut self) -> Option<&mut Type> {
|
|
match self {
|
|
Self::Sandwiched { sup, .. } => Some(sup),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub enum FreeKind<T> {
|
|
Linked(T),
|
|
Unbound {
|
|
id: Id,
|
|
lev: Level,
|
|
constraint: Constraint,
|
|
},
|
|
NamedUnbound {
|
|
name: Str,
|
|
lev: Level,
|
|
constraint: Constraint,
|
|
},
|
|
}
|
|
|
|
impl<T: fmt::Display> fmt::Display for FreeKind<T> {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
Self::Linked(t) => write!(f, "({t})"),
|
|
Self::NamedUnbound {
|
|
name,
|
|
lev,
|
|
constraint,
|
|
} => write!(f, "?{name}({constraint})[{lev}]"),
|
|
Self::Unbound {
|
|
id,
|
|
lev,
|
|
constraint,
|
|
} => write!(f, "?{id}({constraint})[{lev}]"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: LimitedDisplay> LimitedDisplay for FreeKind<T> {
|
|
fn limited_fmt(&self, f: &mut fmt::Formatter<'_>, limit: usize) -> fmt::Result {
|
|
match self {
|
|
Self::Linked(t) => t.limited_fmt(f, limit),
|
|
Self::NamedUnbound {
|
|
name,
|
|
lev,
|
|
constraint,
|
|
} => write!(f, "?{name}({constraint})[{lev}]"),
|
|
Self::Unbound {
|
|
id,
|
|
lev,
|
|
constraint,
|
|
} => write!(f, "?{id}({constraint})[{lev}]"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T> FreeKind<T> {
|
|
pub const fn unbound(id: Id, lev: Level, constraint: Constraint) -> Self {
|
|
Self::Unbound {
|
|
id,
|
|
lev,
|
|
constraint,
|
|
}
|
|
}
|
|
|
|
pub const fn named_unbound(name: Str, lev: Level, constraint: Constraint) -> Self {
|
|
Self::NamedUnbound {
|
|
name,
|
|
lev,
|
|
constraint,
|
|
}
|
|
}
|
|
|
|
pub const fn constraint(&self) -> Option<&Constraint> {
|
|
match self {
|
|
Self::Unbound { constraint, .. } | Self::NamedUnbound { constraint, .. } => {
|
|
Some(constraint)
|
|
}
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub struct Free<T>(RcCell<FreeKind<T>>);
|
|
|
|
impl<T: fmt::Display> fmt::Display for Free<T> {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(f, "{}", self.0.borrow())
|
|
}
|
|
}
|
|
|
|
impl<T: LimitedDisplay> Free<T> {
|
|
fn limited_fmt(&self, f: &mut fmt::Formatter<'_>, limit: usize) -> fmt::Result {
|
|
self.0.borrow().limited_fmt(f, limit)
|
|
}
|
|
}
|
|
|
|
impl<T: Clone + HasLevel> Free<T> {
|
|
pub fn new(f: FreeKind<T>) -> Self {
|
|
Self(RcCell::new(f))
|
|
}
|
|
|
|
pub fn new_unbound(level: Level, constraint: Constraint) -> Self {
|
|
UNBOUND_ID.with(|id| {
|
|
*id.borrow_mut() += 1;
|
|
Self(RcCell::new(FreeKind::unbound(
|
|
*id.borrow(),
|
|
level,
|
|
constraint,
|
|
)))
|
|
})
|
|
}
|
|
|
|
pub fn new_named_unbound(name: Str, level: Level, constraint: Constraint) -> Self {
|
|
Self(RcCell::new(FreeKind::named_unbound(
|
|
name, level, constraint,
|
|
)))
|
|
}
|
|
|
|
pub fn new_linked(t: T) -> Self {
|
|
Self(RcCell::new(FreeKind::Linked(t)))
|
|
}
|
|
|
|
pub fn link(&self, to: &T) {
|
|
*self.0.borrow_mut() = FreeKind::Linked(to.clone());
|
|
}
|
|
|
|
pub fn update_level(&self, level: Level) {
|
|
match &mut *self.0.borrow_mut() {
|
|
FreeKind::Unbound { lev, .. } | FreeKind::NamedUnbound { lev, .. } if level < *lev => {
|
|
*lev = level;
|
|
}
|
|
FreeKind::Linked(t) => {
|
|
t.update_level(level);
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
pub fn lift(&self) {
|
|
match &mut *self.0.borrow_mut() {
|
|
FreeKind::Unbound { lev, .. } | FreeKind::NamedUnbound { lev, .. } => {
|
|
*lev += 1;
|
|
}
|
|
FreeKind::Linked(t) => {
|
|
if let Some(lev) = t.level() {
|
|
t.update_level(lev + 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn level(&self) -> Option<Level> {
|
|
match &*self.0.borrow() {
|
|
FreeKind::Unbound { lev, .. } | FreeKind::NamedUnbound { lev, .. } => Some(*lev),
|
|
FreeKind::Linked(t) => t.level(),
|
|
}
|
|
}
|
|
|
|
pub fn update_constraint(&self, new_constraint: Constraint) {
|
|
match &mut *self.0.borrow_mut() {
|
|
FreeKind::Unbound { constraint, .. } | FreeKind::NamedUnbound { constraint, .. } => {
|
|
*constraint = new_constraint;
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
pub fn get_name(&self) -> Option<Str> {
|
|
match self.0.clone_inner() {
|
|
FreeKind::Linked(_) => panic!("the value is linked"),
|
|
FreeKind::Unbound { .. } => None,
|
|
FreeKind::NamedUnbound { name, .. } => Some(name),
|
|
}
|
|
}
|
|
|
|
pub fn unwrap_unbound(self) -> (Option<Str>, usize, Constraint) {
|
|
match self.0.clone_inner() {
|
|
FreeKind::Linked(_) => panic!("the value is linked"),
|
|
FreeKind::Unbound {
|
|
constraint, lev, ..
|
|
} => (None, lev, constraint),
|
|
FreeKind::NamedUnbound {
|
|
name,
|
|
lev,
|
|
constraint,
|
|
} => (Some(name), lev, constraint),
|
|
}
|
|
}
|
|
|
|
pub fn unwrap_linked(self) -> T {
|
|
match self.0.clone_inner() {
|
|
FreeKind::Linked(t) => t,
|
|
FreeKind::Unbound { .. } | FreeKind::NamedUnbound { .. } => {
|
|
panic!("the value is unbounded")
|
|
}
|
|
}
|
|
}
|
|
|
|
/// returns linked type (panic if self is unbounded)
|
|
/// NOTE: check by `.is_linked` before call
|
|
pub fn crack(&self) -> Ref<'_, T> {
|
|
Ref::map(self.0.borrow(), |f| match f {
|
|
FreeKind::Linked(t) => t,
|
|
FreeKind::Unbound { .. } | FreeKind::NamedUnbound { .. } => {
|
|
panic!("the value is unbounded")
|
|
}
|
|
})
|
|
}
|
|
|
|
pub fn crack_constraint(&self) -> Ref<'_, Constraint> {
|
|
Ref::map(self.0.borrow(), |f| match f {
|
|
FreeKind::Linked(_) => panic!("the value is linked"),
|
|
FreeKind::Unbound { constraint, .. } | FreeKind::NamedUnbound { constraint, .. } => {
|
|
constraint
|
|
}
|
|
})
|
|
}
|
|
|
|
pub fn type_of(&self) -> Option<Type> {
|
|
self.0.borrow().constraint().and_then(|c| c.typ().cloned())
|
|
}
|
|
|
|
pub fn crack_subtype(&self) -> Option<Type> {
|
|
self.0
|
|
.borrow()
|
|
.constraint()
|
|
.and_then(|c| c.super_type().cloned())
|
|
}
|
|
|
|
pub fn crack_bound_types(&self) -> Option<(Type, Type)> {
|
|
self.0
|
|
.borrow()
|
|
.constraint()
|
|
.and_then(|c| c.sub_sup_type().map(|(l, r)| (l.clone(), r.clone())))
|
|
}
|
|
|
|
pub fn is_unbound(&self) -> bool {
|
|
matches!(
|
|
&*self.0.borrow(),
|
|
FreeKind::Unbound { .. } | FreeKind::NamedUnbound { .. }
|
|
)
|
|
}
|
|
|
|
pub fn constraint_is_typeof(&self) -> bool {
|
|
matches!(
|
|
&*self.0.borrow(),
|
|
FreeKind::Unbound { constraint, .. }
|
|
| FreeKind::NamedUnbound { constraint, .. } if constraint.typ().is_some()
|
|
)
|
|
}
|
|
|
|
pub fn constraint_is_supertypeof(&self) -> bool {
|
|
matches!(
|
|
&*self.0.borrow(),
|
|
FreeKind::Unbound { constraint, .. }
|
|
| FreeKind::NamedUnbound { constraint, .. } if constraint.sub_type().is_some()
|
|
)
|
|
}
|
|
|
|
pub fn constraint_is_subtypeof(&self) -> bool {
|
|
matches!(
|
|
&*self.0.borrow(),
|
|
FreeKind::Unbound { constraint, .. }
|
|
| FreeKind::NamedUnbound { constraint, .. } if constraint.super_type().is_some()
|
|
)
|
|
}
|
|
|
|
pub fn constraint_is_sandwiched(&self) -> bool {
|
|
matches!(
|
|
&*self.0.borrow(),
|
|
FreeKind::Unbound { constraint, .. }
|
|
| FreeKind::NamedUnbound { constraint, .. } if constraint.sub_sup_type().is_some()
|
|
)
|
|
}
|
|
|
|
pub fn is_linked(&self) -> bool {
|
|
matches!(&*self.0.borrow(), FreeKind::Linked(_))
|
|
}
|
|
|
|
pub fn unbound_name(&self) -> Option<Str> {
|
|
match &*self.0.borrow() {
|
|
FreeKind::NamedUnbound { name, .. } => Some(name.clone()),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn borrow(&self) -> Ref<'_, FreeKind<T>> {
|
|
self.0.borrow()
|
|
}
|
|
pub fn borrow_mut(&self) -> RefMut<'_, FreeKind<T>> {
|
|
self.0.borrow_mut()
|
|
}
|
|
}
|
|
|
|
impl Free<TyParam> {
|
|
pub fn map<F>(&self, f: F)
|
|
where
|
|
F: Fn(TyParam) -> TyParam,
|
|
{
|
|
match &mut *self.0.borrow_mut() {
|
|
FreeKind::Unbound { .. } | FreeKind::NamedUnbound { .. } => {
|
|
panic!("the value is unbounded")
|
|
}
|
|
FreeKind::Linked(t) => {
|
|
*t = f(mem::take(t));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub type FreeTyVar = Free<Type>;
|
|
pub type FreeTyParam = Free<TyParam>;
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub struct UserConstSubr {
|
|
code: CodeObj,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub struct BuiltinConstSubr {
|
|
subr: fn(Vec<ValueObj>) -> ValueObj,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub enum ConstSubr {
|
|
User(UserConstSubr),
|
|
Builtin(BuiltinConstSubr),
|
|
}
|
|
|
|
impl ConstSubr {
|
|
pub fn call(&self, args: Vec<ValueObj>) -> ValueObj {
|
|
match self {
|
|
ConstSubr::User(_user) => todo!(),
|
|
ConstSubr::Builtin(builtin) => (builtin.subr)(args),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 型引数
|
|
/// データのみ、その評価結果は別に持つ
|
|
/// __Info__: 連携型パラメータがあるので、比較には`rec_eq`を使うこと
|
|
/// * Literal: 1, "aa", True, None, ... (don't use container literals, they can only hold literals)
|
|
/// * Type: Int, Add(?R, ?O), ...
|
|
/// * Mono: I, N, ...
|
|
/// * Attr: math.PI, ...
|
|
/// * Array: `[1, 2, N]`
|
|
/// * Tuple: (1, N, True)
|
|
/// * App: Array(Int), Fib(10), ...
|
|
/// * QuantVar: N: Nat, ...
|
|
/// * FreeVar: ?I: Int, ...
|
|
/// * UnaryOp: -N, ~B, ...
|
|
/// * BinOp: 1 + 1, N * 2, ...
|
|
/// * Erased: _: Type, _: Nat, ...
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub enum TyParam {
|
|
Value(ValueObj),
|
|
Type(Box<Type>),
|
|
Array(Vec<TyParam>),
|
|
Tuple(Vec<TyParam>),
|
|
Mono(Str),
|
|
MonoProj {
|
|
obj: Box<TyParam>,
|
|
attr: Str,
|
|
},
|
|
App {
|
|
name: Str,
|
|
args: Vec<TyParam>,
|
|
},
|
|
UnaryOp {
|
|
op: OpKind,
|
|
val: Box<TyParam>,
|
|
},
|
|
BinOp {
|
|
op: OpKind,
|
|
lhs: Box<TyParam>,
|
|
rhs: Box<TyParam>,
|
|
},
|
|
Erased(Box<Type>),
|
|
MonoQVar(Str),
|
|
PolyQVar {
|
|
name: Str,
|
|
args: Vec<TyParam>,
|
|
},
|
|
FreeVar(FreeTyParam),
|
|
Failure,
|
|
}
|
|
|
|
impl fmt::Display for TyParam {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
self.limited_fmt(f, 10)
|
|
}
|
|
}
|
|
|
|
impl LimitedDisplay for TyParam {
|
|
fn limited_fmt(&self, f: &mut fmt::Formatter<'_>, limit: usize) -> fmt::Result {
|
|
if limit == 0 { return write!(f, "...") }
|
|
match self {
|
|
Self::Value(v) => write!(f, "{v}"),
|
|
Self::Failure => write!(f, "<Failure>"),
|
|
Self::Type(t) => t.limited_fmt(f, limit - 1),
|
|
Self::FreeVar(fv) => fv.limited_fmt(f, limit - 1),
|
|
Self::UnaryOp { op, val } => {
|
|
write!(f, "{}", op)?;
|
|
val.limited_fmt(f, limit - 1)
|
|
}
|
|
Self::BinOp { op, lhs, rhs } => {
|
|
lhs.limited_fmt(f, limit - 1)?;
|
|
write!(f, " {} ", op)?;
|
|
rhs.limited_fmt(f, limit - 1)
|
|
}
|
|
Self::App { name, args } => {
|
|
write!(f, "{}", name)?;
|
|
write!(f, "(")?;
|
|
for (i, arg) in args.iter().enumerate() {
|
|
if i > 0 {
|
|
write!(f, ", ")?;
|
|
}
|
|
arg.limited_fmt(f, limit - 1)?;
|
|
}
|
|
write!(f, ")")?;
|
|
Ok(())
|
|
}
|
|
Self::PolyQVar { name, args } => {
|
|
write!(f, "'{}", name)?;
|
|
write!(f, "(")?;
|
|
for (i, arg) in args.iter().enumerate() {
|
|
if i > 0 {
|
|
write!(f, ", ")?;
|
|
}
|
|
arg.limited_fmt(f, limit - 1)?;
|
|
}
|
|
write!(f, ")")?;
|
|
Ok(())
|
|
}
|
|
Self::Erased(t) => {
|
|
write!(f, "_: ")?;
|
|
t.limited_fmt(f, limit - 1)
|
|
},
|
|
Self::Mono(name) => write!(f, "{}", name),
|
|
Self::MonoQVar(name) => write!(f, "'{}", name),
|
|
Self::MonoProj { obj, attr } => {
|
|
write!(f, "{}.", obj)?;
|
|
write!(f, "{}", attr)
|
|
}
|
|
Self::Array(arr) => {
|
|
write!(f, "[")?;
|
|
for (i, t) in arr.iter().enumerate() {
|
|
if i > 0 {
|
|
write!(f, ", ")?;
|
|
}
|
|
t.limited_fmt(f, limit - 1)?;
|
|
}
|
|
write!(f, "]")
|
|
}
|
|
Self::Tuple(tuple) => {
|
|
write!(f, "(")?;
|
|
for (i, t) in tuple.iter().enumerate() {
|
|
if i > 0 {
|
|
write!(f, ", ")?;
|
|
}
|
|
t.limited_fmt(f, limit - 1)?;
|
|
}
|
|
write!(f, ")")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Default for TyParam {
|
|
#[inline]
|
|
fn default() -> Self {
|
|
Self::Failure
|
|
}
|
|
}
|
|
|
|
impl Add for TyParam {
|
|
type Output = Self;
|
|
fn add(self, rhs: Self) -> Self::Output {
|
|
Self::bin(OpKind::Add, self, rhs)
|
|
}
|
|
}
|
|
|
|
impl Sub for TyParam {
|
|
type Output = Self;
|
|
fn sub(self, rhs: Self) -> Self::Output {
|
|
Self::bin(OpKind::Sub, self, rhs)
|
|
}
|
|
}
|
|
|
|
impl Mul for TyParam {
|
|
type Output = Self;
|
|
fn mul(self, rhs: Self) -> Self::Output {
|
|
Self::bin(OpKind::Mul, self, rhs)
|
|
}
|
|
}
|
|
|
|
impl Div for TyParam {
|
|
type Output = Self;
|
|
fn div(self, rhs: Self) -> Self::Output {
|
|
Self::bin(OpKind::Div, self, rhs)
|
|
}
|
|
}
|
|
|
|
impl Neg for TyParam {
|
|
type Output = Self;
|
|
fn neg(self) -> Self::Output {
|
|
Self::unary(OpKind::Neg, self)
|
|
}
|
|
}
|
|
|
|
impl From<Range<TyParam>> for TyParam {
|
|
fn from(r: Range<TyParam>) -> Self {
|
|
Self::t(Type::int_interval(IntervalOp::RightOpen, r.start, r.end))
|
|
}
|
|
}
|
|
|
|
impl From<Range<&TyParam>> for TyParam {
|
|
fn from(r: Range<&TyParam>) -> Self {
|
|
Self::t(Type::int_interval(
|
|
IntervalOp::RightOpen,
|
|
r.start.clone(),
|
|
r.end.clone(),
|
|
))
|
|
}
|
|
}
|
|
|
|
impl From<RangeInclusive<TyParam>> for TyParam {
|
|
fn from(r: RangeInclusive<TyParam>) -> Self {
|
|
let (start, end) = r.into_inner();
|
|
Self::t(Type::int_interval(IntervalOp::Closed, start, end))
|
|
}
|
|
}
|
|
|
|
impl From<RangeInclusive<&TyParam>> for TyParam {
|
|
fn from(r: RangeInclusive<&TyParam>) -> Self {
|
|
let (start, end) = r.into_inner();
|
|
Self::t(Type::int_interval(
|
|
IntervalOp::Closed,
|
|
start.clone(),
|
|
end.clone(),
|
|
))
|
|
}
|
|
}
|
|
|
|
impl<V: Into<ValueObj>> From<V> for TyParam {
|
|
fn from(v: V) -> Self {
|
|
Self::Value(v.into())
|
|
}
|
|
}
|
|
|
|
impl HasLevel for TyParam {
|
|
fn level(&self) -> Option<Level> {
|
|
match self {
|
|
Self::Type(t) => t.level(),
|
|
Self::FreeVar(fv) => fv.level(),
|
|
Self::UnaryOp { val, .. } => val.level(),
|
|
Self::BinOp { lhs, rhs, .. } => lhs.level().and_then(|l| rhs.level().map(|r| l.max(r))),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn update_level(&self, level: Level) {
|
|
match self {
|
|
Self::FreeVar(fv) => fv.update_level(level),
|
|
Self::UnaryOp { val, .. } => val.update_level(level),
|
|
Self::BinOp { lhs, rhs, .. } => {
|
|
lhs.update_level(level);
|
|
rhs.update_level(level);
|
|
}
|
|
Self::App { args, .. } | Self::PolyQVar { args, .. } => {
|
|
for arg in args.iter() {
|
|
arg.update_level(level);
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
fn lift(&self) {
|
|
match self {
|
|
Self::FreeVar(fv) => fv.lift(),
|
|
Self::UnaryOp { val, .. } => val.lift(),
|
|
Self::BinOp { lhs, rhs, .. } => {
|
|
lhs.lift();
|
|
rhs.lift();
|
|
}
|
|
Self::App { args, .. } | Self::PolyQVar { args, .. } => {
|
|
for arg in args.iter() {
|
|
arg.lift();
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TyParam {
|
|
pub fn t(t: Type) -> Self {
|
|
Self::Type(Box::new(t))
|
|
}
|
|
|
|
pub fn mono<S: Into<Str>>(name: S) -> Self {
|
|
Self::Mono(name.into())
|
|
}
|
|
|
|
pub fn mono_q<S: Into<Str>>(name: S) -> Self {
|
|
Self::MonoQVar(name.into())
|
|
}
|
|
|
|
pub fn mono_proj<S: Into<Str>>(obj: TyParam, attr: S) -> Self {
|
|
Self::MonoProj {
|
|
obj: Box::new(obj),
|
|
attr: attr.into(),
|
|
}
|
|
}
|
|
|
|
// TODO: polymorphic type
|
|
pub fn array_t(t: Str, len: TyParam) -> Self {
|
|
Self::Array(vec![TyParam::t(Type::mono(t)), len])
|
|
}
|
|
|
|
pub fn free_var(level: usize, t: Type) -> Self {
|
|
let constraint = Constraint::type_of(t);
|
|
Self::FreeVar(FreeTyParam::new_unbound(level, constraint))
|
|
}
|
|
|
|
pub fn named_free_var(name: Str, level: usize, t: Type) -> Self {
|
|
let constraint = Constraint::type_of(t);
|
|
Self::FreeVar(FreeTyParam::new_named_unbound(name, level, constraint))
|
|
}
|
|
|
|
#[inline]
|
|
pub fn value<V: Into<ValueObj>>(v: V) -> Self {
|
|
Self::Value(v.into())
|
|
}
|
|
|
|
#[inline]
|
|
pub fn unary(op: OpKind, val: TyParam) -> Self {
|
|
Self::UnaryOp {
|
|
op,
|
|
val: Box::new(val),
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub fn mutate(self) -> Self {
|
|
Self::unary(OpKind::Mutate, self)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn bin(op: OpKind, lhs: TyParam, rhs: TyParam) -> Self {
|
|
Self::BinOp {
|
|
op,
|
|
lhs: Box::new(lhs),
|
|
rhs: Box::new(rhs),
|
|
}
|
|
}
|
|
|
|
pub fn app(name: &'static str, args: Vec<TyParam>) -> Self {
|
|
Self::App {
|
|
name: Str::ever(name),
|
|
args,
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub fn erased(t: Type) -> Self {
|
|
Self::Erased(Box::new(t))
|
|
}
|
|
|
|
// if self: Ratio, Succ(self) => self+ε
|
|
pub fn succ(self) -> Self {
|
|
Self::app("Succ", vec![self])
|
|
}
|
|
|
|
// if self: Ratio, Pred(self) => self-ε
|
|
pub fn pred(self) -> Self {
|
|
Self::app("Pred", vec![self])
|
|
}
|
|
|
|
/// 型変数の内容を考慮した再帰的(Recursive)比較を行う
|
|
pub fn rec_eq(&self, other: &Self) -> bool {
|
|
match (self, other) {
|
|
(Self::Type(l), Self::Type(r)) => l.rec_eq(r),
|
|
(Self::FreeVar(fv), o) | (o, Self::FreeVar(fv)) => match &*fv.borrow() {
|
|
FreeKind::Linked(tp) => tp.rec_eq(o),
|
|
_ => self == o,
|
|
},
|
|
(Self::MonoProj { obj: lo, attr: la }, Self::MonoProj { obj: ro, attr: ra }) => {
|
|
lo.rec_eq(ro) && la == ra
|
|
}
|
|
(Self::Array(l), Self::Array(r)) | (Self::Tuple(l), Self::Tuple(r)) => {
|
|
l.iter().zip(r.iter()).all(|(l, r)| l.rec_eq(r))
|
|
}
|
|
(
|
|
Self::App {
|
|
name: ln,
|
|
args: lps,
|
|
},
|
|
Self::App {
|
|
name: rn,
|
|
args: rps,
|
|
},
|
|
) => ln == rn && lps.iter().zip(rps.iter()).all(|(l, r)| l.rec_eq(r)),
|
|
(Self::UnaryOp { op: lop, val: lv }, Self::UnaryOp { op: rop, val: rv }) => {
|
|
lop == rop && lv.rec_eq(rv)
|
|
}
|
|
(
|
|
Self::BinOp {
|
|
op: lop,
|
|
lhs: ll,
|
|
rhs: lr,
|
|
},
|
|
Self::BinOp {
|
|
op: rop,
|
|
lhs: rl,
|
|
rhs: rr,
|
|
},
|
|
) => lop == rop && ll.rec_eq(rl) && lr.rec_eq(rr),
|
|
(Self::Erased(l), Self::Erased(r)) => l.rec_eq(r),
|
|
_ => self == other,
|
|
}
|
|
}
|
|
|
|
// 定数の比較など環境が必要な場合はContext::try_cmpを使う
|
|
pub fn cheap_cmp(&self, r: &TyParam) -> Option<TyParamOrdering> {
|
|
match (self, r) {
|
|
(Self::Type(l), Self::Type(r)) =>
|
|
if l.rec_eq(r) { Some(TyParamOrdering::Equal) } else { Some(TyParamOrdering::NotEqual) },
|
|
(Self::Value(l), Self::Value(r)) =>
|
|
l.try_cmp(r).map(Into::into),
|
|
(Self::FreeVar(fv), p) if fv.is_linked() =>
|
|
fv.crack().cheap_cmp(p),
|
|
(p, Self::FreeVar(fv)) if fv.is_linked() =>
|
|
p.cheap_cmp(&*fv.crack()),
|
|
(Self::FreeVar{ .. } | Self::Erased(_), Self::FreeVar{ .. } | Self::Erased(_))
|
|
/* if v.is_unbound() */ => Some(Any),
|
|
(Self::App{ name, args }, Self::App{ name: rname, args: rargs })
|
|
| (Self::PolyQVar{ name, args }, Self::PolyQVar{ name: rname, args: rargs }) =>
|
|
if name == rname
|
|
&& args.len() == rargs.len()
|
|
&& args.iter().zip(rargs.iter()).all(|(l, r)| l.cheap_cmp(r) == Some(Equal)) {
|
|
Some(TyParamOrdering::Equal)
|
|
} else {
|
|
Some(TyParamOrdering::NotEqual)
|
|
},
|
|
(l, r @ (Self::Erased(_) | Self::Mono{ .. } | Self::FreeVar{ .. })) =>
|
|
r.cheap_cmp(l).map(|ord| ord.reverse()),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn has_unbound_var(&self) -> bool {
|
|
match self {
|
|
Self::FreeVar(fv) => {
|
|
if fv.is_unbound() {
|
|
true
|
|
} else {
|
|
fv.crack().has_unbound_var()
|
|
}
|
|
}
|
|
Self::Type(t) => t.has_unbound_var(),
|
|
Self::MonoProj { obj, .. } => obj.has_unbound_var(),
|
|
Self::Array(ts) | Self::Tuple(ts) => ts.iter().any(|t| t.has_unbound_var()),
|
|
Self::UnaryOp { val, .. } => val.has_unbound_var(),
|
|
Self::BinOp { lhs, rhs, .. } => lhs.has_unbound_var() || rhs.has_unbound_var(),
|
|
Self::App { args, .. } | Self::PolyQVar { args, .. } => {
|
|
args.iter().any(|p| p.has_unbound_var())
|
|
}
|
|
Self::Erased(t) => t.has_unbound_var(),
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
pub fn has_no_unbound_var(&self) -> bool {
|
|
!self.has_unbound_var()
|
|
}
|
|
|
|
pub fn has_upper_bound(&self) -> bool {
|
|
match self {
|
|
// TODO: 型によっては上限がある
|
|
// また、上限がないもの同士の加算等も上限はない
|
|
Self::Erased(_) | Self::MonoQVar(_) => false,
|
|
Self::FreeVar(fv) => !fv.is_unbound(), // != fv.is_linked(),
|
|
_ => true,
|
|
}
|
|
}
|
|
|
|
pub fn has_lower_bound(&self) -> bool {
|
|
match self {
|
|
Self::Erased(_) | Self::MonoQVar(_) => false,
|
|
Self::FreeVar(fv) => !fv.is_unbound(),
|
|
_ => true,
|
|
}
|
|
}
|
|
|
|
pub fn update_constraint(&self, new_constraint: Constraint) {
|
|
match self {
|
|
Self::Type(t) => t.update_constraint(new_constraint),
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
#[repr(u8)]
|
|
pub enum TyParamOrdering {
|
|
Less,
|
|
Equal,
|
|
Greater,
|
|
LessEqual, // Less or Equal
|
|
NotEqual, // Less or Greater
|
|
GreaterEqual, // Greater or Equal
|
|
Any,
|
|
NoRelation,
|
|
}
|
|
|
|
use TyParamOrdering::*;
|
|
|
|
impl From<Ordering> for TyParamOrdering {
|
|
fn from(o: Ordering) -> Self {
|
|
match o {
|
|
Ordering::Less => Less,
|
|
Ordering::Equal => Equal,
|
|
Ordering::Greater => Greater,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<TyParamOrdering> for Ordering {
|
|
type Error = ();
|
|
fn try_from(o: TyParamOrdering) -> Result<Self, Self::Error> {
|
|
match o {
|
|
Less => Ok(Ordering::Less),
|
|
Equal => Ok(Ordering::Equal),
|
|
Greater => Ok(Ordering::Greater),
|
|
_ => Err(()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TyParamOrdering {
|
|
pub const fn is_lt(&self) -> bool {
|
|
matches!(self, Less | LessEqual | Any)
|
|
}
|
|
pub const fn is_le(&self) -> bool {
|
|
matches!(self, Less | Equal | LessEqual | Any)
|
|
}
|
|
pub const fn is_gt(&self) -> bool {
|
|
matches!(self, Greater | GreaterEqual | Any)
|
|
}
|
|
pub const fn is_ge(&self) -> bool {
|
|
matches!(self, Greater | Equal | GreaterEqual | Any)
|
|
}
|
|
pub const fn is_eq(&self) -> bool {
|
|
matches!(self, Equal | Any)
|
|
}
|
|
pub const fn is_ne(&self) -> bool {
|
|
matches!(self, Less | Greater | NotEqual | Any)
|
|
}
|
|
pub const fn reverse(&self) -> Self {
|
|
match self {
|
|
Less => Greater,
|
|
Greater => Less,
|
|
LessEqual => GreaterEqual,
|
|
GreaterEqual => LessEqual,
|
|
Equal => NotEqual,
|
|
NotEqual => Equal,
|
|
Any | NoRelation => Any,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub enum TyBound {
|
|
// e.g.
|
|
// A :> Int => Sandwiched{sub: Int, mid: A, sup: Obj}
|
|
// A <: {I: Int | I > 0} => Sandwiched{sub: Never, mid: A, sup: {I: Int | I > 0}}
|
|
/// Sub <: Mid <: Sup
|
|
Sandwiched {
|
|
sub: Type,
|
|
mid: Type,
|
|
sup: Type,
|
|
},
|
|
// TyParam::MonoQuantVarに型の情報が含まれているので、boundsからは除去される
|
|
// e.g. N: Nat => Instance{name: N, t: Nat}
|
|
Instance {
|
|
name: Str,
|
|
t: Type,
|
|
},
|
|
}
|
|
|
|
impl fmt::Display for TyBound {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
Self::Sandwiched { sub, mid, sup } => {
|
|
if sub.rec_eq(&Type::Never) {
|
|
write!(f, "{mid} <: {sup}")
|
|
} else if sup.rec_eq(&Type::Obj) {
|
|
write!(f, "{sub} <: {mid}")
|
|
} else {
|
|
write!(f, "{sub} <: {mid} <: {sup}")
|
|
}
|
|
}
|
|
Self::Instance { name, t } => write!(f, "'{name}: {t}"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl HasLevel for TyBound {
|
|
fn level(&self) -> Option<usize> {
|
|
todo!()
|
|
}
|
|
|
|
fn update_level(&self, level: usize) {
|
|
match self {
|
|
Self::Sandwiched { sub, mid, sup } => {
|
|
sub.update_level(level);
|
|
mid.update_level(level);
|
|
sup.update_level(level);
|
|
}
|
|
Self::Instance { t, .. } => {
|
|
t.update_level(level);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn lift(&self) {
|
|
match self {
|
|
Self::Sandwiched { sub, mid, sup } => {
|
|
sub.lift();
|
|
mid.lift();
|
|
sup.lift();
|
|
}
|
|
Self::Instance { t, .. } => {
|
|
t.lift();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TyBound {
|
|
pub const fn sandwiched(sub: Type, mid: Type, sup: Type) -> Self {
|
|
Self::Sandwiched { sub, mid, sup }
|
|
}
|
|
|
|
pub const fn subtype_of(sub: Type, sup: Type) -> Self {
|
|
Self::sandwiched(Type::Never, sub, sup)
|
|
}
|
|
|
|
pub const fn static_instance(name: &'static str, t: Type) -> Self {
|
|
Self::Instance {
|
|
name: Str::ever(name),
|
|
t,
|
|
}
|
|
}
|
|
|
|
pub const fn instance(name: Str, t: Type) -> Self {
|
|
Self::Instance { name, t }
|
|
}
|
|
|
|
pub fn mentions_as_instance(&self, name: &str) -> bool {
|
|
matches!(self, Self::Instance{ name: n, .. } if &n[..] == name)
|
|
}
|
|
|
|
pub fn mentions_as_subtype(&self, name: &str) -> bool {
|
|
matches!(self, Self::Sandwiched{ sub, .. } if sub.name() == name)
|
|
}
|
|
|
|
pub fn has_unbound_var(&self) -> bool {
|
|
match self {
|
|
Self::Sandwiched { sub, mid, sup } => {
|
|
sub.has_unbound_var() || mid.has_unbound_var() || sup.has_unbound_var()
|
|
}
|
|
Self::Instance { t, .. } => t.has_unbound_var(),
|
|
}
|
|
}
|
|
|
|
pub const fn t(&self) -> &Type {
|
|
match self {
|
|
Self::Sandwiched { .. } => todo!(),
|
|
Self::Instance { t, .. } => t,
|
|
}
|
|
}
|
|
|
|
pub fn lhs(&self) -> &str {
|
|
match self {
|
|
Self::Sandwiched { mid, .. } => mid.name(),
|
|
Self::Instance { name, .. } => name,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub enum Predicate {
|
|
Value(ValueObj), // True/False
|
|
Const(Str),
|
|
/// i == 0 => Eq{ lhs: "i", rhs: 0 }
|
|
Equal {
|
|
lhs: Str,
|
|
rhs: TyParam,
|
|
},
|
|
/// i > 0 => i >= 0+ε => GreaterEqual{ lhs: "i", rhs: 0+ε }
|
|
GreaterEqual {
|
|
lhs: Str,
|
|
rhs: TyParam,
|
|
},
|
|
LessEqual {
|
|
lhs: Str,
|
|
rhs: TyParam,
|
|
},
|
|
NotEqual {
|
|
lhs: Str,
|
|
rhs: TyParam,
|
|
},
|
|
Or(Box<Predicate>, Box<Predicate>),
|
|
And(Box<Predicate>, Box<Predicate>),
|
|
Not(Box<Predicate>, Box<Predicate>),
|
|
}
|
|
|
|
impl fmt::Display for Predicate {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
Self::Value(v) => write!(f, "{v}"),
|
|
Self::Const(c) => write!(f, "{c}"),
|
|
Self::Equal { lhs, rhs } => write!(f, "{lhs} == {rhs}"),
|
|
Self::GreaterEqual { lhs, rhs } => write!(f, "{lhs} >= {rhs}"),
|
|
Self::LessEqual { lhs, rhs } => write!(f, "{lhs} <= {rhs}"),
|
|
Self::NotEqual { lhs, rhs } => write!(f, "{lhs} != {rhs}"),
|
|
Self::Or(l, r) => write!(f, "({l}) or ({r})"),
|
|
Self::And(l, r) => write!(f, "({l}) and ({r})"),
|
|
Self::Not(l, r) => write!(f, "({l}) not ({r})"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl HasLevel for Predicate {
|
|
fn level(&self) -> Option<usize> {
|
|
match self {
|
|
Self::Value(_) | Self::Const(_) => None,
|
|
Self::Equal { rhs, .. }
|
|
| Self::GreaterEqual { rhs, .. }
|
|
| Self::LessEqual { rhs, .. }
|
|
| Self::NotEqual { rhs, .. } => rhs.level(),
|
|
Self::And(_lhs, _rhs) | Self::Or(_lhs, _rhs) | Self::Not(_lhs, _rhs) => todo!(),
|
|
}
|
|
}
|
|
|
|
fn update_level(&self, level: usize) {
|
|
match self {
|
|
Self::Value(_) | Self::Const(_) => {}
|
|
Self::Equal { rhs, .. }
|
|
| Self::GreaterEqual { rhs, .. }
|
|
| Self::LessEqual { rhs, .. }
|
|
| Self::NotEqual { rhs, .. } => {
|
|
rhs.update_level(level);
|
|
}
|
|
Self::And(lhs, rhs) | Self::Or(lhs, rhs) | Self::Not(lhs, rhs) => {
|
|
lhs.update_level(level);
|
|
rhs.update_level(level);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn lift(&self) {
|
|
match self {
|
|
Self::Value(_) | Self::Const(_) => {}
|
|
Self::Equal { rhs, .. }
|
|
| Self::GreaterEqual { rhs, .. }
|
|
| Self::LessEqual { rhs, .. }
|
|
| Self::NotEqual { rhs, .. } => {
|
|
rhs.lift();
|
|
}
|
|
Self::And(lhs, rhs) | Self::Or(lhs, rhs) | Self::Not(lhs, rhs) => {
|
|
lhs.lift();
|
|
rhs.lift();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Predicate {
|
|
pub const fn eq(lhs: Str, rhs: TyParam) -> Self {
|
|
Self::Equal { lhs, rhs }
|
|
}
|
|
pub const fn ne(lhs: Str, rhs: TyParam) -> Self {
|
|
Self::NotEqual { lhs, rhs }
|
|
}
|
|
/// >=
|
|
pub const fn ge(lhs: Str, rhs: TyParam) -> Self {
|
|
Self::GreaterEqual { lhs, rhs }
|
|
}
|
|
/// <=
|
|
pub const fn le(lhs: Str, rhs: TyParam) -> Self {
|
|
Self::LessEqual { lhs, rhs }
|
|
}
|
|
|
|
pub fn and(lhs: Predicate, rhs: Predicate) -> Self {
|
|
Self::And(Box::new(lhs), Box::new(rhs))
|
|
}
|
|
|
|
pub fn or(lhs: Predicate, rhs: Predicate) -> Self {
|
|
Self::Or(Box::new(lhs), Box::new(rhs))
|
|
}
|
|
|
|
pub fn not(lhs: Predicate, rhs: Predicate) -> Self {
|
|
Self::Not(Box::new(lhs), Box::new(rhs))
|
|
}
|
|
|
|
pub fn subject(&self) -> Option<&str> {
|
|
match self {
|
|
Self::Equal { lhs, .. }
|
|
| Self::LessEqual { lhs, .. }
|
|
| Self::GreaterEqual { lhs, .. }
|
|
| Self::NotEqual { lhs, .. } => Some(&lhs[..]),
|
|
Self::And(lhs, rhs) | Self::Or(lhs, rhs) | Self::Not(lhs, rhs) => {
|
|
let l = lhs.subject();
|
|
let r = rhs.subject();
|
|
if l != r {
|
|
todo!()
|
|
} else {
|
|
l
|
|
}
|
|
}
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn change_subject_name(self, name: Str) -> Self {
|
|
match self {
|
|
Self::Equal { rhs, .. } => Self::eq(name, rhs),
|
|
Self::GreaterEqual { rhs, .. } => Self::ge(name, rhs),
|
|
Self::LessEqual { rhs, .. } => Self::le(name, rhs),
|
|
Self::NotEqual { rhs, .. } => Self::ne(name, rhs),
|
|
Self::And(lhs, rhs) => Self::and(
|
|
lhs.change_subject_name(name.clone()),
|
|
rhs.change_subject_name(name),
|
|
),
|
|
Self::Or(lhs, rhs) => Self::or(
|
|
lhs.change_subject_name(name.clone()),
|
|
rhs.change_subject_name(name),
|
|
),
|
|
Self::Not(lhs, rhs) => Self::not(
|
|
lhs.change_subject_name(name.clone()),
|
|
rhs.change_subject_name(name),
|
|
),
|
|
_ => self,
|
|
}
|
|
}
|
|
|
|
pub fn mentions(&self, name: &str) -> bool {
|
|
match self {
|
|
Self::Const(n) => &n[..] == name,
|
|
Self::Equal { lhs, .. }
|
|
| Self::LessEqual { lhs, .. }
|
|
| Self::GreaterEqual { lhs, .. }
|
|
| Self::NotEqual { lhs, .. } => &lhs[..] == name,
|
|
Self::And(lhs, rhs) | Self::Or(lhs, rhs) | Self::Not(lhs, rhs) => {
|
|
lhs.mentions(name) || rhs.mentions(name)
|
|
}
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
pub fn can_be_false(&self) -> bool {
|
|
match self {
|
|
Self::Value(l) => matches!(l, ValueObj::Bool(false)),
|
|
Self::Const(_) => todo!(),
|
|
Self::Or(lhs, rhs) => lhs.can_be_false() || rhs.can_be_false(),
|
|
Self::And(lhs, rhs) => lhs.can_be_false() && rhs.can_be_false(),
|
|
Self::Not(lhs, rhs) => lhs.can_be_false() && !rhs.can_be_false(),
|
|
_ => true,
|
|
}
|
|
}
|
|
|
|
pub fn has_unbound_var(&self) -> bool {
|
|
match self {
|
|
Self::Value(_) => false,
|
|
Self::Const(_) => false,
|
|
Self::Equal { rhs, .. }
|
|
| Self::GreaterEqual { rhs, .. }
|
|
| Self::LessEqual { rhs, .. }
|
|
| Self::NotEqual { rhs, .. } => rhs.has_unbound_var(),
|
|
Self::Or(lhs, rhs) | Self::And(lhs, rhs) | Self::Not(lhs, rhs) => {
|
|
lhs.has_unbound_var() || rhs.has_unbound_var()
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn min_max<'a>(
|
|
&'a self,
|
|
min: Option<&'a TyParam>,
|
|
max: Option<&'a TyParam>,
|
|
) -> (Option<&'a TyParam>, Option<&'a TyParam>) {
|
|
match self {
|
|
Predicate::Equal { rhs: _, .. } => todo!(),
|
|
// {I | I <= 1; I <= 2}
|
|
Predicate::LessEqual { rhs, .. } => (
|
|
min,
|
|
max.map(|l: &TyParam| match l.cheap_cmp(rhs) {
|
|
Some(c) if c.is_ge() => l,
|
|
Some(_) => rhs,
|
|
_ => l,
|
|
})
|
|
.or(Some(rhs)),
|
|
),
|
|
// {I | I >= 1; I >= 2}
|
|
Predicate::GreaterEqual { rhs, .. } => (
|
|
min.map(|l: &TyParam| match l.cheap_cmp(rhs) {
|
|
Some(c) if c.is_le() => l,
|
|
Some(_) => rhs,
|
|
_ => l,
|
|
})
|
|
.or(Some(rhs)),
|
|
max,
|
|
),
|
|
Predicate::And(_l, _r) => todo!(),
|
|
_ => todo!(),
|
|
}
|
|
}
|
|
|
|
pub fn typarams(&self) -> Vec<&TyParam> {
|
|
match self {
|
|
Self::Value(_) | Self::Const(_) => vec![],
|
|
Self::Equal { rhs, .. }
|
|
| Self::GreaterEqual { rhs, .. }
|
|
| Self::LessEqual { rhs, .. }
|
|
| Self::NotEqual { rhs, .. } => vec![rhs],
|
|
Self::And(lhs, rhs) | Self::Or(lhs, rhs) | Self::Not(lhs, rhs) => {
|
|
lhs.typarams().into_iter().chain(rhs.typarams()).collect()
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn typarams_mut(&mut self) -> Vec<&mut TyParam> {
|
|
match self {
|
|
Self::Value(_) | Self::Const(_) => vec![],
|
|
Self::Equal { rhs, .. }
|
|
| Self::GreaterEqual { rhs, .. }
|
|
| Self::LessEqual { rhs, .. }
|
|
| Self::NotEqual { rhs, .. } => vec![rhs],
|
|
Self::And(lhs, rhs) | Self::Or(lhs, rhs) | Self::Not(lhs, rhs) => lhs
|
|
.typarams_mut()
|
|
.into_iter()
|
|
.chain(rhs.typarams_mut())
|
|
.collect(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
pub enum IntervalOp {
|
|
/// ..
|
|
Closed,
|
|
/// <..
|
|
LeftOpen,
|
|
/// ..<
|
|
RightOpen,
|
|
/// <..<
|
|
Open,
|
|
}
|
|
|
|
impl IntervalOp {
|
|
pub const fn is_closed(&self) -> bool {
|
|
matches!(self, Self::Closed)
|
|
}
|
|
pub const fn is_left_open(&self) -> bool {
|
|
matches!(self, Self::LeftOpen | Self::Open)
|
|
}
|
|
pub const fn is_right_open(&self) -> bool {
|
|
matches!(self, Self::RightOpen | Self::Open)
|
|
}
|
|
pub const fn is_open(&self) -> bool {
|
|
matches!(self, Self::Open)
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for IntervalOp {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
Self::Closed => write!(f, ".."),
|
|
Self::LeftOpen => write!(f, "<.."),
|
|
Self::RightOpen => write!(f, "..<"),
|
|
Self::Open => write!(f, "<..<"),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub struct ParamTy {
|
|
pub name: Option<Str>,
|
|
pub ty: Type,
|
|
}
|
|
|
|
impl fmt::Display for ParamTy {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
if let Some(name) = &self.name {
|
|
write!(f, "{}: {}", name, self.ty)
|
|
} else {
|
|
write!(f, "{}", self.ty)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ParamTy {
|
|
pub const fn new(name: Option<Str>, ty: Type) -> Self {
|
|
Self { name, ty }
|
|
}
|
|
|
|
pub const fn named(name: Str, ty: Type) -> Self {
|
|
Self {
|
|
name: Some(name),
|
|
ty,
|
|
}
|
|
}
|
|
|
|
pub const fn anonymous(ty: Type) -> Self {
|
|
Self::new(None, ty)
|
|
}
|
|
}
|
|
|
|
/// e.g.
|
|
/// (x: Int, ?base: Int) -> Int
|
|
/// => SubrTy{ kind: Func, non_default_params: [x: Int], default_params: [base: Int] return_t: Int }
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub struct SubrType {
|
|
pub kind: SubrKind,
|
|
pub non_default_params: Vec<ParamTy>,
|
|
pub default_params: Vec<ParamTy>,
|
|
pub return_t: Box<Type>,
|
|
}
|
|
|
|
impl fmt::Display for SubrType {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
self.limited_fmt(f, 10)
|
|
}
|
|
}
|
|
|
|
impl SubrType {
|
|
pub fn new(
|
|
kind: SubrKind,
|
|
non_default_params: Vec<ParamTy>,
|
|
default_params: Vec<ParamTy>,
|
|
return_t: Type,
|
|
) -> Self {
|
|
Self {
|
|
kind,
|
|
non_default_params,
|
|
default_params,
|
|
return_t: Box::new(return_t),
|
|
}
|
|
}
|
|
|
|
pub fn varargs_idx(&self) -> (Option<usize>, Option<usize>) {
|
|
(
|
|
self.non_default_params
|
|
.iter()
|
|
.position(|t| t.ty.is_varargs()),
|
|
self.default_params.iter().position(|t| t.ty.is_varargs()),
|
|
)
|
|
}
|
|
|
|
pub fn limited_fmt(&self, f: &mut fmt::Formatter<'_>, limit: usize) -> fmt::Result {
|
|
if limit == 0 {
|
|
return write!(f, "...");
|
|
}
|
|
let mut default_params = String::new();
|
|
for default_param in self.default_params.iter() {
|
|
default_params.push_str(&format!(
|
|
"{} |= {}, ",
|
|
default_param.name.as_ref().unwrap(),
|
|
default_param.ty
|
|
));
|
|
}
|
|
default_params.pop();
|
|
default_params.pop();
|
|
write!(
|
|
f,
|
|
"{}({}, {}) {} {}",
|
|
self.kind.prefix(),
|
|
fmt_vec(&self.non_default_params),
|
|
default_params,
|
|
self.kind.arrow(),
|
|
self.return_t,
|
|
)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub enum RefineKind {
|
|
Interval { min: TyParam, max: TyParam }, // e.g. {I: Int | I >= 2; I <= 10} 2..10
|
|
Enum(Set<TyParam>), // e.g. {I: Int | I == 1 or I == 2} {1, 2}
|
|
Complex,
|
|
}
|
|
|
|
/// e.g.
|
|
/// ```
|
|
/// {I: Int | I >= 0}
|
|
/// {_: StrWithLen N | N >= 0}
|
|
/// {T: (Int, Int) | T.0 >= 0, T.1 >= 0}
|
|
/// ```
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub struct RefinementType {
|
|
pub var: Str,
|
|
pub t: Box<Type>,
|
|
pub preds: Set<Predicate>,
|
|
}
|
|
|
|
impl fmt::Display for RefinementType {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(
|
|
f,
|
|
"{{{}: {} | {}}}",
|
|
self.var,
|
|
self.t,
|
|
fmt_set_split_with(&self.preds, "; ")
|
|
)
|
|
}
|
|
}
|
|
|
|
impl RefinementType {
|
|
pub fn new(var: Str, t: Type, preds: Set<Predicate>) -> Self {
|
|
Self {
|
|
var,
|
|
t: Box::new(t),
|
|
preds,
|
|
}
|
|
}
|
|
|
|
pub fn bound(&self) -> TyBound {
|
|
TyBound::instance(self.var.clone(), *self.t.clone())
|
|
}
|
|
|
|
pub fn limited_fmt(&self, f: &mut fmt::Formatter<'_>, limit: usize) -> fmt::Result {
|
|
write!(f, "{{{}: ", self.var)?;
|
|
self.t.limited_fmt(f, limit - 1)?;
|
|
write!(f, "| {}}}", fmt_set_split_with(&self.preds, "; "))
|
|
}
|
|
}
|
|
|
|
/// e.g.
|
|
/// ```
|
|
/// |T: Type| T -> T == Quantified{ unbound_t: (T -> T), bounds: [T: Type] }
|
|
/// ```
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub struct QuantifiedType {
|
|
pub unbound_callable: Box<Type>,
|
|
pub bounds: Set<TyBound>,
|
|
}
|
|
|
|
impl fmt::Display for QuantifiedType {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
self.limited_fmt(f, 10)
|
|
}
|
|
}
|
|
|
|
impl QuantifiedType {
|
|
pub fn new(unbound_callable: Type, bounds: Set<TyBound>) -> Self {
|
|
Self {
|
|
unbound_callable: Box::new(unbound_callable),
|
|
bounds,
|
|
}
|
|
}
|
|
|
|
pub fn limited_fmt(&self, f: &mut fmt::Formatter<'_>, limit: usize) -> fmt::Result {
|
|
write!(f, "|{}| ", fmt_set_split_with(&self.bounds, "; "))?;
|
|
self.unbound_callable.limited_fmt(f, limit)
|
|
}
|
|
}
|
|
|
|
type SelfType = Type;
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub enum SubrKind {
|
|
Func,
|
|
Proc,
|
|
FuncMethod(Box<SelfType>),
|
|
ProcMethod {
|
|
before: Box<SelfType>,
|
|
after: Option<Box<SelfType>>,
|
|
},
|
|
}
|
|
|
|
impl HasLevel for SubrKind {
|
|
fn level(&self) -> Option<Level> {
|
|
todo!()
|
|
}
|
|
|
|
fn update_level(&self, level: usize) {
|
|
match self {
|
|
Self::FuncMethod(t) => t.update_level(level),
|
|
Self::ProcMethod { before, after } => {
|
|
before.update_level(level);
|
|
if let Some(t) = after.as_ref() {
|
|
t.update_level(level);
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
fn lift(&self) {
|
|
match self {
|
|
Self::FuncMethod(t) => t.lift(),
|
|
Self::ProcMethod { before, after } => {
|
|
before.lift();
|
|
if let Some(t) = after.as_ref() {
|
|
t.lift();
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl SubrKind {
|
|
pub fn fn_met(t: SelfType) -> Self {
|
|
SubrKind::FuncMethod(Box::new(t))
|
|
}
|
|
|
|
pub fn pr_met(before: SelfType, after: Option<SelfType>) -> Self {
|
|
Self::ProcMethod {
|
|
before: Box::new(before),
|
|
after: after.map(Box::new),
|
|
}
|
|
}
|
|
|
|
pub const fn arrow(&self) -> &str {
|
|
match self {
|
|
Self::Func | Self::FuncMethod(_) => "->",
|
|
Self::Proc | Self::ProcMethod { .. } => "=>",
|
|
}
|
|
}
|
|
|
|
pub const fn inner_len(&self) -> usize {
|
|
match self {
|
|
Self::Func | Self::Proc => 0,
|
|
Self::FuncMethod(_) | Self::ProcMethod { .. } => 1,
|
|
}
|
|
}
|
|
|
|
pub fn prefix(&self) -> String {
|
|
match self {
|
|
Self::Func | Self::Proc => "".to_string(),
|
|
Self::FuncMethod(t) => format!("{t}."),
|
|
Self::ProcMethod { before, after } => {
|
|
if let Some(after) = after {
|
|
format!("({before} ~> {after}).")
|
|
} else {
|
|
format!("{before}.")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn has_unbound_var(&self) -> bool {
|
|
match self {
|
|
Self::Func | Self::Proc => false,
|
|
Self::FuncMethod(t) => t.has_unbound_var(),
|
|
Self::ProcMethod { before, after } => {
|
|
before.has_unbound_var()
|
|
|| after.as_ref().map(|t| t.has_unbound_var()).unwrap_or(false)
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn same_kind_as(&self, other: &Self) -> bool {
|
|
matches!(
|
|
(self, other),
|
|
(Self::Func, Self::Func)
|
|
| (Self::Proc, Self::Proc)
|
|
| (Self::FuncMethod(_), Self::FuncMethod(_))
|
|
| (Self::ProcMethod { .. }, Self::ProcMethod { .. })
|
|
)
|
|
}
|
|
|
|
pub fn self_t(&self) -> Option<&SelfType> {
|
|
match self {
|
|
Self::FuncMethod(t) | Self::ProcMethod { before: t, .. } => Some(t),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn self_t_mut(&mut self) -> Option<&mut SelfType> {
|
|
match self {
|
|
Self::FuncMethod(t) | Self::ProcMethod { before: t, .. } => Some(t),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
pub enum Ownership {
|
|
Owned,
|
|
Ref,
|
|
RefMut,
|
|
}
|
|
|
|
impl Ownership {
|
|
pub const fn is_owned(&self) -> bool {
|
|
matches!(self, Self::Owned)
|
|
}
|
|
pub const fn is_ref(&self) -> bool {
|
|
matches!(self, Self::Ref)
|
|
}
|
|
pub const fn is_refmut(&self) -> bool {
|
|
matches!(self, Self::RefMut)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub enum ArgsOwnership {
|
|
Args {
|
|
self_: Option<Ownership>,
|
|
non_defaults: Vec<Ownership>,
|
|
defaults: Vec<Ownership>,
|
|
},
|
|
VarArgs(Ownership), // TODO: defaults
|
|
VarArgsDefault(Ownership),
|
|
}
|
|
|
|
impl ArgsOwnership {
|
|
pub const fn args(
|
|
self_: Option<Ownership>,
|
|
non_defaults: Vec<Ownership>,
|
|
defaults: Vec<Ownership>,
|
|
) -> Self {
|
|
Self::Args {
|
|
self_,
|
|
non_defaults,
|
|
defaults,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// NOTE: 連携型変数があるので、比較には`ref_eq`を使うこと
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub enum Type {
|
|
/* Monomorphic (builtin) types */
|
|
Obj, // {=}
|
|
Int,
|
|
Nat,
|
|
Ratio,
|
|
Float,
|
|
Bool,
|
|
Str,
|
|
NoneType,
|
|
Code,
|
|
Module,
|
|
Frame,
|
|
Error,
|
|
Inf, // {∞}
|
|
NegInf, // {-∞}
|
|
// TODO: PolyType/Class
|
|
Type,
|
|
Class,
|
|
Trait,
|
|
Patch,
|
|
NotImplemented,
|
|
Ellipsis, // これはクラスのほうで型推論用のマーカーではない
|
|
Never, // {}
|
|
Mono(Str), // others
|
|
/* Polymorphic types */
|
|
Ref(Box<Type>),
|
|
RefMut(Box<Type>),
|
|
Subr(SubrType),
|
|
// CallableはProcの上位型なので、変数に!をつける
|
|
Callable {
|
|
param_ts: Vec<Type>,
|
|
return_t: Box<Type>,
|
|
},
|
|
Record(Dict<Field, Type>), // e.g. {x = Int}
|
|
// e.g. {T -> T | T: Type}, {I: Int | I > 0}, {S | N: Nat; S: Str N; N > 1}
|
|
// 区間型と列挙型は篩型に変換される
|
|
// f 0 = ...はf _: {0} == {I: Int | I == 0}のシンタックスシュガー
|
|
// e.g.
|
|
// {0, 1, 2} => {I: Int | I == 0 or I == 1 or I == 2}
|
|
// 1..10 => {I: Int | I >= 1 and I <= 10}
|
|
Refinement(RefinementType),
|
|
// e.g. |T: Type| T -> T
|
|
Quantified(QuantifiedType),
|
|
And(Box<Type>, Box<Type>),
|
|
Not(Box<Type>, Box<Type>),
|
|
Or(Box<Type>, Box<Type>),
|
|
VarArgs(Box<Type>), // ...T
|
|
Poly {
|
|
name: Str,
|
|
params: Vec<TyParam>,
|
|
}, // T(params)
|
|
/* Special types (inference-time types) */
|
|
MonoQVar(Str), // QuantifiedTyの中で使う一般化型変数、利便性のためMonoとは区別する
|
|
PolyQVar {
|
|
name: Str,
|
|
params: Vec<TyParam>,
|
|
},
|
|
FreeVar(FreeTyVar), // a reference to the type of other expression, see docs/compiler/inference.md
|
|
MonoProj {
|
|
lhs: Box<Type>,
|
|
rhs: Str,
|
|
}, // e.g. T.U
|
|
Failure, // when failed to infer (e.g. get the type of `match`)
|
|
/// used to represent `TyParam` is not initialized (see `erg_compiler::context::instantiate_tp`)
|
|
Uninited,
|
|
}
|
|
|
|
impl fmt::Display for Type {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
self.limited_fmt(f, 10)
|
|
}
|
|
}
|
|
|
|
impl LimitedDisplay for Type {
|
|
fn limited_fmt(&self, f: &mut fmt::Formatter<'_>, limit: usize) -> fmt::Result {
|
|
if limit == 0 {
|
|
return write!(f, "...");
|
|
}
|
|
match self {
|
|
Self::Mono(name) => write!(f, "{name}"),
|
|
Self::Ref(t) | Self::RefMut(t) => {
|
|
write!(f, "{}(", self.name())?;
|
|
t.limited_fmt(f, limit - 1)?;
|
|
write!(f, ")")
|
|
}
|
|
Self::Subr(sub) => sub.limited_fmt(f, limit - 1),
|
|
Self::Callable { param_ts, return_t } => {
|
|
write!(f, "Callable((")?;
|
|
for (i, t) in param_ts.iter().enumerate() {
|
|
if i > 0 {
|
|
write!(f, ", ")?;
|
|
}
|
|
t.limited_fmt(f, limit - 1)?;
|
|
}
|
|
write!(f, "), ")?;
|
|
return_t.limited_fmt(f, limit - 1)?;
|
|
write!(f, ")")
|
|
}
|
|
Self::Record(attrs) => {
|
|
write!(f, "{{")?;
|
|
if let Some((field, t)) = attrs.iter().next() {
|
|
write!(f, "{field} = ")?;
|
|
t.limited_fmt(f, limit - 1)?;
|
|
}
|
|
for (field, t) in attrs.iter().skip(1) {
|
|
write!(f, "; {field} = ")?;
|
|
t.limited_fmt(f, limit - 1)?;
|
|
}
|
|
write!(f, "}}")
|
|
}
|
|
Self::Refinement(refinement) => refinement.limited_fmt(f, limit - 1),
|
|
Self::Quantified(quantified) => quantified.limited_fmt(f, limit - 1),
|
|
Self::And(lhs, rhs) => {
|
|
lhs.limited_fmt(f, limit - 1)?;
|
|
write!(f, " and ")?;
|
|
rhs.limited_fmt(f, limit - 1)
|
|
},
|
|
Self::Not(lhs, rhs) => {
|
|
lhs.limited_fmt(f, limit - 1)?;
|
|
write!(f, " not ")?;
|
|
rhs.limited_fmt(f, limit - 1)
|
|
}
|
|
Self::Or(lhs, rhs) => {
|
|
lhs.limited_fmt(f, limit - 1)?;
|
|
write!(f, " or ")?;
|
|
rhs.limited_fmt(f, limit - 1)
|
|
}
|
|
Self::VarArgs(t) => {
|
|
write!(f, "...")?;
|
|
t.limited_fmt(f, limit - 1)
|
|
},
|
|
Self::Poly { name, params } => {
|
|
write!(f, "{name}(")?;
|
|
for (i, tp) in params.iter().enumerate() {
|
|
if i > 0 {
|
|
write!(f, ", ")?;
|
|
}
|
|
tp.limited_fmt(f, limit - 1)?;
|
|
}
|
|
write!(f, ")")
|
|
}
|
|
Self::MonoQVar(name) => write!(f, "'{name}"),
|
|
Self::FreeVar(fv) => fv.limited_fmt(f, limit - 1),
|
|
Self::MonoProj { lhs, rhs } => {
|
|
lhs.limited_fmt(f, limit - 1)?;
|
|
write!(f, ".{rhs}")
|
|
},
|
|
_ => write!(f, "{}", self.name()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Default for Type {
|
|
fn default() -> Self {
|
|
Self::Failure
|
|
}
|
|
}
|
|
|
|
impl From<Range<TyParam>> for Type {
|
|
fn from(r: Range<TyParam>) -> Self {
|
|
Type::int_interval(IntervalOp::RightOpen, r.start, r.end)
|
|
}
|
|
}
|
|
|
|
impl From<Range<&TyParam>> for Type {
|
|
fn from(r: Range<&TyParam>) -> Self {
|
|
Type::int_interval(IntervalOp::RightOpen, r.start.clone(), r.end.clone())
|
|
}
|
|
}
|
|
|
|
impl From<RangeInclusive<TyParam>> for Type {
|
|
fn from(r: RangeInclusive<TyParam>) -> Self {
|
|
let (start, end) = r.into_inner();
|
|
Type::int_interval(IntervalOp::Closed, start, end)
|
|
}
|
|
}
|
|
|
|
impl From<RangeInclusive<&TyParam>> for Type {
|
|
fn from(r: RangeInclusive<&TyParam>) -> Self {
|
|
let (start, end) = r.into_inner();
|
|
Type::int_interval(IntervalOp::Closed, start.clone(), end.clone())
|
|
}
|
|
}
|
|
|
|
impl From<&str> for Type {
|
|
fn from(item: &str) -> Self {
|
|
match item {
|
|
"Obj" => Self::Obj,
|
|
"Int" => Self::Int,
|
|
"Nat" => Self::Nat,
|
|
"Ratio" => Self::Ratio,
|
|
"Float" => Self::Float,
|
|
"Bool" => Self::Bool,
|
|
"Str" => Self::Str,
|
|
"NoneType" => Self::NoneType,
|
|
"Type" => Self::Type,
|
|
"Class" => Self::Class,
|
|
"Trait" => Self::Trait,
|
|
"Patch" => Self::Patch,
|
|
"Code" => Self::Code,
|
|
"Module" => Self::Module,
|
|
"Frame" => Self::Frame,
|
|
"Error" => Self::Error,
|
|
// "Array" => Self::Array(Box::new(Type::Illegal)),
|
|
"Ellipsis" => Self::Ellipsis,
|
|
"NotImplemented" => Self::NotImplemented,
|
|
"Never" => Self::Never,
|
|
"Inf" => Self::Inf,
|
|
"_" => Self::Top(),
|
|
other => Self::Mono(Str::rc(other)),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn get_t_from_tp(tp: &TyParam) -> Option<Type> {
|
|
match tp {
|
|
TyParam::FreeVar(fv) if fv.is_linked() => get_t_from_tp(&fv.crack()),
|
|
TyParam::Type(t) => Some(*t.clone()),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
impl HasType for Type {
|
|
#[inline]
|
|
fn ref_t(&self) -> &Type {
|
|
self
|
|
}
|
|
#[inline]
|
|
fn ref_mut_t(&mut self) -> &mut Type {
|
|
self
|
|
}
|
|
fn inner_ts(&self) -> Vec<Type> {
|
|
match self {
|
|
Self::Ref(t) | Self::RefMut(t) | Self::VarArgs(t) => {
|
|
vec![t.as_ref().clone()]
|
|
}
|
|
// Self::And(ts) | Self::Or(ts) => ,
|
|
Self::Subr(_sub) => todo!(),
|
|
Self::Callable { param_ts, .. } => param_ts.clone(),
|
|
Self::Poly { params, .. } => params.iter().filter_map(get_t_from_tp).collect(),
|
|
_ => vec![],
|
|
}
|
|
}
|
|
fn signature_t(&self) -> Option<&Type> {
|
|
None
|
|
}
|
|
fn signature_mut_t(&mut self) -> Option<&mut Type> {
|
|
None
|
|
}
|
|
}
|
|
|
|
impl HasLevel for Type {
|
|
// FIXME: 複合型のレベル
|
|
fn level(&self) -> Option<usize> {
|
|
match self {
|
|
Self::FreeVar(v) => v.level(),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn update_level(&self, level: Level) {
|
|
match self {
|
|
Self::FreeVar(v) => v.update_level(level),
|
|
Self::Ref(t) | Self::RefMut(t) | Self::VarArgs(t) => t.update_level(level),
|
|
Self::Callable { param_ts, return_t } => {
|
|
for p in param_ts.iter() {
|
|
p.update_level(level);
|
|
}
|
|
return_t.update_level(level);
|
|
}
|
|
Self::Subr(subr) => {
|
|
subr.kind.update_level(level);
|
|
for p in subr
|
|
.non_default_params
|
|
.iter()
|
|
.chain(subr.default_params.iter())
|
|
{
|
|
p.ty.update_level(level);
|
|
}
|
|
subr.return_t.update_level(level);
|
|
}
|
|
Self::And(lhs, rhs) | Self::Or(lhs, rhs) | Self::Not(lhs, rhs) => {
|
|
lhs.update_level(level);
|
|
rhs.update_level(level);
|
|
}
|
|
Self::Record(attrs) => {
|
|
for t in attrs.values() {
|
|
t.update_level(level);
|
|
}
|
|
}
|
|
Self::Poly { params, .. } => {
|
|
for p in params.iter() {
|
|
p.update_level(level);
|
|
}
|
|
}
|
|
Self::MonoProj { lhs, .. } => {
|
|
lhs.update_level(level);
|
|
}
|
|
Self::Refinement(refine) => {
|
|
refine.t.update_level(level);
|
|
for pred in refine.preds.iter() {
|
|
pred.update_level(level);
|
|
}
|
|
}
|
|
Self::Quantified(quant) => {
|
|
quant.unbound_callable.update_level(level);
|
|
for bound in quant.bounds.iter() {
|
|
bound.update_level(level);
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
fn lift(&self) {
|
|
match self {
|
|
Self::FreeVar(v) => v.lift(),
|
|
Self::Ref(t) | Self::RefMut(t) | Self::VarArgs(t) => t.lift(),
|
|
Self::Callable { param_ts, return_t } => {
|
|
for p in param_ts.iter() {
|
|
p.lift();
|
|
}
|
|
return_t.lift();
|
|
}
|
|
Self::Subr(subr) => {
|
|
subr.kind.lift();
|
|
for p in subr
|
|
.non_default_params
|
|
.iter()
|
|
.chain(subr.default_params.iter())
|
|
{
|
|
p.ty.lift();
|
|
}
|
|
subr.return_t.lift();
|
|
}
|
|
Self::And(lhs, rhs) | Self::Or(lhs, rhs) | Self::Not(lhs, rhs) => {
|
|
lhs.lift();
|
|
rhs.lift();
|
|
}
|
|
Self::Record(attrs) => {
|
|
for t in attrs.values() {
|
|
t.lift();
|
|
}
|
|
}
|
|
Self::Poly { params, .. } => {
|
|
for p in params.iter() {
|
|
p.lift();
|
|
}
|
|
}
|
|
Self::MonoProj { lhs, .. } => {
|
|
lhs.lift();
|
|
}
|
|
Self::Refinement(refine) => {
|
|
refine.t.lift();
|
|
for pred in refine.preds.iter() {
|
|
pred.lift();
|
|
}
|
|
}
|
|
Self::Quantified(quant) => {
|
|
quant.unbound_callable.lift();
|
|
for bound in quant.bounds.iter() {
|
|
bound.lift();
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Type {
|
|
pub const OBJ: &'static Self = &Self::Obj;
|
|
pub const NONE: &'static Self = &Self::NoneType;
|
|
pub const NOT_IMPLEMENTED: &'static Self = &Self::NotImplemented;
|
|
pub const ELLIPSIS: &'static Self = &Self::Ellipsis;
|
|
pub const INF: &'static Self = &Self::Inf;
|
|
pub const NEG_INF: &'static Self = &Self::NegInf;
|
|
pub const NEVER: &'static Self = &Self::Never;
|
|
pub const FAILURE: &'static Self = &Self::Failure;
|
|
|
|
/// Top := {=}
|
|
#[allow(non_snake_case)]
|
|
pub const fn Top() -> Self {
|
|
Self::Mono(Str::ever("Top"))
|
|
}
|
|
/// Bottom := {}
|
|
#[allow(non_snake_case)]
|
|
pub const fn Bottom() -> Self {
|
|
Self::Mono(Str::ever("Bottom"))
|
|
}
|
|
|
|
#[inline]
|
|
pub fn free_var(level: usize, constraint: Constraint) -> Self {
|
|
Self::FreeVar(Free::new_unbound(level, constraint))
|
|
}
|
|
|
|
#[inline]
|
|
pub fn named_free_var(name: Str, level: usize, constraint: Constraint) -> Self {
|
|
Self::FreeVar(Free::new_named_unbound(name, level, constraint))
|
|
}
|
|
|
|
pub fn array(elem_t: Type, len: TyParam) -> Self {
|
|
Self::poly("Array", vec![TyParam::t(elem_t), len])
|
|
}
|
|
|
|
pub fn array_mut(elem_t: Type, len: TyParam) -> Self {
|
|
Self::poly("Array!", vec![TyParam::t(elem_t), len])
|
|
}
|
|
|
|
pub fn dict(k_t: Type, v_t: Type) -> Self {
|
|
Self::poly("Dict", vec![TyParam::t(k_t), TyParam::t(v_t)])
|
|
}
|
|
|
|
pub fn tuple(args: Vec<Type>) -> Self {
|
|
Self::poly("Tuple", args.into_iter().map(TyParam::t).collect())
|
|
}
|
|
|
|
#[inline]
|
|
pub fn var_args(elem_t: Type) -> Self {
|
|
Self::VarArgs(Box::new(elem_t))
|
|
}
|
|
|
|
#[inline]
|
|
pub fn range(t: Type) -> Self {
|
|
Self::poly("Range", vec![TyParam::t(t)])
|
|
}
|
|
|
|
pub fn enum_t(s: Set<ValueObj>) -> Self {
|
|
assert!(s.is_homogeneous());
|
|
let name = Str::from(fresh_varname());
|
|
let preds = s
|
|
.iter()
|
|
.map(|o| Predicate::eq(name.clone(), TyParam::value(o.clone())))
|
|
.collect();
|
|
let refine = RefinementType::new(name, s.inner_class(), preds);
|
|
Self::Refinement(refine)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn int_interval<P: Into<TyParam>, Q: Into<TyParam>>(op: IntervalOp, l: P, r: Q) -> Self {
|
|
let l = l.into();
|
|
let r = r.into();
|
|
let l = l.try_into().unwrap_or_else(|l| todo!("{l}"));
|
|
let r = r.try_into().unwrap_or_else(|r| todo!("{r}"));
|
|
let name = Str::from(fresh_varname());
|
|
let pred = match op {
|
|
IntervalOp::LeftOpen if l == TyParam::value(NegInf) => Predicate::le(name.clone(), r),
|
|
// l<..r => {I: classof(l) | I >= l+ε and I <= r}
|
|
IntervalOp::LeftOpen => Predicate::and(
|
|
Predicate::ge(name.clone(), TyParam::succ(l)),
|
|
Predicate::le(name.clone(), r),
|
|
),
|
|
IntervalOp::RightOpen if r == TyParam::value(Inf) => Predicate::ge(name.clone(), l),
|
|
// l..<r => {I: classof(l) | I >= l and I <= r-ε}
|
|
IntervalOp::RightOpen => Predicate::and(
|
|
Predicate::ge(name.clone(), l),
|
|
Predicate::le(name.clone(), TyParam::pred(r)),
|
|
),
|
|
// l..r => {I: classof(l) | I >= l and I <= r}
|
|
IntervalOp::Closed => Predicate::and(
|
|
Predicate::ge(name.clone(), l),
|
|
Predicate::le(name.clone(), r),
|
|
),
|
|
IntervalOp::Open if l == TyParam::value(NegInf) && r == TyParam::value(Inf) => {
|
|
return Type::refinement(name, Type::Int, set! {})
|
|
}
|
|
// l<..<r => {I: classof(l) | I >= l+ε and I <= r-ε}
|
|
IntervalOp::Open => Predicate::and(
|
|
Predicate::ge(name.clone(), TyParam::succ(l)),
|
|
Predicate::le(name.clone(), TyParam::pred(r)),
|
|
),
|
|
};
|
|
Type::refinement(name, Type::Int, set! {pred})
|
|
}
|
|
|
|
pub fn iter(t: Type) -> Self {
|
|
Self::poly("Iter", vec![TyParam::t(t)])
|
|
}
|
|
|
|
pub fn ref_(t: Type) -> Self {
|
|
Self::Ref(Box::new(t))
|
|
}
|
|
|
|
pub fn ref_mut(t: Type) -> Self {
|
|
Self::RefMut(Box::new(t))
|
|
}
|
|
|
|
pub fn option(t: Type) -> Self {
|
|
Self::poly("Option", vec![TyParam::t(t)])
|
|
}
|
|
|
|
pub fn option_mut(t: Type) -> Self {
|
|
Self::poly("Option!", vec![TyParam::t(t)])
|
|
}
|
|
|
|
pub fn subr(
|
|
kind: SubrKind,
|
|
non_default_params: Vec<ParamTy>,
|
|
default_params: Vec<ParamTy>,
|
|
return_t: Type,
|
|
) -> Self {
|
|
Self::Subr(SubrType::new(
|
|
kind,
|
|
non_default_params,
|
|
default_params,
|
|
return_t,
|
|
))
|
|
}
|
|
|
|
pub fn func(
|
|
non_default_params: Vec<ParamTy>,
|
|
default_params: Vec<ParamTy>,
|
|
return_t: Type,
|
|
) -> Self {
|
|
Self::Subr(SubrType::new(
|
|
SubrKind::Func,
|
|
non_default_params,
|
|
default_params,
|
|
return_t,
|
|
))
|
|
}
|
|
|
|
pub fn func1(param_t: Type, return_t: Type) -> Self {
|
|
Self::func(vec![ParamTy::anonymous(param_t)], vec![], return_t)
|
|
}
|
|
|
|
pub fn kind1(param: Type) -> Self {
|
|
Self::func1(param, Type::Type)
|
|
}
|
|
|
|
pub fn func2(l: Type, r: Type, return_t: Type) -> Self {
|
|
Self::func(
|
|
vec![ParamTy::anonymous(l), ParamTy::anonymous(r)],
|
|
vec![],
|
|
return_t,
|
|
)
|
|
}
|
|
|
|
pub fn bin_op(l: Type, r: Type, return_t: Type) -> Self {
|
|
Self::nd_func(
|
|
vec![
|
|
ParamTy::named(Str::ever("lhs"), l.clone()),
|
|
ParamTy::named(Str::ever("rhs"), r.clone()),
|
|
],
|
|
return_t,
|
|
)
|
|
}
|
|
|
|
pub fn anon_param_func(
|
|
non_default_params: Vec<Type>,
|
|
default_params: Vec<Type>,
|
|
return_t: Type,
|
|
) -> Self {
|
|
let non_default_params = non_default_params
|
|
.into_iter()
|
|
.map(ParamTy::anonymous)
|
|
.collect();
|
|
let default_params = default_params.into_iter().map(ParamTy::anonymous).collect();
|
|
Self::func(non_default_params, default_params, return_t)
|
|
}
|
|
|
|
pub fn proc(
|
|
non_default_params: Vec<ParamTy>,
|
|
default_params: Vec<ParamTy>,
|
|
return_t: Type,
|
|
) -> Self {
|
|
Self::Subr(SubrType::new(
|
|
SubrKind::Proc,
|
|
non_default_params,
|
|
default_params,
|
|
return_t,
|
|
))
|
|
}
|
|
|
|
pub fn proc1(param_t: Type, return_t: Type) -> Self {
|
|
Self::proc(vec![ParamTy::anonymous(param_t)], vec![], return_t)
|
|
}
|
|
|
|
pub fn proc2(l: Type, r: Type, return_t: Type) -> Self {
|
|
Self::proc(
|
|
vec![ParamTy::anonymous(l), ParamTy::anonymous(r)],
|
|
vec![],
|
|
return_t,
|
|
)
|
|
}
|
|
|
|
pub fn anon_param_proc(
|
|
non_default_params: Vec<Type>,
|
|
default_params: Vec<Type>,
|
|
return_t: Type,
|
|
) -> Self {
|
|
let non_default_params = non_default_params
|
|
.into_iter()
|
|
.map(ParamTy::anonymous)
|
|
.collect();
|
|
let default_params = default_params.into_iter().map(ParamTy::anonymous).collect();
|
|
Self::proc(non_default_params, default_params, return_t)
|
|
}
|
|
|
|
pub fn fn_met(
|
|
self_t: Type,
|
|
non_default_params: Vec<ParamTy>,
|
|
default_params: Vec<ParamTy>,
|
|
return_t: Type,
|
|
) -> Self {
|
|
Self::Subr(SubrType::new(
|
|
SubrKind::FuncMethod(Box::new(self_t)),
|
|
non_default_params,
|
|
default_params,
|
|
return_t,
|
|
))
|
|
}
|
|
|
|
pub fn fn0_met(self_t: Type, return_t: Type) -> Self {
|
|
Self::fn_met(self_t, vec![], vec![], return_t)
|
|
}
|
|
|
|
pub fn fn1_met(self_t: Type, input_t: Type, return_t: Type) -> Self {
|
|
Self::fn_met(self_t, vec![ParamTy::anonymous(input_t)], vec![], return_t)
|
|
}
|
|
|
|
pub fn anon_param_fn_met(
|
|
self_t: Type,
|
|
non_default_params: Vec<Type>,
|
|
default_params: Vec<Type>,
|
|
return_t: Type,
|
|
) -> Self {
|
|
let non_default_params = non_default_params
|
|
.into_iter()
|
|
.map(ParamTy::anonymous)
|
|
.collect();
|
|
let default_params = default_params.into_iter().map(ParamTy::anonymous).collect();
|
|
Self::fn_met(self_t, non_default_params, default_params, return_t)
|
|
}
|
|
|
|
pub fn pr_met(
|
|
self_before: Type,
|
|
self_after: Option<Type>,
|
|
non_default_params: Vec<ParamTy>,
|
|
default_params: Vec<ParamTy>,
|
|
return_t: Type,
|
|
) -> Self {
|
|
Self::Subr(SubrType::new(
|
|
SubrKind::pr_met(self_before, self_after),
|
|
non_default_params,
|
|
default_params,
|
|
return_t,
|
|
))
|
|
}
|
|
|
|
pub fn pr0_met(self_before: Type, self_after: Option<Type>, return_t: Type) -> Self {
|
|
Self::pr_met(self_before, self_after, vec![], vec![], return_t)
|
|
}
|
|
|
|
pub fn pr1_met(
|
|
self_before: Type,
|
|
self_after: Option<Type>,
|
|
input_t: Type,
|
|
return_t: Type,
|
|
) -> Self {
|
|
Self::pr_met(
|
|
self_before,
|
|
self_after,
|
|
vec![ParamTy::anonymous(input_t)],
|
|
vec![],
|
|
return_t,
|
|
)
|
|
}
|
|
|
|
pub fn anon_param_pr_met(
|
|
self_before: Type,
|
|
self_after: Option<Type>,
|
|
non_default_params: Vec<Type>,
|
|
default_params: Vec<Type>,
|
|
return_t: Type,
|
|
) -> Self {
|
|
let non_default_params = non_default_params
|
|
.into_iter()
|
|
.map(ParamTy::anonymous)
|
|
.collect();
|
|
let default_params = default_params.into_iter().map(ParamTy::anonymous).collect();
|
|
Self::pr_met(
|
|
self_before,
|
|
self_after,
|
|
non_default_params,
|
|
default_params,
|
|
return_t,
|
|
)
|
|
}
|
|
|
|
/// function type with non-default parameters
|
|
#[inline]
|
|
pub fn nd_func(params: Vec<ParamTy>, ret: Type) -> Type {
|
|
Type::func(params, vec![], ret)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn nd_proc(params: Vec<ParamTy>, ret: Type) -> Type {
|
|
Type::proc(params, vec![], ret)
|
|
}
|
|
|
|
pub fn callable(param_ts: Vec<Type>, return_t: Type) -> Self {
|
|
Self::Callable {
|
|
param_ts,
|
|
return_t: Box::new(return_t),
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub fn mono<S: Into<Str>>(name: S) -> Self {
|
|
Self::Mono(name.into())
|
|
}
|
|
|
|
#[inline]
|
|
pub fn mono_q<S: Into<Str>>(name: S) -> Self {
|
|
Self::MonoQVar(name.into())
|
|
}
|
|
|
|
#[inline]
|
|
pub fn poly<S: Into<Str>>(name: S, params: Vec<TyParam>) -> Self {
|
|
Self::Poly {
|
|
name: name.into(),
|
|
params,
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub fn poly_q<S: Into<Str>>(name: S, params: Vec<TyParam>) -> Self {
|
|
Self::PolyQVar {
|
|
name: name.into(),
|
|
params,
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub fn mono_proj<S: Into<Str>>(lhs: Type, rhs: S) -> Self {
|
|
Self::MonoProj {
|
|
lhs: Box::new(lhs),
|
|
rhs: rhs.into(),
|
|
}
|
|
}
|
|
|
|
/// ```rust
|
|
/// {I: Int | I >= 0}
|
|
/// => Refinement{
|
|
/// layout: TyParam::MonoQ "I",
|
|
/// bounds: [TyBound::Instance("I", "Int")],
|
|
/// preds: [Predicate::GreaterEqual("I", 0)]
|
|
/// }
|
|
/// ```
|
|
#[inline]
|
|
pub fn refinement(var: Str, t: Type, preds: Set<Predicate>) -> Self {
|
|
Self::Refinement(RefinementType::new(var, t, preds))
|
|
}
|
|
|
|
/// quantified((T -> T), T: Type) => |T: Type| T -> T
|
|
pub fn quantified(unbound_t: Type, bounds: Set<TyBound>) -> Self {
|
|
Self::Quantified(QuantifiedType::new(unbound_t, bounds))
|
|
}
|
|
|
|
pub fn and(lhs: Self, rhs: Self) -> Self {
|
|
Self::And(Box::new(lhs), Box::new(rhs))
|
|
}
|
|
|
|
pub fn or(lhs: Self, rhs: Self) -> Self {
|
|
Self::Or(Box::new(lhs), Box::new(rhs))
|
|
}
|
|
|
|
pub fn not(lhs: Self, rhs: Self) -> Self {
|
|
Self::Not(Box::new(lhs), Box::new(rhs))
|
|
}
|
|
|
|
pub fn is_mono_q(&self) -> bool {
|
|
match self {
|
|
Self::FreeVar(fv) if fv.is_linked() => fv.crack().is_mono_q(),
|
|
Self::MonoQVar(_) => true,
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
/// 本来は型環境が必要
|
|
pub fn mutate(self) -> Self {
|
|
match self {
|
|
Self::Int => Self::mono("Int!"),
|
|
Self::Nat => Self::mono("Nat!"),
|
|
Self::Ratio => Self::mono("Ratio!"),
|
|
Self::Float => Self::mono("Float!"),
|
|
Self::Bool => Self::mono("Bool!"),
|
|
Self::Str => Self::mono("Str!"),
|
|
_ => todo!(),
|
|
}
|
|
}
|
|
|
|
pub fn is_mut(&self) -> bool {
|
|
match self {
|
|
Self::FreeVar(fv) => {
|
|
if fv.is_linked() {
|
|
fv.crack().is_mut()
|
|
} else {
|
|
fv.unbound_name().unwrap().ends_with('!')
|
|
}
|
|
}
|
|
Self::Mono(name)
|
|
| Self::MonoQVar(name)
|
|
| Self::Poly { name, .. }
|
|
| Self::PolyQVar { name, .. }
|
|
| Self::MonoProj { rhs: name, .. } => name.ends_with('!'),
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
pub fn is_nonelike(&self) -> bool {
|
|
match self {
|
|
Self::NoneType => true,
|
|
Self::Poly { name, params } if &name[..] == "Option" || &name[..] == "Option!" => {
|
|
let inner_t = enum_unwrap!(params.first().unwrap(), TyParam::Type);
|
|
inner_t.is_nonelike()
|
|
}
|
|
Self::Poly { name, params } if &name[..] == "Tuple" => params.is_empty(),
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
pub fn args_ownership(&self) -> ArgsOwnership {
|
|
match self {
|
|
Self::Subr(subr) => {
|
|
let self_ = subr.kind.self_t().map(|t| t.ownership());
|
|
let mut nd_args = vec![];
|
|
for nd_param in subr.non_default_params.iter() {
|
|
let ownership = match &nd_param.ty {
|
|
Self::Ref(_) => Ownership::Ref,
|
|
Self::RefMut(_) => Ownership::RefMut,
|
|
Self::VarArgs(t) => return ArgsOwnership::VarArgs(t.ownership()),
|
|
_ => Ownership::Owned,
|
|
};
|
|
nd_args.push(ownership);
|
|
}
|
|
let mut d_args = vec![];
|
|
for d_param in subr.default_params.iter() {
|
|
let ownership = match &d_param.ty {
|
|
Self::Ref(_) => Ownership::Ref,
|
|
Self::RefMut(_) => Ownership::RefMut,
|
|
Self::VarArgs(t) => return ArgsOwnership::VarArgsDefault(t.ownership()),
|
|
_ => Ownership::Owned,
|
|
};
|
|
d_args.push(ownership);
|
|
}
|
|
ArgsOwnership::args(self_, nd_args, d_args)
|
|
}
|
|
_ => todo!(),
|
|
}
|
|
}
|
|
|
|
pub fn ownership(&self) -> Ownership {
|
|
match self {
|
|
Self::Ref(_) => Ownership::Ref,
|
|
Self::RefMut(_) => Ownership::RefMut,
|
|
_ => Ownership::Owned,
|
|
}
|
|
}
|
|
|
|
pub fn rec_eq(&self, other: &Self) -> bool {
|
|
match (self, other) {
|
|
(Self::FreeVar(v), other) => match &*v.borrow() {
|
|
FreeKind::Linked(t) => t.rec_eq(other),
|
|
_ => self == other,
|
|
},
|
|
(self_, Self::FreeVar(v)) => match &*v.borrow() {
|
|
FreeKind::Linked(t) => t.rec_eq(self_),
|
|
_ => self_ == other,
|
|
},
|
|
(Self::Ref(l), Self::Ref(r)) | (Self::RefMut(l), Self::RefMut(r)) => l.rec_eq(r),
|
|
(Self::Subr(l), Self::Subr(r)) => {
|
|
match (&l.kind, &r.kind) {
|
|
(SubrKind::Func, SubrKind::Func) | (SubrKind::Proc, SubrKind::Proc) => {}
|
|
(SubrKind::FuncMethod(l), SubrKind::FuncMethod(r)) if !l.rec_eq(r.as_ref()) => {
|
|
return false
|
|
}
|
|
(
|
|
SubrKind::ProcMethod { before, after },
|
|
SubrKind::ProcMethod {
|
|
before: rbefore,
|
|
after: rafter,
|
|
},
|
|
) if !before.rec_eq(rbefore.as_ref())
|
|
|| !after
|
|
.as_ref()
|
|
.zip(rafter.as_ref())
|
|
.map(|(l, r)| l.rec_eq(r))
|
|
.unwrap_or(false) =>
|
|
{
|
|
return false
|
|
}
|
|
_ => return false,
|
|
}
|
|
if !l
|
|
.default_params
|
|
.iter()
|
|
.zip(r.default_params.iter())
|
|
.all(|(l, r)| l.name == r.name && l.ty.rec_eq(&r.ty))
|
|
{
|
|
return false;
|
|
}
|
|
if !l
|
|
.non_default_params
|
|
.iter()
|
|
.zip(r.non_default_params.iter())
|
|
.all(|(l, r)| l.name == r.name && l.ty.rec_eq(&r.ty))
|
|
{
|
|
return false;
|
|
}
|
|
l.return_t.rec_eq(&r.return_t)
|
|
}
|
|
(
|
|
Self::Callable {
|
|
param_ts: _lps,
|
|
return_t: _lr,
|
|
},
|
|
Self::Callable {
|
|
param_ts: _rps,
|
|
return_t: _rr,
|
|
},
|
|
) => todo!(),
|
|
(Self::Record(lhs), Self::Record(rhs)) => {
|
|
for (l_field, l_t) in lhs.iter() {
|
|
if let Some(r_t) = rhs.get(l_field) {
|
|
if !l_t.rec_eq(r_t) {
|
|
return false;
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
true
|
|
}
|
|
(Self::Refinement(l), Self::Refinement(r)) => l.t.rec_eq(&r.t) && l.preds == r.preds,
|
|
(Self::Quantified(l), Self::Quantified(r)) => {
|
|
l.unbound_callable.rec_eq(&r.unbound_callable) && l.bounds == r.bounds
|
|
}
|
|
(Self::And(ll, lr), Self::And(rl, rr))
|
|
| (Self::Not(ll, lr), Self::Not(rl, rr))
|
|
| (Self::Or(ll, lr), Self::Or(rl, rr)) => {
|
|
ll.rec_eq(rl) && lr.rec_eq(rr)
|
|
},
|
|
(Self::VarArgs(l), Self::VarArgs(r)) => l.rec_eq(r),
|
|
(
|
|
Self::Poly {
|
|
name: ln,
|
|
params: lps,
|
|
}
|
|
| Self::PolyQVar {
|
|
name: ln,
|
|
params: lps,
|
|
},
|
|
Self::Poly {
|
|
name: rn,
|
|
params: rps,
|
|
}
|
|
| Self::PolyQVar {
|
|
name: rn,
|
|
params: rps,
|
|
},
|
|
) => ln == rn && lps.iter().zip(rps.iter()).all(|(l, r)| l.rec_eq(r)),
|
|
(
|
|
Self::MonoProj { lhs, rhs },
|
|
Self::MonoProj {
|
|
lhs: rlhs,
|
|
rhs: rrhs,
|
|
},
|
|
) => lhs.rec_eq(rlhs) && rhs == rrhs,
|
|
_ => self == other,
|
|
}
|
|
}
|
|
|
|
/// 共通部分(A and B)を返す
|
|
/// 型同士の包含関係はここでは検査しない(TypeCheckerでする)
|
|
pub fn intersection(lhs: &Self, rhs: &Self) -> Self {
|
|
if lhs == rhs {
|
|
return lhs.clone();
|
|
}
|
|
match (lhs, rhs) {
|
|
// { .i: Int } and { .s: Str } == { .i: Int, .s: Str }
|
|
(Self::Record(l), Self::Record(r)) => Self::Record(l.clone().concat(r.clone())),
|
|
(t, Self::Obj) | (Self::Obj, t) => t.clone(),
|
|
(_, Self::Never) | (Self::Never, _) => Self::Never,
|
|
(l, r) => Self::and(l.clone(), r.clone()),
|
|
}
|
|
}
|
|
|
|
pub fn name(&self) -> &str {
|
|
match self {
|
|
Self::Obj => "Obj",
|
|
Self::Int => "Int",
|
|
Self::Nat => "Nat",
|
|
Self::Ratio => "Ratio",
|
|
Self::Float => "Float",
|
|
Self::Bool => "Bool",
|
|
Self::Str => "Str",
|
|
Self::NoneType => "None",
|
|
Self::Type => "Type",
|
|
Self::Class => "Class",
|
|
Self::Trait => "Trait",
|
|
Self::Patch => "Patch",
|
|
Self::Code => "Code",
|
|
Self::Module => "Module",
|
|
Self::Frame => "Frame",
|
|
Self::Error => "Error",
|
|
Self::Inf => "Inf",
|
|
Self::NegInf => "NegInf",
|
|
Self::Mono(name) | Self::MonoQVar(name) => name,
|
|
Self::And(_, _) => "And",
|
|
Self::Not(_, _) => "Not",
|
|
Self::Or(_, _) => "Or",
|
|
Self::Ref(_) => "Ref",
|
|
Self::RefMut(_) => "Ref!",
|
|
Self::Subr(SubrType {
|
|
kind: SubrKind::Func,
|
|
..
|
|
}) => "Func",
|
|
Self::Subr(SubrType {
|
|
kind: SubrKind::Proc,
|
|
..
|
|
}) => "Proc",
|
|
Self::Subr(SubrType {
|
|
kind: SubrKind::FuncMethod(_),
|
|
..
|
|
}) => "FuncMethod",
|
|
Self::Subr(SubrType {
|
|
kind: SubrKind::ProcMethod { .. },
|
|
..
|
|
}) => "ProcMethod",
|
|
Self::Callable { .. } => "Callable",
|
|
Self::Record(_) => "Record",
|
|
Self::VarArgs(_) => "VarArgs",
|
|
Self::Poly { name, .. } | Self::PolyQVar { name, .. } => name,
|
|
// NOTE: compiler/codegen/convert_to_python_methodでクラス名を使うため、こうすると都合が良い
|
|
Self::Refinement(refine) => refine.t.name(),
|
|
Self::Quantified(_) => "Quantified",
|
|
Self::Ellipsis => "Ellipsis",
|
|
Self::NotImplemented => "NotImplemented",
|
|
Self::Never => "Never",
|
|
Self::FreeVar(_) => "?", // TODO: 中身がSomeなら表示したい
|
|
Self::MonoProj { .. } => "MonoProj",
|
|
Self::Failure => "<Failure>",
|
|
Self::Uninited => "<Uninited>",
|
|
}
|
|
}
|
|
|
|
pub const fn is_free_var(&self) -> bool {
|
|
matches!(self, Self::FreeVar(_))
|
|
}
|
|
|
|
pub const fn is_varargs(&self) -> bool {
|
|
matches!(self, Self::VarArgs(_))
|
|
}
|
|
|
|
pub fn is_monomorphic(&self) -> bool {
|
|
self.typarams_len() == 0
|
|
}
|
|
|
|
pub const fn is_callable(&self) -> bool {
|
|
matches!(self, Self::Subr { .. } | Self::Callable { .. })
|
|
}
|
|
|
|
pub fn has_unbound_var(&self) -> bool {
|
|
match self {
|
|
Self::FreeVar(fv) => {
|
|
if fv.is_unbound() {
|
|
true
|
|
} else {
|
|
fv.crack().has_unbound_var()
|
|
}
|
|
}
|
|
Self::Ref(t) | Self::RefMut(t) | Self::VarArgs(t) => t.has_unbound_var(),
|
|
Self::And(lhs, rhs) | Self::Not(lhs, rhs) | Self::Or(lhs, rhs) => {
|
|
lhs.has_unbound_var() || rhs.has_unbound_var()
|
|
}
|
|
Self::Callable { param_ts, return_t } => {
|
|
param_ts.iter().any(|t| t.has_unbound_var()) || return_t.has_unbound_var()
|
|
}
|
|
Self::Subr(subr) => {
|
|
subr.kind.has_unbound_var()
|
|
|| subr
|
|
.non_default_params
|
|
.iter()
|
|
.any(|p| p.ty.has_unbound_var())
|
|
|| subr.default_params.iter().any(|p| p.ty.has_unbound_var())
|
|
|| subr.return_t.has_unbound_var()
|
|
}
|
|
Self::Record(r) => r.values().any(|t| t.has_unbound_var()),
|
|
Self::Refinement(refine) => {
|
|
refine.t.has_unbound_var() || refine.preds.iter().any(|p| p.has_unbound_var())
|
|
}
|
|
Self::Quantified(quant) => {
|
|
quant.unbound_callable.has_unbound_var()
|
|
|| quant.bounds.iter().any(|b| b.has_unbound_var())
|
|
}
|
|
Self::Poly { params, .. } | Self::PolyQVar { params, .. } => {
|
|
params.iter().any(|p| p.has_unbound_var())
|
|
}
|
|
Self::MonoProj { lhs, .. } => lhs.has_no_unbound_var(),
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
pub fn has_no_unbound_var(&self) -> bool {
|
|
!self.has_unbound_var()
|
|
}
|
|
|
|
pub fn typarams_len(&self) -> usize {
|
|
match self {
|
|
// REVIEw:
|
|
Self::Ref(_) | Self::RefMut(_) => 1,
|
|
Self::And(_, _) | Self::Or(_, _) | Self::Not(_, _) => 2,
|
|
Self::Subr(subr) => {
|
|
subr.kind.inner_len()
|
|
+ subr.non_default_params.len()
|
|
+ subr.default_params.len()
|
|
+ 1
|
|
}
|
|
Self::Callable { param_ts, .. } => param_ts.len() + 1,
|
|
Self::Poly { params, .. } | Self::PolyQVar { params, .. } => params.len(),
|
|
_ => 0,
|
|
}
|
|
}
|
|
|
|
pub fn typarams(&self) -> Vec<TyParam> {
|
|
match self {
|
|
Self::FreeVar(f) if f.is_linked() => f.crack().typarams(),
|
|
Self::FreeVar(_unbound) => vec![],
|
|
Self::Ref(t) | Self::RefMut(t) => vec![TyParam::t(*t.clone())],
|
|
Self::And(lhs, rhs) | Self::Not(lhs, rhs) | Self::Or(lhs, rhs) => {
|
|
vec![TyParam::t(*lhs.clone()), TyParam::t(*rhs.clone())]
|
|
}
|
|
Self::Subr(subr) => {
|
|
if let Some(self_t) = subr.kind.self_t() {
|
|
[
|
|
vec![TyParam::t(self_t.clone())],
|
|
subr.non_default_params
|
|
.iter()
|
|
.map(|t| TyParam::t(t.ty.clone()))
|
|
.collect(),
|
|
subr.default_params
|
|
.iter()
|
|
.map(|t| TyParam::t(t.ty.clone()))
|
|
.collect(),
|
|
]
|
|
.concat()
|
|
} else {
|
|
[
|
|
subr.non_default_params
|
|
.iter()
|
|
.map(|t| TyParam::t(t.ty.clone()))
|
|
.collect::<Vec<_>>(),
|
|
subr.default_params
|
|
.iter()
|
|
.map(|t| TyParam::t(t.ty.clone()))
|
|
.collect(),
|
|
]
|
|
.concat()
|
|
}
|
|
}
|
|
Self::Callable { param_ts: _, .. } => todo!(),
|
|
Self::Poly { params, .. } | Self::PolyQVar { params, .. } => params.clone(),
|
|
_ => vec![],
|
|
}
|
|
}
|
|
|
|
pub const fn self_t(&self) -> Option<&Type> {
|
|
match self {
|
|
Self::Subr(SubrType {
|
|
kind: SubrKind::FuncMethod(self_t) | SubrKind::ProcMethod { before: self_t, .. },
|
|
..
|
|
}) => Some(self_t),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub const fn non_default_params(&self) -> Option<&Vec<ParamTy>> {
|
|
match self {
|
|
Self::Subr(SubrType {
|
|
non_default_params, ..
|
|
}) => Some(non_default_params),
|
|
Self::Callable { param_ts: _, .. } => todo!(),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub const fn default_params(&self) -> Option<&Vec<ParamTy>> {
|
|
match self {
|
|
Self::Subr(SubrType { default_params, .. }) => Some(default_params),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub const fn return_t(&self) -> Option<&Type> {
|
|
match self {
|
|
Self::Subr(SubrType { return_t, .. }) | Self::Callable { return_t, .. } => {
|
|
Some(return_t)
|
|
}
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn mut_return_t(&mut self) -> Option<&mut Type> {
|
|
match self {
|
|
Self::Subr(SubrType { return_t, .. }) | Self::Callable { return_t, .. } => {
|
|
Some(return_t)
|
|
}
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn update_constraint(&self, new_constraint: Constraint) {
|
|
match self {
|
|
Self::FreeVar(fv) => {
|
|
fv.update_constraint(new_constraint);
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub mod type_constrs {
|
|
use crate::ty::*;
|
|
|
|
#[inline]
|
|
pub const fn param_t(name: &'static str, ty: Type) -> ParamTy {
|
|
ParamTy::new(Some(Str::ever(name)), ty)
|
|
}
|
|
|
|
#[inline]
|
|
pub const fn anon(ty: Type) -> ParamTy {
|
|
ParamTy::anonymous(ty)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn mono<S: Into<Str>>(name: S) -> Type {
|
|
Type::mono(name)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn mono_q<S: Into<Str>>(name: S) -> Type {
|
|
Type::mono_q(name)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn mono_proj<S: Into<Str>>(lhs: Type, rhs: S) -> Type {
|
|
Type::mono_proj(lhs, rhs)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn poly<S: Into<Str>>(name: S, params: Vec<TyParam>) -> Type {
|
|
Type::poly(name, params)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn poly_q<S: Into<Str>>(name: S, params: Vec<TyParam>) -> Type {
|
|
Type::poly_q(name, params)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn func(non_default_params: Vec<ParamTy>, default_params: Vec<ParamTy>, ret: Type) -> Type {
|
|
Type::func(non_default_params, default_params, ret)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn proc(non_default_params: Vec<ParamTy>, default_params: Vec<ParamTy>, ret: Type) -> Type {
|
|
Type::proc(non_default_params, default_params, ret)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn nd_func(params: Vec<ParamTy>, ret: Type) -> Type {
|
|
Type::nd_func(params, ret)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn nd_proc(params: Vec<ParamTy>, ret: Type) -> Type {
|
|
Type::nd_proc(params, ret)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn fn0_met(self_t: Type, return_t: Type) -> Type {
|
|
Type::fn0_met(self_t, return_t)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn fn1_met(self_t: Type, input_t: Type, return_t: Type) -> Type {
|
|
Type::fn1_met(self_t, input_t, return_t)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn quant(unbound_t: Type, bounds: Set<TyBound>) -> Type {
|
|
Type::quantified(unbound_t, bounds)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn instance(name: Str, t: Type) -> TyBound {
|
|
TyBound::instance(name, t)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn static_instance(name: &'static str, t: Type) -> TyBound {
|
|
TyBound::static_instance(name, t)
|
|
}
|
|
|
|
/// Sub <: Sup
|
|
#[inline]
|
|
pub fn subtypeof(sub: Type, sup: Type) -> TyBound {
|
|
TyBound::sandwiched(Type::Never, sub, sup)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn mono_q_tp<S: Into<Str>>(name: S) -> TyParam {
|
|
TyParam::mono_q(name)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn mono_tp<S: Into<Str>>(name: S) -> TyParam {
|
|
TyParam::mono(name)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn ty_tp(t: Type) -> TyParam {
|
|
TyParam::t(t)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn value<V: Into<ValueObj>>(v: V) -> TyParam {
|
|
TyParam::value(v)
|
|
}
|
|
}
|
|
|
|
/// バイトコード命令で、in-place型付けをするオブジェクト
|
|
/// MaybeBigがついている場合、固定長でない可能性あり(実行時検査が必要)
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
#[repr(u8)]
|
|
pub enum TypeCode {
|
|
Int32 = 1,
|
|
Nat64,
|
|
Float64,
|
|
Bool,
|
|
Str,
|
|
StrMut,
|
|
Array, // 要素数は検査済みなので、気にする必要はない
|
|
ArrayMut,
|
|
// Dict,
|
|
Func,
|
|
Proc,
|
|
MaybeBigInt,
|
|
MaybeBigNat,
|
|
MaybeBigFloat,
|
|
MaybeBigStr,
|
|
Other,
|
|
Illegal,
|
|
}
|
|
|
|
// TODO:
|
|
impl From<&Type> for TypeCode {
|
|
fn from(arg: &Type) -> Self {
|
|
match arg {
|
|
Type::Int => Self::Int32,
|
|
Type::Nat => Self::Nat64,
|
|
Type::Float => Self::Float64,
|
|
Type::Bool => Self::Bool,
|
|
Type::Str => Self::Str,
|
|
Type::Mono(name) => match &name[..] {
|
|
"Int!" => Self::Int32,
|
|
"Nat!" => Self::Nat64,
|
|
"Float!" => Self::Float64,
|
|
"Bool!" => Self::Bool,
|
|
"Str!" => Self::Str,
|
|
_ => Self::Other,
|
|
},
|
|
Type::Poly { name, .. } => match &name[..] {
|
|
"Array" | "Array!" => Self::Array,
|
|
"Func" => Self::Func,
|
|
"Proc" => Self::Proc,
|
|
_ => Self::Other,
|
|
},
|
|
Type::Refinement(refine) => Self::from(&*refine.t),
|
|
_ => Self::Other,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// バイトコード命令で、in-place型付けをするオブジェクトペア
|
|
/// とりあえずは必要性の高いペアから登録する
|
|
/// 全ての式の型が確認されているので、戻り値の型は不要
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
#[repr(u8)]
|
|
pub enum TypePair {
|
|
IntInt = 1,
|
|
IntNat,
|
|
IntFloat,
|
|
IntStr,
|
|
IntBool,
|
|
IntArray,
|
|
IntFunc,
|
|
IntProc,
|
|
NatInt,
|
|
NatNat,
|
|
NatFloat,
|
|
NatStr,
|
|
NatBool,
|
|
NatArray,
|
|
NatFunc,
|
|
NatProc,
|
|
FloatInt,
|
|
FloatNat,
|
|
FloatFloat,
|
|
FloatStr,
|
|
FloatBool,
|
|
FloatArray,
|
|
FloatFunc,
|
|
FloatProc,
|
|
BoolInt,
|
|
BoolNat,
|
|
BoolFloat,
|
|
BoolStr,
|
|
BoolBool,
|
|
BoolArray,
|
|
BoolFunc,
|
|
BoolProc,
|
|
StrInt,
|
|
StrNat,
|
|
StrFloat,
|
|
StrBool,
|
|
StrStr,
|
|
StrArray,
|
|
StrFunc,
|
|
StrProc,
|
|
// 要素数は検査済みなので、気にする必要はない
|
|
ArrayInt,
|
|
ArrayNat,
|
|
ArrayFloat,
|
|
ArrayStr,
|
|
ArrayBool,
|
|
ArrayArray,
|
|
ArrayFunc,
|
|
ArrayProc,
|
|
FuncInt,
|
|
FuncNat,
|
|
FuncFloat,
|
|
FuncStr,
|
|
FuncBool,
|
|
FuncArray,
|
|
FuncFunc,
|
|
FuncProc,
|
|
ProcInt,
|
|
ProcNat,
|
|
ProcFloat,
|
|
ProcStr,
|
|
ProcBool,
|
|
ProcArray,
|
|
ProcFunc,
|
|
ProcProc,
|
|
Others,
|
|
Illegals,
|
|
}
|
|
|
|
impl From<u8> for TypePair {
|
|
fn from(code: u8) -> Self {
|
|
match code {
|
|
1 => Self::IntInt,
|
|
2 => Self::IntNat,
|
|
3 => Self::IntFloat,
|
|
4 => Self::IntStr,
|
|
5 => Self::IntBool,
|
|
6 => Self::IntArray,
|
|
7 => Self::IntFunc,
|
|
8 => Self::IntProc,
|
|
9 => Self::NatInt,
|
|
10 => Self::NatNat,
|
|
11 => Self::NatFloat,
|
|
12 => Self::NatStr,
|
|
13 => Self::NatBool,
|
|
14 => Self::NatArray,
|
|
15 => Self::NatFunc,
|
|
16 => Self::NatProc,
|
|
17 => Self::FloatInt,
|
|
18 => Self::FloatNat,
|
|
19 => Self::FloatFloat,
|
|
20 => Self::FloatStr,
|
|
21 => Self::FloatBool,
|
|
22 => Self::FloatArray,
|
|
23 => Self::FloatFunc,
|
|
24 => Self::FloatProc,
|
|
25 => Self::BoolInt,
|
|
26 => Self::BoolNat,
|
|
27 => Self::BoolFloat,
|
|
28 => Self::BoolStr,
|
|
29 => Self::BoolBool,
|
|
30 => Self::BoolArray,
|
|
31 => Self::BoolFunc,
|
|
32 => Self::BoolProc,
|
|
33 => Self::StrInt,
|
|
34 => Self::StrNat,
|
|
35 => Self::StrFloat,
|
|
36 => Self::StrBool,
|
|
37 => Self::StrStr,
|
|
38 => Self::StrArray,
|
|
39 => Self::StrFunc,
|
|
40 => Self::StrProc,
|
|
// 要素数は検査済みなので、気にする必要はない
|
|
41 => Self::ArrayInt,
|
|
42 => Self::ArrayNat,
|
|
43 => Self::ArrayFloat,
|
|
44 => Self::ArrayStr,
|
|
45 => Self::ArrayBool,
|
|
46 => Self::ArrayArray,
|
|
47 => Self::ArrayFunc,
|
|
48 => Self::ArrayProc,
|
|
49 => Self::FuncInt,
|
|
50 => Self::FuncNat,
|
|
51 => Self::FuncFloat,
|
|
52 => Self::FuncStr,
|
|
53 => Self::FuncBool,
|
|
54 => Self::FuncArray,
|
|
55 => Self::FuncFunc,
|
|
56 => Self::FuncProc,
|
|
57 => Self::ProcInt,
|
|
58 => Self::ProcNat,
|
|
59 => Self::ProcFloat,
|
|
60 => Self::ProcStr,
|
|
61 => Self::ProcBool,
|
|
62 => Self::ProcArray,
|
|
63 => Self::ProcProc,
|
|
64 => Self::Others,
|
|
_ => Self::Illegals,
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO:
|
|
impl TypePair {
|
|
pub fn new(lhs: &Type, rhs: &Type) -> Self {
|
|
match (lhs, rhs) {
|
|
(Type::Int, Type::Int) => Self::IntInt,
|
|
(Type::Int, Type::Nat) => Self::IntNat,
|
|
(Type::Int, Type::Float) => Self::IntFloat,
|
|
(Type::Int, Type::Str) => Self::IntStr,
|
|
(Type::Int, Type::Bool) => Self::IntBool,
|
|
(Type::Int, Type::Poly { name, .. }) if &name[..] == "Array" => Self::IntArray,
|
|
(Type::Int, Type::Poly { name, .. }) if &name[..] == "Func" => Self::IntFunc,
|
|
(Type::Int, Type::Poly { name, .. }) if &name[..] == "Proc" => Self::IntProc,
|
|
(Type::Nat, Type::Int) => Self::NatInt,
|
|
(Type::Nat, Type::Nat) => Self::NatNat,
|
|
(Type::Nat, Type::Float) => Self::NatFloat,
|
|
(Type::Nat, Type::Str) => Self::NatStr,
|
|
(Type::Nat, Type::Bool) => Self::NatBool,
|
|
(Type::Nat, Type::Poly { name, .. }) if &name[..] == "Array" => Self::NatArray,
|
|
(Type::Nat, Type::Poly { name, .. }) if &name[..] == "Func" => Self::NatFunc,
|
|
(Type::Nat, Type::Poly { name, .. }) if &name[..] == "Proc" => Self::NatProc,
|
|
(Type::Float, Type::Int) => Self::FloatInt,
|
|
(Type::Float, Type::Nat) => Self::FloatNat,
|
|
(Type::Float, Type::Float) => Self::FloatFloat,
|
|
(Type::Float, Type::Str) => Self::FloatStr,
|
|
(Type::Float, Type::Bool) => Self::FloatBool,
|
|
(Type::Float, Type::Poly { name, .. }) if &name[..] == "Array" => Self::FloatArray,
|
|
(Type::Float, Type::Poly { name, .. }) if &name[..] == "Func" => Self::FloatFunc,
|
|
(Type::Float, Type::Poly { name, .. }) if &name[..] == "Proc" => Self::FloatProc,
|
|
(Type::Bool, Type::Int) => Self::BoolInt,
|
|
(Type::Bool, Type::Nat) => Self::BoolNat,
|
|
(Type::Bool, Type::Float) => Self::BoolFloat,
|
|
(Type::Bool, Type::Str) => Self::BoolStr,
|
|
(Type::Bool, Type::Bool) => Self::BoolBool,
|
|
(Type::Bool, Type::Poly { name, .. }) if &name[..] == "Array" => Self::BoolArray,
|
|
(Type::Bool, Type::Poly { name, .. }) if &name[..] == "Func" => Self::BoolFunc,
|
|
(Type::Bool, Type::Poly { name, .. }) if &name[..] == "Proc" => Self::BoolProc,
|
|
(Type::Str, Type::Int) => Self::StrInt,
|
|
(Type::Str, Type::Nat) => Self::StrNat,
|
|
(Type::Str, Type::Float) => Self::StrFloat,
|
|
(Type::Str, Type::Bool) => Self::StrBool,
|
|
(Type::Str, Type::Str) => Self::StrStr,
|
|
(Type::Str, Type::Poly { name, .. }) if &name[..] == "Array" => Self::StrArray,
|
|
(Type::Str, Type::Poly { name, .. }) if &name[..] == "Func" => Self::StrFunc,
|
|
(Type::Str, Type::Poly { name, .. }) if &name[..] == "Proc" => Self::StrProc,
|
|
// 要素数は検査済みなので、気にする必要はない
|
|
(Type::Poly { name, .. }, Type::Int) if &name[..] == "Array" => Self::ArrayInt,
|
|
(Type::Poly { name, .. }, Type::Nat) if &name[..] == "Array" => Self::ArrayNat,
|
|
(Type::Poly { name, .. }, Type::Float) if &name[..] == "Array" => Self::ArrayFloat,
|
|
(Type::Poly { name, .. }, Type::Str) if &name[..] == "Array" => Self::ArrayStr,
|
|
(Type::Poly { name, .. }, Type::Bool) if &name[..] == "Array" => Self::ArrayBool,
|
|
(Type::Poly { name: ln, .. }, Type::Poly { name: rn, .. })
|
|
if &ln[..] == "Array" && &rn[..] == "Array" =>
|
|
{
|
|
Self::ArrayArray
|
|
}
|
|
(Type::Poly { name: ln, .. }, Type::Poly { name: rn, .. })
|
|
if &ln[..] == "Array" && &rn[..] == "Func" =>
|
|
{
|
|
Self::ArrayFunc
|
|
}
|
|
(Type::Poly { name: ln, .. }, Type::Poly { name: rn, .. })
|
|
if &ln[..] == "Array" && &rn[..] == "Proc" =>
|
|
{
|
|
Self::ArrayProc
|
|
}
|
|
(Type::Poly { name, .. }, Type::Int) if &name[..] == "Func" => Self::FuncInt,
|
|
(Type::Poly { name, .. }, Type::Nat) if &name[..] == "Func" => Self::FuncNat,
|
|
(Type::Poly { name, .. }, Type::Float) if &name[..] == "Func" => Self::FuncFloat,
|
|
(Type::Poly { name, .. }, Type::Str) if &name[..] == "Func" => Self::FuncStr,
|
|
(Type::Poly { name, .. }, Type::Bool) if &name[..] == "Func" => Self::FuncBool,
|
|
(Type::Poly { name: ln, .. }, Type::Poly { name: rn, .. })
|
|
if &ln[..] == "Func" && &rn[..] == "Array" =>
|
|
{
|
|
Self::FuncArray
|
|
}
|
|
(Type::Poly { name: ln, .. }, Type::Poly { name: rn, .. })
|
|
if &ln[..] == "Func" && &rn[..] == "Func" =>
|
|
{
|
|
Self::FuncFunc
|
|
}
|
|
(Type::Poly { name: ln, .. }, Type::Poly { name: rn, .. })
|
|
if &ln[..] == "Func" && &rn[..] == "Proc" =>
|
|
{
|
|
Self::FuncProc
|
|
}
|
|
(Type::Poly { name, .. }, Type::Int) if &name[..] == "Proc" => Self::ProcInt,
|
|
(Type::Poly { name, .. }, Type::Nat) if &name[..] == "Proc" => Self::ProcNat,
|
|
(Type::Poly { name, .. }, Type::Float) if &name[..] == "Proc" => Self::ProcFloat,
|
|
(Type::Poly { name, .. }, Type::Str) if &name[..] == "Proc" => Self::ProcStr,
|
|
(Type::Poly { name, .. }, Type::Bool) if &name[..] == "Proc" => Self::ProcBool,
|
|
(Type::Poly { name: ln, .. }, Type::Poly { name: rn, .. })
|
|
if &ln[..] == "Proc" && &rn[..] == "Array" =>
|
|
{
|
|
Self::ProcArray
|
|
}
|
|
(Type::Poly { name: ln, .. }, Type::Poly { name: rn, .. })
|
|
if &ln[..] == "Proc" && &rn[..] == "Func" =>
|
|
{
|
|
Self::ProcFunc
|
|
}
|
|
(Type::Poly { name: ln, .. }, Type::Poly { name: rn, .. })
|
|
if &ln[..] == "Proc" && &rn[..] == "Proc" =>
|
|
{
|
|
Self::ProcProc
|
|
}
|
|
(Type::Refinement(refine), r) => Self::new(&*refine.t, r),
|
|
(l, Type::Refinement(refine)) => Self::new(l, &*refine.t),
|
|
(_, _) => Self::Others,
|
|
}
|
|
}
|
|
}
|