Merge pull request #459 from aiken-lang/remove-multi-subjects

Cleanup implementation from multi-subjects when/is
This commit is contained in:
Matthias Benkort 2023-03-17 14:58:56 +01:00 committed by GitHub
commit 3eccc349aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 257 additions and 370 deletions

View File

@ -1,5 +1,3 @@
use std::{fmt, ops::Range, sync::Arc};
use crate::{ use crate::{
builtins::{self, bool}, builtins::{self, bool},
expr::{TypedExpr, UntypedExpr}, expr::{TypedExpr, UntypedExpr},
@ -8,6 +6,8 @@ use crate::{
}; };
use miette::Diagnostic; use miette::Diagnostic;
use owo_colors::{OwoColorize, Stream::Stdout}; use owo_colors::{OwoColorize, Stream::Stdout};
use std::{fmt, ops::Range, sync::Arc};
use vec1::Vec1;
pub const ASSERT_VARIABLE: &str = "_try"; pub const ASSERT_VARIABLE: &str = "_try";
pub const CAPTURE_VARIABLE: &str = "_capture"; pub const CAPTURE_VARIABLE: &str = "_capture";
@ -909,26 +909,26 @@ pub type MultiPattern<PatternConstructor, Type> = Vec<Pattern<PatternConstructor
pub type UntypedMultiPattern = MultiPattern<(), ()>; pub type UntypedMultiPattern = MultiPattern<(), ()>;
pub type TypedMultiPattern = MultiPattern<PatternConstructor, Arc<Type>>; pub type TypedMultiPattern = MultiPattern<PatternConstructor, Arc<Type>>;
pub type TypedClause = Clause<TypedExpr, PatternConstructor, Arc<Type>>; #[derive(Debug, Clone, PartialEq)]
pub type UntypedClause = Clause<UntypedExpr, (), ()>; pub struct UntypedClause {
pub location: Span,
pub patterns: Vec1<Pattern<(), ()>>,
pub guard: Option<ClauseGuard<()>>,
pub then: UntypedExpr,
}
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Clause<Expr, PatternConstructor, Type> { pub struct TypedClause {
pub location: Span, pub location: Span,
pub pattern: MultiPattern<PatternConstructor, Type>, pub pattern: Pattern<PatternConstructor, Arc<Type>>,
pub alternative_patterns: Vec<MultiPattern<PatternConstructor, Type>>, pub guard: Option<ClauseGuard<Arc<Type>>>,
pub guard: Option<ClauseGuard<Type>>, pub then: TypedExpr,
pub then: Expr,
} }
impl TypedClause { impl TypedClause {
pub fn location(&self) -> Span { pub fn location(&self) -> Span {
Span { Span {
start: self start: self.pattern.location().start,
.pattern
.get(0)
.map(|p| p.location().start)
.unwrap_or_default(),
end: self.then.location().end, end: self.then.location().end,
} }
} }
@ -936,29 +936,6 @@ impl TypedClause {
pub fn find_node(&self, byte_index: usize) -> Option<&TypedExpr> { pub fn find_node(&self, byte_index: usize) -> Option<&TypedExpr> {
self.then.find_node(byte_index) self.then.find_node(byte_index)
} }
pub fn desugarize(self) -> Vec<Self> {
let mut alternative_patterns = self
.alternative_patterns
.into_iter()
.map(|pattern| Self {
location: self.location,
pattern,
alternative_patterns: vec![],
guard: self.guard.clone(),
then: self.then.clone(),
})
.collect::<Vec<_>>();
let mut clauses = vec![Self {
alternative_patterns: vec![],
..self
}];
clauses.append(&mut alternative_patterns);
clauses
}
} }
pub type UntypedClauseGuard = ClauseGuard<()>; pub type UntypedClauseGuard = ClauseGuard<()>;

View File

@ -18,8 +18,8 @@ use uplc::{
use crate::{ use crate::{
air::Air, air::Air,
ast::{ ast::{
AssignmentKind, BinOp, Clause, ClauseGuard, Constant, DataType, Pattern, Span, TypedArg, AssignmentKind, BinOp, ClauseGuard, Constant, DataType, Pattern, Span, TypedArg,
TypedDataType, UnOp, TypedClause, TypedDataType, UnOp,
}, },
expr::TypedExpr, expr::TypedExpr,
tipo::{PatternConstructor, Type, TypeVar, ValueConstructor, ValueConstructorVariant}, tipo::{PatternConstructor, Type, TypeVar, ValueConstructor, ValueConstructorVariant},
@ -396,9 +396,7 @@ pub fn convert_data_to_type(term: Term<Name>, field_type: &Arc<Type>) -> Term<Na
} }
} }
pub fn rearrange_clauses( pub fn rearrange_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
clauses: Vec<Clause<TypedExpr, PatternConstructor, Arc<Type>>>,
) -> Vec<Clause<TypedExpr, PatternConstructor, Arc<Type>>> {
let mut sorted_clauses = clauses; let mut sorted_clauses = clauses;
// if we have a list sort clauses so we can plug holes for cases not covered by clauses // if we have a list sort clauses so we can plug holes for cases not covered by clauses
@ -406,11 +404,11 @@ pub fn rearrange_clauses(
// let's sort clauses by a safer manner // let's sort clauses by a safer manner
// TODO: how shall tails be weighted? Since any clause after will not run // TODO: how shall tails be weighted? Since any clause after will not run
sorted_clauses.sort_by(|clause1, clause2| { sorted_clauses.sort_by(|clause1, clause2| {
let clause1_len = match &clause1.pattern[0] { let clause1_len = match &clause1.pattern {
Pattern::List { elements, tail, .. } => elements.len() + usize::from(tail.is_some()), Pattern::List { elements, tail, .. } => elements.len() + usize::from(tail.is_some()),
_ => 10000000, _ => 10000000,
}; };
let clause2_len = match &clause2.pattern[0] { let clause2_len = match &clause2.pattern {
Pattern::List { elements, tail, .. } => elements.len() + usize::from(tail.is_some()), Pattern::List { elements, tail, .. } => elements.len() + usize::from(tail.is_some()),
_ => 10000001, _ => 10000001,
}; };
@ -427,7 +425,7 @@ pub fn rearrange_clauses(
// If we have a catch all, use that. Otherwise use todo which will result in error // If we have a catch all, use that. Otherwise use todo which will result in error
// TODO: fill in todo label with description // TODO: fill in todo label with description
let plug_in_then = match &sorted_clauses[sorted_clauses.len() - 1].pattern[0] { let plug_in_then = match &sorted_clauses[sorted_clauses.len() - 1].pattern {
Pattern::Var { name, .. } => { Pattern::Var { name, .. } => {
assign_plug_in_name = Some(name); assign_plug_in_name = Some(name);
sorted_clauses[sorted_clauses.len() - 1].clone().then sorted_clauses[sorted_clauses.len() - 1].clone().then
@ -452,7 +450,7 @@ pub fn rearrange_clauses(
}; };
for (index, clause) in sorted_clauses.iter().enumerate() { for (index, clause) in sorted_clauses.iter().enumerate() {
if let Pattern::List { elements, .. } = &clause.pattern[0] { if let Pattern::List { elements, .. } = &clause.pattern {
// found a hole and now we plug it // found a hole and now we plug it
while elems_len < elements.len() { while elems_len < elements.len() {
let mut discard_elems = vec![]; let mut discard_elems = vec![];
@ -466,9 +464,9 @@ pub fn rearrange_clauses(
// If we have a named catch all then in scope the name and create list of discards, otherwise list of discards // If we have a named catch all then in scope the name and create list of discards, otherwise list of discards
let clause_to_fill = if let Some(name) = assign_plug_in_name { let clause_to_fill = if let Some(name) = assign_plug_in_name {
Clause { TypedClause {
location: Span::empty(), location: Span::empty(),
pattern: vec![Pattern::Assign { pattern: Pattern::Assign {
name: name.clone(), name: name.clone(),
location: Span::empty(), location: Span::empty(),
pattern: Pattern::List { pattern: Pattern::List {
@ -477,20 +475,18 @@ pub fn rearrange_clauses(
tail: None, tail: None,
} }
.into(), .into(),
}], },
alternative_patterns: vec![],
guard: None, guard: None,
then: plug_in_then.clone(), then: plug_in_then.clone(),
} }
} else { } else {
Clause { TypedClause {
location: Span::empty(), location: Span::empty(),
pattern: vec![Pattern::List { pattern: Pattern::List {
location: Span::empty(), location: Span::empty(),
elements: discard_elems, elements: discard_elems,
tail: None, tail: None,
}], },
alternative_patterns: vec![],
guard: None, guard: None,
then: plug_in_then.clone(), then: plug_in_then.clone(),
} }
@ -502,7 +498,7 @@ pub fn rearrange_clauses(
} }
// if we have a pattern with no clause guards and a tail then no lists will get past here to other clauses // if we have a pattern with no clause guards and a tail then no lists will get past here to other clauses
match &clause.pattern[0] { match &clause.pattern {
Pattern::Var { .. } => { Pattern::Var { .. } => {
last_clause_index = index + 1; last_clause_index = index + 1;
last_clause_set = true; last_clause_set = true;
@ -533,14 +529,13 @@ pub fn rearrange_clauses(
// If the last condition doesn't have a catch all or tail then add a catch all with a todo // If the last condition doesn't have a catch all or tail then add a catch all with a todo
if index == sorted_clauses.len() - 1 { if index == sorted_clauses.len() - 1 {
if let Pattern::List { tail: None, .. } = &clause.pattern[0] { if let Pattern::List { tail: None, .. } = &clause.pattern {
final_clauses.push(Clause { final_clauses.push(TypedClause {
location: Span::empty(), location: Span::empty(),
pattern: vec![Pattern::Discard { pattern: Pattern::Discard {
name: "_".to_string(), name: "_".to_string(),
location: Span::empty(), location: Span::empty(),
}], },
alternative_patterns: vec![],
guard: None, guard: None,
then: plug_in_then.clone(), then: plug_in_then.clone(),
}); });

View File

@ -4,9 +4,9 @@ use vec1::Vec1;
use crate::{ use crate::{
ast::{ ast::{
Annotation, Arg, AssignmentKind, BinOp, ByteArrayFormatPreference, CallArg, Clause, Annotation, Arg, AssignmentKind, BinOp, ByteArrayFormatPreference, CallArg,
DefinitionLocation, IfBranch, Pattern, RecordUpdateSpread, Span, TraceKind, DefinitionLocation, IfBranch, Pattern, RecordUpdateSpread, Span, TraceKind, TypedClause,
TypedRecordUpdateArg, UnOp, UntypedRecordUpdateArg, TypedRecordUpdateArg, UnOp, UntypedClause, UntypedRecordUpdateArg,
}, },
builtins::void, builtins::void,
tipo::{ModuleValueConstructor, PatternConstructor, Type, ValueConstructor}, tipo::{ModuleValueConstructor, PatternConstructor, Type, ValueConstructor},
@ -102,8 +102,8 @@ pub enum TypedExpr {
When { When {
location: Span, location: Span,
tipo: Arc<Type>, tipo: Arc<Type>,
subjects: Vec<Self>, subject: Box<Self>,
clauses: Vec<Clause<Self, PatternConstructor, Arc<Type>>>, clauses: Vec<TypedClause>,
}, },
If { If {
@ -355,10 +355,9 @@ impl TypedExpr {
TypedExpr::Assignment { value, .. } => value.find_node(byte_index), TypedExpr::Assignment { value, .. } => value.find_node(byte_index),
TypedExpr::When { TypedExpr::When {
subjects, clauses, .. subject, clauses, ..
} => subjects } => subject
.iter() .find_node(byte_index)
.find_map(|subject| subject.find_node(byte_index))
.or_else(|| { .or_else(|| {
clauses clauses
.iter() .iter()
@ -481,8 +480,8 @@ pub enum UntypedExpr {
When { When {
location: Span, location: Span,
subjects: Vec<Self>, subject: Box<Self>,
clauses: Vec<Clause<Self, (), ()>>, clauses: Vec<UntypedClause>,
}, },
If { If {

View File

@ -728,8 +728,8 @@ impl<'comments> Formatter<'comments> {
} => self.trace(kind, text, then), } => self.trace(kind, text, then),
UntypedExpr::When { UntypedExpr::When {
subjects, clauses, .. subject, clauses, ..
} => self.when(subjects, clauses), } => self.when(subject, clauses),
UntypedExpr::FieldAccess { UntypedExpr::FieldAccess {
label, container, .. label, container, ..
@ -933,14 +933,11 @@ impl<'comments> Formatter<'comments> {
pub fn when<'a>( pub fn when<'a>(
&mut self, &mut self,
subjects: &'a [UntypedExpr], subject: &'a UntypedExpr,
clauses: &'a [UntypedClause], clauses: &'a [UntypedClause],
) -> Document<'a> { ) -> Document<'a> {
let subjects_doc = break_("when", "when ") let subjects_doc = break_("when", "when ")
.append(join( .append(self.wrap_expr(subject))
subjects.iter().map(|s| self.wrap_expr(s)),
break_(",", ", "),
))
.nest(INDENT) .nest(INDENT)
.append(break_("", " ")) .append(break_("", " "))
.append("is {") .append("is {")
@ -1449,9 +1446,7 @@ impl<'comments> Formatter<'comments> {
let space_before = self.pop_empty_lines(clause.location.start); let space_before = self.pop_empty_lines(clause.location.start);
let after_position = clause.location.end; let after_position = clause.location.end;
let clause_doc = join( let clause_doc = join(
std::iter::once(&clause.pattern) clause.patterns.iter().map(|p| self.pattern(p)),
.chain(&clause.alternative_patterns)
.map(|p| join(p.iter().map(|p| self.pattern(p)), ", ".to_doc())),
" | ".to_doc(), " | ".to_doc(),
); );
let clause_doc = match &clause.guard { let clause_doc = match &clause.guard {

View File

@ -1,6 +1,3 @@
use chumsky::prelude::*;
use vec1::Vec1;
pub mod error; pub mod error;
pub mod extra; pub mod extra;
pub mod lexer; pub mod lexer;
@ -13,10 +10,11 @@ use crate::{
}, },
expr, expr,
}; };
use chumsky::prelude::*;
use error::ParseError; use error::ParseError;
use extra::ModuleExtra; use extra::ModuleExtra;
use token::Token; use token::Token;
use vec1::{vec1, Vec1};
pub fn module( pub fn module(
src: &str, src: &str,
@ -923,7 +921,7 @@ pub fn expr_parser(
let when_clause_parser = pattern_parser() let when_clause_parser = pattern_parser()
.then( .then(
just(Token::Vbar) just(Token::Vbar)
.ignore_then(pattern_parser().map(|pattern| vec![pattern])) .ignore_then(pattern_parser())
.repeated() .repeated()
.or_not(), .or_not(),
) )
@ -962,26 +960,29 @@ pub fn expr_parser(
}), }),
))) )))
.map_with_span( .map_with_span(
|(((pattern, alternative_patterns_opt), guard), then), span| ast::UntypedClause { |(((pattern, alternative_patterns_opt), guard), then), span| {
let mut patterns = vec1![pattern];
patterns.append(&mut alternative_patterns_opt.unwrap_or_default());
ast::UntypedClause {
location: span, location: span,
pattern: vec![pattern], patterns,
alternative_patterns: alternative_patterns_opt.unwrap_or_default(),
guard, guard,
then, then,
}
}, },
); );
let when_parser = just(Token::When) let when_parser = just(Token::When)
// TODO: If subject is empty we should return ParseErrorType::ExpectedExpr, // TODO: If subject is empty we should return ParseErrorType::ExpectedExpr,
.ignore_then(r.clone().separated_by(just(Token::Comma))) .ignore_then(r.clone().map(Box::new))
.then_ignore(just(Token::Is)) .then_ignore(just(Token::Is))
.then_ignore(just(Token::LeftBrace)) .then_ignore(just(Token::LeftBrace))
// TODO: If clauses are empty we should return ParseErrorType::NoCaseClause // TODO: If clauses are empty we should return ParseErrorType::NoCaseClause
.then(when_clause_parser.repeated()) .then(when_clause_parser.repeated())
.then_ignore(just(Token::RightBrace)) .then_ignore(just(Token::RightBrace))
.map_with_span(|(subjects, clauses), span| expr::UntypedExpr::When { .map_with_span(|(subject, clauses), span| expr::UntypedExpr::When {
location: span, location: span,
subjects, subject,
clauses, clauses,
}); });

View File

@ -1,11 +1,11 @@
use chumsky::prelude::*;
use indoc::indoc;
use pretty_assertions::assert_eq;
use crate::{ use crate::{
ast::{self, Constant, DataType, Function, ModuleConstant, Span, TypeAlias, Use}, ast::{self, Constant, DataType, Function, ModuleConstant, Span, TypeAlias, Use},
expr, parser, expr, parser,
}; };
use chumsky::prelude::*;
use indoc::indoc;
use pretty_assertions::assert_eq;
use vec1::vec1;
fn assert_definitions(code: &str, definitions: Vec<ast::UntypedDefinition>) { fn assert_definitions(code: &str, definitions: Vec<ast::UntypedDefinition>) {
let (module, _extra) = parser::module(code, ast::ModuleKind::Validator).unwrap(); let (module, _extra) = parser::module(code, ast::ModuleKind::Validator).unwrap();
@ -933,39 +933,38 @@ fn when() {
}], }],
body: expr::UntypedExpr::When { body: expr::UntypedExpr::When {
location: Span::new((), 23..132), location: Span::new((), 23..132),
subjects: vec![expr::UntypedExpr::Var { subject: Box::new(expr::UntypedExpr::Var {
location: Span::new((), 28..29), location: Span::new((), 28..29),
name: "a".to_string(), name: "a".to_string(),
}], }),
clauses: vec![ clauses: vec![
ast::Clause { ast::UntypedClause {
location: Span::new((), 39..45), location: Span::new((), 39..45),
pattern: vec![ast::Pattern::Int { patterns: vec1![ast::Pattern::Int {
location: Span::new((), 39..40), location: Span::new((), 39..40),
value: "2".to_string(), value: "2".to_string(),
}], }],
alternative_patterns: vec![],
guard: None, guard: None,
then: expr::UntypedExpr::Int { then: expr::UntypedExpr::Int {
location: Span::new((), 44..45), location: Span::new((), 44..45),
value: "3".to_string(), value: "3".to_string(),
}, },
}, },
ast::Clause { ast::UntypedClause {
location: Span::new((), 50..106), location: Span::new((), 50..106),
pattern: vec![ast::Pattern::Int { patterns: vec1![
ast::Pattern::Int {
location: Span::new((), 50..51), location: Span::new((), 50..51),
value: "1".to_string(), value: "1".to_string()
}], },
alternative_patterns: vec![ ast::Pattern::Int {
vec![ast::Pattern::Int {
location: Span::new((), 54..55), location: Span::new((), 54..55),
value: "4".to_string(), value: "4".to_string(),
}], },
vec![ast::Pattern::Int { ast::Pattern::Int {
location: Span::new((), 58..59), location: Span::new((), 58..59),
value: "5".to_string(), value: "5".to_string(),
}], },
], ],
guard: None, guard: None,
then: expr::UntypedExpr::Sequence { then: expr::UntypedExpr::Sequence {
@ -991,26 +990,24 @@ fn when() {
], ],
}, },
}, },
ast::Clause { ast::UntypedClause {
location: Span::new((), 111..117), location: Span::new((), 111..117),
pattern: vec![ast::Pattern::Int { patterns: vec1![ast::Pattern::Int {
location: Span::new((), 111..112), location: Span::new((), 111..112),
value: "3".to_string(), value: "3".to_string(),
}], }],
alternative_patterns: vec![],
guard: None, guard: None,
then: expr::UntypedExpr::Int { then: expr::UntypedExpr::Int {
location: Span::new((), 116..117), location: Span::new((), 116..117),
value: "9".to_string(), value: "9".to_string(),
}, },
}, },
ast::Clause { ast::UntypedClause {
location: Span::new((), 122..128), location: Span::new((), 122..128),
pattern: vec![ast::Pattern::Discard { patterns: vec1![ast::Pattern::Discard {
name: "_".to_string(), name: "_".to_string(),
location: Span::new((), 122..123), location: Span::new((), 122..123),
}], }],
alternative_patterns: vec![],
guard: None, guard: None,
then: expr::UntypedExpr::Int { then: expr::UntypedExpr::Int {
location: Span::new((), 127..128), location: Span::new((), 127..128),
@ -2154,13 +2151,13 @@ fn tuple_pattern() {
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::When { body: expr::UntypedExpr::When {
location: Span::new((), 13..49), location: Span::new((), 13..49),
subjects: vec![expr::UntypedExpr::Var { subject: Box::new(expr::UntypedExpr::Var {
location: Span::new((), 18..19), location: Span::new((), 18..19),
name: "a".to_string(), name: "a".to_string(),
}], }),
clauses: vec![ast::Clause { clauses: vec![ast::UntypedClause {
location: Span::new((), 29..45), location: Span::new((), 29..45),
pattern: vec![ast::Pattern::Tuple { patterns: vec1![ast::Pattern::Tuple {
location: Span::new((), 29..37), location: Span::new((), 29..37),
elems: vec![ elems: vec![
ast::Pattern::Var { ast::Pattern::Var {
@ -2173,7 +2170,6 @@ fn tuple_pattern() {
}, },
], ],
}], }],
alternative_patterns: vec![],
guard: None, guard: None,
then: expr::UntypedExpr::Var { then: expr::UntypedExpr::Var {
location: Span::new((), 41..45), location: Span::new((), 41..45),
@ -2324,19 +2320,18 @@ fn clause_guards() {
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::When { body: expr::UntypedExpr::When {
location: Span::new((), 13..250), location: Span::new((), 13..250),
subjects: vec![expr::UntypedExpr::Var { subject: Box::new(expr::UntypedExpr::Var {
location: Span::new((), 18..19), location: Span::new((), 18..19),
name: "a".to_string(), name: "a".to_string(),
}], }),
clauses: vec![ clauses: vec![
ast::Clause { ast::UntypedClause {
location: Span::new((), 29..44), location: Span::new((), 29..44),
pattern: vec![ast::Pattern::Discard { patterns: vec1![ast::Pattern::Discard {
name: "_".to_string(), name: "_".to_string(),
location: Span::new((), 29..30), location: Span::new((), 29..30),
}], }],
alternative_patterns: vec![], guard: Some(ast::UntypedClauseGuard::Constant(ast::Constant::Int {
guard: Some(ast::ClauseGuard::Constant(ast::Constant::Int {
location: Span::new((), 34..36), location: Span::new((), 34..36),
value: "42".to_string(), value: "42".to_string(),
})), })),
@ -2345,14 +2340,13 @@ fn clause_guards() {
name: "Void".to_string(), name: "Void".to_string(),
}, },
}, },
ast::Clause { ast::UntypedClause {
location: Span::new((), 49..65), location: Span::new((), 49..65),
pattern: vec![ast::Pattern::Discard { patterns: vec1![ast::Pattern::Discard {
name: "_".to_string(), name: "_".to_string(),
location: Span::new((), 49..50), location: Span::new((), 49..50),
}], }],
alternative_patterns: vec![], guard: Some(ast::UntypedClauseGuard::Var {
guard: Some(ast::ClauseGuard::Var {
location: Span::new((), 54..57), location: Span::new((), 54..57),
name: "bar".to_string(), name: "bar".to_string(),
tipo: (), tipo: (),
@ -2362,14 +2356,13 @@ fn clause_guards() {
name: "Void".to_string(), name: "Void".to_string(),
}, },
}, },
ast::Clause { ast::UntypedClause {
location: Span::new((), 70..87), location: Span::new((), 70..87),
pattern: vec![ast::Pattern::Discard { patterns: vec1![ast::Pattern::Discard {
name: "_".to_string(), name: "_".to_string(),
location: Span::new((), 70..71), location: Span::new((), 70..71),
}], }],
alternative_patterns: vec![], guard: Some(ast::UntypedClauseGuard::Var {
guard: Some(ast::ClauseGuard::Var {
location: Span::new((), 75..79), location: Span::new((), 75..79),
tipo: (), tipo: (),
name: "True".to_string(), name: "True".to_string(),
@ -2379,28 +2372,27 @@ fn clause_guards() {
name: "Void".to_string(), name: "Void".to_string(),
}, },
}, },
ast::Clause { ast::UntypedClause {
location: Span::new((), 92..116), location: Span::new((), 92..116),
pattern: vec![ast::Pattern::Discard { patterns: vec1![ast::Pattern::Discard {
name: "_".to_string(), name: "_".to_string(),
location: Span::new((), 92..93), location: Span::new((), 92..93),
}], }],
alternative_patterns: vec![], guard: Some(ast::UntypedClauseGuard::Or {
guard: Some(ast::ClauseGuard::Or {
location: Span::new((), 97..108), location: Span::new((), 97..108),
left: Box::new(ast::ClauseGuard::Var { left: Box::new(ast::UntypedClauseGuard::Var {
location: Span::new((), 97..98), location: Span::new((), 97..98),
name: "a".to_string(), name: "a".to_string(),
tipo: (), tipo: (),
}), }),
right: Box::new(ast::ClauseGuard::And { right: Box::new(ast::UntypedClauseGuard::And {
location: Span::new((), 102..108), location: Span::new((), 102..108),
left: Box::new(ast::ClauseGuard::Var { left: Box::new(ast::UntypedClauseGuard::Var {
location: Span::new((), 102..103), location: Span::new((), 102..103),
name: "b".to_string(), name: "b".to_string(),
tipo: (), tipo: (),
}), }),
right: Box::new(ast::ClauseGuard::Var { right: Box::new(ast::UntypedClauseGuard::Var {
location: Span::new((), 107..108), location: Span::new((), 107..108),
name: "c".to_string(), name: "c".to_string(),
tipo: (), tipo: (),
@ -2412,29 +2404,28 @@ fn clause_guards() {
name: "Void".to_string(), name: "Void".to_string(),
}, },
}, },
ast::Clause { ast::UntypedClause {
location: Span::new((), 121..147), location: Span::new((), 121..147),
pattern: vec![ast::Pattern::Discard { patterns: vec1![ast::Pattern::Discard {
name: "_".to_string(), name: "_".to_string(),
location: Span::new((), 121..122), location: Span::new((), 121..122),
}], }],
alternative_patterns: vec![], guard: Some(ast::UntypedClauseGuard::And {
guard: Some(ast::ClauseGuard::And {
location: Span::new((), 127..139), location: Span::new((), 127..139),
left: Box::new(ast::ClauseGuard::Or { left: Box::new(ast::UntypedClauseGuard::Or {
location: Span::new((), 127..133), location: Span::new((), 127..133),
left: Box::new(ast::ClauseGuard::Var { left: Box::new(ast::UntypedClauseGuard::Var {
location: Span::new((), 127..128), location: Span::new((), 127..128),
name: "a".to_string(), name: "a".to_string(),
tipo: (), tipo: (),
}), }),
right: Box::new(ast::ClauseGuard::Var { right: Box::new(ast::UntypedClauseGuard::Var {
location: Span::new((), 132..133), location: Span::new((), 132..133),
name: "b".to_string(), name: "b".to_string(),
tipo: (), tipo: (),
}), }),
}), }),
right: Box::new(ast::ClauseGuard::Var { right: Box::new(ast::UntypedClauseGuard::Var {
location: Span::new((), 138..139), location: Span::new((), 138..139),
name: "c".to_string(), name: "c".to_string(),
tipo: (), tipo: (),
@ -2445,39 +2436,38 @@ fn clause_guards() {
name: "Void".to_string(), name: "Void".to_string(),
}, },
}, },
ast::Clause { ast::UntypedClause {
location: Span::new((), 152..191), location: Span::new((), 152..191),
pattern: vec![ast::Pattern::Discard { patterns: vec1![ast::Pattern::Discard {
name: "_".to_string(), name: "_".to_string(),
location: Span::new((), 152..153), location: Span::new((), 152..153),
}], }],
alternative_patterns: vec![], guard: Some(ast::UntypedClauseGuard::Or {
guard: Some(ast::ClauseGuard::Or {
location: Span::new((), 157..183), location: Span::new((), 157..183),
left: Box::new(ast::ClauseGuard::Or { left: Box::new(ast::UntypedClauseGuard::Or {
location: Span::new((), 157..174), location: Span::new((), 157..174),
left: Box::new(ast::ClauseGuard::LtEqInt { left: Box::new(ast::UntypedClauseGuard::LtEqInt {
location: Span::new((), 157..164), location: Span::new((), 157..164),
left: Box::new(ast::ClauseGuard::Var { left: Box::new(ast::UntypedClauseGuard::Var {
location: Span::new((), 157..158), location: Span::new((), 157..158),
name: "a".to_string(), name: "a".to_string(),
tipo: (), tipo: (),
}), }),
right: Box::new(ast::ClauseGuard::Constant( right: Box::new(ast::UntypedClauseGuard::Constant(
ast::Constant::Int { ast::Constant::Int {
location: Span::new((), 162..164), location: Span::new((), 162..164),
value: "42".to_string(), value: "42".to_string(),
}, },
)), )),
}), }),
right: Box::new(ast::ClauseGuard::GtInt { right: Box::new(ast::UntypedClauseGuard::GtInt {
location: Span::new((), 168..174), location: Span::new((), 168..174),
left: Box::new(ast::ClauseGuard::Var { left: Box::new(ast::UntypedClauseGuard::Var {
location: Span::new((), 168..169), location: Span::new((), 168..169),
name: "b".to_string(), name: "b".to_string(),
tipo: (), tipo: (),
}), }),
right: Box::new(ast::ClauseGuard::Constant( right: Box::new(ast::UntypedClauseGuard::Constant(
ast::Constant::Int { ast::Constant::Int {
location: Span::new((), 172..174), location: Span::new((), 172..174),
value: "14".to_string(), value: "14".to_string(),
@ -2485,41 +2475,44 @@ fn clause_guards() {
)), )),
}), }),
}), }),
right: Box::new(ast::ClauseGuard::Constant(ast::Constant::ByteArray { right: Box::new(ast::UntypedClauseGuard::Constant(
ast::Constant::ByteArray {
location: Span::new((), 178..183), location: Span::new((), 178..183),
bytes: String::from("str").into_bytes(), bytes: String::from("str").into_bytes(),
preferred_format: ast::ByteArrayFormatPreference::Utf8String, preferred_format: ast::ByteArrayFormatPreference::Utf8String,
})), },
)),
}), }),
then: expr::UntypedExpr::Var { then: expr::UntypedExpr::Var {
location: Span::new((), 187..191), location: Span::new((), 187..191),
name: "Void".to_string(), name: "Void".to_string(),
}, },
}, },
ast::Clause { ast::UntypedClause {
location: Span::new((), 196..222), location: Span::new((), 196..222),
pattern: vec![ast::Pattern::Discard { patterns: vec1![ast::Pattern::Discard {
name: "_".to_string(), name: "_".to_string(),
location: Span::new((), 196..197), location: Span::new((), 196..197),
}], }],
alternative_patterns: vec![], guard: Some(ast::UntypedClauseGuard::And {
guard: Some(ast::ClauseGuard::And {
location: Span::new((), 201..214), location: Span::new((), 201..214),
left: Box::new(ast::ClauseGuard::Equals { left: Box::new(ast::UntypedClauseGuard::Equals {
location: Span::new((), 201..208), location: Span::new((), 201..208),
left: Box::new(ast::ClauseGuard::Var { left: Box::new(ast::UntypedClauseGuard::Var {
location: Span::new((), 201..202), location: Span::new((), 201..202),
name: "a".to_string(), name: "a".to_string(),
tipo: (), tipo: (),
}), }),
right: Box::new(ast::ClauseGuard::Constant(ast::Constant::Int { right: Box::new(ast::UntypedClauseGuard::Constant(
ast::Constant::Int {
location: Span::new((), 206..208), location: Span::new((), 206..208),
value: "14".to_string(), value: "14".to_string(),
})), },
)),
}), }),
right: Box::new(ast::ClauseGuard::Not { right: Box::new(ast::UntypedClauseGuard::Not {
location: Span::new((), 212..214), location: Span::new((), 212..214),
value: Box::new(ast::ClauseGuard::Var { value: Box::new(ast::UntypedClauseGuard::Var {
location: Span::new((), 213..214), location: Span::new((), 213..214),
name: "b".to_string(), name: "b".to_string(),
tipo: (), tipo: (),
@ -2531,18 +2524,17 @@ fn clause_guards() {
name: "Void".to_string(), name: "Void".to_string(),
}, },
}, },
ast::Clause { ast::UntypedClause {
location: Span::new((), 227..246), location: Span::new((), 227..246),
pattern: vec![ast::Pattern::Discard { patterns: vec1![ast::Pattern::Discard {
name: "_".to_string(), name: "_".to_string(),
location: Span::new((), 227..228), location: Span::new((), 227..228),
}], }],
alternative_patterns: vec![], guard: Some(ast::UntypedClauseGuard::Not {
guard: Some(ast::ClauseGuard::Not {
location: Span::new((), 232..238), location: Span::new((), 232..238),
value: Box::new(ast::ClauseGuard::Not { value: Box::new(ast::UntypedClauseGuard::Not {
location: Span::new((), 233..238), location: Span::new((), 233..238),
value: Box::new(ast::ClauseGuard::Var { value: Box::new(ast::UntypedClauseGuard::Var {
location: Span::new((), 234..238), location: Span::new((), 234..238),
tipo: (), tipo: (),
name: "True".to_string(), name: "True".to_string(),
@ -2826,14 +2818,14 @@ fn parse_keyword_error() {
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::When { body: expr::UntypedExpr::When {
location: Span::new((), 54..110), location: Span::new((), 54..110),
subjects: vec![expr::UntypedExpr::Var { subject: Box::new(expr::UntypedExpr::Var {
location: Span::new((), 59..60), location: Span::new((), 59..60),
name: "x".to_string(), name: "x".to_string(),
}], }),
clauses: vec![ clauses: vec![
ast::Clause { ast::UntypedClause {
location: Span::new((), 72..89), location: Span::new((), 72..89),
pattern: vec![ast::Pattern::Constructor { patterns: vec1![ast::Pattern::Constructor {
is_record: false, is_record: false,
location: Span::new((), 72..81), location: Span::new((), 72..81),
name: "Something".to_string(), name: "Something".to_string(),
@ -2843,20 +2835,18 @@ fn parse_keyword_error() {
with_spread: false, with_spread: false,
tipo: (), tipo: (),
}], }],
alternative_patterns: vec![],
guard: None, guard: None,
then: expr::UntypedExpr::Var { then: expr::UntypedExpr::Var {
location: Span::new((), 85..89), location: Span::new((), 85..89),
name: "Void".to_string(), name: "Void".to_string(),
}, },
}, },
ast::Clause { ast::UntypedClause {
location: Span::new((), 96..106), location: Span::new((), 96..106),
pattern: vec![ast::Pattern::Discard { patterns: vec1![ast::Pattern::Discard {
name: "_".to_string(), name: "_".to_string(),
location: Span::new((), 96..97), location: Span::new((), 96..97),
}], }],
alternative_patterns: vec![],
guard: None, guard: None,
then: expr::UntypedExpr::Trace { then: expr::UntypedExpr::Trace {
kind: ast::TraceKind::Error, kind: ast::TraceKind::Error,
@ -2927,14 +2917,14 @@ fn parse_keyword_todo() {
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::When { body: expr::UntypedExpr::When {
location: Span::new((), 53..121), location: Span::new((), 53..121),
subjects: vec![expr::UntypedExpr::Var { subject: Box::new(expr::UntypedExpr::Var {
location: Span::new((), 58..59), location: Span::new((), 58..59),
name: "x".to_string(), name: "x".to_string(),
}], }),
clauses: vec![ clauses: vec![
ast::Clause { ast::UntypedClause {
location: Span::new((), 71..82), location: Span::new((), 71..82),
pattern: vec![ast::Pattern::Constructor { patterns: vec1![ast::Pattern::Constructor {
is_record: false, is_record: false,
location: Span::new((), 71..74), location: Span::new((), 71..74),
name: "Foo".to_string(), name: "Foo".to_string(),
@ -2944,7 +2934,6 @@ fn parse_keyword_todo() {
with_spread: false, with_spread: false,
tipo: (), tipo: (),
}], }],
alternative_patterns: vec![],
guard: None, guard: None,
then: expr::UntypedExpr::Trace { then: expr::UntypedExpr::Trace {
kind: ast::TraceKind::Todo, kind: ast::TraceKind::Todo,
@ -2958,9 +2947,9 @@ fn parse_keyword_todo() {
}), }),
}, },
}, },
ast::Clause { ast::UntypedClause {
location: Span::new((), 89..100), location: Span::new((), 89..100),
pattern: vec![ast::Pattern::Constructor { patterns: vec1![ast::Pattern::Constructor {
is_record: false, is_record: false,
location: Span::new((), 89..92), location: Span::new((), 89..92),
name: "Bar".to_string(), name: "Bar".to_string(),
@ -2970,20 +2959,18 @@ fn parse_keyword_todo() {
with_spread: false, with_spread: false,
tipo: (), tipo: (),
}], }],
alternative_patterns: vec![],
guard: None, guard: None,
then: expr::UntypedExpr::Var { then: expr::UntypedExpr::Var {
location: Span::new((), 96..100), location: Span::new((), 96..100),
name: "True".to_string(), name: "True".to_string(),
}, },
}, },
ast::Clause { ast::UntypedClause {
location: Span::new((), 107..117), location: Span::new((), 107..117),
pattern: vec![ast::Pattern::Discard { patterns: vec1![ast::Pattern::Discard {
name: "_".to_string(), name: "_".to_string(),
location: Span::new((), 107..108), location: Span::new((), 107..108),
}], }],
alternative_patterns: vec![],
guard: None, guard: None,
then: expr::UntypedExpr::Var { then: expr::UntypedExpr::Var {
location: Span::new((), 112..117), location: Span::new((), 112..117),

View File

@ -315,22 +315,6 @@ From there, you can define 'increment', a function that takes a single argument
given: usize, given: usize,
}, },
// TODO: Since we do not actually support patterns on multiple items, we won't likely ever
// encounter that error. We could simplify a bit the type-checker and get rid of that error
// eventually.
#[error(
"I counted {} different clauses in a multi-pattern instead of {}.\n",
given.if_supports_color(Stdout, |s| s.purple()),
expected.if_supports_color(Stdout, |s| s.purple()),
)]
#[diagnostic(code("arity::clause"))]
IncorrectNumClausePatterns {
#[label]
location: Span,
expected: usize,
given: usize,
},
#[error( #[error(
"I saw a pattern on a constructor that has {} field(s) be matched with {} argument(s).\n", "I saw a pattern on a constructor that has {} field(s) be matched with {} argument(s).\n",
expected.if_supports_color(Stdout, |s| s.purple()), expected.if_supports_color(Stdout, |s| s.purple()),

View File

@ -1,3 +1,4 @@
use crate::ast::TypedPattern;
use std::{cmp::Ordering, collections::HashMap, sync::Arc}; use std::{cmp::Ordering, collections::HashMap, sync::Arc};
use vec1::Vec1; use vec1::Vec1;
@ -5,10 +6,10 @@ use vec1::Vec1;
use crate::{ use crate::{
ast::{ ast::{
Annotation, Arg, ArgName, AssignmentKind, BinOp, ByteArrayFormatPreference, CallArg, Annotation, Arg, ArgName, AssignmentKind, BinOp, ByteArrayFormatPreference, CallArg,
Clause, ClauseGuard, Constant, IfBranch, RecordUpdateSpread, Span, TraceKind, Tracing, ClauseGuard, Constant, IfBranch, RecordUpdateSpread, Span, TraceKind, Tracing, TypedArg,
TypedArg, TypedCallArg, TypedClause, TypedClauseGuard, TypedIfBranch, TypedMultiPattern, TypedCallArg, TypedClause, TypedClauseGuard, TypedIfBranch, TypedRecordUpdateArg, UnOp,
TypedRecordUpdateArg, UnOp, UntypedArg, UntypedClause, UntypedClauseGuard, UntypedIfBranch, UntypedArg, UntypedClause, UntypedClauseGuard, UntypedIfBranch, UntypedPattern,
UntypedMultiPattern, UntypedPattern, UntypedRecordUpdateArg, UntypedRecordUpdateArg,
}, },
builtins::{bool, byte_array, function, int, list, string, tuple}, builtins::{bool, byte_array, function, int, list, string, tuple},
expr::{TypedExpr, UntypedExpr}, expr::{TypedExpr, UntypedExpr},
@ -22,7 +23,7 @@ use super::{
hydrator::Hydrator, hydrator::Hydrator,
pattern::PatternTyper, pattern::PatternTyper,
pipe::PipeTyper, pipe::PipeTyper,
PatternConstructor, RecordAccessor, Type, ValueConstructor, ValueConstructorVariant, RecordAccessor, Type, ValueConstructor, ValueConstructorVariant,
}; };
#[derive(Debug)] #[derive(Debug)]
@ -45,44 +46,24 @@ pub(crate) struct ExprTyper<'a, 'b> {
impl<'a, 'b> ExprTyper<'a, 'b> { impl<'a, 'b> ExprTyper<'a, 'b> {
fn check_when_exhaustiveness( fn check_when_exhaustiveness(
&mut self, &mut self,
subjects_count: usize, subject: &Type,
subjects: &[Arc<Type>], typed_clauses: &[TypedClause],
typed_clauses: &[Clause<TypedExpr, PatternConstructor, Arc<Type>>],
location: Span, location: Span,
) -> Result<(), Vec<String>> { ) -> Result<(), Vec<String>> {
// Because exhaustiveness checking in presence of multiple subjects is similar let value_typ = collapse_links(Arc::new(subject.clone()));
// to full exhaustiveness checking of tuples or other nested record patterns,
// and we currently only do only limited exhaustiveness checking of custom types
// at the top level of patterns, only consider case expressions with one subject.
if subjects_count != 1 {
return Ok(());
}
let subject_type = subjects
.get(0)
.expect("Asserted there's one case subject but found none");
let value_typ = collapse_links(subject_type.clone());
// Currently guards in exhaustiveness checking are assumed that they can fail, // Currently guards in exhaustiveness checking are assumed that they can fail,
// so we go through all clauses and pluck out only the patterns // so we go through all clauses and pluck out only the patterns
// for clauses that don't have guards. // for clauses that don't have guards.
let mut patterns = Vec::new(); let mut patterns = Vec::new();
for clause in typed_clauses { for clause in typed_clauses {
if let Clause { guard: None, .. } = clause { if let TypedClause {
// clause.pattern is a list of patterns for all subjects guard: None,
if let Some(pattern) = clause.pattern.get(0) { pattern,
patterns.push(pattern.clone()); ..
} } = clause
{
// A clause can be built with alternative patterns as well, e.g. `Audio(_) | Text(_) ->`. patterns.push(pattern.clone())
// We're interested in all patterns so we build a flattened list.
for alternative_pattern in &clause.alternative_patterns {
// clause.alternative_pattern is a list of patterns for all subjects
if let Some(pattern) = alternative_pattern.get(0) {
patterns.push(pattern.clone());
}
}
} }
} }
@ -309,10 +290,10 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
UntypedExpr::When { UntypedExpr::When {
location, location,
subjects, subject,
clauses, clauses,
.. ..
} => self.infer_when(subjects, clauses, location), } => self.infer_when(*subject, clauses, location),
UntypedExpr::List { UntypedExpr::List {
location, location,
@ -1093,35 +1074,34 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
fn infer_clause( fn infer_clause(
&mut self, &mut self,
clause: UntypedClause, clause: UntypedClause,
subjects: &[Arc<Type>], subject: &Type,
) -> Result<TypedClause, Error> { ) -> Result<Vec<TypedClause>, Error> {
let Clause { let UntypedClause {
pattern, patterns,
alternative_patterns,
guard, guard,
then, then,
location, location,
} = clause; } = clause;
let (guard, then, typed_pattern, typed_alternatives) = self.in_new_scope(|scope| { let (guard, then, typed_patterns) = self.in_new_scope(|scope| {
// Check the types let typed_patterns = scope.infer_clause_pattern(patterns, subject, &location)?;
let (typed_pattern, typed_alternatives) =
scope.infer_clause_pattern(pattern, alternative_patterns, subjects, &location)?;
let guard = scope.infer_optional_clause_guard(guard)?; let guard = scope.infer_optional_clause_guard(guard)?;
let then = scope.infer(then)?; let then = scope.infer(then)?;
Ok::<_, Error>((guard, then, typed_pattern, typed_alternatives)) Ok::<_, Error>((guard, then, typed_patterns))
})?; })?;
Ok(Clause { Ok(typed_patterns
.into_iter()
.map(|pattern| TypedClause {
location, location,
pattern: typed_pattern, pattern,
alternative_patterns: typed_alternatives, guard: guard.clone(),
guard, then: then.clone(),
then,
}) })
.collect())
} }
fn infer_clause_guard(&mut self, guard: UntypedClauseGuard) -> Result<TypedClauseGuard, Error> { fn infer_clause_guard(&mut self, guard: UntypedClauseGuard) -> Result<TypedClauseGuard, Error> {
@ -1333,26 +1313,23 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
fn infer_clause_pattern( fn infer_clause_pattern(
&mut self, &mut self,
pattern: UntypedMultiPattern, patterns: Vec1<UntypedPattern>,
alternatives: Vec<UntypedMultiPattern>, subject: &Type,
subjects: &[Arc<Type>],
location: &Span, location: &Span,
) -> Result<(TypedMultiPattern, Vec<TypedMultiPattern>), Error> { ) -> Result<Vec<TypedPattern>, Error> {
let mut pattern_typer = PatternTyper::new(self.environment, &self.hydrator); let mut pattern_typer = PatternTyper::new(self.environment, &self.hydrator);
let typed_pattern = pattern_typer.infer_multi_pattern(pattern, subjects, location)?; let mut typed_patterns = Vec::with_capacity(patterns.len());
for (ix, pattern) in patterns.into_iter().enumerate() {
// Each case clause has one or more patterns that may match the if ix == 0 {
// subject in order for the clause to be selected, so we must type typed_patterns.push(pattern_typer.infer_pattern(pattern, subject)?);
// check every pattern. } else {
let mut typed_alternatives = Vec::with_capacity(alternatives.len()); typed_patterns
.push(pattern_typer.infer_alternative_pattern(pattern, subject, location)?);
for m in alternatives { }
typed_alternatives
.push(pattern_typer.infer_alternative_multi_pattern(m, subjects, location)?);
} }
Ok((typed_pattern, typed_alternatives)) Ok(typed_patterns)
} }
// TODO: extract the type annotation checking into a infer_module_const // TODO: extract the type annotation checking into a infer_module_const
@ -1865,7 +1842,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
fn infer_when( fn infer_when(
&mut self, &mut self,
subjects: Vec<UntypedExpr>, subject: UntypedExpr,
clauses: Vec<UntypedClause>, clauses: Vec<UntypedClause>,
location: Span, location: Span,
) -> Result<TypedExpr, Error> { ) -> Result<TypedExpr, Error> {
@ -1873,36 +1850,24 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
// that suggests that a `let` binding should be used instead. // that suggests that a `let` binding should be used instead.
if clauses.len() == 1 { if clauses.len() == 1 {
self.environment.warnings.push(Warning::SingleWhenClause { self.environment.warnings.push(Warning::SingleWhenClause {
location: clauses[0].pattern[0].location(), location: clauses[0].patterns[0].location(),
sample: UntypedExpr::Assignment { sample: UntypedExpr::Assignment {
location: Span::empty(), location: Span::empty(),
value: Box::new(subjects[0].clone()), value: Box::new(subject.clone()),
pattern: clauses[0].pattern[0].clone(), pattern: clauses[0].patterns[0].clone(),
kind: AssignmentKind::Let, kind: AssignmentKind::Let,
annotation: None, annotation: None,
}, },
}); });
} }
let subjects_count = subjects.len(); let typed_subject = self.infer(subject)?;
let subject_type = typed_subject.tipo();
let mut typed_subjects = Vec::with_capacity(subjects_count);
let mut subject_types = Vec::with_capacity(subjects_count);
let mut typed_clauses = Vec::new();
let return_type = self.new_unbound_var(); let return_type = self.new_unbound_var();
for subject in subjects { let mut typed_clauses = Vec::new();
let subject = self.infer(subject)?;
subject_types.push(subject.tipo());
typed_subjects.push(subject);
}
for clause in clauses { for clause in clauses {
let typed_clause = self.infer_clause(clause, &subject_types)?; for typed_clause in self.infer_clause(clause, &subject_type)? {
self.unify( self.unify(
return_type.clone(), return_type.clone(),
typed_clause.then.tipo(), typed_clause.then.tipo(),
@ -1911,11 +1876,12 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
) )
.map_err(|e| e.case_clause_mismatch())?; .map_err(|e| e.case_clause_mismatch())?;
typed_clauses.append(&mut typed_clause.desugarize()); typed_clauses.push(typed_clause)
}
} }
if let Err(unmatched) = if let Err(unmatched) =
self.check_when_exhaustiveness(subjects_count, &subject_types, &typed_clauses, location) self.check_when_exhaustiveness(&subject_type, &typed_clauses, location)
{ {
return Err(Error::NotExhaustivePatternMatch { return Err(Error::NotExhaustivePatternMatch {
location, location,
@ -1927,7 +1893,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
Ok(TypedExpr::When { Ok(TypedExpr::When {
location, location,
tipo: return_type, tipo: return_type,
subjects: typed_subjects, subject: Box::new(typed_subject),
clauses: typed_clauses, clauses: typed_clauses,
}) })
} }

View File

@ -15,7 +15,7 @@ use super::{
PatternConstructor, Type, ValueConstructorVariant, PatternConstructor, Type, ValueConstructorVariant,
}; };
use crate::{ use crate::{
ast::{CallArg, Pattern, Span, TypedPattern, UntypedMultiPattern, UntypedPattern}, ast::{CallArg, Pattern, Span, TypedPattern, UntypedPattern},
builtins::{int, list, tuple}, builtins::{int, list, tuple},
}; };
@ -96,14 +96,14 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
} }
} }
pub fn infer_alternative_multi_pattern( pub fn infer_alternative_pattern(
&mut self, &mut self,
multi_pattern: UntypedMultiPattern, pattern: UntypedPattern,
subjects: &[Arc<Type>], subject: &Type,
location: &Span, location: &Span,
) -> Result<Vec<TypedPattern>, Error> { ) -> Result<TypedPattern, Error> {
self.mode = PatternMode::Alternative(vec![]); self.mode = PatternMode::Alternative(vec![]);
let typed_multi = self.infer_multi_pattern(multi_pattern, subjects, location)?; let typed_pattern = self.infer_pattern(pattern, subject)?;
match &self.mode { match &self.mode {
PatternMode::Initial => panic!("Pattern mode switched from Alternative to Initial"), PatternMode::Initial => panic!("Pattern mode switched from Alternative to Initial"),
PatternMode::Alternative(assigned) PatternMode::Alternative(assigned)
@ -123,32 +123,16 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
.clone(), .clone(),
}) })
} }
PatternMode::Alternative(_) => Ok(typed_multi), PatternMode::Alternative(_) => Ok(typed_pattern),
} }
} }
pub fn infer_multi_pattern( pub fn infer_pattern(
&mut self, &mut self,
multi_pattern: UntypedMultiPattern, pattern: UntypedPattern,
subjects: &[Arc<Type>], subject: &Type,
location: &Span, ) -> Result<TypedPattern, Error> {
) -> Result<Vec<TypedPattern>, Error> { self.unify(pattern, Arc::new(subject.clone()), None, false)
// If there are N subjects the multi-pattern is expected to be N patterns
if subjects.len() != multi_pattern.len() {
return Err(Error::IncorrectNumClausePatterns {
location: *location,
expected: subjects.len(),
given: multi_pattern.len(),
});
}
// Unify each pattern in the multi-pattern with the corresponding subject
let mut typed_multi = Vec::with_capacity(multi_pattern.len());
for (pattern, subject_type) in multi_pattern.into_iter().zip(subjects) {
let pattern = self.unify(pattern, subject_type.clone(), None, false)?;
typed_multi.push(pattern);
}
Ok(typed_multi)
} }
/// When we have an assignment or a case expression we unify the pattern with the /// When we have an assignment or a case expression we unify the pattern with the

View File

@ -20,7 +20,7 @@ use uplc::{
use crate::{ use crate::{
air::Air, air::Air,
ast::{ ast::{
ArgName, AssignmentKind, BinOp, Clause, Pattern, Span, TypedArg, TypedDataType, ArgName, AssignmentKind, BinOp, Pattern, Span, TypedArg, TypedClause, TypedDataType,
TypedFunction, UnOp, TypedFunction, UnOp,
}, },
builder::{ builder::{
@ -476,13 +476,11 @@ impl<'a> CodeGenerator<'a> {
ir_stack.append(&mut pattern_vec); ir_stack.append(&mut pattern_vec);
} }
TypedExpr::When { TypedExpr::When {
subjects, clauses, .. subject, clauses, ..
} => { } => {
let subject_name = format!("__subject_name_{}", self.id_gen.next()); let subject_name = format!("__subject_name_{}", self.id_gen.next());
let constr_var = format!("__constr_name_{}", self.id_gen.next()); let constr_var = format!("__constr_name_{}", self.id_gen.next());
// assuming one subject at the moment
let subject = subjects[0].clone();
let subject_tipo = subject.tipo(); let subject_tipo = subject.tipo();
if clauses.len() <= 1 { if clauses.len() <= 1 {
let mut value_vec: Vec<Air> = vec![]; let mut value_vec: Vec<Air> = vec![];
@ -491,10 +489,10 @@ impl<'a> CodeGenerator<'a> {
self.build_ir(&clauses[0].then, &mut value_vec, scope.clone()); self.build_ir(&clauses[0].then, &mut value_vec, scope.clone());
self.build_ir(&subject, &mut subject_vec, scope.clone()); self.build_ir(subject, &mut subject_vec, scope.clone());
self.assignment_ir( self.assignment_ir(
&clauses[0].pattern[0], &clauses[0].pattern,
&mut pattern_vec, &mut pattern_vec,
&mut subject_vec, &mut subject_vec,
&subject_tipo, &subject_tipo,
@ -508,12 +506,14 @@ impl<'a> CodeGenerator<'a> {
ir_stack.append(&mut pattern_vec); ir_stack.append(&mut pattern_vec);
ir_stack.append(&mut value_vec); ir_stack.append(&mut value_vec);
} else { } else {
println!("{clauses:?}");
// HERE TODO // HERE TODO
let clauses = if subject_tipo.is_list() { let clauses = if subject_tipo.is_list() {
rearrange_clauses(clauses.clone()) rearrange_clauses(clauses.clone())
} else { } else {
clauses.clone() clauses.clone()
}; };
println!("{clauses:?}");
if let Some((last_clause, clauses)) = clauses.split_last() { if let Some((last_clause, clauses)) = clauses.split_last() {
let mut pattern_vec = vec![]; let mut pattern_vec = vec![];
@ -532,7 +532,7 @@ impl<'a> CodeGenerator<'a> {
scope.clone(), scope.clone(),
); );
let last_pattern = &last_clause.pattern[0]; let last_pattern = &last_clause.pattern;
let mut final_scope = scope.clone(); let mut final_scope = scope.clone();
@ -571,7 +571,7 @@ impl<'a> CodeGenerator<'a> {
let mut subject_scope = scope.clone(); let mut subject_scope = scope.clone();
subject_scope.push(self.id_gen.next()); subject_scope.push(self.id_gen.next());
self.build_ir(&subject, ir_stack, subject_scope.clone()); self.build_ir(subject, ir_stack, subject_scope.clone());
let mut scope = scope; let mut scope = scope;
scope.push(self.id_gen.next()); scope.push(self.id_gen.next());
@ -603,7 +603,7 @@ impl<'a> CodeGenerator<'a> {
let mut scope = scope; let mut scope = scope;
scope.push(self.id_gen.next()); scope.push(self.id_gen.next());
self.build_ir(&subject, ir_stack, scope); self.build_ir(subject, ir_stack, scope);
} }
ir_stack.append(&mut pattern_vec); ir_stack.append(&mut pattern_vec);
@ -817,7 +817,7 @@ impl<'a> CodeGenerator<'a> {
&mut self, &mut self,
ir_stack: &mut Vec<Air>, ir_stack: &mut Vec<Air>,
clause_properties: &mut ClauseProperties, clause_properties: &mut ClauseProperties,
clauses: &[Clause<TypedExpr, PatternConstructor, Arc<Type>>], clauses: &[TypedClause],
subject_type: &Arc<Type>, subject_type: &Arc<Type>,
scope: Vec<u64>, scope: Vec<u64>,
) { ) {
@ -876,7 +876,7 @@ impl<'a> CodeGenerator<'a> {
} => { } => {
let subject_name = original_subject_name.clone(); let subject_name = original_subject_name.clone();
self.when_ir( self.when_ir(
&clause.pattern[0], &clause.pattern,
&mut clause_subject_vec, &mut clause_subject_vec,
&mut clause_then_vec, &mut clause_then_vec,
subject_type, subject_type,
@ -922,16 +922,16 @@ impl<'a> CodeGenerator<'a> {
.. ..
} => { } => {
let (current_clause_index, has_tail) = let (current_clause_index, has_tail) =
if let Pattern::List { elements, tail, .. } = &clause.pattern[0] { if let Pattern::List { elements, tail, .. } = &clause.pattern {
(elements.len(), tail.is_some()) (elements.len(), tail.is_some())
} else if let Pattern::Assign { pattern, .. } = &clause.pattern[0] { } else if let Pattern::Assign { pattern, .. } = &clause.pattern {
if let Pattern::List { elements, tail, .. } = pattern.as_ref() { if let Pattern::List { elements, tail, .. } = pattern.as_ref() {
(elements.len(), tail.is_some()) (elements.len(), tail.is_some())
} else { } else {
unreachable!("{:#?}", pattern) unreachable!("{:#?}", pattern)
} }
} else { } else {
unreachable!("{:#?}", &clause.pattern[0]) unreachable!("{:#?}", &clause.pattern)
}; };
let prev_index = *current_index; let prev_index = *current_index;
@ -943,7 +943,7 @@ impl<'a> CodeGenerator<'a> {
}; };
self.when_ir( self.when_ir(
&clause.pattern[0], &clause.pattern,
&mut clause_subject_vec, &mut clause_subject_vec,
&mut clause_then_vec, &mut clause_then_vec,
subject_type, subject_type,
@ -955,11 +955,10 @@ impl<'a> CodeGenerator<'a> {
None None
} else { } else {
let next_list_size = if let Pattern::List { elements, .. } = let next_list_size = if let Pattern::List { elements, .. } =
&clauses[index + 1].pattern[0] &clauses[index + 1].pattern
{ {
elements.len() elements.len()
} else if let Pattern::Assign { pattern, .. } = } else if let Pattern::Assign { pattern, .. } = &clauses[index + 1].pattern
&clauses[index + 1].pattern[0]
{ {
if let Pattern::List { elements, .. } = pattern.as_ref() { if let Pattern::List { elements, .. } = pattern.as_ref() {
elements.len() elements.len()
@ -1008,7 +1007,7 @@ impl<'a> CodeGenerator<'a> {
let subject_name = original_subject_name.clone(); let subject_name = original_subject_name.clone();
self.when_ir( self.when_ir(
&clause.pattern[0], &clause.pattern,
&mut clause_subject_vec, &mut clause_subject_vec,
&mut clause_then_vec, &mut clause_then_vec,
subject_type, subject_type,