forked from M-Labs/nac3
nac3core/typecheck: added basic location information
This commit is contained in:
parent
e47d063efc
commit
957ceb74e4
|
@ -15,6 +15,8 @@ pub struct DefinitionId(pub usize);
|
||||||
|
|
||||||
pub enum TopLevelDef {
|
pub enum TopLevelDef {
|
||||||
Class {
|
Class {
|
||||||
|
// name for error messages and symbols
|
||||||
|
name: String,
|
||||||
// object ID used for TypeEnum
|
// object ID used for TypeEnum
|
||||||
object_id: DefinitionId,
|
object_id: DefinitionId,
|
||||||
// type variables bounded to the class.
|
// type variables bounded to the class.
|
||||||
|
@ -135,11 +137,11 @@ impl TopLevelComposer {
|
||||||
let primitives = Self::make_primitives();
|
let primitives = Self::make_primitives();
|
||||||
|
|
||||||
let top_level_def_list = vec![
|
let top_level_def_list = vec![
|
||||||
Arc::new(RwLock::new(Self::make_top_level_class_def(0, None))),
|
Arc::new(RwLock::new(Self::make_top_level_class_def(0, None, "int32"))),
|
||||||
Arc::new(RwLock::new(Self::make_top_level_class_def(1, None))),
|
Arc::new(RwLock::new(Self::make_top_level_class_def(1, None, "int64"))),
|
||||||
Arc::new(RwLock::new(Self::make_top_level_class_def(2, None))),
|
Arc::new(RwLock::new(Self::make_top_level_class_def(2, None, "float"))),
|
||||||
Arc::new(RwLock::new(Self::make_top_level_class_def(3, None))),
|
Arc::new(RwLock::new(Self::make_top_level_class_def(3, None, "bool"))),
|
||||||
Arc::new(RwLock::new(Self::make_top_level_class_def(4, None))),
|
Arc::new(RwLock::new(Self::make_top_level_class_def(4, None, "none"))),
|
||||||
];
|
];
|
||||||
|
|
||||||
let ast_list: Vec<Option<ast::Stmt<()>>> = vec![None, None, None, None, None];
|
let ast_list: Vec<Option<ast::Stmt<()>>> = vec![None, None, None, None, None];
|
||||||
|
@ -171,8 +173,10 @@ impl TopLevelComposer {
|
||||||
pub fn make_top_level_class_def(
|
pub fn make_top_level_class_def(
|
||||||
index: usize,
|
index: usize,
|
||||||
resolver: Option<Arc<Mutex<dyn SymbolResolver + Send + Sync>>>,
|
resolver: Option<Arc<Mutex<dyn SymbolResolver + Send + Sync>>>,
|
||||||
|
name: &str,
|
||||||
) -> TopLevelDef {
|
) -> TopLevelDef {
|
||||||
TopLevelDef::Class {
|
TopLevelDef::Class {
|
||||||
|
name: name.to_string(),
|
||||||
object_id: DefinitionId(index),
|
object_id: DefinitionId(index),
|
||||||
type_vars: Default::default(),
|
type_vars: Default::default(),
|
||||||
fields: Default::default(),
|
fields: Default::default(),
|
||||||
|
@ -216,6 +220,7 @@ impl TopLevelComposer {
|
||||||
Arc::new(RwLock::new(Self::make_top_level_class_def(
|
Arc::new(RwLock::new(Self::make_top_level_class_def(
|
||||||
class_def_id,
|
class_def_id,
|
||||||
resolver.clone(),
|
resolver.clone(),
|
||||||
|
name.as_str(),
|
||||||
))),
|
))),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
|
@ -77,7 +77,7 @@ impl<'a> fold::Fold<()> for Inferencer<'a> {
|
||||||
let target = Box::new(self.fold_expr(*target)?);
|
let target = Box::new(self.fold_expr(*target)?);
|
||||||
let value = if let Some(v) = value {
|
let value = if let Some(v) = value {
|
||||||
let ty = Box::new(self.fold_expr(*v)?);
|
let ty = Box::new(self.fold_expr(*v)?);
|
||||||
self.unifier.unify(target.custom.unwrap(), ty.custom.unwrap())?;
|
self.unify(target.custom.unwrap(), ty.custom.unwrap(), &node.location)?;
|
||||||
Some(ty)
|
Some(ty)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -88,7 +88,7 @@ impl<'a> fold::Fold<()> for Inferencer<'a> {
|
||||||
&self.primitives,
|
&self.primitives,
|
||||||
annotation.as_ref(),
|
annotation.as_ref(),
|
||||||
)?;
|
)?;
|
||||||
self.unifier.unify(annotation_type, target.custom.unwrap())?;
|
self.unify(annotation_type, target.custom.unwrap(), &node.location)?;
|
||||||
let annotation = Box::new(NaiveFolder().fold_expr(*annotation)?);
|
let annotation = Box::new(NaiveFolder().fold_expr(*annotation)?);
|
||||||
Located {
|
Located {
|
||||||
location: node.location,
|
location: node.location,
|
||||||
|
@ -101,21 +101,21 @@ impl<'a> fold::Fold<()> for Inferencer<'a> {
|
||||||
match &stmt.node {
|
match &stmt.node {
|
||||||
ast::StmtKind::For { target, iter, .. } => {
|
ast::StmtKind::For { target, iter, .. } => {
|
||||||
let list = self.unifier.add_ty(TypeEnum::TList { ty: target.custom.unwrap() });
|
let list = self.unifier.add_ty(TypeEnum::TList { ty: target.custom.unwrap() });
|
||||||
self.unifier.unify(list, iter.custom.unwrap())?;
|
self.unify(list, iter.custom.unwrap(), &iter.location)?;
|
||||||
}
|
}
|
||||||
ast::StmtKind::If { test, .. } | ast::StmtKind::While { test, .. } => {
|
ast::StmtKind::If { test, .. } | ast::StmtKind::While { test, .. } => {
|
||||||
self.unifier.unify(test.custom.unwrap(), self.primitives.bool)?;
|
self.unify(test.custom.unwrap(), self.primitives.bool, &test.location)?;
|
||||||
}
|
}
|
||||||
ast::StmtKind::Assign { targets, value, .. } => {
|
ast::StmtKind::Assign { targets, value, .. } => {
|
||||||
for target in targets.iter() {
|
for target in targets.iter() {
|
||||||
self.unifier.unify(target.custom.unwrap(), value.custom.unwrap())?;
|
self.unify(target.custom.unwrap(), value.custom.unwrap(), &target.location)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::StmtKind::AnnAssign { .. } | ast::StmtKind::Expr { .. } => {}
|
ast::StmtKind::AnnAssign { .. } | ast::StmtKind::Expr { .. } => {}
|
||||||
ast::StmtKind::Break | ast::StmtKind::Continue => {}
|
ast::StmtKind::Break | ast::StmtKind::Continue => {}
|
||||||
ast::StmtKind::Return { value } => match (value, self.function_data.return_type) {
|
ast::StmtKind::Return { value } => match (value, self.function_data.return_type) {
|
||||||
(Some(v), Some(v1)) => {
|
(Some(v), Some(v1)) => {
|
||||||
self.unifier.unify(v.custom.unwrap(), v1)?;
|
self.unify(v.custom.unwrap(), v1, &v.location)?;
|
||||||
}
|
}
|
||||||
(Some(_), None) => {
|
(Some(_), None) => {
|
||||||
return Err("Unexpected return value".to_string());
|
return Err("Unexpected return value".to_string());
|
||||||
|
@ -178,8 +178,12 @@ type InferenceResult = Result<Type, String>;
|
||||||
impl<'a> Inferencer<'a> {
|
impl<'a> Inferencer<'a> {
|
||||||
/// Constrain a <: b
|
/// Constrain a <: b
|
||||||
/// Currently implemented as unification
|
/// Currently implemented as unification
|
||||||
fn constrain(&mut self, a: Type, b: Type) -> Result<(), String> {
|
fn constrain(&mut self, a: Type, b: Type, location: &Location) -> Result<(), String> {
|
||||||
self.unifier.unify(a, b)
|
self.unifier.unify(a, b).map_err(|old| format!("{} at {}", old, location))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unify(&mut self, a: Type, b: Type, location: &Location) -> Result<(), String> {
|
||||||
|
self.unifier.unify(a, b).map_err(|old| format!("{} at {}", old, location))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_method_call(
|
fn build_method_call(
|
||||||
|
@ -200,7 +204,7 @@ impl<'a> Inferencer<'a> {
|
||||||
let call = self.unifier.add_ty(TypeEnum::TCall(vec![call].into()));
|
let call = self.unifier.add_ty(TypeEnum::TCall(vec![call].into()));
|
||||||
let fields = once((method, call)).collect();
|
let fields = once((method, call)).collect();
|
||||||
let record = self.unifier.add_record(fields);
|
let record = self.unifier.add_record(fields);
|
||||||
self.constrain(obj, record)?;
|
self.constrain(obj, record, &location)?;
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,7 +253,7 @@ impl<'a> Inferencer<'a> {
|
||||||
vars: Default::default(),
|
vars: Default::default(),
|
||||||
};
|
};
|
||||||
let body = new_context.fold_expr(body)?;
|
let body = new_context.fold_expr(body)?;
|
||||||
new_context.unifier.unify(fun.ret, body.custom.unwrap())?;
|
new_context.unify(fun.ret, body.custom.unwrap(), &location)?;
|
||||||
let mut args = new_context.fold_arguments(args)?;
|
let mut args = new_context.fold_arguments(args)?;
|
||||||
for (arg, (name, ty)) in args.args.iter_mut().zip(fn_args.iter()) {
|
for (arg, (name, ty)) in args.args.iter_mut().zip(fn_args.iter()) {
|
||||||
assert_eq!(&arg.node.arg, name);
|
assert_eq!(&arg.node.arg, name);
|
||||||
|
@ -299,10 +303,10 @@ impl<'a> Inferencer<'a> {
|
||||||
// iter should be a list of targets...
|
// iter should be a list of targets...
|
||||||
// actually it should be an iterator of targets, but we don't have iter type for now
|
// actually it should be an iterator of targets, but we don't have iter type for now
|
||||||
let list = new_context.unifier.add_ty(TypeEnum::TList { ty: target.custom.unwrap() });
|
let list = new_context.unifier.add_ty(TypeEnum::TList { ty: target.custom.unwrap() });
|
||||||
new_context.unifier.unify(iter.custom.unwrap(), list)?;
|
new_context.unify(iter.custom.unwrap(), list, &iter.location)?;
|
||||||
// if conditions should be bool
|
// if conditions should be bool
|
||||||
for v in ifs.iter() {
|
for v in ifs.iter() {
|
||||||
new_context.unifier.unify(v.custom.unwrap(), new_context.primitives.bool)?;
|
new_context.unify(v.custom.unwrap(), new_context.primitives.bool, &v.location)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Located {
|
Ok(Located {
|
||||||
|
@ -409,7 +413,7 @@ impl<'a> Inferencer<'a> {
|
||||||
});
|
});
|
||||||
self.calls.insert(location.into(), call);
|
self.calls.insert(location.into(), call);
|
||||||
let call = self.unifier.add_ty(TypeEnum::TCall(vec![call].into()));
|
let call = self.unifier.add_ty(TypeEnum::TCall(vec![call].into()));
|
||||||
self.unifier.unify(func.custom.unwrap(), call)?;
|
self.unify(func.custom.unwrap(), call, &func.location)?;
|
||||||
|
|
||||||
Ok(Located { location, custom: Some(ret), node: ExprKind::Call { func, args, keywords } })
|
Ok(Located { location, custom: Some(ret), node: ExprKind::Call { func, args, keywords } })
|
||||||
}
|
}
|
||||||
|
@ -454,7 +458,7 @@ impl<'a> Inferencer<'a> {
|
||||||
fn infer_list(&mut self, elts: &[ast::Expr<Option<Type>>]) -> InferenceResult {
|
fn infer_list(&mut self, elts: &[ast::Expr<Option<Type>>]) -> InferenceResult {
|
||||||
let (ty, _) = self.unifier.get_fresh_var();
|
let (ty, _) = self.unifier.get_fresh_var();
|
||||||
for t in elts.iter() {
|
for t in elts.iter() {
|
||||||
self.unifier.unify(ty, t.custom.unwrap())?;
|
self.unify(ty, t.custom.unwrap(), &t.location)?;
|
||||||
}
|
}
|
||||||
Ok(self.unifier.add_ty(TypeEnum::TList { ty }))
|
Ok(self.unifier.add_ty(TypeEnum::TList { ty }))
|
||||||
}
|
}
|
||||||
|
@ -468,14 +472,14 @@ impl<'a> Inferencer<'a> {
|
||||||
let (attr_ty, _) = self.unifier.get_fresh_var();
|
let (attr_ty, _) = self.unifier.get_fresh_var();
|
||||||
let fields = once((attr.to_string(), attr_ty)).collect();
|
let fields = once((attr.to_string(), attr_ty)).collect();
|
||||||
let record = self.unifier.add_record(fields);
|
let record = self.unifier.add_record(fields);
|
||||||
self.constrain(value.custom.unwrap(), record)?;
|
self.constrain(value.custom.unwrap(), record, &value.location)?;
|
||||||
Ok(attr_ty)
|
Ok(attr_ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_bool_ops(&mut self, values: &[ast::Expr<Option<Type>>]) -> InferenceResult {
|
fn infer_bool_ops(&mut self, values: &[ast::Expr<Option<Type>>]) -> InferenceResult {
|
||||||
let b = self.primitives.bool;
|
let b = self.primitives.bool;
|
||||||
for v in values {
|
for v in values {
|
||||||
self.constrain(v.custom.unwrap(), b)?;
|
self.constrain(v.custom.unwrap(), b, &v.location)?;
|
||||||
}
|
}
|
||||||
Ok(b)
|
Ok(b)
|
||||||
}
|
}
|
||||||
|
@ -543,10 +547,10 @@ impl<'a> Inferencer<'a> {
|
||||||
match &slice.node {
|
match &slice.node {
|
||||||
ast::ExprKind::Slice { lower, upper, step } => {
|
ast::ExprKind::Slice { lower, upper, step } => {
|
||||||
for v in [lower.as_ref(), upper.as_ref(), step.as_ref()].iter().flatten() {
|
for v in [lower.as_ref(), upper.as_ref(), step.as_ref()].iter().flatten() {
|
||||||
self.constrain(v.custom.unwrap(), self.primitives.int32)?;
|
self.constrain(v.custom.unwrap(), self.primitives.int32, &v.location)?;
|
||||||
}
|
}
|
||||||
let list = self.unifier.add_ty(TypeEnum::TList { ty });
|
let list = self.unifier.add_ty(TypeEnum::TList { ty });
|
||||||
self.constrain(value.custom.unwrap(), list)?;
|
self.constrain(value.custom.unwrap(), list, &value.location)?;
|
||||||
Ok(list)
|
Ok(list)
|
||||||
}
|
}
|
||||||
ast::ExprKind::Constant { value: ast::Constant::Int(val), .. } => {
|
ast::ExprKind::Constant { value: ast::Constant::Int(val), .. } => {
|
||||||
|
@ -554,14 +558,14 @@ impl<'a> Inferencer<'a> {
|
||||||
let ind: i32 = val.try_into().map_err(|_| "Index must be int32".to_string())?;
|
let ind: i32 = val.try_into().map_err(|_| "Index must be int32".to_string())?;
|
||||||
let map = once((ind, ty)).collect();
|
let map = once((ind, ty)).collect();
|
||||||
let seq = self.unifier.add_sequence(map);
|
let seq = self.unifier.add_sequence(map);
|
||||||
self.constrain(value.custom.unwrap(), seq)?;
|
self.constrain(value.custom.unwrap(), seq, &value.location)?;
|
||||||
Ok(ty)
|
Ok(ty)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// the index is not a constant, so value can only be a list
|
// the index is not a constant, so value can only be a list
|
||||||
self.constrain(slice.custom.unwrap(), self.primitives.int32)?;
|
self.constrain(slice.custom.unwrap(), self.primitives.int32, &slice.location)?;
|
||||||
let list = self.unifier.add_ty(TypeEnum::TList { ty });
|
let list = self.unifier.add_ty(TypeEnum::TList { ty });
|
||||||
self.constrain(value.custom.unwrap(), list)?;
|
self.constrain(value.custom.unwrap(), list, &value.location)?;
|
||||||
Ok(ty)
|
Ok(ty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -573,10 +577,10 @@ impl<'a> Inferencer<'a> {
|
||||||
body: &ast::Expr<Option<Type>>,
|
body: &ast::Expr<Option<Type>>,
|
||||||
orelse: &ast::Expr<Option<Type>>,
|
orelse: &ast::Expr<Option<Type>>,
|
||||||
) -> InferenceResult {
|
) -> InferenceResult {
|
||||||
self.constrain(test.custom.unwrap(), self.primitives.bool)?;
|
self.constrain(test.custom.unwrap(), self.primitives.bool, &test.location)?;
|
||||||
let ty = self.unifier.get_fresh_var().0;
|
let ty = self.unifier.get_fresh_var().0;
|
||||||
self.constrain(body.custom.unwrap(), ty)?;
|
self.constrain(body.custom.unwrap(), ty, &body.location)?;
|
||||||
self.constrain(orelse.custom.unwrap(), ty)?;
|
self.constrain(orelse.custom.unwrap(), ty, &orelse.location)?;
|
||||||
Ok(ty)
|
Ok(ty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,9 +145,10 @@ impl TestEnvironment {
|
||||||
params: HashMap::new().into(),
|
params: HashMap::new().into(),
|
||||||
});
|
});
|
||||||
identifier_mapping.insert("None".into(), none);
|
identifier_mapping.insert("None".into(), none);
|
||||||
for i in 0..5 {
|
for (i, name) in ["int32", "int64", "float", "bool", "none"].iter().enumerate() {
|
||||||
top_level_defs.push(
|
top_level_defs.push(
|
||||||
RwLock::new(TopLevelDef::Class {
|
RwLock::new(TopLevelDef::Class {
|
||||||
|
name: format!("obj{}", i),
|
||||||
object_id: DefinitionId(i),
|
object_id: DefinitionId(i),
|
||||||
type_vars: Default::default(),
|
type_vars: Default::default(),
|
||||||
fields: Default::default(),
|
fields: Default::default(),
|
||||||
|
@ -170,6 +171,7 @@ impl TestEnvironment {
|
||||||
});
|
});
|
||||||
top_level_defs.push(
|
top_level_defs.push(
|
||||||
RwLock::new(TopLevelDef::Class {
|
RwLock::new(TopLevelDef::Class {
|
||||||
|
name: "Foo".to_string(),
|
||||||
object_id: DefinitionId(5),
|
object_id: DefinitionId(5),
|
||||||
type_vars: vec![v0],
|
type_vars: vec![v0],
|
||||||
fields: [("a".into(), v0)].into(),
|
fields: [("a".into(), v0)].into(),
|
||||||
|
@ -206,6 +208,7 @@ impl TestEnvironment {
|
||||||
});
|
});
|
||||||
top_level_defs.push(
|
top_level_defs.push(
|
||||||
RwLock::new(TopLevelDef::Class {
|
RwLock::new(TopLevelDef::Class {
|
||||||
|
name: "Bar".to_string(),
|
||||||
object_id: DefinitionId(6),
|
object_id: DefinitionId(6),
|
||||||
type_vars: Default::default(),
|
type_vars: Default::default(),
|
||||||
fields: [("a".into(), int32), ("b".into(), fun)].into(),
|
fields: [("a".into(), int32), ("b".into(), fun)].into(),
|
||||||
|
@ -233,6 +236,7 @@ impl TestEnvironment {
|
||||||
});
|
});
|
||||||
top_level_defs.push(
|
top_level_defs.push(
|
||||||
RwLock::new(TopLevelDef::Class {
|
RwLock::new(TopLevelDef::Class {
|
||||||
|
name: "Bar2".to_string(),
|
||||||
object_id: DefinitionId(7),
|
object_id: DefinitionId(7),
|
||||||
type_vars: Default::default(),
|
type_vars: Default::default(),
|
||||||
fields: [("a".into(), bool), ("b".into(), fun)].into(),
|
fields: [("a".into(), bool), ("b".into(), fun)].into(),
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use super::unification_table::{UnificationKey, UnificationTable};
|
use super::unification_table::{UnificationKey, UnificationTable};
|
||||||
use crate::symbol_resolver::SymbolValue;
|
use crate::symbol_resolver::SymbolValue;
|
||||||
use crate::top_level::DefinitionId;
|
use crate::top_level::{DefinitionId, TopLevelContext, TopLevelDef};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test;
|
mod test;
|
||||||
|
@ -99,6 +99,7 @@ pub type SharedUnifier = Arc<Mutex<(UnificationTable<TypeEnum>, u32, Vec<Call>)>
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Unifier {
|
pub struct Unifier {
|
||||||
|
pub top_level: Option<Arc<TopLevelContext>>,
|
||||||
unification_table: UnificationTable<Rc<TypeEnum>>,
|
unification_table: UnificationTable<Rc<TypeEnum>>,
|
||||||
calls: Vec<Rc<Call>>,
|
calls: Vec<Rc<Call>>,
|
||||||
var_id: u32,
|
var_id: u32,
|
||||||
|
@ -107,7 +108,12 @@ pub struct Unifier {
|
||||||
impl Unifier {
|
impl Unifier {
|
||||||
/// Get an empty unifier
|
/// Get an empty unifier
|
||||||
pub fn new() -> Unifier {
|
pub fn new() -> Unifier {
|
||||||
Unifier { unification_table: UnificationTable::new(), var_id: 0, calls: Vec::new() }
|
Unifier {
|
||||||
|
unification_table: UnificationTable::new(),
|
||||||
|
var_id: 0,
|
||||||
|
calls: Vec::new(),
|
||||||
|
top_level: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine if the two types are the same
|
/// Determine if the two types are the same
|
||||||
|
@ -121,6 +127,7 @@ impl Unifier {
|
||||||
unification_table: UnificationTable::from_send(&lock.0),
|
unification_table: UnificationTable::from_send(&lock.0),
|
||||||
var_id: lock.1,
|
var_id: lock.1,
|
||||||
calls: lock.2.iter().map(|v| Rc::new(v.clone())).collect_vec(),
|
calls: lock.2.iter().map(|v| Rc::new(v.clone())).collect_vec(),
|
||||||
|
top_level: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,7 +345,7 @@ impl Unifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err("Incompatible".to_string());
|
return Err("Incompatible type variables".to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let range1 = range1.borrow();
|
let range1 = range1.borrow();
|
||||||
|
@ -464,7 +471,7 @@ impl Unifier {
|
||||||
TObj { obj_id: id2, params: params2, .. },
|
TObj { obj_id: id2, params: params2, .. },
|
||||||
) => {
|
) => {
|
||||||
if id1 != id2 {
|
if id1 != id2 {
|
||||||
return Err(format!("Cannot unify objects with ID {} and {}", id1.0, id2.0));
|
self.incompatible_types(a, b)?;
|
||||||
}
|
}
|
||||||
for (x, y) in zip(params1.borrow().values(), params2.borrow().values()) {
|
for (x, y) in zip(params1.borrow().values(), params2.borrow().values()) {
|
||||||
self.unify(*x, *y)?;
|
self.unify(*x, *y)?;
|
||||||
|
@ -552,7 +559,7 @@ impl Unifier {
|
||||||
return Err("Functions differ in parameter names.".to_string());
|
return Err("Functions differ in parameter names.".to_string());
|
||||||
}
|
}
|
||||||
if x.default_value != y.default_value {
|
if x.default_value != y.default_value {
|
||||||
return Err("Functions differ in optional parameters.".to_string());
|
return Err("Functions differ in optional parameters value".to_string());
|
||||||
}
|
}
|
||||||
self.unify(x.ty, y.ty)?;
|
self.unify(x.ty, y.ty)?;
|
||||||
}
|
}
|
||||||
|
@ -561,7 +568,7 @@ impl Unifier {
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if swapped {
|
if swapped {
|
||||||
return self.incompatible_types(&*ty_a, &*ty_b);
|
return self.incompatible_types(a, b);
|
||||||
} else {
|
} else {
|
||||||
self.unify_impl(b, a, true)?;
|
self.unify_impl(b, a, true)?;
|
||||||
}
|
}
|
||||||
|
@ -570,6 +577,28 @@ impl Unifier {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn internal_stringify(&mut self, ty: Type) -> String {
|
||||||
|
let top_level = self.top_level.clone();
|
||||||
|
self.stringify(
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
name.clone()
|
||||||
|
} else {
|
||||||
|
unreachable!("expected class definition")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
&mut |id| format!("var{}", id),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get string representation of the type
|
/// Get string representation of the type
|
||||||
pub fn stringify<F, G>(&mut self, ty: Type, obj_to_name: &mut F, var_to_name: &mut G) -> String
|
pub fn stringify<F, G>(&mut self, ty: Type, obj_to_name: &mut F, var_to_name: &mut G) -> String
|
||||||
where
|
where
|
||||||
|
@ -642,8 +671,8 @@ impl Unifier {
|
||||||
table.set_value(a, ty_b)
|
table.set_value(a, ty_b)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn incompatible_types(&self, a: &TypeEnum, b: &TypeEnum) -> Result<(), String> {
|
fn incompatible_types(&mut self, a: Type, b: Type) -> Result<(), String> {
|
||||||
Err(format!("Cannot unify {} with {}", a.get_type_name(), b.get_type_name()))
|
Err(format!("Cannot unify {} with {}", self.internal_stringify(a), self.internal_stringify(b)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Instantiate a function if it hasn't been instantiated.
|
/// Instantiate a function if it hasn't been instantiated.
|
||||||
|
@ -949,9 +978,9 @@ impl Unifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"Cannot unify type variable {} with {} due to incompatible value range",
|
"Cannot unify variable {} with {} due to incompatible value range",
|
||||||
id,
|
id,
|
||||||
self.get_ty(b).get_type_name()
|
self.internal_stringify(b)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ def run() -> int32:
|
||||||
height = 36.0
|
height = 36.0
|
||||||
aspectRatio = 2.0
|
aspectRatio = 2.0
|
||||||
|
|
||||||
|
test = 1.0 + 1
|
||||||
|
|
||||||
yScale = (maxX-minX)*(height/width)*aspectRatio
|
yScale = (maxX-minX)*(height/width)*aspectRatio
|
||||||
|
|
||||||
y = 0.0
|
y = 0.0
|
||||||
|
|
|
@ -53,7 +53,8 @@ fn main() {
|
||||||
let (_, composer) = TopLevelComposer::new();
|
let (_, composer) = TopLevelComposer::new();
|
||||||
let mut unifier = composer.unifier.clone();
|
let mut unifier = composer.unifier.clone();
|
||||||
let primitives = composer.primitives.clone();
|
let primitives = composer.primitives.clone();
|
||||||
let top_level = composer.to_top_level_context();
|
let top_level = Arc::new(composer.to_top_level_context());
|
||||||
|
unifier.top_level = Some(top_level.clone());
|
||||||
let fun = unifier.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
|
let fun = unifier.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
|
||||||
args: vec![FuncArg {
|
args: vec![FuncArg {
|
||||||
name: "c".into(),
|
name: "c".into(),
|
||||||
|
|
Loading…
Reference in New Issue