Use inferred Fuzzer inner type for unify error when possible.

This commit is contained in:
KtorZ 2024-03-08 15:57:22 +01:00
parent eb07365e73
commit 877d10ef22
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
1 changed files with 48 additions and 26 deletions

View File

@ -342,8 +342,39 @@ fn infer_definition(
let typed_via = let typed_via =
ExprTyper::new(environment, lines, tracing).infer(arg.via.clone())?; ExprTyper::new(environment, lines, tracing).infer(arg.via.clone())?;
let (inferred_annotation, inner_type) = let hydrator: &mut Hydrator = hydrators.get_mut(&f.name).unwrap();
infer_fuzzer(environment, &typed_via.tipo(), &arg.via.location())?;
let provided_inner_type = arg
.annotation
.as_ref()
.map(|ann| hydrator.type_from_annotation(ann, environment))
.transpose()?;
let (inferred_annotation, inferred_inner_type) = infer_fuzzer(
environment,
provided_inner_type.clone(),
&typed_via.tipo(),
&arg.via.location(),
)?;
// Ensure that the annotation, if any, matches the type inferred from the
// Fuzzer.
if let Some(provided_inner_type) = provided_inner_type {
if !arg
.annotation
.as_ref()
.unwrap()
.is_logically_equal(&inferred_annotation)
{
return Err(Error::CouldNotUnify {
location: arg.location,
expected: inferred_inner_type.clone(),
given: provided_inner_type.clone(),
situation: Some(UnifyErrorSituation::FuzzerAnnotationMismatch),
rigid_type_names: hydrator.rigid_names(),
});
}
}
// Replace the pre-registered type for the test function, to allow inferring // Replace the pre-registered type for the test function, to allow inferring
// the function body with the right type arguments. // the function body with the right type arguments.
@ -354,30 +385,14 @@ fn infer_definition(
if let Type::Fn { ref ret, .. } = scope.tipo.as_ref() { if let Type::Fn { ref ret, .. } = scope.tipo.as_ref() {
scope.tipo = Rc::new(Type::Fn { scope.tipo = Rc::new(Type::Fn {
ret: ret.clone(), ret: ret.clone(),
args: vec![inner_type.clone()], args: vec![inferred_inner_type.clone()],
}) })
} }
// Ensure that the annotation, if any, matches the type inferred from the Ok((
// Fuzzer. Some((typed_via, inferred_inner_type)),
if let Some(ref provided_annotation) = arg.annotation { Some(inferred_annotation),
let hydrator: &mut Hydrator = hydrators.get_mut(&f.name).unwrap(); ))
let given =
hydrator.type_from_annotation(provided_annotation, environment)?;
if !provided_annotation.is_logically_equal(&inferred_annotation) {
return Err(Error::CouldNotUnify {
location: arg.location,
expected: inner_type.clone(),
given,
situation: Some(UnifyErrorSituation::FuzzerAnnotationMismatch),
rigid_type_names: hydrator.rigid_names(),
});
}
}
Ok((Some((typed_via, inner_type)), Some(inferred_annotation)))
} }
None => Ok((None, None)), None => Ok((None, None)),
}?; }?;
@ -745,12 +760,17 @@ fn infer_function(
fn infer_fuzzer( fn infer_fuzzer(
environment: &mut Environment<'_>, environment: &mut Environment<'_>,
expected_inner_type: Option<Rc<Type>>,
tipo: &Rc<Type>, tipo: &Rc<Type>,
location: &Span, location: &Span,
) -> Result<(Annotation, Rc<Type>), Error> { ) -> Result<(Annotation, Rc<Type>), Error> {
let could_not_unify = || Error::CouldNotUnify { let could_not_unify = || Error::CouldNotUnify {
location: *location, location: *location,
expected: fuzzer(generic_var(0)), expected: fuzzer(
expected_inner_type
.clone()
.unwrap_or_else(|| generic_var(0)),
),
given: tipo.clone(), given: tipo.clone(),
situation: None, situation: None,
rigid_type_names: HashMap::new(), rigid_type_names: HashMap::new(),
@ -789,8 +809,10 @@ fn infer_fuzzer(
_ => Err(could_not_unify()), _ => Err(could_not_unify()),
}, },
Type::Var { tipo } => match &*tipo.deref().borrow() { Type::Var { tipo, .. } => match &*tipo.deref().borrow() {
TypeVar::Link { tipo } => infer_fuzzer(environment, tipo, location), TypeVar::Link { tipo } => {
infer_fuzzer(environment, expected_inner_type, tipo, location)
}
_ => Err(Error::GenericLeftAtBoundary { _ => Err(Error::GenericLeftAtBoundary {
location: *location, location: *location,
}), }),