Rework 'is_opaque' to also check for inner types.

Also removed the duplication in infer_assignment and moved the check down.
This commit is contained in:
KtorZ 2024-03-13 13:14:38 +01:00 committed by rvcas
parent 22b618116e
commit f10cf73905
No known key found for this signature in database
GPG Key ID: C09B64E263F7D68C
2 changed files with 29 additions and 27 deletions

View File

@ -195,10 +195,14 @@ impl Type {
}
}
pub fn is_opaque(&self) -> bool {
pub fn is_or_holds_opaque(&self) -> bool {
match self {
Type::App { opaque, .. } => *opaque,
_ => false,
Type::Var { tipo, .. } => tipo.borrow().is_or_holds_opaque(),
Type::App { opaque, args, .. } => {
*opaque || args.iter().any(|arg| arg.is_or_holds_opaque())
}
Type::Tuple { elems, .. } => elems.iter().any(|elem| elem.is_or_holds_opaque()),
Type::Fn { .. } => false,
}
}
@ -845,6 +849,13 @@ impl TypeVar {
matches!(self, Self::Unbound { .. })
}
pub fn is_or_holds_opaque(&self) -> bool {
match self {
Self::Link { tipo } => tipo.is_or_holds_opaque(),
_ => false,
}
}
pub fn is_void(&self) -> bool {
match self {
Self::Link { tipo } => tipo.is_void(),

View File

@ -928,18 +928,13 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
let mut value_typ = typed_value.tipo();
let value_is_data = value_typ.is_data();
let value_is_opaque = value_typ.is_opaque();
// Check that any type annotation is accurate.
let pattern = if let Some(ann) = annotation {
let ann_typ = if let Some(ann) = annotation {
let ann_typ = self
.type_from_annotation(ann)
.map(|t| self.instantiate(t, &mut HashMap::new()))?;
if kind.is_expect() && (ann_typ.is_opaque() || value_is_opaque) {
return Err(Error::ExpectOnOpaqueType { location });
}
self.unify(
ann_typ.clone(),
value_typ.clone(),
@ -949,13 +944,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
value_typ = ann_typ.clone();
// Ensure the pattern matches the type of the value
PatternTyper::new(self.environment, &self.hydrator).unify(
untyped_pattern.clone(),
value_typ.clone(),
Some(ann_typ),
kind.is_let(),
)?
Some(ann_typ)
} else {
if value_is_data && !untyped_pattern.is_var() && !untyped_pattern.is_discard() {
let ann = Annotation::Constructor {
@ -976,19 +965,21 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
});
}
if kind.is_expect() && value_is_opaque {
return Err(Error::ExpectOnOpaqueType { location });
}
// Ensure the pattern matches the type of the value
PatternTyper::new(self.environment, &self.hydrator).unify(
untyped_pattern.clone(),
value_typ.clone(),
None,
kind.is_let(),
)?
None
};
if kind.is_expect() && value_typ.is_or_holds_opaque() {
return Err(Error::ExpectOnOpaqueType { location });
}
// Ensure the pattern matches the type of the value
let pattern = PatternTyper::new(self.environment, &self.hydrator).unify(
untyped_pattern.clone(),
value_typ.clone(),
ann_typ,
kind.is_let(),
)?;
// If `expect` is explicitly used, we still check exhaustiveness but instead of returning an
// error we emit a warning which explains that using `expect` is unnecessary.
match kind {