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:
rvcas 2023-02-03 22:35:05 -05:00 committed by Lucas
parent 2b554d105a
commit c126f6acda
7 changed files with 140 additions and 101 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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