2021-07-14 08:12:47 +08:00
|
|
|
use std::cell::RefCell;
|
2021-07-15 16:00:23 +08:00
|
|
|
use std::collections::HashMap;
|
2022-02-21 17:52:34 +08:00
|
|
|
use std::fmt::Display;
|
2021-07-14 15:58:58 +08:00
|
|
|
use std::rc::Rc;
|
2021-08-03 13:38:27 +08:00
|
|
|
use std::sync::{Arc, Mutex};
|
2021-10-16 15:56:13 +08:00
|
|
|
use std::{borrow::Cow, collections::HashSet};
|
2022-11-18 16:15:46 +08:00
|
|
|
use std::iter::zip;
|
|
|
|
use itertools::Itertools;
|
2021-01-04 14:49:48 +08:00
|
|
|
|
2022-02-21 18:27:46 +08:00
|
|
|
use nac3parser::ast::{Location, StrRef};
|
2021-09-22 17:19:27 +08:00
|
|
|
|
2022-02-21 17:52:34 +08:00
|
|
|
use super::type_error::{TypeError, TypeErrorKind};
|
2022-02-21 18:27:46 +08:00
|
|
|
use super::unification_table::{UnificationKey, UnificationTable};
|
2021-08-07 17:25:14 +08:00
|
|
|
use crate::symbol_resolver::SymbolValue;
|
2021-08-24 17:14:34 +08:00
|
|
|
use crate::toplevel::{DefinitionId, TopLevelContext, TopLevelDef};
|
2021-07-22 11:37:29 +08:00
|
|
|
|
2021-07-21 13:28:05 +08:00
|
|
|
#[cfg(test)]
|
2021-07-21 15:36:35 +08:00
|
|
|
mod test;
|
2021-07-21 13:28:05 +08:00
|
|
|
|
2022-04-13 11:32:31 +08:00
|
|
|
/// Handle for a type, implemented as a key in the unification table.
|
2021-07-22 11:37:29 +08:00
|
|
|
pub type Type = UnificationKey;
|
2021-01-04 14:49:48 +08:00
|
|
|
|
2021-09-07 00:20:40 +08:00
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
2022-02-21 17:52:34 +08:00
|
|
|
pub struct CallId(pub(super) usize);
|
2021-08-13 13:33:59 +08:00
|
|
|
|
2021-07-15 16:00:23 +08:00
|
|
|
pub type Mapping<K, V = Type> = HashMap<K, V>;
|
2021-07-16 15:55:52 +08:00
|
|
|
type VarMap = Mapping<u32>;
|
2021-01-04 14:49:48 +08:00
|
|
|
|
2021-07-14 16:40:50 +08:00
|
|
|
#[derive(Clone)]
|
2021-07-15 16:00:23 +08:00
|
|
|
pub struct Call {
|
2021-07-19 13:35:01 +08:00
|
|
|
pub posargs: Vec<Type>,
|
2021-09-22 17:19:27 +08:00
|
|
|
pub kwargs: HashMap<StrRef, Type>,
|
2021-07-19 13:35:01 +08:00
|
|
|
pub ret: Type,
|
|
|
|
pub fun: RefCell<Option<Type>>,
|
2022-02-21 17:52:34 +08:00
|
|
|
pub loc: Option<Location>,
|
2021-01-04 14:49:48 +08:00
|
|
|
}
|
|
|
|
|
2021-07-14 16:40:50 +08:00
|
|
|
#[derive(Clone)]
|
2021-07-15 16:00:23 +08:00
|
|
|
pub struct FuncArg {
|
2021-09-22 17:19:27 +08:00
|
|
|
pub name: StrRef,
|
2021-07-19 13:35:01 +08:00
|
|
|
pub ty: Type,
|
2021-08-07 17:25:14 +08:00
|
|
|
pub default_value: Option<SymbolValue>,
|
2021-01-04 14:49:48 +08:00
|
|
|
}
|
|
|
|
|
2021-07-16 15:55:52 +08:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct FunSignature {
|
2021-07-19 13:35:01 +08:00
|
|
|
pub args: Vec<FuncArg>,
|
|
|
|
pub ret: Type,
|
2021-07-19 16:51:58 +08:00
|
|
|
pub vars: VarMap,
|
2021-07-16 15:55:52 +08:00
|
|
|
}
|
|
|
|
|
2022-02-21 17:52:34 +08:00
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
|
|
pub enum RecordKey {
|
|
|
|
Str(StrRef),
|
2022-02-21 18:27:46 +08:00
|
|
|
Int(i32),
|
2022-02-21 17:52:34 +08:00
|
|
|
}
|
|
|
|
|
2022-03-26 15:09:15 +08:00
|
|
|
impl Type {
|
|
|
|
// a wrapper function for cleaner code so that we don't need to
|
|
|
|
// write this long pattern matching just to get the field `obj_id`
|
|
|
|
pub fn get_obj_id(self, unifier: &Unifier) -> DefinitionId {
|
|
|
|
if let TypeEnum::TObj { obj_id, .. } = unifier.get_ty_immutable(self).as_ref() {
|
|
|
|
*obj_id
|
|
|
|
} else {
|
|
|
|
unreachable!("expect a object type")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-21 17:52:34 +08:00
|
|
|
impl From<&RecordKey> for StrRef {
|
|
|
|
fn from(r: &RecordKey) -> Self {
|
|
|
|
match r {
|
|
|
|
RecordKey::Str(s) => *s,
|
2022-02-21 18:27:46 +08:00
|
|
|
RecordKey::Int(i) => StrRef::from(i.to_string()),
|
2022-02-21 17:52:34 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<StrRef> for RecordKey {
|
|
|
|
fn from(s: StrRef) -> Self {
|
|
|
|
RecordKey::Str(s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<&str> for RecordKey {
|
|
|
|
fn from(s: &str) -> Self {
|
|
|
|
RecordKey::Str(s.into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<i32> for RecordKey {
|
|
|
|
fn from(i: i32) -> Self {
|
|
|
|
RecordKey::Int(i)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for RecordKey {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
match self {
|
|
|
|
RecordKey::Str(s) => write!(f, "{}", s),
|
2022-02-21 18:27:46 +08:00
|
|
|
RecordKey::Int(i) => write!(f, "{}", i),
|
2022-02-21 17:52:34 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
pub struct RecordField {
|
|
|
|
ty: Type,
|
|
|
|
mutable: bool,
|
2022-02-21 18:27:46 +08:00
|
|
|
loc: Option<Location>,
|
2022-02-21 17:52:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl RecordField {
|
|
|
|
pub fn new(ty: Type, mutable: bool, loc: Option<Location>) -> RecordField {
|
|
|
|
RecordField { ty, mutable, loc }
|
|
|
|
}
|
2021-07-23 15:25:44 +08:00
|
|
|
}
|
|
|
|
|
2023-10-31 11:41:13 +08:00
|
|
|
/// Category of variable and value types.
|
2021-07-22 11:37:29 +08:00
|
|
|
#[derive(Clone)]
|
2021-07-15 16:00:23 +08:00
|
|
|
pub enum TypeEnum {
|
2021-07-30 11:28:27 +08:00
|
|
|
TRigidVar {
|
|
|
|
id: u32,
|
2022-02-21 17:52:34 +08:00
|
|
|
name: Option<StrRef>,
|
2022-02-21 18:27:46 +08:00
|
|
|
loc: Option<Location>,
|
2021-07-30 11:28:27 +08:00
|
|
|
},
|
2023-10-31 11:41:13 +08:00
|
|
|
|
|
|
|
/// A type variable.
|
2021-07-14 08:12:47 +08:00
|
|
|
TVar {
|
|
|
|
id: u32,
|
2022-02-21 17:52:34 +08:00
|
|
|
// empty indicates this is not a struct/tuple/list
|
|
|
|
fields: Option<Mapping<RecordKey, RecordField>>,
|
2021-07-23 15:25:44 +08:00
|
|
|
// empty indicates no restriction
|
2022-02-21 17:52:34 +08:00
|
|
|
range: Vec<Type>,
|
|
|
|
name: Option<StrRef>,
|
2022-02-21 18:27:46 +08:00
|
|
|
loc: Option<Location>,
|
2023-12-05 14:37:08 +08:00
|
|
|
/// Whether this type variable refers to a const-generic variable.
|
|
|
|
is_const_generic: bool,
|
|
|
|
},
|
|
|
|
|
|
|
|
/// A constant for substitution into a const generic variable.
|
|
|
|
TConstant {
|
|
|
|
/// The value of the constant.
|
|
|
|
value: SymbolValue,
|
|
|
|
/// The underlying type of the value.
|
|
|
|
ty: Type,
|
|
|
|
loc: Option<Location>,
|
2021-07-14 08:12:47 +08:00
|
|
|
},
|
2023-10-31 11:41:13 +08:00
|
|
|
|
|
|
|
/// A tuple type.
|
2021-07-14 08:12:47 +08:00
|
|
|
TTuple {
|
2023-10-31 11:41:13 +08:00
|
|
|
/// The types of elements present in this tuple.
|
2021-07-14 15:58:58 +08:00
|
|
|
ty: Vec<Type>,
|
2021-07-14 08:12:47 +08:00
|
|
|
},
|
2023-10-31 11:41:13 +08:00
|
|
|
|
|
|
|
/// A list type.
|
2021-07-14 08:12:47 +08:00
|
|
|
TList {
|
2023-10-31 11:41:13 +08:00
|
|
|
/// The type of elements present in this list.
|
2021-07-14 08:12:47 +08:00
|
|
|
ty: Type,
|
|
|
|
},
|
2023-10-31 11:41:13 +08:00
|
|
|
|
|
|
|
/// An object type.
|
2021-07-14 08:12:47 +08:00
|
|
|
TObj {
|
2023-10-31 11:41:13 +08:00
|
|
|
/// The [DefintionId] of this object type.
|
2021-08-06 10:30:57 +08:00
|
|
|
obj_id: DefinitionId,
|
2023-10-31 11:41:13 +08:00
|
|
|
|
|
|
|
/// The fields present in this object type.
|
|
|
|
///
|
|
|
|
/// The key of the [Mapping] is the identifier of the field, while the value is a tuple
|
|
|
|
/// containing the [Type] of the field, and a `bool` indicating whether the field is a
|
|
|
|
/// variable (as opposed to a function).
|
2022-02-21 17:52:34 +08:00
|
|
|
fields: Mapping<StrRef, (Type, bool)>,
|
2023-10-31 11:41:13 +08:00
|
|
|
|
|
|
|
/// Mapping between the ID of type variables and the [Type] representing the type variables
|
|
|
|
/// of this object type.
|
2022-02-21 17:52:34 +08:00
|
|
|
params: VarMap,
|
2021-07-14 08:12:47 +08:00
|
|
|
},
|
|
|
|
TVirtual {
|
2021-07-14 15:24:00 +08:00
|
|
|
ty: Type,
|
2021-07-14 08:12:47 +08:00
|
|
|
},
|
2022-02-21 17:52:34 +08:00
|
|
|
TCall(Vec<CallId>),
|
2023-10-31 11:41:13 +08:00
|
|
|
|
|
|
|
/// A function type.
|
2022-02-21 17:52:34 +08:00
|
|
|
TFunc(FunSignature),
|
2021-01-04 14:49:48 +08:00
|
|
|
}
|
2021-06-30 16:28:18 +08:00
|
|
|
|
|
|
|
impl TypeEnum {
|
2021-07-16 13:55:29 +08:00
|
|
|
pub fn get_type_name(&self) -> &'static str {
|
2021-07-14 15:24:00 +08:00
|
|
|
match self {
|
2021-07-30 11:28:27 +08:00
|
|
|
TypeEnum::TRigidVar { .. } => "TRigidVar",
|
2021-07-14 15:24:00 +08:00
|
|
|
TypeEnum::TVar { .. } => "TVar",
|
2023-12-05 14:37:08 +08:00
|
|
|
TypeEnum::TConstant { .. } => "TConstant",
|
2021-07-14 15:24:00 +08:00
|
|
|
TypeEnum::TTuple { .. } => "TTuple",
|
|
|
|
TypeEnum::TList { .. } => "TList",
|
|
|
|
TypeEnum::TObj { .. } => "TObj",
|
|
|
|
TypeEnum::TVirtual { .. } => "TVirtual",
|
|
|
|
TypeEnum::TCall { .. } => "TCall",
|
|
|
|
TypeEnum::TFunc { .. } => "TFunc",
|
|
|
|
}
|
|
|
|
}
|
2021-07-14 08:12:47 +08:00
|
|
|
}
|
|
|
|
|
2021-08-13 13:33:59 +08:00
|
|
|
pub type SharedUnifier = Arc<Mutex<(UnificationTable<TypeEnum>, u32, Vec<Call>)>>;
|
2021-08-03 13:38:27 +08:00
|
|
|
|
2021-08-19 15:30:15 +08:00
|
|
|
#[derive(Clone)]
|
2021-07-15 16:00:23 +08:00
|
|
|
pub struct Unifier {
|
2022-03-18 01:07:44 +08:00
|
|
|
pub(crate) top_level: Option<Arc<TopLevelContext>>,
|
|
|
|
pub(crate) unification_table: UnificationTable<Rc<TypeEnum>>,
|
|
|
|
pub(crate) calls: Vec<Rc<Call>>,
|
2021-07-16 15:55:52 +08:00
|
|
|
var_id: u32,
|
2021-10-16 15:56:13 +08:00
|
|
|
unify_cache: HashSet<(Type, Type)>,
|
2022-02-25 14:47:19 +08:00
|
|
|
snapshot: Option<(usize, u32)>
|
2021-07-14 08:12:47 +08:00
|
|
|
}
|
|
|
|
|
2021-09-22 17:56:48 +08:00
|
|
|
impl Default for Unifier {
|
|
|
|
fn default() -> Self {
|
|
|
|
Unifier::new()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-14 08:12:47 +08:00
|
|
|
impl Unifier {
|
2021-07-21 14:24:46 +08:00
|
|
|
/// Get an empty unifier
|
2021-07-15 16:00:23 +08:00
|
|
|
pub fn new() -> Unifier {
|
2021-08-21 14:51:46 +08:00
|
|
|
Unifier {
|
|
|
|
unification_table: UnificationTable::new(),
|
|
|
|
var_id: 0,
|
|
|
|
calls: Vec::new(),
|
2021-10-16 15:56:13 +08:00
|
|
|
unify_cache: HashSet::new(),
|
2021-08-21 14:51:46 +08:00
|
|
|
top_level: None,
|
2022-02-25 14:47:19 +08:00
|
|
|
snapshot: None,
|
2021-08-21 14:51:46 +08:00
|
|
|
}
|
2021-07-15 16:00:23 +08:00
|
|
|
}
|
|
|
|
|
2022-02-21 17:52:34 +08:00
|
|
|
pub unsafe fn get_unification_table(&mut self) -> &mut UnificationTable<Rc<TypeEnum>> {
|
|
|
|
&mut self.unification_table
|
|
|
|
}
|
|
|
|
|
2021-08-05 14:55:23 +08:00
|
|
|
/// Determine if the two types are the same
|
|
|
|
pub fn unioned(&mut self, a: Type, b: Type) -> bool {
|
|
|
|
self.unification_table.unioned(a, b)
|
|
|
|
}
|
|
|
|
|
2021-08-03 13:38:27 +08:00
|
|
|
pub fn from_shared_unifier(unifier: &SharedUnifier) -> Unifier {
|
|
|
|
let lock = unifier.lock().unwrap();
|
2021-08-13 13:33:59 +08:00
|
|
|
Unifier {
|
|
|
|
unification_table: UnificationTable::from_send(&lock.0),
|
|
|
|
var_id: lock.1,
|
|
|
|
calls: lock.2.iter().map(|v| Rc::new(v.clone())).collect_vec(),
|
2021-08-21 14:51:46 +08:00
|
|
|
top_level: None,
|
2021-10-16 15:56:13 +08:00
|
|
|
unify_cache: HashSet::new(),
|
2022-02-25 14:47:19 +08:00
|
|
|
snapshot: None,
|
2021-08-13 13:33:59 +08:00
|
|
|
}
|
2021-08-03 13:38:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_shared_unifier(&self) -> SharedUnifier {
|
2021-08-13 13:33:59 +08:00
|
|
|
Arc::new(Mutex::new((
|
|
|
|
self.unification_table.get_send(),
|
|
|
|
self.var_id,
|
|
|
|
self.calls.iter().map(|v| v.as_ref().clone()).collect_vec(),
|
|
|
|
)))
|
2021-08-03 13:38:27 +08:00
|
|
|
}
|
|
|
|
|
2021-07-16 13:55:29 +08:00
|
|
|
/// Register a type to the unifier.
|
|
|
|
/// Returns a key in the unification_table.
|
2021-07-16 15:55:52 +08:00
|
|
|
pub fn add_ty(&mut self, a: TypeEnum) -> Type {
|
2021-07-23 15:25:44 +08:00
|
|
|
self.unification_table.new_key(Rc::new(a))
|
|
|
|
}
|
|
|
|
|
2022-02-21 17:52:34 +08:00
|
|
|
pub fn add_record(&mut self, fields: Mapping<RecordKey, RecordField>) -> Type {
|
2021-07-23 15:25:44 +08:00
|
|
|
let id = self.var_id + 1;
|
|
|
|
self.var_id += 1;
|
|
|
|
self.add_ty(TypeEnum::TVar {
|
|
|
|
id,
|
2022-02-21 17:52:34 +08:00
|
|
|
range: vec![],
|
|
|
|
fields: Some(fields),
|
|
|
|
name: None,
|
|
|
|
loc: None,
|
2023-12-05 14:37:08 +08:00
|
|
|
is_const_generic: false,
|
2021-07-23 15:25:44 +08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-08-13 13:33:59 +08:00
|
|
|
pub fn add_call(&mut self, call: Call) -> CallId {
|
|
|
|
let id = CallId(self.calls.len());
|
|
|
|
self.calls.push(Rc::new(call));
|
|
|
|
id
|
|
|
|
}
|
|
|
|
|
2021-08-19 15:30:15 +08:00
|
|
|
pub fn get_call_signature(&mut self, id: CallId) -> Option<FunSignature> {
|
|
|
|
let fun = self.calls.get(id.0).unwrap().fun.borrow().unwrap();
|
|
|
|
if let TypeEnum::TFunc(sign) = &*self.get_ty(fun) {
|
2022-02-21 17:52:34 +08:00
|
|
|
Some(sign.clone())
|
2021-08-19 15:30:15 +08:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-21 17:52:34 +08:00
|
|
|
pub fn get_call_signature_immutable(&self, id: CallId) -> Option<FunSignature> {
|
|
|
|
let fun = self.calls.get(id.0).unwrap().fun.borrow().unwrap();
|
|
|
|
if let TypeEnum::TFunc(sign) = &*self.get_ty_immutable(fun) {
|
|
|
|
Some(sign.clone())
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
2021-08-05 14:55:23 +08:00
|
|
|
}
|
|
|
|
|
2022-02-21 17:52:34 +08:00
|
|
|
pub fn get_representative(&mut self, ty: Type) -> Type {
|
|
|
|
self.unification_table.get_representative(ty)
|
2021-07-15 16:00:23 +08:00
|
|
|
}
|
|
|
|
|
2021-07-16 13:55:29 +08:00
|
|
|
/// Get the TypeEnum of a type.
|
2021-07-23 15:25:44 +08:00
|
|
|
pub fn get_ty(&mut self, a: Type) -> Rc<TypeEnum> {
|
2021-07-22 11:37:29 +08:00
|
|
|
self.unification_table.probe_value(a).clone()
|
2021-07-15 16:00:23 +08:00
|
|
|
}
|
|
|
|
|
2022-02-21 17:52:34 +08:00
|
|
|
pub fn get_ty_immutable(&self, a: Type) -> Rc<TypeEnum> {
|
|
|
|
self.unification_table.probe_value_immutable(a).clone()
|
|
|
|
}
|
|
|
|
|
2022-02-21 18:27:46 +08:00
|
|
|
pub fn get_fresh_rigid_var(
|
|
|
|
&mut self,
|
|
|
|
name: Option<StrRef>,
|
|
|
|
loc: Option<Location>,
|
|
|
|
) -> (Type, u32) {
|
2021-07-30 11:28:27 +08:00
|
|
|
let id = self.var_id + 1;
|
|
|
|
self.var_id += 1;
|
2022-02-21 17:52:34 +08:00
|
|
|
(self.add_ty(TypeEnum::TRigidVar { id, name, loc }), id)
|
2021-07-30 11:28:27 +08:00
|
|
|
}
|
|
|
|
|
2022-02-21 17:52:34 +08:00
|
|
|
pub fn get_dummy_var(&mut self) -> (Type, u32) {
|
|
|
|
self.get_fresh_var_with_range(&[], None, None)
|
|
|
|
}
|
|
|
|
|
2023-10-31 11:41:13 +08:00
|
|
|
/// Returns a fresh [type variable][TypeEnum::TVar] with no associated range.
|
|
|
|
///
|
|
|
|
/// This type variable can be instantiated by any type.
|
2022-02-21 17:52:34 +08:00
|
|
|
pub fn get_fresh_var(&mut self, name: Option<StrRef>, loc: Option<Location>) -> (Type, u32) {
|
|
|
|
self.get_fresh_var_with_range(&[], name, loc)
|
2021-07-19 16:51:58 +08:00
|
|
|
}
|
|
|
|
|
2023-10-31 11:41:13 +08:00
|
|
|
/// Returns a fresh [type variable][TypeEnum::TVar] with the range specified by `range`.
|
|
|
|
///
|
|
|
|
/// This type variable can be instantiated by any type present in `range`.
|
2022-02-21 18:27:46 +08:00
|
|
|
pub fn get_fresh_var_with_range(
|
|
|
|
&mut self,
|
|
|
|
range: &[Type],
|
|
|
|
name: Option<StrRef>,
|
|
|
|
loc: Option<Location>,
|
|
|
|
) -> (Type, u32) {
|
2021-07-21 14:24:46 +08:00
|
|
|
let id = self.var_id + 1;
|
|
|
|
self.var_id += 1;
|
2022-02-21 17:52:34 +08:00
|
|
|
let range = range.to_vec();
|
2023-12-05 14:37:08 +08:00
|
|
|
(self.add_ty(TypeEnum::TVar { id, range, fields: None, name, loc, is_const_generic: false }), id)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a fresh type representing a constant generic variable with the given underlying type
|
|
|
|
/// `ty`.
|
|
|
|
pub fn get_fresh_const_generic_var(
|
|
|
|
&mut self,
|
|
|
|
ty: Type,
|
|
|
|
name: Option<StrRef>,
|
|
|
|
loc: Option<Location>,
|
|
|
|
) -> (Type, u32) {
|
|
|
|
let id = self.var_id + 1;
|
|
|
|
self.var_id += 1;
|
|
|
|
(self.add_ty(TypeEnum::TVar { id, range: vec![ty], fields: None, name, loc, is_const_generic: true }), id)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a fresh type representing a [fresh constant][TypeEnum::TConstant] with the given
|
|
|
|
/// `value` and type `ty`.
|
|
|
|
pub fn get_fresh_constant(
|
|
|
|
&mut self,
|
|
|
|
value: SymbolValue,
|
|
|
|
ty: Type,
|
|
|
|
loc: Option<Location>,
|
|
|
|
) -> Type {
|
|
|
|
assert!(matches!(self.get_ty(ty).as_ref(), TypeEnum::TObj { .. }));
|
|
|
|
|
|
|
|
self.add_ty(TypeEnum::TConstant { ty, value, loc })
|
2021-07-21 14:24:46 +08:00
|
|
|
}
|
|
|
|
|
2021-07-30 11:28:27 +08:00
|
|
|
/// Unification would not unify rigid variables with other types, but we want to do this for
|
|
|
|
/// function instantiations, so we make it explicit.
|
|
|
|
pub fn replace_rigid_var(&mut self, rigid: Type, b: Type) {
|
|
|
|
assert!(matches!(&*self.get_ty(rigid), TypeEnum::TRigidVar { .. }));
|
|
|
|
self.set_a_to_b(rigid, b);
|
|
|
|
}
|
|
|
|
|
2021-07-30 16:32:50 +08:00
|
|
|
pub fn get_instantiations(&mut self, ty: Type) -> Option<Vec<Type>> {
|
|
|
|
match &*self.get_ty(ty) {
|
|
|
|
TypeEnum::TVar { range, .. } => {
|
|
|
|
if range.is_empty() {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(
|
|
|
|
range
|
|
|
|
.iter()
|
2023-12-06 11:49:02 +08:00
|
|
|
.flat_map(|ty| self.get_instantiations(*ty).unwrap_or_else(|| vec![*ty]))
|
2021-07-30 16:32:50 +08:00
|
|
|
.collect_vec(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TypeEnum::TList { ty } => self
|
|
|
|
.get_instantiations(*ty)
|
|
|
|
.map(|ty| ty.iter().map(|&ty| self.add_ty(TypeEnum::TList { ty })).collect_vec()),
|
|
|
|
TypeEnum::TVirtual { ty } => self.get_instantiations(*ty).map(|ty| {
|
|
|
|
ty.iter().map(|&ty| self.add_ty(TypeEnum::TVirtual { ty })).collect_vec()
|
|
|
|
}),
|
|
|
|
TypeEnum::TTuple { ty } => {
|
|
|
|
let tuples = ty
|
|
|
|
.iter()
|
|
|
|
.map(|ty| self.get_instantiations(*ty).unwrap_or_else(|| vec![*ty]))
|
|
|
|
.multi_cartesian_product()
|
|
|
|
.collect_vec();
|
|
|
|
if tuples.len() == 1 {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(
|
|
|
|
tuples.into_iter().map(|ty| self.add_ty(TypeEnum::TTuple { ty })).collect(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TypeEnum::TObj { params, .. } => {
|
2022-02-21 17:52:34 +08:00
|
|
|
let (keys, params): (Vec<u32>, Vec<Type>) = params.iter().unzip();
|
2021-07-30 16:32:50 +08:00
|
|
|
let params = params
|
|
|
|
.into_iter()
|
2022-02-21 17:52:34 +08:00
|
|
|
.map(|ty| self.get_instantiations(ty).unwrap_or_else(|| vec![ty]))
|
2021-07-30 16:32:50 +08:00
|
|
|
.multi_cartesian_product()
|
|
|
|
.collect_vec();
|
|
|
|
if params.len() <= 1 {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(
|
|
|
|
params
|
|
|
|
.into_iter()
|
|
|
|
.map(|params| {
|
|
|
|
self.subst(
|
|
|
|
ty,
|
2022-02-21 18:27:46 +08:00
|
|
|
&zip(keys.iter().cloned(), params.iter().cloned()).collect(),
|
2021-07-30 16:32:50 +08:00
|
|
|
)
|
|
|
|
.unwrap_or(ty)
|
|
|
|
})
|
|
|
|
.collect(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-28 17:25:19 +08:00
|
|
|
pub fn is_concrete(&mut self, a: Type, allowed_typevars: &[Type]) -> bool {
|
|
|
|
use TypeEnum::*;
|
|
|
|
match &*self.get_ty(a) {
|
2023-12-05 14:37:08 +08:00
|
|
|
TRigidVar { .. } | TConstant { .. } => true,
|
2021-07-28 17:25:19 +08:00
|
|
|
TVar { .. } => allowed_typevars.iter().any(|b| self.unification_table.unioned(a, *b)),
|
|
|
|
TCall { .. } => false,
|
|
|
|
TList { ty } => self.is_concrete(*ty, allowed_typevars),
|
|
|
|
TTuple { ty } => ty.iter().all(|ty| self.is_concrete(*ty, allowed_typevars)),
|
|
|
|
TObj { params: vars, .. } => {
|
2022-02-21 17:52:34 +08:00
|
|
|
vars.values().all(|ty| self.is_concrete(*ty, allowed_typevars))
|
2021-07-28 17:25:19 +08:00
|
|
|
}
|
|
|
|
// functions are instantiated for each call sites, so the function type can contain
|
|
|
|
// type variables.
|
|
|
|
TFunc { .. } => true,
|
|
|
|
TVirtual { ty } => self.is_concrete(*ty, allowed_typevars),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-25 14:47:19 +08:00
|
|
|
fn restore_snapshot(&mut self) {
|
|
|
|
if let Some(snapshot) = self.snapshot.take() {
|
|
|
|
self.unification_table.restore_snapshot(snapshot);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn discard_snapshot(&mut self, snapshot: (usize, u32)) {
|
|
|
|
if self.snapshot == Some(snapshot) {
|
|
|
|
self.unification_table.discard_snapshot(snapshot);
|
|
|
|
self.snapshot = None;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-16 15:56:13 +08:00
|
|
|
pub fn unify_call(
|
|
|
|
&mut self,
|
|
|
|
call: &Call,
|
|
|
|
b: Type,
|
|
|
|
signature: &FunSignature,
|
|
|
|
required: &[StrRef],
|
2022-02-21 17:52:34 +08:00
|
|
|
) -> Result<(), TypeError> {
|
2022-02-25 14:47:19 +08:00
|
|
|
let snapshot = self.unification_table.get_snapshot();
|
|
|
|
if self.snapshot.is_none() {
|
|
|
|
self.snapshot = Some(snapshot);
|
|
|
|
}
|
|
|
|
|
2022-02-21 17:52:34 +08:00
|
|
|
let Call { posargs, kwargs, ret, fun, loc } = call;
|
2023-12-06 11:49:02 +08:00
|
|
|
let instantiated = self.instantiate_fun(b, signature);
|
2021-09-22 17:45:21 +08:00
|
|
|
let r = self.get_ty(instantiated);
|
|
|
|
let r = r.as_ref();
|
|
|
|
let signature;
|
2023-12-06 11:49:02 +08:00
|
|
|
if let TypeEnum::TFunc(s) = r {
|
2021-09-22 17:45:21 +08:00
|
|
|
signature = s;
|
|
|
|
} else {
|
|
|
|
unreachable!();
|
|
|
|
}
|
|
|
|
// we check to make sure that all required arguments (those without default
|
|
|
|
// arguments) are provided, and do not provide the same argument twice.
|
|
|
|
let mut required = required.to_vec();
|
2022-02-21 18:27:46 +08:00
|
|
|
let mut all_names: Vec<_> = signature.args.iter().map(|v| (v.name, v.ty)).rev().collect();
|
2021-09-22 17:45:21 +08:00
|
|
|
for (i, t) in posargs.iter().enumerate() {
|
2022-02-21 17:52:34 +08:00
|
|
|
if signature.args.len() <= i {
|
2022-02-25 20:01:11 +08:00
|
|
|
self.restore_snapshot();
|
2022-02-21 18:27:46 +08:00
|
|
|
return Err(TypeError::new(
|
2022-03-05 03:59:45 +08:00
|
|
|
TypeErrorKind::TooManyArguments {
|
|
|
|
expected: signature.args.len(),
|
|
|
|
got: posargs.len() + kwargs.len(),
|
|
|
|
},
|
2022-02-21 18:27:46 +08:00
|
|
|
*loc,
|
|
|
|
));
|
2021-09-22 17:45:21 +08:00
|
|
|
}
|
2022-02-21 17:52:34 +08:00
|
|
|
required.pop();
|
|
|
|
let (name, expected) = all_names.pop().unwrap();
|
2022-02-21 18:27:46 +08:00
|
|
|
self.unify_impl(expected, *t, false).map_err(|_| {
|
2022-02-25 14:47:19 +08:00
|
|
|
self.restore_snapshot();
|
2022-02-21 18:27:46 +08:00
|
|
|
TypeError::new(TypeErrorKind::IncorrectArgType { name, expected, got: *t }, *loc)
|
|
|
|
})?;
|
2021-09-22 17:45:21 +08:00
|
|
|
}
|
|
|
|
for (k, t) in kwargs.iter() {
|
|
|
|
if let Some(i) = required.iter().position(|v| v == k) {
|
|
|
|
required.remove(i);
|
|
|
|
}
|
|
|
|
let i = all_names
|
|
|
|
.iter()
|
|
|
|
.position(|v| &v.0 == k)
|
2022-02-25 14:47:19 +08:00
|
|
|
.ok_or_else(|| {
|
|
|
|
self.restore_snapshot();
|
|
|
|
TypeError::new(TypeErrorKind::UnknownArgName(*k), *loc)
|
|
|
|
})?;
|
2022-02-21 17:52:34 +08:00
|
|
|
let (name, expected) = all_names.remove(i);
|
2022-02-21 18:27:46 +08:00
|
|
|
self.unify_impl(expected, *t, false).map_err(|_| {
|
2022-02-25 14:47:19 +08:00
|
|
|
self.restore_snapshot();
|
2022-02-21 18:27:46 +08:00
|
|
|
TypeError::new(TypeErrorKind::IncorrectArgType { name, expected, got: *t }, *loc)
|
|
|
|
})?;
|
2021-09-22 17:45:21 +08:00
|
|
|
}
|
|
|
|
if !required.is_empty() {
|
2022-02-25 14:47:19 +08:00
|
|
|
self.restore_snapshot();
|
2022-02-21 18:27:46 +08:00
|
|
|
return Err(TypeError::new(
|
|
|
|
TypeErrorKind::MissingArgs(required.iter().join(", ")),
|
|
|
|
*loc,
|
|
|
|
));
|
2021-09-22 17:45:21 +08:00
|
|
|
}
|
2022-02-21 18:27:46 +08:00
|
|
|
self.unify_impl(*ret, signature.ret, false).map_err(|mut err| {
|
2022-02-25 14:47:19 +08:00
|
|
|
self.restore_snapshot();
|
2022-02-21 18:27:46 +08:00
|
|
|
if err.loc.is_none() {
|
|
|
|
err.loc = *loc;
|
|
|
|
}
|
|
|
|
err
|
|
|
|
})?;
|
2021-09-22 17:45:21 +08:00
|
|
|
*fun.borrow_mut() = Some(instantiated);
|
2022-02-25 14:47:19 +08:00
|
|
|
|
|
|
|
self.discard_snapshot(snapshot);
|
2021-09-22 17:45:21 +08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-02-21 17:52:34 +08:00
|
|
|
pub fn unify(&mut self, a: Type, b: Type) -> Result<(), TypeError> {
|
2022-02-25 14:47:19 +08:00
|
|
|
let snapshot = self.unification_table.get_snapshot();
|
|
|
|
if self.snapshot.is_none() {
|
|
|
|
self.snapshot = Some(snapshot);
|
|
|
|
}
|
2021-10-16 15:56:13 +08:00
|
|
|
self.unify_cache.clear();
|
2021-07-23 15:25:44 +08:00
|
|
|
if self.unification_table.unioned(a, b) {
|
2022-02-25 20:01:11 +08:00
|
|
|
self.discard_snapshot(snapshot);
|
2021-07-23 15:25:44 +08:00
|
|
|
Ok(())
|
|
|
|
} else {
|
2022-02-25 14:47:19 +08:00
|
|
|
let result = self.unify_impl(a, b, false);
|
|
|
|
if result.is_err() {
|
|
|
|
self.restore_snapshot();
|
|
|
|
}
|
|
|
|
self.discard_snapshot(snapshot);
|
|
|
|
result
|
2021-07-21 14:24:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-21 17:52:34 +08:00
|
|
|
fn unify_impl(&mut self, a: Type, b: Type, swapped: bool) -> Result<(), TypeError> {
|
2021-07-19 16:51:58 +08:00
|
|
|
use TypeEnum::*;
|
2021-10-16 15:56:13 +08:00
|
|
|
|
|
|
|
if !swapped {
|
|
|
|
let rep_a = self.unification_table.get_representative(a);
|
|
|
|
let rep_b = self.unification_table.get_representative(b);
|
|
|
|
if rep_a == rep_b || self.unify_cache.contains(&(rep_a, rep_b)) {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
self.unify_cache.insert((rep_a, rep_b));
|
|
|
|
}
|
|
|
|
|
2021-07-23 15:25:44 +08:00
|
|
|
let (ty_a, ty_b) = {
|
2021-07-16 15:55:52 +08:00
|
|
|
(
|
2021-07-22 11:37:29 +08:00
|
|
|
self.unification_table.probe_value(a).clone(),
|
|
|
|
self.unification_table.probe_value(b).clone(),
|
2021-07-16 15:55:52 +08:00
|
|
|
)
|
2021-07-14 08:12:47 +08:00
|
|
|
};
|
2021-07-19 16:51:58 +08:00
|
|
|
match (&*ty_a, &*ty_b) {
|
2022-02-21 18:27:46 +08:00
|
|
|
(
|
2023-12-05 14:37:08 +08:00
|
|
|
TVar { fields: fields1, id, name: name1, loc: loc1, is_const_generic: false, .. },
|
|
|
|
TVar { fields: fields2, id: id2, name: name2, loc: loc2, is_const_generic: false, .. },
|
2022-02-21 18:27:46 +08:00
|
|
|
) => {
|
2022-02-21 17:52:34 +08:00
|
|
|
let new_fields = match (fields1, fields2) {
|
|
|
|
(None, None) => None,
|
|
|
|
(None, Some(fields)) => Some(fields.clone()),
|
|
|
|
(_, None) => {
|
2021-07-23 15:25:44 +08:00
|
|
|
return self.unify_impl(b, a, true);
|
2022-02-21 18:27:46 +08:00
|
|
|
}
|
2022-02-21 17:52:34 +08:00
|
|
|
(Some(fields1), Some(fields2)) => {
|
|
|
|
let mut new_fields: Mapping<_, _> = fields2.clone();
|
|
|
|
for (key, val1) in fields1.iter() {
|
|
|
|
if let Some(val2) = fields2.get(key) {
|
2022-02-21 18:27:46 +08:00
|
|
|
self.unify_impl(val1.ty, val2.ty, false).map_err(|_| {
|
|
|
|
TypeError::new(
|
|
|
|
TypeErrorKind::FieldUnificationError {
|
|
|
|
field: *key,
|
|
|
|
types: (val1.ty, val2.ty),
|
|
|
|
loc: (*loc1, *loc2),
|
|
|
|
},
|
|
|
|
None,
|
|
|
|
)
|
|
|
|
})?;
|
|
|
|
new_fields.insert(
|
|
|
|
*key,
|
|
|
|
RecordField::new(
|
|
|
|
val1.ty,
|
|
|
|
val1.mutable || val2.mutable,
|
|
|
|
val1.loc.or(val2.loc),
|
|
|
|
),
|
|
|
|
);
|
2021-07-23 15:25:44 +08:00
|
|
|
} else {
|
2022-02-21 17:52:34 +08:00
|
|
|
new_fields.insert(*key, *val1);
|
2021-07-23 15:25:44 +08:00
|
|
|
}
|
|
|
|
}
|
2022-02-21 17:52:34 +08:00
|
|
|
Some(new_fields)
|
2021-07-23 15:25:44 +08:00
|
|
|
}
|
2022-02-21 17:52:34 +08:00
|
|
|
};
|
2022-02-21 18:27:46 +08:00
|
|
|
let intersection = self
|
|
|
|
.get_intersection(a, b)
|
|
|
|
.map_err(|_| TypeError::new(TypeErrorKind::IncompatibleTypes(a, b), None))?
|
|
|
|
.unwrap();
|
2023-10-26 13:52:40 +08:00
|
|
|
let range = if let TVar { range, .. } = &*self.get_ty(intersection) {
|
2022-02-21 17:52:34 +08:00
|
|
|
range.clone()
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
};
|
|
|
|
self.unification_table.unify(a, b);
|
2022-02-21 18:27:46 +08:00
|
|
|
self.unification_table.set_value(
|
|
|
|
a,
|
2023-10-26 13:52:40 +08:00
|
|
|
Rc::new(TVar {
|
2022-03-23 00:22:28 +08:00
|
|
|
id: name1.map_or(*id2, |_| *id),
|
2022-02-21 18:27:46 +08:00
|
|
|
fields: new_fields,
|
|
|
|
range,
|
|
|
|
name: name1.or(*name2),
|
|
|
|
loc: loc1.or(*loc2),
|
2023-12-05 14:37:08 +08:00
|
|
|
is_const_generic: false,
|
2022-02-21 18:27:46 +08:00
|
|
|
}),
|
|
|
|
);
|
2021-07-14 08:12:47 +08:00
|
|
|
}
|
2023-12-05 14:37:08 +08:00
|
|
|
(TVar { fields: None, range, is_const_generic: false, .. }, _) => {
|
2021-07-26 14:38:18 +08:00
|
|
|
// We check for the range of the type variable to see if unification is allowed.
|
|
|
|
// Note that although b may be compatible with a, we may have to constrain type
|
|
|
|
// variables in b to make sure that instantiations of b would always be compatible
|
|
|
|
// with a.
|
|
|
|
// The return value x of check_var_compatibility would be a new type that is
|
|
|
|
// guaranteed to be compatible with a under all possible instantiations. So we
|
|
|
|
// unify x with b to recursively apply the constrains, and then set a to x.
|
2022-02-21 18:27:46 +08:00
|
|
|
let x = self
|
|
|
|
.check_var_compatibility(b, range)
|
|
|
|
.map_err(|_| {
|
|
|
|
TypeError::new(TypeErrorKind::IncompatibleRange(b, range.clone()), None)
|
|
|
|
})?
|
|
|
|
.unwrap_or(b);
|
2021-10-16 15:56:13 +08:00
|
|
|
self.unify_impl(x, b, false)?;
|
2021-07-26 14:20:09 +08:00
|
|
|
self.set_a_to_b(a, x);
|
2021-07-23 15:25:44 +08:00
|
|
|
}
|
2023-12-05 14:37:08 +08:00
|
|
|
(TVar { fields: Some(fields), range, is_const_generic: false, .. }, TTuple { ty }) => {
|
2021-07-23 15:25:44 +08:00
|
|
|
let len = ty.len() as i32;
|
2022-02-21 17:52:34 +08:00
|
|
|
for (k, v) in fields.iter() {
|
|
|
|
match *k {
|
|
|
|
RecordKey::Int(i) => {
|
|
|
|
if v.mutable {
|
|
|
|
return Err(TypeError::new(
|
2022-02-21 18:27:46 +08:00
|
|
|
TypeErrorKind::MutationError(*k, b),
|
|
|
|
v.loc,
|
|
|
|
));
|
2022-02-21 17:52:34 +08:00
|
|
|
}
|
|
|
|
let ind = if i < 0 { len + i } else { i };
|
|
|
|
if ind >= len || ind < 0 {
|
|
|
|
return Err(TypeError::new(
|
2022-02-21 18:27:46 +08:00
|
|
|
TypeErrorKind::TupleIndexOutOfBounds { index: i, len },
|
|
|
|
v.loc,
|
|
|
|
));
|
2022-02-21 17:52:34 +08:00
|
|
|
}
|
2022-02-21 18:27:46 +08:00
|
|
|
self.unify_impl(v.ty, ty[ind as usize], false)
|
|
|
|
.map_err(|e| e.at(v.loc))?;
|
|
|
|
}
|
|
|
|
RecordKey::Str(_) => {
|
|
|
|
return Err(TypeError::new(TypeErrorKind::NoSuchField(*k, b), v.loc))
|
2022-02-21 17:52:34 +08:00
|
|
|
}
|
2021-07-14 15:24:00 +08:00
|
|
|
}
|
|
|
|
}
|
2022-02-21 17:52:34 +08:00
|
|
|
let x = self.check_var_compatibility(b, range)?.unwrap_or(b);
|
2021-10-16 15:56:13 +08:00
|
|
|
self.unify_impl(x, b, false)?;
|
2021-07-26 14:20:09 +08:00
|
|
|
self.set_a_to_b(a, x);
|
2021-07-14 15:24:00 +08:00
|
|
|
}
|
2023-12-05 14:37:08 +08:00
|
|
|
(TVar { fields: Some(fields), range, is_const_generic: false, .. }, TList { ty }) => {
|
2022-02-21 17:52:34 +08:00
|
|
|
for (k, v) in fields.iter() {
|
|
|
|
match *k {
|
2022-02-21 18:27:46 +08:00
|
|
|
RecordKey::Int(_) => {
|
|
|
|
self.unify_impl(v.ty, *ty, false).map_err(|e| e.at(v.loc))?
|
|
|
|
}
|
|
|
|
RecordKey::Str(_) => {
|
|
|
|
return Err(TypeError::new(TypeErrorKind::NoSuchField(*k, b), v.loc))
|
|
|
|
}
|
2022-02-21 17:52:34 +08:00
|
|
|
}
|
2021-07-14 15:24:00 +08:00
|
|
|
}
|
2022-02-21 17:52:34 +08:00
|
|
|
let x = self.check_var_compatibility(b, range)?.unwrap_or(b);
|
2021-10-16 15:56:13 +08:00
|
|
|
self.unify_impl(x, b, false)?;
|
2021-07-26 14:20:09 +08:00
|
|
|
self.set_a_to_b(a, x);
|
2021-07-19 16:51:58 +08:00
|
|
|
}
|
2023-12-05 14:37:08 +08:00
|
|
|
|
|
|
|
(TVar { id: id1, range: ty1, is_const_generic: true, .. }, TVar { id: id2, range: ty2, .. }) => {
|
|
|
|
let ty1 = ty1[0];
|
|
|
|
let ty2 = ty2[0];
|
|
|
|
|
|
|
|
if id1 != id2 {
|
|
|
|
self.unify_impl(ty1, ty2, false)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
self.set_a_to_b(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
(TVar { range: ty1, is_const_generic: true, .. }, TConstant { ty: ty2, .. }) => {
|
|
|
|
let ty1 = ty1[0];
|
|
|
|
|
|
|
|
self.unify_impl(ty1, *ty2, false)?;
|
|
|
|
self.set_a_to_b(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
(TConstant { value: val1, ty: ty1, .. }, TConstant { value: val2, ty: ty2, .. }) => {
|
|
|
|
if val1 != val2 {
|
|
|
|
eprintln!("VALUE MISMATCH: lhs={val1:?} rhs={val2:?} eq={}", val1 == val2);
|
|
|
|
return self.incompatible_types(a, b)
|
|
|
|
}
|
|
|
|
self.unify_impl(*ty1, *ty2, false)?;
|
|
|
|
|
|
|
|
self.set_a_to_b(a, b);
|
|
|
|
}
|
|
|
|
|
2021-07-19 16:51:58 +08:00
|
|
|
(TTuple { ty: ty1 }, TTuple { ty: ty2 }) => {
|
|
|
|
if ty1.len() != ty2.len() {
|
2022-02-21 17:52:34 +08:00
|
|
|
return Err(TypeError::new(TypeErrorKind::IncompatibleTypes(a, b), None));
|
2021-07-19 16:51:58 +08:00
|
|
|
}
|
|
|
|
for (x, y) in ty1.iter().zip(ty2.iter()) {
|
2022-04-22 15:31:55 +08:00
|
|
|
if self.unify_impl(*x, *y, false).is_err() {
|
|
|
|
return Err(TypeError::new(TypeErrorKind::IncompatibleTypes(a, b), None));
|
|
|
|
}
|
2021-07-19 16:51:58 +08:00
|
|
|
}
|
|
|
|
self.set_a_to_b(a, b);
|
2021-07-14 15:24:00 +08:00
|
|
|
}
|
2021-07-19 16:51:58 +08:00
|
|
|
(TList { ty: ty1 }, TList { ty: ty2 }) => {
|
2022-04-22 15:31:55 +08:00
|
|
|
if self.unify_impl(*ty1, *ty2, false).is_err() {
|
|
|
|
return Err(TypeError::new(TypeErrorKind::IncompatibleTypes(a, b), None));
|
|
|
|
}
|
2021-07-19 16:51:58 +08:00
|
|
|
self.set_a_to_b(a, b);
|
|
|
|
}
|
2022-02-21 17:52:34 +08:00
|
|
|
(TVar { fields: Some(map), range, .. }, TObj { fields, .. }) => {
|
|
|
|
for (k, field) in map.iter() {
|
|
|
|
match *k {
|
|
|
|
RecordKey::Str(s) => {
|
2022-02-21 18:27:46 +08:00
|
|
|
let (ty, mutable) = fields.get(&s).copied().ok_or_else(|| {
|
|
|
|
TypeError::new(TypeErrorKind::NoSuchField(*k, b), field.loc)
|
|
|
|
})?;
|
2022-02-21 17:52:34 +08:00
|
|
|
// typevar represents the usage of the variable
|
|
|
|
// it is OK to have immutable usage for mutable fields
|
|
|
|
// but cannot have mutable usage for immutable fields
|
2022-02-21 18:27:46 +08:00
|
|
|
if field.mutable && !mutable {
|
2022-02-21 17:52:34 +08:00
|
|
|
return Err(TypeError::new(
|
2022-02-21 18:27:46 +08:00
|
|
|
TypeErrorKind::MutationError(*k, b),
|
|
|
|
field.loc,
|
|
|
|
));
|
2022-02-21 17:52:34 +08:00
|
|
|
}
|
2022-02-21 18:27:46 +08:00
|
|
|
self.unify_impl(field.ty, ty, false).map_err(|v| v.at(field.loc))?;
|
|
|
|
}
|
|
|
|
RecordKey::Int(_) => {
|
|
|
|
return Err(TypeError::new(
|
|
|
|
TypeErrorKind::NoSuchField(*k, b),
|
|
|
|
field.loc,
|
|
|
|
))
|
2022-02-21 17:52:34 +08:00
|
|
|
}
|
2021-11-06 22:48:08 +08:00
|
|
|
}
|
2021-07-14 15:24:00 +08:00
|
|
|
}
|
2022-02-21 17:52:34 +08:00
|
|
|
let x = self.check_var_compatibility(b, range)?.unwrap_or(b);
|
2021-10-16 15:56:13 +08:00
|
|
|
self.unify_impl(x, b, false)?;
|
2021-07-26 14:20:09 +08:00
|
|
|
self.set_a_to_b(a, x);
|
2021-07-14 15:24:00 +08:00
|
|
|
}
|
2022-02-21 17:52:34 +08:00
|
|
|
(TVar { fields: Some(map), range, .. }, TVirtual { ty }) => {
|
2021-07-23 16:19:00 +08:00
|
|
|
let ty = self.get_ty(*ty);
|
|
|
|
if let TObj { fields, .. } = ty.as_ref() {
|
2022-02-21 17:52:34 +08:00
|
|
|
for (k, field) in map.iter() {
|
|
|
|
match *k {
|
|
|
|
RecordKey::Str(s) => {
|
2022-02-21 18:27:46 +08:00
|
|
|
let (ty, _) = fields.get(&s).copied().ok_or_else(|| {
|
|
|
|
TypeError::new(TypeErrorKind::NoSuchField(*k, b), field.loc)
|
|
|
|
})?;
|
2022-02-21 17:52:34 +08:00
|
|
|
if !matches!(self.get_ty(ty).as_ref(), TFunc { .. }) {
|
|
|
|
return Err(TypeError::new(
|
2022-02-21 18:27:46 +08:00
|
|
|
TypeErrorKind::NoSuchField(*k, b),
|
|
|
|
field.loc,
|
|
|
|
));
|
2022-02-21 17:52:34 +08:00
|
|
|
}
|
|
|
|
if field.mutable {
|
|
|
|
return Err(TypeError::new(
|
2022-02-21 18:27:46 +08:00
|
|
|
TypeErrorKind::MutationError(*k, b),
|
|
|
|
field.loc,
|
|
|
|
));
|
2022-02-21 17:52:34 +08:00
|
|
|
}
|
|
|
|
self.unify_impl(field.ty, ty, false)
|
|
|
|
.map_err(|v| v.at(field.loc))?;
|
|
|
|
}
|
2022-02-21 18:27:46 +08:00
|
|
|
RecordKey::Int(_) => {
|
|
|
|
return Err(TypeError::new(
|
|
|
|
TypeErrorKind::NoSuchField(*k, b),
|
|
|
|
field.loc,
|
|
|
|
))
|
|
|
|
}
|
2021-11-06 22:48:08 +08:00
|
|
|
}
|
2021-07-23 16:19:00 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// require annotation...
|
2022-02-21 18:27:46 +08:00
|
|
|
return Err(TypeError::new(TypeErrorKind::RequiresTypeAnn, None));
|
2021-07-23 16:19:00 +08:00
|
|
|
}
|
2022-02-21 17:52:34 +08:00
|
|
|
let x = self.check_var_compatibility(b, range)?.unwrap_or(b);
|
2021-10-16 15:56:13 +08:00
|
|
|
self.unify_impl(x, b, false)?;
|
2021-07-26 14:20:09 +08:00
|
|
|
self.set_a_to_b(a, x);
|
2021-07-19 16:51:58 +08:00
|
|
|
}
|
|
|
|
(
|
2021-07-23 15:25:44 +08:00
|
|
|
TObj { obj_id: id1, params: params1, .. },
|
|
|
|
TObj { obj_id: id2, params: params2, .. },
|
2021-07-19 16:51:58 +08:00
|
|
|
) => {
|
|
|
|
if id1 != id2 {
|
2021-08-21 14:51:46 +08:00
|
|
|
self.incompatible_types(a, b)?;
|
2021-07-19 16:51:58 +08:00
|
|
|
}
|
2023-12-05 14:37:08 +08:00
|
|
|
|
|
|
|
// Sort the type arguments by its UnificationKey first, since `HashMap::iter` visits
|
|
|
|
// all K-V pairs "in arbitrary order"
|
|
|
|
let (tv1, tv2) = (
|
|
|
|
params1.iter().sorted_by_key(|(k, _)| *k).map(|(_, v)| v).collect_vec(),
|
|
|
|
params2.iter().sorted_by_key(|(k, _)| *k).map(|(_, v)| v).collect_vec(),
|
|
|
|
);
|
|
|
|
for (x, y) in zip(tv1, tv2) {
|
2022-04-22 15:31:55 +08:00
|
|
|
if self.unify_impl(*x, *y, false).is_err() {
|
|
|
|
return Err(TypeError::new(TypeErrorKind::IncompatibleTypes(a, b), None));
|
|
|
|
};
|
2021-07-14 17:20:12 +08:00
|
|
|
}
|
2021-07-19 16:51:58 +08:00
|
|
|
self.set_a_to_b(a, b);
|
|
|
|
}
|
|
|
|
(TVirtual { ty: ty1 }, TVirtual { ty: ty2 }) => {
|
2022-04-22 15:31:55 +08:00
|
|
|
if self.unify_impl(*ty1, *ty2, false).is_err() {
|
|
|
|
return Err(TypeError::new(TypeErrorKind::IncompatibleTypes(a, b), None));
|
|
|
|
};
|
2021-07-19 16:51:58 +08:00
|
|
|
self.set_a_to_b(a, b);
|
2021-07-14 17:20:12 +08:00
|
|
|
}
|
2021-07-23 15:25:44 +08:00
|
|
|
(TCall(calls1), TCall(calls2)) => {
|
2021-07-26 14:38:18 +08:00
|
|
|
// we do not unify individual calls, instead we defer until the unification wtih a
|
|
|
|
// function definition.
|
2022-02-21 17:52:34 +08:00
|
|
|
let calls = calls1.iter().chain(calls2.iter()).cloned().collect();
|
|
|
|
self.set_a_to_b(a, b);
|
|
|
|
self.unification_table.set_value(b, Rc::new(TCall(calls)));
|
2021-07-14 17:20:12 +08:00
|
|
|
}
|
2021-07-23 15:25:44 +08:00
|
|
|
(TCall(calls), TFunc(signature)) => {
|
2021-09-22 17:19:27 +08:00
|
|
|
let required: Vec<StrRef> = signature
|
2021-07-19 16:51:58 +08:00
|
|
|
.args
|
|
|
|
.iter()
|
2021-08-07 17:25:14 +08:00
|
|
|
.filter(|v| v.default_value.is_none())
|
2021-09-22 17:19:27 +08:00
|
|
|
.map(|v| v.name)
|
2021-07-19 16:51:58 +08:00
|
|
|
.rev()
|
|
|
|
.collect();
|
2021-07-26 14:38:18 +08:00
|
|
|
// we unify every calls to the function signature.
|
2022-02-21 17:52:34 +08:00
|
|
|
for c in calls.iter() {
|
2021-09-22 17:45:21 +08:00
|
|
|
let call = self.calls[c.0].clone();
|
2022-02-21 17:52:34 +08:00
|
|
|
self.unify_call(&call, b, signature, &required)?;
|
2021-07-16 15:55:52 +08:00
|
|
|
}
|
2021-07-19 16:51:58 +08:00
|
|
|
self.set_a_to_b(a, b);
|
|
|
|
}
|
|
|
|
(TFunc(sign1), TFunc(sign2)) => {
|
|
|
|
if !sign1.vars.is_empty() || !sign2.vars.is_empty() {
|
2022-02-21 17:52:34 +08:00
|
|
|
return Err(TypeError::new(TypeErrorKind::PolymorphicFunctionPointer, None));
|
2021-07-16 15:55:52 +08:00
|
|
|
}
|
2021-07-19 16:51:58 +08:00
|
|
|
if sign1.args.len() != sign2.args.len() {
|
2022-02-21 17:52:34 +08:00
|
|
|
return Err(TypeError::new(TypeErrorKind::IncompatibleTypes(a, b), None));
|
2021-07-19 16:51:58 +08:00
|
|
|
}
|
|
|
|
for (x, y) in sign1.args.iter().zip(sign2.args.iter()) {
|
2022-02-21 17:52:34 +08:00
|
|
|
if x.name != y.name || x.default_value != y.default_value {
|
|
|
|
return Err(TypeError::new(TypeErrorKind::IncompatibleTypes(a, b), None));
|
2021-07-16 15:55:52 +08:00
|
|
|
}
|
2022-04-22 15:31:55 +08:00
|
|
|
if self.unify_impl(x.ty, y.ty, false).is_err() {
|
|
|
|
return Err(TypeError::new(TypeErrorKind::IncompatibleTypes(a, b), None));
|
|
|
|
};
|
2021-07-19 16:51:58 +08:00
|
|
|
}
|
2022-04-22 15:31:55 +08:00
|
|
|
if self.unify_impl(sign1.ret, sign2.ret, false).is_err() {
|
|
|
|
return Err(TypeError::new(TypeErrorKind::IncompatibleTypes(a, b), None));
|
|
|
|
};
|
2021-07-19 16:51:58 +08:00
|
|
|
self.set_a_to_b(a, b);
|
|
|
|
}
|
2022-02-21 17:52:34 +08:00
|
|
|
(TVar { fields: Some(fields), .. }, _) => {
|
|
|
|
let (k, v) = fields.iter().next().unwrap();
|
|
|
|
return Err(TypeError::new(TypeErrorKind::NoSuchField(*k, b), v.loc));
|
|
|
|
}
|
2021-07-19 16:51:58 +08:00
|
|
|
_ => {
|
|
|
|
if swapped {
|
2021-08-21 14:51:46 +08:00
|
|
|
return self.incompatible_types(a, b);
|
2021-07-19 16:51:58 +08:00
|
|
|
} else {
|
|
|
|
self.unify_impl(b, a, true)?;
|
2021-07-16 15:55:52 +08:00
|
|
|
}
|
|
|
|
}
|
2021-07-14 15:24:00 +08:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-02-21 17:52:34 +08:00
|
|
|
pub fn stringify(&self, ty: Type) -> String {
|
|
|
|
self.stringify_with_notes(ty, &mut None)
|
|
|
|
}
|
|
|
|
|
2022-02-21 18:27:46 +08:00
|
|
|
pub fn stringify_with_notes(
|
|
|
|
&self,
|
|
|
|
ty: Type,
|
|
|
|
notes: &mut Option<HashMap<u32, String>>,
|
|
|
|
) -> String {
|
2021-08-21 14:51:46 +08:00
|
|
|
let top_level = self.top_level.clone();
|
2022-02-21 17:52:34 +08:00
|
|
|
self.internal_stringify(
|
2021-08-21 14:51:46 +08:00
|
|
|
ty,
|
|
|
|
&mut |id| {
|
|
|
|
top_level.as_ref().map_or_else(
|
|
|
|
|| format!("{}", id),
|
|
|
|
|top_level| {
|
|
|
|
if let TopLevelDef::Class { name, .. } =
|
|
|
|
&*top_level.definitions.read()[id].read()
|
|
|
|
{
|
2021-09-22 17:19:27 +08:00
|
|
|
name.to_string()
|
2021-08-21 14:51:46 +08:00
|
|
|
} else {
|
|
|
|
unreachable!("expected class definition")
|
|
|
|
}
|
|
|
|
},
|
|
|
|
)
|
|
|
|
},
|
2022-04-12 09:28:17 +08:00
|
|
|
&mut |id| format!("typevar{}", id),
|
2022-02-21 18:27:46 +08:00
|
|
|
notes,
|
2021-08-21 14:51:46 +08:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-07-23 15:25:44 +08:00
|
|
|
/// Get string representation of the type
|
2022-02-21 18:27:46 +08:00
|
|
|
pub fn internal_stringify<F, G>(
|
|
|
|
&self,
|
|
|
|
ty: Type,
|
|
|
|
obj_to_name: &mut F,
|
|
|
|
var_to_name: &mut G,
|
|
|
|
notes: &mut Option<HashMap<u32, String>>,
|
|
|
|
) -> String
|
2021-07-23 15:25:44 +08:00
|
|
|
where
|
|
|
|
F: FnMut(usize) -> String,
|
|
|
|
G: FnMut(u32) -> String,
|
|
|
|
{
|
2022-02-21 17:52:34 +08:00
|
|
|
let ty = self.unification_table.probe_value_immutable(ty).clone();
|
2021-07-23 15:25:44 +08:00
|
|
|
match ty.as_ref() {
|
2022-02-21 18:27:46 +08:00
|
|
|
TypeEnum::TRigidVar { id, name, .. } => {
|
|
|
|
name.map(|v| v.to_string()).unwrap_or_else(|| var_to_name(*id))
|
|
|
|
}
|
2022-02-21 17:52:34 +08:00
|
|
|
TypeEnum::TVar { id, name, fields, range, .. } => {
|
|
|
|
let n = if let Some(fields) = fields {
|
2022-02-21 18:27:46 +08:00
|
|
|
let mut fields = fields.iter().map(|(k, f)| {
|
|
|
|
format!(
|
|
|
|
"{}={}",
|
|
|
|
k,
|
|
|
|
self.internal_stringify(f.ty, obj_to_name, var_to_name, notes)
|
|
|
|
)
|
|
|
|
});
|
2022-02-21 17:52:34 +08:00
|
|
|
let fields = fields.join(", ");
|
2022-02-21 18:27:46 +08:00
|
|
|
format!(
|
|
|
|
"{}[{}]",
|
|
|
|
name.map(|v| v.to_string()).unwrap_or_else(|| var_to_name(*id)),
|
|
|
|
fields
|
|
|
|
)
|
2022-02-21 17:52:34 +08:00
|
|
|
} else {
|
|
|
|
name.map(|v| v.to_string()).unwrap_or_else(|| var_to_name(*id))
|
|
|
|
};
|
2022-02-21 18:27:46 +08:00
|
|
|
if !range.is_empty() && notes.is_some() && !notes.as_ref().unwrap().contains_key(id)
|
|
|
|
{
|
2022-02-21 17:52:34 +08:00
|
|
|
// just in case if there is any cyclic dependency
|
|
|
|
notes.as_mut().unwrap().insert(*id, "".into());
|
2022-02-21 18:27:46 +08:00
|
|
|
let body = format!(
|
|
|
|
"{} ∈ {{{}}}",
|
|
|
|
n,
|
|
|
|
range
|
|
|
|
.iter()
|
|
|
|
.map(|v| self.internal_stringify(*v, obj_to_name, var_to_name, notes))
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join(", ")
|
|
|
|
);
|
2022-02-21 17:52:34 +08:00
|
|
|
notes.as_mut().unwrap().insert(*id, body);
|
|
|
|
};
|
|
|
|
n
|
2021-07-14 16:40:50 +08:00
|
|
|
}
|
2023-12-05 14:37:08 +08:00
|
|
|
TypeEnum::TConstant { value, .. } => {
|
|
|
|
format!("const({value})")
|
|
|
|
}
|
2021-07-14 16:40:50 +08:00
|
|
|
TypeEnum::TTuple { ty } => {
|
2022-02-21 18:27:46 +08:00
|
|
|
let mut fields =
|
|
|
|
ty.iter().map(|v| self.internal_stringify(*v, obj_to_name, var_to_name, notes));
|
2021-07-23 15:25:44 +08:00
|
|
|
format!("tuple[{}]", fields.join(", "))
|
2021-07-14 16:40:50 +08:00
|
|
|
}
|
2021-07-23 15:25:44 +08:00
|
|
|
TypeEnum::TList { ty } => {
|
2022-02-21 17:52:34 +08:00
|
|
|
format!("list[{}]", self.internal_stringify(*ty, obj_to_name, var_to_name, notes))
|
2021-07-14 16:40:50 +08:00
|
|
|
}
|
2021-07-23 15:25:44 +08:00
|
|
|
TypeEnum::TVirtual { ty } => {
|
2022-02-21 18:27:46 +08:00
|
|
|
format!(
|
|
|
|
"virtual[{}]",
|
|
|
|
self.internal_stringify(*ty, obj_to_name, var_to_name, notes)
|
|
|
|
)
|
2021-07-19 13:34:45 +08:00
|
|
|
}
|
2021-07-23 15:25:44 +08:00
|
|
|
TypeEnum::TObj { obj_id, params, .. } => {
|
2021-08-06 10:30:57 +08:00
|
|
|
let name = obj_to_name(obj_id.0);
|
2021-07-23 15:25:44 +08:00
|
|
|
if !params.is_empty() {
|
2022-02-21 18:27:46 +08:00
|
|
|
let params = params
|
|
|
|
.iter()
|
|
|
|
.map(|(_, v)| self.internal_stringify(*v, obj_to_name, var_to_name, notes));
|
2021-09-12 13:14:46 +08:00
|
|
|
// sort to preserve order
|
2021-09-09 02:03:44 +08:00
|
|
|
let mut params = params.sorted();
|
2021-07-23 15:25:44 +08:00
|
|
|
format!("{}[{}]", name, params.join(", "))
|
|
|
|
} else {
|
|
|
|
name
|
2021-07-14 16:40:50 +08:00
|
|
|
}
|
|
|
|
}
|
2021-07-23 15:25:44 +08:00
|
|
|
TypeEnum::TCall { .. } => "call".to_owned(),
|
|
|
|
TypeEnum::TFunc(signature) => {
|
|
|
|
let params = signature
|
|
|
|
.args
|
2021-07-14 16:40:50 +08:00
|
|
|
.iter()
|
2021-07-23 15:25:44 +08:00
|
|
|
.map(|arg| {
|
2022-02-21 17:52:34 +08:00
|
|
|
if let Some(dv) = &arg.default_value {
|
2022-02-21 18:27:46 +08:00
|
|
|
format!(
|
|
|
|
"{}:{}={}",
|
|
|
|
arg.name,
|
|
|
|
self.internal_stringify(arg.ty, obj_to_name, var_to_name, notes),
|
|
|
|
dv
|
|
|
|
)
|
2022-02-21 17:52:34 +08:00
|
|
|
} else {
|
2022-02-21 18:27:46 +08:00
|
|
|
format!(
|
|
|
|
"{}:{}",
|
|
|
|
arg.name,
|
|
|
|
self.internal_stringify(arg.ty, obj_to_name, var_to_name, notes)
|
|
|
|
)
|
2022-02-21 17:52:34 +08:00
|
|
|
}
|
2021-07-14 16:40:50 +08:00
|
|
|
})
|
2021-07-23 15:25:44 +08:00
|
|
|
.join(", ");
|
2022-02-21 17:52:34 +08:00
|
|
|
let ret = self.internal_stringify(signature.ret, obj_to_name, var_to_name, notes);
|
2021-07-23 15:25:44 +08:00
|
|
|
format!("fn[[{}], {}]", params, ret)
|
2021-07-14 16:40:50 +08:00
|
|
|
}
|
2021-07-23 15:25:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-05 14:37:08 +08:00
|
|
|
/// Unifies `a` and `b` together, and set the value to the value of `b`.
|
2021-07-23 15:25:44 +08:00
|
|
|
fn set_a_to_b(&mut self, a: Type, b: Type) {
|
|
|
|
let table = &mut self.unification_table;
|
|
|
|
let ty_b = table.probe_value(b).clone();
|
|
|
|
table.unify(a, b);
|
|
|
|
table.set_value(a, ty_b)
|
|
|
|
}
|
|
|
|
|
2022-02-21 17:52:34 +08:00
|
|
|
fn incompatible_types(&mut self, a: Type, b: Type) -> Result<(), TypeError> {
|
|
|
|
Err(TypeError::new(TypeErrorKind::IncompatibleTypes(a, b), None))
|
2021-07-23 15:25:44 +08:00
|
|
|
}
|
|
|
|
|
2021-07-28 17:25:19 +08:00
|
|
|
/// Instantiate a function if it hasn't been instantiated.
|
2021-07-23 15:25:44 +08:00
|
|
|
/// Returns Some(T) where T is the instantiated type.
|
|
|
|
/// Returns None if the function is already instantiated.
|
|
|
|
fn instantiate_fun(&mut self, ty: Type, fun: &FunSignature) -> Type {
|
2021-11-09 01:15:41 +08:00
|
|
|
let mut instantiated = true;
|
2021-07-23 15:25:44 +08:00
|
|
|
let mut vars = Vec::new();
|
|
|
|
for (k, v) in fun.vars.iter() {
|
2022-02-21 17:52:34 +08:00
|
|
|
if let TypeEnum::TVar { id, name, loc, range, .. } =
|
2021-07-23 15:25:44 +08:00
|
|
|
self.unification_table.probe_value(*v).as_ref()
|
|
|
|
{
|
2021-11-22 15:06:16 +08:00
|
|
|
// for class methods that contain type vars not in class declaration,
|
|
|
|
// as long as there exits one uninstantiated type var, the function is not instantiated,
|
|
|
|
// and need to do substitution on those type vars
|
2021-11-09 01:15:41 +08:00
|
|
|
if k == id {
|
|
|
|
instantiated = false;
|
2022-02-21 17:52:34 +08:00
|
|
|
vars.push((*k, range.clone(), *name, *loc));
|
2021-07-23 15:25:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if instantiated {
|
|
|
|
ty
|
|
|
|
} else {
|
|
|
|
let mapping = vars
|
|
|
|
.into_iter()
|
2022-02-21 18:27:46 +08:00
|
|
|
.map(|(k, range, name, loc)| {
|
|
|
|
(k, self.get_fresh_var_with_range(range.as_ref(), name, loc).0)
|
|
|
|
})
|
2021-07-23 15:25:44 +08:00
|
|
|
.collect();
|
|
|
|
self.subst(ty, &mapping).unwrap_or(ty)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-16 14:34:52 +08:00
|
|
|
/// Substitute type variables within a type into other types.
|
|
|
|
/// If this returns Some(T), T would be the substituted type.
|
|
|
|
/// If this returns None, the result type would be the original type
|
|
|
|
/// (no substitution has to be done).
|
2021-08-11 17:28:29 +08:00
|
|
|
pub fn subst(&mut self, a: Type, mapping: &VarMap) -> Option<Type> {
|
2021-09-12 21:33:21 +08:00
|
|
|
self.subst_impl(a, mapping, &mut HashMap::new())
|
|
|
|
}
|
|
|
|
|
2021-09-20 14:24:16 +08:00
|
|
|
fn subst_impl(
|
|
|
|
&mut self,
|
|
|
|
a: Type,
|
|
|
|
mapping: &VarMap,
|
|
|
|
cache: &mut HashMap<Type, Option<Type>>,
|
|
|
|
) -> Option<Type> {
|
2021-09-12 21:33:21 +08:00
|
|
|
let cached = cache.get_mut(&a);
|
|
|
|
if let Some(cached) = cached {
|
|
|
|
if cached.is_none() {
|
2022-02-21 17:52:34 +08:00
|
|
|
*cached = Some(self.get_fresh_var(None, None).0);
|
2021-09-12 21:33:21 +08:00
|
|
|
}
|
|
|
|
return *cached;
|
|
|
|
}
|
|
|
|
|
2021-07-23 15:25:44 +08:00
|
|
|
let ty = self.unification_table.probe_value(a).clone();
|
2021-07-14 15:24:00 +08:00
|
|
|
// this function would only be called when we instantiate functions.
|
|
|
|
// function type signature should ONLY contain concrete types and type
|
|
|
|
// variables, i.e. things like TRecord, TCall should not occur, and we
|
|
|
|
// should be safe to not implement the substitution for those variants.
|
2021-07-14 15:58:58 +08:00
|
|
|
match &*ty {
|
2021-07-30 11:28:27 +08:00
|
|
|
TypeEnum::TRigidVar { .. } => None,
|
2021-10-16 15:56:13 +08:00
|
|
|
TypeEnum::TVar { id, .. } => mapping.get(id).cloned(),
|
2021-07-14 15:24:00 +08:00
|
|
|
TypeEnum::TTuple { ty } => {
|
2021-07-23 15:25:44 +08:00
|
|
|
let mut new_ty = Cow::from(ty);
|
2021-07-14 15:24:00 +08:00
|
|
|
for (i, t) in ty.iter().enumerate() {
|
2021-09-12 21:33:21 +08:00
|
|
|
if let Some(t1) = self.subst_impl(*t, mapping, cache) {
|
2021-07-23 15:25:44 +08:00
|
|
|
new_ty.to_mut()[i] = t1;
|
2021-07-14 15:24:00 +08:00
|
|
|
}
|
|
|
|
}
|
2021-07-23 15:25:44 +08:00
|
|
|
if matches!(new_ty, Cow::Owned(_)) {
|
|
|
|
Some(self.add_ty(TypeEnum::TTuple { ty: new_ty.into_owned() }))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TypeEnum::TList { ty } => {
|
2021-09-12 21:33:21 +08:00
|
|
|
self.subst_impl(*ty, mapping, cache).map(|t| self.add_ty(TypeEnum::TList { ty: t }))
|
2021-07-23 15:25:44 +08:00
|
|
|
}
|
2021-09-20 14:24:16 +08:00
|
|
|
TypeEnum::TVirtual { ty } => self
|
|
|
|
.subst_impl(*ty, mapping, cache)
|
|
|
|
.map(|t| self.add_ty(TypeEnum::TVirtual { ty: t })),
|
2021-07-23 15:25:44 +08:00
|
|
|
TypeEnum::TObj { obj_id, fields, params } => {
|
2021-07-14 15:24:00 +08:00
|
|
|
// Type variables in field types must be present in the type parameter.
|
|
|
|
// If the mapping does not contain any type variables in the
|
|
|
|
// parameter list, we don't need to substitute the fields.
|
|
|
|
// This is also used to prevent infinite substitution...
|
|
|
|
let need_subst = params.values().any(|v| {
|
2021-07-23 15:25:44 +08:00
|
|
|
let ty = self.unification_table.probe_value(*v);
|
|
|
|
if let TypeEnum::TVar { id, .. } = ty.as_ref() {
|
2021-10-16 15:56:13 +08:00
|
|
|
mapping.contains_key(id)
|
2021-07-14 08:12:47 +08:00
|
|
|
} else {
|
2021-07-14 15:24:00 +08:00
|
|
|
false
|
2021-07-14 08:12:47 +08:00
|
|
|
}
|
2021-07-14 15:24:00 +08:00
|
|
|
});
|
|
|
|
if need_subst {
|
2021-09-12 21:33:21 +08:00
|
|
|
cache.insert(a, None);
|
2021-07-15 16:00:23 +08:00
|
|
|
let obj_id = *obj_id;
|
2021-09-20 14:24:16 +08:00
|
|
|
let params =
|
2022-02-21 17:52:34 +08:00
|
|
|
self.subst_map(params, mapping, cache).unwrap_or_else(|| params.clone());
|
2022-02-21 18:27:46 +08:00
|
|
|
let fields =
|
|
|
|
self.subst_map2(fields, mapping, cache).unwrap_or_else(|| fields.clone());
|
2022-02-21 17:52:34 +08:00
|
|
|
let new_ty = self.add_ty(TypeEnum::TObj { obj_id, params, fields });
|
2021-09-12 21:33:21 +08:00
|
|
|
if let Some(var) = cache.get(&a).unwrap() {
|
2021-10-16 15:56:13 +08:00
|
|
|
self.unify_impl(new_ty, *var, false).unwrap();
|
2021-09-12 21:33:21 +08:00
|
|
|
}
|
|
|
|
Some(new_ty)
|
2021-07-14 16:40:50 +08:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
2022-02-21 17:52:34 +08:00
|
|
|
TypeEnum::TFunc(FunSignature { args, ret, vars: params }) => {
|
2021-09-12 21:33:21 +08:00
|
|
|
let new_params = self.subst_map(params, mapping, cache);
|
|
|
|
let new_ret = self.subst_impl(*ret, mapping, cache);
|
2021-07-23 15:25:44 +08:00
|
|
|
let mut new_args = Cow::from(args);
|
2021-07-14 16:40:50 +08:00
|
|
|
for (i, t) in args.iter().enumerate() {
|
2021-09-12 21:33:21 +08:00
|
|
|
if let Some(t1) = self.subst_impl(t.ty, mapping, cache) {
|
2021-07-23 15:25:44 +08:00
|
|
|
let mut t = t.clone();
|
|
|
|
t.ty = t1;
|
|
|
|
new_args.to_mut()[i] = t;
|
2021-07-14 16:40:50 +08:00
|
|
|
}
|
|
|
|
}
|
2021-07-23 15:25:44 +08:00
|
|
|
if new_params.is_some() || new_ret.is_some() || matches!(new_args, Cow::Owned(..)) {
|
2021-07-15 16:00:23 +08:00
|
|
|
let params = new_params.unwrap_or_else(|| params.clone());
|
2023-12-06 11:49:02 +08:00
|
|
|
let ret = new_ret.unwrap_or(*ret);
|
2021-07-23 15:25:44 +08:00
|
|
|
let args = new_args.into_owned();
|
2022-02-21 18:27:46 +08:00
|
|
|
Some(self.add_ty(TypeEnum::TFunc(FunSignature { args, ret, vars: params })))
|
2021-07-14 15:24:00 +08:00
|
|
|
} else {
|
|
|
|
None
|
2021-07-14 08:12:47 +08:00
|
|
|
}
|
|
|
|
}
|
2021-10-16 15:56:13 +08:00
|
|
|
_ => {
|
|
|
|
unreachable!("{} not expected", ty.get_type_name())
|
|
|
|
}
|
2021-06-30 16:28:18 +08:00
|
|
|
}
|
|
|
|
}
|
2021-07-14 15:24:00 +08:00
|
|
|
|
2021-09-20 14:24:16 +08:00
|
|
|
fn subst_map<K>(
|
|
|
|
&mut self,
|
|
|
|
map: &Mapping<K>,
|
|
|
|
mapping: &VarMap,
|
|
|
|
cache: &mut HashMap<Type, Option<Type>>,
|
|
|
|
) -> Option<Mapping<K>>
|
2021-07-14 15:24:00 +08:00
|
|
|
where
|
2023-10-26 13:52:40 +08:00
|
|
|
K: std::hash::Hash + Eq + Clone,
|
2021-07-14 15:24:00 +08:00
|
|
|
{
|
|
|
|
let mut map2 = None;
|
|
|
|
for (k, v) in map.iter() {
|
2021-09-12 21:33:21 +08:00
|
|
|
if let Some(v1) = self.subst_impl(*v, mapping, cache) {
|
2021-07-14 15:24:00 +08:00
|
|
|
if map2.is_none() {
|
|
|
|
map2 = Some(map.clone());
|
|
|
|
}
|
|
|
|
*map2.as_mut().unwrap().get_mut(k).unwrap() = v1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
map2
|
|
|
|
}
|
2021-07-15 16:00:23 +08:00
|
|
|
|
2021-11-06 22:48:08 +08:00
|
|
|
fn subst_map2<K>(
|
|
|
|
&mut self,
|
|
|
|
map: &Mapping<K, (Type, bool)>,
|
|
|
|
mapping: &VarMap,
|
|
|
|
cache: &mut HashMap<Type, Option<Type>>,
|
|
|
|
) -> Option<Mapping<K, (Type, bool)>>
|
|
|
|
where
|
2023-10-26 13:52:40 +08:00
|
|
|
K: std::hash::Hash + Eq + Clone,
|
2021-11-06 22:48:08 +08:00
|
|
|
{
|
|
|
|
let mut map2 = None;
|
|
|
|
for (k, (v, mutability)) in map.iter() {
|
|
|
|
if let Some(v1) = self.subst_impl(*v, mapping, cache) {
|
|
|
|
if map2.is_none() {
|
|
|
|
map2 = Some(map.clone());
|
|
|
|
}
|
|
|
|
*map2.as_mut().unwrap().get_mut(k).unwrap() = (v1, *mutability);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
map2
|
|
|
|
}
|
|
|
|
|
2021-07-26 14:20:09 +08:00
|
|
|
fn get_intersection(&mut self, a: Type, b: Type) -> Result<Option<Type>, ()> {
|
2021-07-23 15:25:44 +08:00
|
|
|
use TypeEnum::*;
|
2021-07-23 17:22:05 +08:00
|
|
|
let x = self.get_ty(a);
|
|
|
|
let y = self.get_ty(b);
|
|
|
|
match (x.as_ref(), y.as_ref()) {
|
2022-02-21 18:27:46 +08:00
|
|
|
(
|
|
|
|
TVar { range: range1, name, loc, .. },
|
|
|
|
TVar { fields, range: range2, name: name2, loc: loc2, .. },
|
|
|
|
) => {
|
2021-07-26 11:55:37 +08:00
|
|
|
// new range is the intersection of them
|
|
|
|
// empty range indicates no constraint
|
2022-02-21 17:52:34 +08:00
|
|
|
if range1.is_empty() {
|
|
|
|
Ok(Some(b))
|
|
|
|
} else if range2.is_empty() {
|
|
|
|
Ok(Some(a))
|
|
|
|
} else {
|
2022-02-21 18:27:46 +08:00
|
|
|
let range = range2
|
|
|
|
.iter()
|
|
|
|
.cartesian_product(range1.iter())
|
|
|
|
.filter_map(|(v1, v2)| {
|
|
|
|
self.get_intersection(*v1, *v2).map(|v| v.unwrap_or(*v1)).ok()
|
|
|
|
})
|
|
|
|
.collect_vec();
|
2021-07-26 11:55:37 +08:00
|
|
|
if range.is_empty() {
|
|
|
|
Err(())
|
|
|
|
} else {
|
|
|
|
let id = self.var_id + 1;
|
|
|
|
self.var_id += 1;
|
2022-02-21 18:27:46 +08:00
|
|
|
let ty = TVar {
|
|
|
|
id,
|
|
|
|
fields: fields.clone(),
|
|
|
|
range,
|
|
|
|
name: name2.or(*name),
|
|
|
|
loc: loc2.or(*loc),
|
2023-12-05 14:37:08 +08:00
|
|
|
is_const_generic: false,
|
2022-02-21 18:27:46 +08:00
|
|
|
};
|
2021-07-26 11:55:37 +08:00
|
|
|
Ok(Some(self.unification_table.new_key(ty.into())))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(_, TVar { range, .. }) => {
|
|
|
|
// range should be restricted to the left hand side
|
|
|
|
if range.is_empty() {
|
|
|
|
Ok(Some(a))
|
|
|
|
} else {
|
|
|
|
for v in range.iter() {
|
2021-07-26 14:20:09 +08:00
|
|
|
let result = self.get_intersection(a, *v);
|
2021-07-26 11:55:37 +08:00
|
|
|
if let Ok(result) = result {
|
|
|
|
return Ok(result.or(Some(a)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(())
|
|
|
|
}
|
|
|
|
}
|
2022-02-21 18:27:46 +08:00
|
|
|
(TVar { range, .. }, _) => self.check_var_compatibility(b, range).or(Err(())),
|
2022-02-21 17:52:34 +08:00
|
|
|
(TTuple { ty: ty1 }, TTuple { ty: ty2 }) if ty1.len() == ty2.len() => {
|
2022-02-21 18:27:46 +08:00
|
|
|
let ty: Vec<_> = zip(ty1.iter(), ty2.iter())
|
|
|
|
.map(|(a, b)| self.get_intersection(*a, *b))
|
|
|
|
.try_collect()?;
|
2022-02-21 17:52:34 +08:00
|
|
|
if ty.iter().any(Option::is_some) {
|
2022-02-21 18:27:46 +08:00
|
|
|
Ok(Some(self.add_ty(TTuple {
|
2023-12-06 11:49:02 +08:00
|
|
|
ty: zip(ty, ty1.iter()).map(|(a, b)| a.unwrap_or(*b)).collect(),
|
2022-02-21 18:27:46 +08:00
|
|
|
})))
|
2021-07-26 11:55:37 +08:00
|
|
|
} else {
|
|
|
|
Ok(None)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(TList { ty: ty1 }, TList { ty: ty2 }) => {
|
2021-07-26 14:20:09 +08:00
|
|
|
Ok(self.get_intersection(*ty1, *ty2)?.map(|ty| self.add_ty(TList { ty })))
|
2021-07-26 11:55:37 +08:00
|
|
|
}
|
|
|
|
(TVirtual { ty: ty1 }, TVirtual { ty: ty2 }) => {
|
2021-07-26 14:20:09 +08:00
|
|
|
Ok(self.get_intersection(*ty1, *ty2)?.map(|ty| self.add_ty(TVirtual { ty })))
|
2021-07-26 11:55:37 +08:00
|
|
|
}
|
2022-02-21 18:27:46 +08:00
|
|
|
(TObj { obj_id: id1, .. }, TObj { obj_id: id2, .. }) if id1 == id2 => Ok(None),
|
2021-07-23 15:25:44 +08:00
|
|
|
// don't deal with function shape for now
|
2021-07-26 11:55:37 +08:00
|
|
|
_ => Err(()),
|
2021-07-15 16:00:23 +08:00
|
|
|
}
|
|
|
|
}
|
2021-07-23 17:22:05 +08:00
|
|
|
|
2021-07-26 14:20:09 +08:00
|
|
|
fn check_var_compatibility(
|
2021-07-26 11:55:37 +08:00
|
|
|
&mut self,
|
|
|
|
b: Type,
|
|
|
|
range: &[Type],
|
2022-02-21 17:52:34 +08:00
|
|
|
) -> Result<Option<Type>, TypeError> {
|
2021-07-26 11:55:37 +08:00
|
|
|
if range.is_empty() {
|
|
|
|
return Ok(None);
|
|
|
|
}
|
2021-07-23 17:22:05 +08:00
|
|
|
for t in range.iter() {
|
2021-07-26 14:20:09 +08:00
|
|
|
let result = self.get_intersection(*t, b);
|
2021-07-26 11:55:37 +08:00
|
|
|
if let Ok(result) = result {
|
|
|
|
return Ok(result);
|
2021-07-23 17:22:05 +08:00
|
|
|
}
|
|
|
|
}
|
2022-02-21 17:52:34 +08:00
|
|
|
Err(TypeError::new(TypeErrorKind::IncompatibleRange(b, range.to_vec()), None))
|
2021-07-23 17:22:05 +08:00
|
|
|
}
|
2021-06-30 16:28:18 +08:00
|
|
|
}
|