diff --git a/crates/aiken-lang/src/tipo.rs b/crates/aiken-lang/src/tipo.rs index d60cb53b..2144c644 100644 --- a/crates/aiken-lang/src/tipo.rs +++ b/crates/aiken-lang/src/tipo.rs @@ -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(), diff --git a/crates/aiken-lang/src/tipo/expr.rs b/crates/aiken-lang/src/tipo/expr.rs index 5777fe4d..2c14a274 100644 --- a/crates/aiken-lang/src/tipo/expr.rs +++ b/crates/aiken-lang/src/tipo/expr.rs @@ -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 {