feat: invert how casting is controlled
I decided to invert how I'm doing it. I'm passing in a new argument to unify in environment called allow_cast: bool and essentially at various unification sites I can control whether or not I want to allow casting to even occur. So we can assume it's false by default always and then we turn it on in a few places vs. just opening the flood gates and locking it down at various sites as they come up# Please enter the commit message for your changes. Lines starting
This commit is contained in:
parent
2b554d105a
commit
c126f6acda
|
@ -1205,19 +1205,30 @@ impl<'a> Environment<'a> {
|
||||||
///
|
///
|
||||||
/// It two types are found to not be the same an error is returned.
|
/// It two types are found to not be the same an error is returned.
|
||||||
#[allow(clippy::only_used_in_recursion)]
|
#[allow(clippy::only_used_in_recursion)]
|
||||||
pub fn unify(&mut self, t1: Arc<Type>, t2: Arc<Type>, location: Span) -> Result<(), Error> {
|
pub fn unify(
|
||||||
|
&mut self,
|
||||||
|
t1: Arc<Type>,
|
||||||
|
t2: Arc<Type>,
|
||||||
|
location: Span,
|
||||||
|
allow_cast: bool,
|
||||||
|
) -> Result<(), Error> {
|
||||||
if t1 == t2 {
|
if t1 == t2 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t1.is_data() || t2.is_data()) && !(t1.is_unbound() || t2.is_unbound()) {
|
if allow_cast
|
||||||
|
&& (t1.is_data() || t2.is_data())
|
||||||
|
&& !(t1.is_unbound() || t2.is_unbound())
|
||||||
|
&& !(t1.is_function() || t2.is_function())
|
||||||
|
&& !(t1.is_generic() || t2.is_generic())
|
||||||
|
{
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collapse right hand side type links. Left hand side will be collapsed in the next block.
|
// Collapse right hand side type links. Left hand side will be collapsed in the next block.
|
||||||
if let Type::Var { tipo } = t2.deref() {
|
if let Type::Var { tipo } = t2.deref() {
|
||||||
if let TypeVar::Link { tipo } = tipo.borrow().deref() {
|
if let TypeVar::Link { tipo } = tipo.borrow().deref() {
|
||||||
return self.unify(t1, tipo.clone(), location);
|
return self.unify(t1, tipo.clone(), location, allow_cast);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1253,7 +1264,7 @@ impl<'a> Environment<'a> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
Action::Unify(t) => self.unify(t, t2, location),
|
Action::Unify(t) => self.unify(t, t2, location, allow_cast),
|
||||||
|
|
||||||
Action::CouldNotUnify => Err(Error::CouldNotUnify {
|
Action::CouldNotUnify => Err(Error::CouldNotUnify {
|
||||||
location,
|
location,
|
||||||
|
@ -1266,7 +1277,9 @@ impl<'a> Environment<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Type::Var { .. } = t2.deref() {
|
if let Type::Var { .. } = t2.deref() {
|
||||||
return self.unify(t2, t1, location).map_err(|e| e.flip_unify());
|
return self
|
||||||
|
.unify(t2, t1, location, allow_cast)
|
||||||
|
.map_err(|e| e.flip_unify());
|
||||||
}
|
}
|
||||||
|
|
||||||
match (t1.deref(), t2.deref()) {
|
match (t1.deref(), t2.deref()) {
|
||||||
|
@ -1288,7 +1301,7 @@ impl<'a> Environment<'a> {
|
||||||
unify_enclosed_type(
|
unify_enclosed_type(
|
||||||
t1.clone(),
|
t1.clone(),
|
||||||
t2.clone(),
|
t2.clone(),
|
||||||
self.unify(a.clone(), b.clone(), location),
|
self.unify(a.clone(), b.clone(), location, allow_cast),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1301,7 +1314,7 @@ impl<'a> Environment<'a> {
|
||||||
unify_enclosed_type(
|
unify_enclosed_type(
|
||||||
t1.clone(),
|
t1.clone(),
|
||||||
t2.clone(),
|
t2.clone(),
|
||||||
self.unify(a.clone(), b.clone(), location),
|
self.unify(a.clone(), b.clone(), location, allow_cast),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1320,17 +1333,16 @@ impl<'a> Environment<'a> {
|
||||||
},
|
},
|
||||||
) if args1.len() == args2.len() => {
|
) if args1.len() == args2.len() => {
|
||||||
for (a, b) in args1.iter().zip(args2) {
|
for (a, b) in args1.iter().zip(args2) {
|
||||||
self.unify(a.clone(), b.clone(), location).map_err(|_| {
|
self.unify(a.clone(), b.clone(), location, allow_cast)
|
||||||
Error::CouldNotUnify {
|
.map_err(|_| Error::CouldNotUnify {
|
||||||
location,
|
location,
|
||||||
expected: t1.clone(),
|
expected: t1.clone(),
|
||||||
given: t2.clone(),
|
given: t2.clone(),
|
||||||
situation: None,
|
situation: None,
|
||||||
rigid_type_names: HashMap::new(),
|
rigid_type_names: HashMap::new(),
|
||||||
}
|
})?;
|
||||||
})?;
|
|
||||||
}
|
}
|
||||||
self.unify(retrn1.clone(), retrn2.clone(), location)
|
self.unify(retrn1.clone(), retrn2.clone(), location, allow_cast)
|
||||||
.map_err(|_| Error::CouldNotUnify {
|
.map_err(|_| Error::CouldNotUnify {
|
||||||
location,
|
location,
|
||||||
expected: t1.clone(),
|
expected: t1.clone(),
|
||||||
|
|
|
@ -951,19 +951,6 @@ fn suggest_unify(
|
||||||
expected.green(),
|
expected.green(),
|
||||||
given.red()
|
given.red()
|
||||||
},
|
},
|
||||||
Some(UnifyErrorSituation::UnsafeCast) => formatdoc! {
|
|
||||||
r#"I am inferring the following type:
|
|
||||||
|
|
||||||
{}
|
|
||||||
|
|
||||||
but I found an expression with a different type:
|
|
||||||
|
|
||||||
{}
|
|
||||||
|
|
||||||
It is unsafe to cast Data without using assert"#,
|
|
||||||
expected.green(),
|
|
||||||
given.red()
|
|
||||||
},
|
|
||||||
None => formatdoc! {
|
None => formatdoc! {
|
||||||
r#"I am inferring the following type:
|
r#"I am inferring the following type:
|
||||||
|
|
||||||
|
@ -1200,9 +1187,6 @@ pub enum UnifyErrorSituation {
|
||||||
|
|
||||||
/// The operands of a binary operator were incorrect.
|
/// The operands of a binary operator were incorrect.
|
||||||
Operator(BinOp),
|
Operator(BinOp),
|
||||||
|
|
||||||
/// Called a function with something of type Data but something else was expected
|
|
||||||
UnsafeCast,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
|
|
@ -17,7 +17,7 @@ use crate::{
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
environment::{assert_no_labeled_arguments, collapse_links, EntityKind, Environment},
|
environment::{assert_no_labeled_arguments, collapse_links, EntityKind, Environment},
|
||||||
error::{Error, UnifyErrorSituation, Warning},
|
error::{Error, Warning},
|
||||||
hydrator::Hydrator,
|
hydrator::Hydrator,
|
||||||
pattern::PatternTyper,
|
pattern::PatternTyper,
|
||||||
pipe::PipeTyper,
|
pipe::PipeTyper,
|
||||||
|
@ -155,7 +155,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
let mut arguments = Vec::new();
|
let mut arguments = Vec::new();
|
||||||
|
|
||||||
for (i, arg) in args.into_iter().enumerate() {
|
for (i, arg) in args.into_iter().enumerate() {
|
||||||
let arg = self.infer_arg(arg, expected_args.get(i).cloned())?;
|
let arg = self.infer_param(arg, expected_args.get(i).cloned())?;
|
||||||
|
|
||||||
arguments.push(arg);
|
arguments.push(arg);
|
||||||
}
|
}
|
||||||
|
@ -394,7 +394,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
|
|
||||||
let right = self.infer(right)?;
|
let right = self.infer(right)?;
|
||||||
|
|
||||||
self.unify(left.tipo(), right.tipo(), right.location())?;
|
self.unify(left.tipo(), right.tipo(), right.location(), false)?;
|
||||||
|
|
||||||
return Ok(TypedExpr::BinOp {
|
return Ok(TypedExpr::BinOp {
|
||||||
location,
|
location,
|
||||||
|
@ -423,13 +423,19 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
input_type.clone(),
|
input_type.clone(),
|
||||||
left.tipo(),
|
left.tipo(),
|
||||||
left.type_defining_location(),
|
left.type_defining_location(),
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
.map_err(|e| e.operator_situation(name))?;
|
.map_err(|e| e.operator_situation(name))?;
|
||||||
|
|
||||||
let right = self.infer(right)?;
|
let right = self.infer(right)?;
|
||||||
|
|
||||||
self.unify(input_type, right.tipo(), right.type_defining_location())
|
self.unify(
|
||||||
.map_err(|e| e.operator_situation(name))?;
|
input_type,
|
||||||
|
right.tipo(),
|
||||||
|
right.type_defining_location(),
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.map_err(|e| e.operator_situation(name))?;
|
||||||
|
|
||||||
Ok(TypedExpr::BinOp {
|
Ok(TypedExpr::BinOp {
|
||||||
location,
|
location,
|
||||||
|
@ -505,7 +511,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
let return_type = self.instantiate(ret.clone(), &mut HashMap::new());
|
let return_type = self.instantiate(ret.clone(), &mut HashMap::new());
|
||||||
|
|
||||||
// Check that the spread variable unifies with the return type of the constructor
|
// Check that the spread variable unifies with the return type of the constructor
|
||||||
self.unify(return_type, spread.tipo(), spread.location())?;
|
self.unify(return_type, spread.tipo(), spread.location(), false)?;
|
||||||
|
|
||||||
let mut arguments = Vec::new();
|
let mut arguments = Vec::new();
|
||||||
|
|
||||||
|
@ -523,7 +529,12 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
// field in the record contained within the spread variable. We
|
// field in the record contained within the spread variable. We
|
||||||
// need to check the spread, and not the constructor, in order
|
// need to check the spread, and not the constructor, in order
|
||||||
// to handle polymorphic types.
|
// to handle polymorphic types.
|
||||||
self.unify(spread_field.tipo(), value.tipo(), value.location())?;
|
self.unify(
|
||||||
|
spread_field.tipo(),
|
||||||
|
value.tipo(),
|
||||||
|
value.location(),
|
||||||
|
spread_field.tipo().is_data(),
|
||||||
|
)?;
|
||||||
|
|
||||||
match field_map.fields.get(&label) {
|
match field_map.fields.get(&label) {
|
||||||
None => {
|
None => {
|
||||||
|
@ -571,7 +582,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
UnOp::Negate => int(),
|
UnOp::Negate => int(),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.unify(tipo.clone(), value.tipo(), value.location())?;
|
self.unify(tipo.clone(), value.tipo(), value.location(), false)?;
|
||||||
|
|
||||||
Ok(TypedExpr::UnOp {
|
Ok(TypedExpr::UnOp {
|
||||||
location,
|
location,
|
||||||
|
@ -754,7 +765,12 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
|
|
||||||
let tipo = self.instantiate(tipo, &mut type_vars);
|
let tipo = self.instantiate(tipo, &mut type_vars);
|
||||||
|
|
||||||
self.unify(accessor_record_type, record.tipo(), record.location())?;
|
self.unify(
|
||||||
|
accessor_record_type,
|
||||||
|
record.tipo(),
|
||||||
|
record.location(),
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
|
|
||||||
Ok(TypedExpr::RecordAccess {
|
Ok(TypedExpr::RecordAccess {
|
||||||
record,
|
record,
|
||||||
|
@ -765,7 +781,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_arg(
|
fn infer_param(
|
||||||
&mut self,
|
&mut self,
|
||||||
arg: UntypedArg,
|
arg: UntypedArg,
|
||||||
expected: Option<Arc<Type>>,
|
expected: Option<Arc<Type>>,
|
||||||
|
@ -788,7 +804,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
// function being type checked, resulting in better type errors and the
|
// function being type checked, resulting in better type errors and the
|
||||||
// record field access syntax working.
|
// record field access syntax working.
|
||||||
if let Some(expected) = expected {
|
if let Some(expected) = expected {
|
||||||
self.unify(expected, tipo.clone(), location)?;
|
self.unify(expected, tipo.clone(), location, false)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Arg {
|
Ok(Arg {
|
||||||
|
@ -820,18 +836,9 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
ann_typ.clone(),
|
ann_typ.clone(),
|
||||||
value_typ.clone(),
|
value_typ.clone(),
|
||||||
typed_value.type_defining_location(),
|
typed_value.type_defining_location(),
|
||||||
|
(kind.is_let() && ann_typ.is_data()) || (kind.is_assert() && value_typ.is_data()),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if value_typ.is_data() && kind.is_let() && !ann_typ.is_data() {
|
|
||||||
return Err(Error::CouldNotUnify {
|
|
||||||
location,
|
|
||||||
expected: ann_typ,
|
|
||||||
given: value_typ,
|
|
||||||
situation: Some(UnifyErrorSituation::UnsafeCast),
|
|
||||||
rigid_type_names: HashMap::new(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
value_typ = ann_typ.clone();
|
value_typ = ann_typ.clone();
|
||||||
|
|
||||||
// Ensure the pattern matches the type of the value
|
// Ensure the pattern matches the type of the value
|
||||||
|
@ -951,17 +958,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
(_, value) => self.infer(value),
|
(_, value) => self.infer(value),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
self.unify(tipo.clone(), value.tipo(), value.location())?;
|
self.unify(tipo.clone(), value.tipo(), value.location(), tipo.is_data())?;
|
||||||
|
|
||||||
if value.tipo().is_data() && !tipo.is_data() {
|
|
||||||
return Err(Error::CouldNotUnify {
|
|
||||||
location: value.location(),
|
|
||||||
expected: tipo,
|
|
||||||
given: value.tipo(),
|
|
||||||
situation: Some(UnifyErrorSituation::UnsafeCast),
|
|
||||||
rigid_type_names: HashMap::new(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
@ -1035,7 +1032,9 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
location, value, ..
|
location, value, ..
|
||||||
} => {
|
} => {
|
||||||
let value = self.infer_clause_guard(*value)?;
|
let value = self.infer_clause_guard(*value)?;
|
||||||
self.unify(bool(), value.tipo(), value.location())?;
|
|
||||||
|
self.unify(bool(), value.tipo(), value.location(), false)?;
|
||||||
|
|
||||||
Ok(ClauseGuard::Not {
|
Ok(ClauseGuard::Not {
|
||||||
location,
|
location,
|
||||||
value: Box::new(value),
|
value: Box::new(value),
|
||||||
|
@ -1050,11 +1049,11 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
} => {
|
} => {
|
||||||
let left = self.infer_clause_guard(*left)?;
|
let left = self.infer_clause_guard(*left)?;
|
||||||
|
|
||||||
self.unify(bool(), left.tipo(), left.location())?;
|
self.unify(bool(), left.tipo(), left.location(), false)?;
|
||||||
|
|
||||||
let right = self.infer_clause_guard(*right)?;
|
let right = self.infer_clause_guard(*right)?;
|
||||||
|
|
||||||
self.unify(bool(), right.tipo(), right.location())?;
|
self.unify(bool(), right.tipo(), right.location(), false)?;
|
||||||
|
|
||||||
Ok(ClauseGuard::And {
|
Ok(ClauseGuard::And {
|
||||||
location,
|
location,
|
||||||
|
@ -1071,11 +1070,11 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
} => {
|
} => {
|
||||||
let left = self.infer_clause_guard(*left)?;
|
let left = self.infer_clause_guard(*left)?;
|
||||||
|
|
||||||
self.unify(bool(), left.tipo(), left.location())?;
|
self.unify(bool(), left.tipo(), left.location(), false)?;
|
||||||
|
|
||||||
let right = self.infer_clause_guard(*right)?;
|
let right = self.infer_clause_guard(*right)?;
|
||||||
|
|
||||||
self.unify(bool(), right.tipo(), right.location())?;
|
self.unify(bool(), right.tipo(), right.location(), false)?;
|
||||||
|
|
||||||
Ok(ClauseGuard::Or {
|
Ok(ClauseGuard::Or {
|
||||||
location,
|
location,
|
||||||
|
@ -1093,7 +1092,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
let left = self.infer_clause_guard(*left)?;
|
let left = self.infer_clause_guard(*left)?;
|
||||||
let right = self.infer_clause_guard(*right)?;
|
let right = self.infer_clause_guard(*right)?;
|
||||||
|
|
||||||
self.unify(left.tipo(), right.tipo(), location)?;
|
self.unify(left.tipo(), right.tipo(), location, false)?;
|
||||||
|
|
||||||
Ok(ClauseGuard::Equals {
|
Ok(ClauseGuard::Equals {
|
||||||
location,
|
location,
|
||||||
|
@ -1111,7 +1110,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
let left = self.infer_clause_guard(*left)?;
|
let left = self.infer_clause_guard(*left)?;
|
||||||
let right = self.infer_clause_guard(*right)?;
|
let right = self.infer_clause_guard(*right)?;
|
||||||
|
|
||||||
self.unify(left.tipo(), right.tipo(), location)?;
|
self.unify(left.tipo(), right.tipo(), location, false)?;
|
||||||
|
|
||||||
Ok(ClauseGuard::NotEquals {
|
Ok(ClauseGuard::NotEquals {
|
||||||
location,
|
location,
|
||||||
|
@ -1128,11 +1127,11 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
} => {
|
} => {
|
||||||
let left = self.infer_clause_guard(*left)?;
|
let left = self.infer_clause_guard(*left)?;
|
||||||
|
|
||||||
self.unify(int(), left.tipo(), left.location())?;
|
self.unify(int(), left.tipo(), left.location(), false)?;
|
||||||
|
|
||||||
let right = self.infer_clause_guard(*right)?;
|
let right = self.infer_clause_guard(*right)?;
|
||||||
|
|
||||||
self.unify(int(), right.tipo(), right.location())?;
|
self.unify(int(), right.tipo(), right.location(), false)?;
|
||||||
|
|
||||||
Ok(ClauseGuard::GtInt {
|
Ok(ClauseGuard::GtInt {
|
||||||
location,
|
location,
|
||||||
|
@ -1149,11 +1148,11 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
} => {
|
} => {
|
||||||
let left = self.infer_clause_guard(*left)?;
|
let left = self.infer_clause_guard(*left)?;
|
||||||
|
|
||||||
self.unify(int(), left.tipo(), left.location())?;
|
self.unify(int(), left.tipo(), left.location(), false)?;
|
||||||
|
|
||||||
let right = self.infer_clause_guard(*right)?;
|
let right = self.infer_clause_guard(*right)?;
|
||||||
|
|
||||||
self.unify(int(), right.tipo(), right.location())?;
|
self.unify(int(), right.tipo(), right.location(), false)?;
|
||||||
|
|
||||||
Ok(ClauseGuard::GtEqInt {
|
Ok(ClauseGuard::GtEqInt {
|
||||||
location,
|
location,
|
||||||
|
@ -1170,11 +1169,11 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
} => {
|
} => {
|
||||||
let left = self.infer_clause_guard(*left)?;
|
let left = self.infer_clause_guard(*left)?;
|
||||||
|
|
||||||
self.unify(int(), left.tipo(), left.location())?;
|
self.unify(int(), left.tipo(), left.location(), false)?;
|
||||||
|
|
||||||
let right = self.infer_clause_guard(*right)?;
|
let right = self.infer_clause_guard(*right)?;
|
||||||
|
|
||||||
self.unify(int(), right.tipo(), right.location())?;
|
self.unify(int(), right.tipo(), right.location(), false)?;
|
||||||
|
|
||||||
Ok(ClauseGuard::LtInt {
|
Ok(ClauseGuard::LtInt {
|
||||||
location,
|
location,
|
||||||
|
@ -1191,11 +1190,11 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
} => {
|
} => {
|
||||||
let left = self.infer_clause_guard(*left)?;
|
let left = self.infer_clause_guard(*left)?;
|
||||||
|
|
||||||
self.unify(int(), left.tipo(), left.location())?;
|
self.unify(int(), left.tipo(), left.location(), false)?;
|
||||||
|
|
||||||
let right = self.infer_clause_guard(*right)?;
|
let right = self.infer_clause_guard(*right)?;
|
||||||
|
|
||||||
self.unify(int(), right.tipo(), right.location())?;
|
self.unify(int(), right.tipo(), right.location(), false)?;
|
||||||
|
|
||||||
Ok(ClauseGuard::LtEqInt {
|
Ok(ClauseGuard::LtEqInt {
|
||||||
location,
|
location,
|
||||||
|
@ -1427,7 +1426,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
|
|
||||||
let value = self.infer_const(&None, value)?;
|
let value = self.infer_const(&None, value)?;
|
||||||
|
|
||||||
self.unify(tipo.clone(), value.tipo(), value.location())?;
|
self.unify(tipo.clone(), value.tipo(), value.location(), tipo.is_data())?;
|
||||||
|
|
||||||
typed_args.push(CallArg {
|
typed_args.push(CallArg {
|
||||||
label,
|
label,
|
||||||
|
@ -1482,7 +1481,12 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
if let Some(ann) = annotation {
|
if let Some(ann) = annotation {
|
||||||
let const_ann = self.type_from_annotation(ann)?;
|
let const_ann = self.type_from_annotation(ann)?;
|
||||||
|
|
||||||
self.unify(const_ann, inferred.tipo(), inferred.location())?;
|
self.unify(
|
||||||
|
const_ann.clone(),
|
||||||
|
inferred.tipo(),
|
||||||
|
inferred.location(),
|
||||||
|
const_ann.is_data(),
|
||||||
|
)?;
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(inferred)
|
Ok(inferred)
|
||||||
|
@ -1500,7 +1504,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
for element in untyped_elements {
|
for element in untyped_elements {
|
||||||
let element = self.infer_const(&None, element)?;
|
let element = self.infer_const(&None, element)?;
|
||||||
|
|
||||||
self.unify(tipo.clone(), element.tipo(), element.location())?;
|
self.unify(tipo.clone(), element.tipo(), element.location(), false)?;
|
||||||
|
|
||||||
elements.push(element);
|
elements.push(element);
|
||||||
}
|
}
|
||||||
|
@ -1522,7 +1526,12 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
|
|
||||||
let condition = self.infer(first.condition.clone())?;
|
let condition = self.infer(first.condition.clone())?;
|
||||||
|
|
||||||
self.unify(bool(), condition.tipo(), condition.type_defining_location())?;
|
self.unify(
|
||||||
|
bool(),
|
||||||
|
condition.tipo(),
|
||||||
|
condition.type_defining_location(),
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
|
|
||||||
let body = self.infer(first.body.clone())?;
|
let body = self.infer(first.body.clone())?;
|
||||||
|
|
||||||
|
@ -1537,11 +1546,21 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
for branch in &branches[1..] {
|
for branch in &branches[1..] {
|
||||||
let condition = self.infer(branch.condition.clone())?;
|
let condition = self.infer(branch.condition.clone())?;
|
||||||
|
|
||||||
self.unify(bool(), condition.tipo(), condition.type_defining_location())?;
|
self.unify(
|
||||||
|
bool(),
|
||||||
|
condition.tipo(),
|
||||||
|
condition.type_defining_location(),
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
|
|
||||||
let body = self.infer(branch.body.clone())?;
|
let body = self.infer(branch.body.clone())?;
|
||||||
|
|
||||||
self.unify(tipo.clone(), body.tipo(), body.type_defining_location())?;
|
self.unify(
|
||||||
|
tipo.clone(),
|
||||||
|
body.tipo(),
|
||||||
|
body.type_defining_location(),
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
|
|
||||||
typed_branches.push(TypedIfBranch {
|
typed_branches.push(TypedIfBranch {
|
||||||
body,
|
body,
|
||||||
|
@ -1556,6 +1575,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
tipo.clone(),
|
tipo.clone(),
|
||||||
typed_final_else.tipo(),
|
typed_final_else.tipo(),
|
||||||
typed_final_else.type_defining_location(),
|
typed_final_else.type_defining_location(),
|
||||||
|
false,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(TypedExpr::If {
|
Ok(TypedExpr::If {
|
||||||
|
@ -1628,11 +1648,16 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
|
|
||||||
// Check that any return type is accurate.
|
// Check that any return type is accurate.
|
||||||
if let Some(return_type) = return_type {
|
if let Some(return_type) = return_type {
|
||||||
self.unify(return_type, body.tipo(), body.type_defining_location())
|
self.unify(
|
||||||
.map_err(|e| {
|
return_type.clone(),
|
||||||
e.return_annotation_mismatch()
|
body.tipo(),
|
||||||
.with_unify_error_rigid_names(&body_rigid_names)
|
body.type_defining_location(),
|
||||||
})?;
|
return_type.is_data(),
|
||||||
|
)
|
||||||
|
.map_err(|e| {
|
||||||
|
e.return_annotation_mismatch()
|
||||||
|
.with_unify_error_rigid_names(&body_rigid_names)
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((args, body))
|
Ok((args, body))
|
||||||
|
@ -1660,7 +1685,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
let element = self.infer(elem)?;
|
let element = self.infer(elem)?;
|
||||||
|
|
||||||
// Ensure they all have the same type
|
// Ensure they all have the same type
|
||||||
self.unify(tipo.clone(), element.tipo(), location)?;
|
self.unify(tipo.clone(), element.tipo(), location, false)?;
|
||||||
|
|
||||||
elems.push(element)
|
elems.push(element)
|
||||||
}
|
}
|
||||||
|
@ -1673,7 +1698,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
let tail = self.infer(*tail)?;
|
let tail = self.infer(*tail)?;
|
||||||
|
|
||||||
// Ensure the tail has the same type as the preceeding elements
|
// Ensure the tail has the same type as the preceeding elements
|
||||||
self.unify(tipo.clone(), tail.tipo(), location)?;
|
self.unify(tipo.clone(), tail.tipo(), location, false)?;
|
||||||
|
|
||||||
Some(Box::new(tail))
|
Some(Box::new(tail))
|
||||||
}
|
}
|
||||||
|
@ -1700,7 +1725,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
Some(guard) => {
|
Some(guard) => {
|
||||||
let guard = self.infer_clause_guard(guard)?;
|
let guard = self.infer_clause_guard(guard)?;
|
||||||
|
|
||||||
self.unify(bool(), guard.tipo(), guard.location())?;
|
self.unify(bool(), guard.tipo(), guard.location(), false)?;
|
||||||
|
|
||||||
Ok(Some(guard))
|
Ok(Some(guard))
|
||||||
}
|
}
|
||||||
|
@ -1986,6 +2011,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
return_type.clone(),
|
return_type.clone(),
|
||||||
typed_clause.then.tipo(),
|
typed_clause.then.tipo(),
|
||||||
typed_clause.location(),
|
typed_clause.location(),
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
.map_err(|e| e.case_clause_mismatch())?;
|
.map_err(|e| e.case_clause_mismatch())?;
|
||||||
|
|
||||||
|
@ -2034,7 +2060,13 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
.type_from_annotation(annotation, self.environment)
|
.type_from_annotation(annotation, self.environment)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unify(&mut self, t1: Arc<Type>, t2: Arc<Type>, location: Span) -> Result<(), Error> {
|
fn unify(
|
||||||
self.environment.unify(t1, t2, location)
|
&mut self,
|
||||||
|
t1: Arc<Type>,
|
||||||
|
t2: Arc<Type>,
|
||||||
|
location: Span,
|
||||||
|
allow_cast: bool,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.environment.unify(t1, t2, location, allow_cast)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,7 +160,7 @@ impl Hydrator {
|
||||||
for (parameter, (location, argument)) in
|
for (parameter, (location, argument)) in
|
||||||
parameter_types.into_iter().zip(argument_types)
|
parameter_types.into_iter().zip(argument_types)
|
||||||
{
|
{
|
||||||
environment.unify(parameter, argument, location)?;
|
environment.unify(parameter, argument, location, false)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(return_type)
|
Ok(return_type)
|
||||||
|
|
|
@ -207,7 +207,7 @@ fn infer_definition(
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Assert that the inferred type matches the type of any recursive call
|
// Assert that the inferred type matches the type of any recursive call
|
||||||
environment.unify(preregistered_type, tipo.clone(), location)?;
|
environment.unify(preregistered_type, tipo.clone(), location, false)?;
|
||||||
|
|
||||||
// Generalise the function if safe to do so
|
// Generalise the function if safe to do so
|
||||||
let tipo = if safe_to_generalise {
|
let tipo = if safe_to_generalise {
|
||||||
|
@ -250,7 +250,7 @@ fn infer_definition(
|
||||||
if let Definition::Fn(f) =
|
if let Definition::Fn(f) =
|
||||||
infer_definition(Definition::Fn(f), module_name, hydrators, environment, kind)?
|
infer_definition(Definition::Fn(f), module_name, hydrators, environment, kind)?
|
||||||
{
|
{
|
||||||
environment.unify(f.return_type.clone(), builtins::bool(), f.location)?;
|
environment.unify(f.return_type.clone(), builtins::bool(), f.location, false)?;
|
||||||
Ok(Definition::Test(f))
|
Ok(Definition::Test(f))
|
||||||
} else {
|
} else {
|
||||||
unreachable!("test defintion inferred as something else than a function?")
|
unreachable!("test defintion inferred as something else than a function?")
|
||||||
|
|
|
@ -82,7 +82,8 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
|
||||||
Some(initial) if self.initial_pattern_vars.contains(name) => {
|
Some(initial) if self.initial_pattern_vars.contains(name) => {
|
||||||
assigned.push(name.to_string());
|
assigned.push(name.to_string());
|
||||||
let initial_typ = initial.tipo.clone();
|
let initial_typ = initial.tipo.clone();
|
||||||
self.environment.unify(initial_typ, typ, err_location)
|
self.environment
|
||||||
|
.unify(initial_typ, typ, err_location, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This variable was not defined in the Initial multi-pattern
|
// This variable was not defined in the Initial multi-pattern
|
||||||
|
@ -280,13 +281,13 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Pattern::Int { location, value } => {
|
Pattern::Int { location, value } => {
|
||||||
self.environment.unify(tipo, int(), location)?;
|
self.environment.unify(tipo, int(), location, false)?;
|
||||||
|
|
||||||
Ok(Pattern::Int { location, value })
|
Ok(Pattern::Int { location, value })
|
||||||
}
|
}
|
||||||
|
|
||||||
Pattern::String { location, value } => {
|
Pattern::String { location, value } => {
|
||||||
self.environment.unify(tipo, string(), location)?;
|
self.environment.unify(tipo, string(), location, false)?;
|
||||||
|
|
||||||
Ok(Pattern::String { location, value })
|
Ok(Pattern::String { location, value })
|
||||||
}
|
}
|
||||||
|
@ -358,7 +359,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
self.environment
|
self.environment
|
||||||
.unify(tuple(elems_types.clone()), tipo, location)?;
|
.unify(tuple(elems_types.clone()), tipo, location, false)?;
|
||||||
|
|
||||||
let mut patterns = vec![];
|
let mut patterns = vec![];
|
||||||
|
|
||||||
|
@ -513,7 +514,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
|
||||||
})
|
})
|
||||||
.try_collect()?;
|
.try_collect()?;
|
||||||
|
|
||||||
self.environment.unify(tipo, ret.clone(), location)?;
|
self.environment.unify(tipo, ret.clone(), location, false)?;
|
||||||
|
|
||||||
Ok(Pattern::Constructor {
|
Ok(Pattern::Constructor {
|
||||||
location,
|
location,
|
||||||
|
@ -543,6 +544,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
|
||||||
tipo,
|
tipo,
|
||||||
instantiated_constructor_type.clone(),
|
instantiated_constructor_type.clone(),
|
||||||
location,
|
location,
|
||||||
|
false,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(Pattern::Constructor {
|
Ok(Pattern::Constructor {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::sync::Arc;
|
use std::{ops::Deref, sync::Arc};
|
||||||
|
|
||||||
use vec1::Vec1;
|
use vec1::Vec1;
|
||||||
|
|
||||||
|
@ -268,6 +268,15 @@ impl<'a, 'b, 'c> PipeTyper<'a, 'b, 'c> {
|
||||||
func.tipo(),
|
func.tipo(),
|
||||||
function(vec![self.argument_type.clone()], return_type.clone()),
|
function(vec![self.argument_type.clone()], return_type.clone()),
|
||||||
func.location(),
|
func.location(),
|
||||||
|
if let Type::Fn { args, .. } = func.tipo().deref() {
|
||||||
|
if let Some(typ) = args.get(0) {
|
||||||
|
typ.is_data()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
},
|
||||||
)
|
)
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
let is_pipe_mismatch = self.check_if_pipe_type_mismatch(&e, func.location());
|
let is_pipe_mismatch = self.check_if_pipe_type_mismatch(&e, func.location());
|
||||||
|
@ -301,7 +310,7 @@ impl<'a, 'b, 'c> PipeTyper<'a, 'b, 'c> {
|
||||||
(Some(a), Some(b)) => self
|
(Some(a), Some(b)) => self
|
||||||
.expr_typer
|
.expr_typer
|
||||||
.environment
|
.environment
|
||||||
.unify(a.clone(), b.clone(), location)
|
.unify(a.clone(), b.clone(), location, a.is_data())
|
||||||
.is_err(),
|
.is_err(),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue