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:
parent
22b618116e
commit
f10cf73905
|
@ -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(),
|
||||||
|
|
|
@ -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,19 +965,21 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if kind.is_expect() && value_is_opaque {
|
None
|
||||||
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(),
|
|
||||||
)?
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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
|
// 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.
|
||||||
match kind {
|
match kind {
|
||||||
|
|
Loading…
Reference in New Issue