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