Merge pull request #459 from aiken-lang/remove-multi-subjects
Cleanup implementation from multi-subjects when/is
This commit is contained in:
commit
3eccc349aa
|
@ -1,5 +1,3 @@
|
|||
use std::{fmt, ops::Range, sync::Arc};
|
||||
|
||||
use crate::{
|
||||
builtins::{self, bool},
|
||||
expr::{TypedExpr, UntypedExpr},
|
||||
|
@ -8,6 +6,8 @@ use crate::{
|
|||
};
|
||||
use miette::Diagnostic;
|
||||
use owo_colors::{OwoColorize, Stream::Stdout};
|
||||
use std::{fmt, ops::Range, sync::Arc};
|
||||
use vec1::Vec1;
|
||||
|
||||
pub const ASSERT_VARIABLE: &str = "_try";
|
||||
pub const CAPTURE_VARIABLE: &str = "_capture";
|
||||
|
@ -909,26 +909,26 @@ pub type MultiPattern<PatternConstructor, Type> = Vec<Pattern<PatternConstructor
|
|||
pub type UntypedMultiPattern = MultiPattern<(), ()>;
|
||||
pub type TypedMultiPattern = MultiPattern<PatternConstructor, Arc<Type>>;
|
||||
|
||||
pub type TypedClause = Clause<TypedExpr, PatternConstructor, Arc<Type>>;
|
||||
pub type UntypedClause = Clause<UntypedExpr, (), ()>;
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct UntypedClause {
|
||||
pub location: Span,
|
||||
pub patterns: Vec1<Pattern<(), ()>>,
|
||||
pub guard: Option<ClauseGuard<()>>,
|
||||
pub then: UntypedExpr,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Clause<Expr, PatternConstructor, Type> {
|
||||
pub struct TypedClause {
|
||||
pub location: Span,
|
||||
pub pattern: MultiPattern<PatternConstructor, Type>,
|
||||
pub alternative_patterns: Vec<MultiPattern<PatternConstructor, Type>>,
|
||||
pub guard: Option<ClauseGuard<Type>>,
|
||||
pub then: Expr,
|
||||
pub pattern: Pattern<PatternConstructor, Arc<Type>>,
|
||||
pub guard: Option<ClauseGuard<Arc<Type>>>,
|
||||
pub then: TypedExpr,
|
||||
}
|
||||
|
||||
impl TypedClause {
|
||||
pub fn location(&self) -> Span {
|
||||
Span {
|
||||
start: self
|
||||
.pattern
|
||||
.get(0)
|
||||
.map(|p| p.location().start)
|
||||
.unwrap_or_default(),
|
||||
start: self.pattern.location().start,
|
||||
end: self.then.location().end,
|
||||
}
|
||||
}
|
||||
|
@ -936,29 +936,6 @@ impl TypedClause {
|
|||
pub fn find_node(&self, byte_index: usize) -> Option<&TypedExpr> {
|
||||
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<()>;
|
||||
|
|
|
@ -18,8 +18,8 @@ use uplc::{
|
|||
use crate::{
|
||||
air::Air,
|
||||
ast::{
|
||||
AssignmentKind, BinOp, Clause, ClauseGuard, Constant, DataType, Pattern, Span, TypedArg,
|
||||
TypedDataType, UnOp,
|
||||
AssignmentKind, BinOp, ClauseGuard, Constant, DataType, Pattern, Span, TypedArg,
|
||||
TypedClause, TypedDataType, UnOp,
|
||||
},
|
||||
expr::TypedExpr,
|
||||
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(
|
||||
clauses: Vec<Clause<TypedExpr, PatternConstructor, Arc<Type>>>,
|
||||
) -> Vec<Clause<TypedExpr, PatternConstructor, Arc<Type>>> {
|
||||
pub fn rearrange_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
|
||||
let mut sorted_clauses = 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
|
||||
// TODO: how shall tails be weighted? Since any clause after will not run
|
||||
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()),
|
||||
_ => 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()),
|
||||
_ => 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
|
||||
// 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, .. } => {
|
||||
assign_plug_in_name = Some(name);
|
||||
sorted_clauses[sorted_clauses.len() - 1].clone().then
|
||||
|
@ -452,7 +450,7 @@ pub fn rearrange_clauses(
|
|||
};
|
||||
|
||||
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
|
||||
while elems_len < elements.len() {
|
||||
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
|
||||
let clause_to_fill = if let Some(name) = assign_plug_in_name {
|
||||
Clause {
|
||||
TypedClause {
|
||||
location: Span::empty(),
|
||||
pattern: vec![Pattern::Assign {
|
||||
pattern: Pattern::Assign {
|
||||
name: name.clone(),
|
||||
location: Span::empty(),
|
||||
pattern: Pattern::List {
|
||||
|
@ -477,20 +475,18 @@ pub fn rearrange_clauses(
|
|||
tail: None,
|
||||
}
|
||||
.into(),
|
||||
}],
|
||||
alternative_patterns: vec![],
|
||||
},
|
||||
guard: None,
|
||||
then: plug_in_then.clone(),
|
||||
}
|
||||
} else {
|
||||
Clause {
|
||||
TypedClause {
|
||||
location: Span::empty(),
|
||||
pattern: vec![Pattern::List {
|
||||
pattern: Pattern::List {
|
||||
location: Span::empty(),
|
||||
elements: discard_elems,
|
||||
tail: None,
|
||||
}],
|
||||
alternative_patterns: vec![],
|
||||
},
|
||||
guard: None,
|
||||
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
|
||||
match &clause.pattern[0] {
|
||||
match &clause.pattern {
|
||||
Pattern::Var { .. } => {
|
||||
last_clause_index = index + 1;
|
||||
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 index == sorted_clauses.len() - 1 {
|
||||
if let Pattern::List { tail: None, .. } = &clause.pattern[0] {
|
||||
final_clauses.push(Clause {
|
||||
if let Pattern::List { tail: None, .. } = &clause.pattern {
|
||||
final_clauses.push(TypedClause {
|
||||
location: Span::empty(),
|
||||
pattern: vec![Pattern::Discard {
|
||||
pattern: Pattern::Discard {
|
||||
name: "_".to_string(),
|
||||
location: Span::empty(),
|
||||
}],
|
||||
alternative_patterns: vec![],
|
||||
},
|
||||
guard: None,
|
||||
then: plug_in_then.clone(),
|
||||
});
|
||||
|
|
|
@ -4,9 +4,9 @@ use vec1::Vec1;
|
|||
|
||||
use crate::{
|
||||
ast::{
|
||||
Annotation, Arg, AssignmentKind, BinOp, ByteArrayFormatPreference, CallArg, Clause,
|
||||
DefinitionLocation, IfBranch, Pattern, RecordUpdateSpread, Span, TraceKind,
|
||||
TypedRecordUpdateArg, UnOp, UntypedRecordUpdateArg,
|
||||
Annotation, Arg, AssignmentKind, BinOp, ByteArrayFormatPreference, CallArg,
|
||||
DefinitionLocation, IfBranch, Pattern, RecordUpdateSpread, Span, TraceKind, TypedClause,
|
||||
TypedRecordUpdateArg, UnOp, UntypedClause, UntypedRecordUpdateArg,
|
||||
},
|
||||
builtins::void,
|
||||
tipo::{ModuleValueConstructor, PatternConstructor, Type, ValueConstructor},
|
||||
|
@ -102,8 +102,8 @@ pub enum TypedExpr {
|
|||
When {
|
||||
location: Span,
|
||||
tipo: Arc<Type>,
|
||||
subjects: Vec<Self>,
|
||||
clauses: Vec<Clause<Self, PatternConstructor, Arc<Type>>>,
|
||||
subject: Box<Self>,
|
||||
clauses: Vec<TypedClause>,
|
||||
},
|
||||
|
||||
If {
|
||||
|
@ -355,10 +355,9 @@ impl TypedExpr {
|
|||
TypedExpr::Assignment { value, .. } => value.find_node(byte_index),
|
||||
|
||||
TypedExpr::When {
|
||||
subjects, clauses, ..
|
||||
} => subjects
|
||||
.iter()
|
||||
.find_map(|subject| subject.find_node(byte_index))
|
||||
subject, clauses, ..
|
||||
} => subject
|
||||
.find_node(byte_index)
|
||||
.or_else(|| {
|
||||
clauses
|
||||
.iter()
|
||||
|
@ -481,8 +480,8 @@ pub enum UntypedExpr {
|
|||
|
||||
When {
|
||||
location: Span,
|
||||
subjects: Vec<Self>,
|
||||
clauses: Vec<Clause<Self, (), ()>>,
|
||||
subject: Box<Self>,
|
||||
clauses: Vec<UntypedClause>,
|
||||
},
|
||||
|
||||
If {
|
||||
|
|
|
@ -728,8 +728,8 @@ impl<'comments> Formatter<'comments> {
|
|||
} => self.trace(kind, text, then),
|
||||
|
||||
UntypedExpr::When {
|
||||
subjects, clauses, ..
|
||||
} => self.when(subjects, clauses),
|
||||
subject, clauses, ..
|
||||
} => self.when(subject, clauses),
|
||||
|
||||
UntypedExpr::FieldAccess {
|
||||
label, container, ..
|
||||
|
@ -933,14 +933,11 @@ impl<'comments> Formatter<'comments> {
|
|||
|
||||
pub fn when<'a>(
|
||||
&mut self,
|
||||
subjects: &'a [UntypedExpr],
|
||||
subject: &'a UntypedExpr,
|
||||
clauses: &'a [UntypedClause],
|
||||
) -> Document<'a> {
|
||||
let subjects_doc = break_("when", "when ")
|
||||
.append(join(
|
||||
subjects.iter().map(|s| self.wrap_expr(s)),
|
||||
break_(",", ", "),
|
||||
))
|
||||
.append(self.wrap_expr(subject))
|
||||
.nest(INDENT)
|
||||
.append(break_("", " "))
|
||||
.append("is {")
|
||||
|
@ -1449,9 +1446,7 @@ impl<'comments> Formatter<'comments> {
|
|||
let space_before = self.pop_empty_lines(clause.location.start);
|
||||
let after_position = clause.location.end;
|
||||
let clause_doc = join(
|
||||
std::iter::once(&clause.pattern)
|
||||
.chain(&clause.alternative_patterns)
|
||||
.map(|p| join(p.iter().map(|p| self.pattern(p)), ", ".to_doc())),
|
||||
clause.patterns.iter().map(|p| self.pattern(p)),
|
||||
" | ".to_doc(),
|
||||
);
|
||||
let clause_doc = match &clause.guard {
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
use chumsky::prelude::*;
|
||||
use vec1::Vec1;
|
||||
|
||||
pub mod error;
|
||||
pub mod extra;
|
||||
pub mod lexer;
|
||||
|
@ -13,10 +10,11 @@ use crate::{
|
|||
},
|
||||
expr,
|
||||
};
|
||||
|
||||
use chumsky::prelude::*;
|
||||
use error::ParseError;
|
||||
use extra::ModuleExtra;
|
||||
use token::Token;
|
||||
use vec1::{vec1, Vec1};
|
||||
|
||||
pub fn module(
|
||||
src: &str,
|
||||
|
@ -923,7 +921,7 @@ pub fn expr_parser(
|
|||
let when_clause_parser = pattern_parser()
|
||||
.then(
|
||||
just(Token::Vbar)
|
||||
.ignore_then(pattern_parser().map(|pattern| vec![pattern]))
|
||||
.ignore_then(pattern_parser())
|
||||
.repeated()
|
||||
.or_not(),
|
||||
)
|
||||
|
@ -962,26 +960,29 @@ pub fn expr_parser(
|
|||
}),
|
||||
)))
|
||||
.map_with_span(
|
||||
|(((pattern, alternative_patterns_opt), guard), then), span| ast::UntypedClause {
|
||||
location: span,
|
||||
pattern: vec![pattern],
|
||||
alternative_patterns: alternative_patterns_opt.unwrap_or_default(),
|
||||
guard,
|
||||
then,
|
||||
|(((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,
|
||||
patterns,
|
||||
guard,
|
||||
then,
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
let when_parser = just(Token::When)
|
||||
// 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::LeftBrace))
|
||||
// TODO: If clauses are empty we should return ParseErrorType::NoCaseClause
|
||||
.then(when_clause_parser.repeated())
|
||||
.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,
|
||||
subjects,
|
||||
subject,
|
||||
clauses,
|
||||
});
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use chumsky::prelude::*;
|
||||
use indoc::indoc;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use crate::{
|
||||
ast::{self, Constant, DataType, Function, ModuleConstant, Span, TypeAlias, Use},
|
||||
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>) {
|
||||
let (module, _extra) = parser::module(code, ast::ModuleKind::Validator).unwrap();
|
||||
|
@ -933,39 +933,38 @@ fn when() {
|
|||
}],
|
||||
body: expr::UntypedExpr::When {
|
||||
location: Span::new((), 23..132),
|
||||
subjects: vec![expr::UntypedExpr::Var {
|
||||
subject: Box::new(expr::UntypedExpr::Var {
|
||||
location: Span::new((), 28..29),
|
||||
name: "a".to_string(),
|
||||
}],
|
||||
}),
|
||||
clauses: vec![
|
||||
ast::Clause {
|
||||
ast::UntypedClause {
|
||||
location: Span::new((), 39..45),
|
||||
pattern: vec![ast::Pattern::Int {
|
||||
patterns: vec1![ast::Pattern::Int {
|
||||
location: Span::new((), 39..40),
|
||||
value: "2".to_string(),
|
||||
}],
|
||||
alternative_patterns: vec![],
|
||||
guard: None,
|
||||
then: expr::UntypedExpr::Int {
|
||||
location: Span::new((), 44..45),
|
||||
value: "3".to_string(),
|
||||
},
|
||||
},
|
||||
ast::Clause {
|
||||
ast::UntypedClause {
|
||||
location: Span::new((), 50..106),
|
||||
pattern: vec![ast::Pattern::Int {
|
||||
location: Span::new((), 50..51),
|
||||
value: "1".to_string(),
|
||||
}],
|
||||
alternative_patterns: vec![
|
||||
vec![ast::Pattern::Int {
|
||||
patterns: vec1![
|
||||
ast::Pattern::Int {
|
||||
location: Span::new((), 50..51),
|
||||
value: "1".to_string()
|
||||
},
|
||||
ast::Pattern::Int {
|
||||
location: Span::new((), 54..55),
|
||||
value: "4".to_string(),
|
||||
}],
|
||||
vec![ast::Pattern::Int {
|
||||
},
|
||||
ast::Pattern::Int {
|
||||
location: Span::new((), 58..59),
|
||||
value: "5".to_string(),
|
||||
}],
|
||||
},
|
||||
],
|
||||
guard: None,
|
||||
then: expr::UntypedExpr::Sequence {
|
||||
|
@ -991,26 +990,24 @@ fn when() {
|
|||
],
|
||||
},
|
||||
},
|
||||
ast::Clause {
|
||||
ast::UntypedClause {
|
||||
location: Span::new((), 111..117),
|
||||
pattern: vec![ast::Pattern::Int {
|
||||
patterns: vec1![ast::Pattern::Int {
|
||||
location: Span::new((), 111..112),
|
||||
value: "3".to_string(),
|
||||
}],
|
||||
alternative_patterns: vec![],
|
||||
guard: None,
|
||||
then: expr::UntypedExpr::Int {
|
||||
location: Span::new((), 116..117),
|
||||
value: "9".to_string(),
|
||||
},
|
||||
},
|
||||
ast::Clause {
|
||||
ast::UntypedClause {
|
||||
location: Span::new((), 122..128),
|
||||
pattern: vec![ast::Pattern::Discard {
|
||||
patterns: vec1![ast::Pattern::Discard {
|
||||
name: "_".to_string(),
|
||||
location: Span::new((), 122..123),
|
||||
}],
|
||||
alternative_patterns: vec![],
|
||||
guard: None,
|
||||
then: expr::UntypedExpr::Int {
|
||||
location: Span::new((), 127..128),
|
||||
|
@ -2154,13 +2151,13 @@ fn tuple_pattern() {
|
|||
arguments: vec![],
|
||||
body: expr::UntypedExpr::When {
|
||||
location: Span::new((), 13..49),
|
||||
subjects: vec![expr::UntypedExpr::Var {
|
||||
subject: Box::new(expr::UntypedExpr::Var {
|
||||
location: Span::new((), 18..19),
|
||||
name: "a".to_string(),
|
||||
}],
|
||||
clauses: vec![ast::Clause {
|
||||
}),
|
||||
clauses: vec![ast::UntypedClause {
|
||||
location: Span::new((), 29..45),
|
||||
pattern: vec![ast::Pattern::Tuple {
|
||||
patterns: vec1![ast::Pattern::Tuple {
|
||||
location: Span::new((), 29..37),
|
||||
elems: vec![
|
||||
ast::Pattern::Var {
|
||||
|
@ -2173,7 +2170,6 @@ fn tuple_pattern() {
|
|||
},
|
||||
],
|
||||
}],
|
||||
alternative_patterns: vec![],
|
||||
guard: None,
|
||||
then: expr::UntypedExpr::Var {
|
||||
location: Span::new((), 41..45),
|
||||
|
@ -2324,19 +2320,18 @@ fn clause_guards() {
|
|||
arguments: vec![],
|
||||
body: expr::UntypedExpr::When {
|
||||
location: Span::new((), 13..250),
|
||||
subjects: vec![expr::UntypedExpr::Var {
|
||||
subject: Box::new(expr::UntypedExpr::Var {
|
||||
location: Span::new((), 18..19),
|
||||
name: "a".to_string(),
|
||||
}],
|
||||
}),
|
||||
clauses: vec![
|
||||
ast::Clause {
|
||||
ast::UntypedClause {
|
||||
location: Span::new((), 29..44),
|
||||
pattern: vec![ast::Pattern::Discard {
|
||||
patterns: vec1![ast::Pattern::Discard {
|
||||
name: "_".to_string(),
|
||||
location: Span::new((), 29..30),
|
||||
}],
|
||||
alternative_patterns: vec![],
|
||||
guard: Some(ast::ClauseGuard::Constant(ast::Constant::Int {
|
||||
guard: Some(ast::UntypedClauseGuard::Constant(ast::Constant::Int {
|
||||
location: Span::new((), 34..36),
|
||||
value: "42".to_string(),
|
||||
})),
|
||||
|
@ -2345,14 +2340,13 @@ fn clause_guards() {
|
|||
name: "Void".to_string(),
|
||||
},
|
||||
},
|
||||
ast::Clause {
|
||||
ast::UntypedClause {
|
||||
location: Span::new((), 49..65),
|
||||
pattern: vec![ast::Pattern::Discard {
|
||||
patterns: vec1![ast::Pattern::Discard {
|
||||
name: "_".to_string(),
|
||||
location: Span::new((), 49..50),
|
||||
}],
|
||||
alternative_patterns: vec![],
|
||||
guard: Some(ast::ClauseGuard::Var {
|
||||
guard: Some(ast::UntypedClauseGuard::Var {
|
||||
location: Span::new((), 54..57),
|
||||
name: "bar".to_string(),
|
||||
tipo: (),
|
||||
|
@ -2362,14 +2356,13 @@ fn clause_guards() {
|
|||
name: "Void".to_string(),
|
||||
},
|
||||
},
|
||||
ast::Clause {
|
||||
ast::UntypedClause {
|
||||
location: Span::new((), 70..87),
|
||||
pattern: vec![ast::Pattern::Discard {
|
||||
patterns: vec1![ast::Pattern::Discard {
|
||||
name: "_".to_string(),
|
||||
location: Span::new((), 70..71),
|
||||
}],
|
||||
alternative_patterns: vec![],
|
||||
guard: Some(ast::ClauseGuard::Var {
|
||||
guard: Some(ast::UntypedClauseGuard::Var {
|
||||
location: Span::new((), 75..79),
|
||||
tipo: (),
|
||||
name: "True".to_string(),
|
||||
|
@ -2379,28 +2372,27 @@ fn clause_guards() {
|
|||
name: "Void".to_string(),
|
||||
},
|
||||
},
|
||||
ast::Clause {
|
||||
ast::UntypedClause {
|
||||
location: Span::new((), 92..116),
|
||||
pattern: vec![ast::Pattern::Discard {
|
||||
patterns: vec1![ast::Pattern::Discard {
|
||||
name: "_".to_string(),
|
||||
location: Span::new((), 92..93),
|
||||
}],
|
||||
alternative_patterns: vec![],
|
||||
guard: Some(ast::ClauseGuard::Or {
|
||||
guard: Some(ast::UntypedClauseGuard::Or {
|
||||
location: Span::new((), 97..108),
|
||||
left: Box::new(ast::ClauseGuard::Var {
|
||||
left: Box::new(ast::UntypedClauseGuard::Var {
|
||||
location: Span::new((), 97..98),
|
||||
name: "a".to_string(),
|
||||
tipo: (),
|
||||
}),
|
||||
right: Box::new(ast::ClauseGuard::And {
|
||||
right: Box::new(ast::UntypedClauseGuard::And {
|
||||
location: Span::new((), 102..108),
|
||||
left: Box::new(ast::ClauseGuard::Var {
|
||||
left: Box::new(ast::UntypedClauseGuard::Var {
|
||||
location: Span::new((), 102..103),
|
||||
name: "b".to_string(),
|
||||
tipo: (),
|
||||
}),
|
||||
right: Box::new(ast::ClauseGuard::Var {
|
||||
right: Box::new(ast::UntypedClauseGuard::Var {
|
||||
location: Span::new((), 107..108),
|
||||
name: "c".to_string(),
|
||||
tipo: (),
|
||||
|
@ -2412,29 +2404,28 @@ fn clause_guards() {
|
|||
name: "Void".to_string(),
|
||||
},
|
||||
},
|
||||
ast::Clause {
|
||||
ast::UntypedClause {
|
||||
location: Span::new((), 121..147),
|
||||
pattern: vec![ast::Pattern::Discard {
|
||||
patterns: vec1![ast::Pattern::Discard {
|
||||
name: "_".to_string(),
|
||||
location: Span::new((), 121..122),
|
||||
}],
|
||||
alternative_patterns: vec![],
|
||||
guard: Some(ast::ClauseGuard::And {
|
||||
guard: Some(ast::UntypedClauseGuard::And {
|
||||
location: Span::new((), 127..139),
|
||||
left: Box::new(ast::ClauseGuard::Or {
|
||||
left: Box::new(ast::UntypedClauseGuard::Or {
|
||||
location: Span::new((), 127..133),
|
||||
left: Box::new(ast::ClauseGuard::Var {
|
||||
left: Box::new(ast::UntypedClauseGuard::Var {
|
||||
location: Span::new((), 127..128),
|
||||
name: "a".to_string(),
|
||||
tipo: (),
|
||||
}),
|
||||
right: Box::new(ast::ClauseGuard::Var {
|
||||
right: Box::new(ast::UntypedClauseGuard::Var {
|
||||
location: Span::new((), 132..133),
|
||||
name: "b".to_string(),
|
||||
tipo: (),
|
||||
}),
|
||||
}),
|
||||
right: Box::new(ast::ClauseGuard::Var {
|
||||
right: Box::new(ast::UntypedClauseGuard::Var {
|
||||
location: Span::new((), 138..139),
|
||||
name: "c".to_string(),
|
||||
tipo: (),
|
||||
|
@ -2445,39 +2436,38 @@ fn clause_guards() {
|
|||
name: "Void".to_string(),
|
||||
},
|
||||
},
|
||||
ast::Clause {
|
||||
ast::UntypedClause {
|
||||
location: Span::new((), 152..191),
|
||||
pattern: vec![ast::Pattern::Discard {
|
||||
patterns: vec1![ast::Pattern::Discard {
|
||||
name: "_".to_string(),
|
||||
location: Span::new((), 152..153),
|
||||
}],
|
||||
alternative_patterns: vec![],
|
||||
guard: Some(ast::ClauseGuard::Or {
|
||||
guard: Some(ast::UntypedClauseGuard::Or {
|
||||
location: Span::new((), 157..183),
|
||||
left: Box::new(ast::ClauseGuard::Or {
|
||||
left: Box::new(ast::UntypedClauseGuard::Or {
|
||||
location: Span::new((), 157..174),
|
||||
left: Box::new(ast::ClauseGuard::LtEqInt {
|
||||
left: Box::new(ast::UntypedClauseGuard::LtEqInt {
|
||||
location: Span::new((), 157..164),
|
||||
left: Box::new(ast::ClauseGuard::Var {
|
||||
left: Box::new(ast::UntypedClauseGuard::Var {
|
||||
location: Span::new((), 157..158),
|
||||
name: "a".to_string(),
|
||||
tipo: (),
|
||||
}),
|
||||
right: Box::new(ast::ClauseGuard::Constant(
|
||||
right: Box::new(ast::UntypedClauseGuard::Constant(
|
||||
ast::Constant::Int {
|
||||
location: Span::new((), 162..164),
|
||||
value: "42".to_string(),
|
||||
},
|
||||
)),
|
||||
}),
|
||||
right: Box::new(ast::ClauseGuard::GtInt {
|
||||
right: Box::new(ast::UntypedClauseGuard::GtInt {
|
||||
location: Span::new((), 168..174),
|
||||
left: Box::new(ast::ClauseGuard::Var {
|
||||
left: Box::new(ast::UntypedClauseGuard::Var {
|
||||
location: Span::new((), 168..169),
|
||||
name: "b".to_string(),
|
||||
tipo: (),
|
||||
}),
|
||||
right: Box::new(ast::ClauseGuard::Constant(
|
||||
right: Box::new(ast::UntypedClauseGuard::Constant(
|
||||
ast::Constant::Int {
|
||||
location: Span::new((), 172..174),
|
||||
value: "14".to_string(),
|
||||
|
@ -2485,41 +2475,44 @@ fn clause_guards() {
|
|||
)),
|
||||
}),
|
||||
}),
|
||||
right: Box::new(ast::ClauseGuard::Constant(ast::Constant::ByteArray {
|
||||
location: Span::new((), 178..183),
|
||||
bytes: String::from("str").into_bytes(),
|
||||
preferred_format: ast::ByteArrayFormatPreference::Utf8String,
|
||||
})),
|
||||
right: Box::new(ast::UntypedClauseGuard::Constant(
|
||||
ast::Constant::ByteArray {
|
||||
location: Span::new((), 178..183),
|
||||
bytes: String::from("str").into_bytes(),
|
||||
preferred_format: ast::ByteArrayFormatPreference::Utf8String,
|
||||
},
|
||||
)),
|
||||
}),
|
||||
then: expr::UntypedExpr::Var {
|
||||
location: Span::new((), 187..191),
|
||||
name: "Void".to_string(),
|
||||
},
|
||||
},
|
||||
ast::Clause {
|
||||
ast::UntypedClause {
|
||||
location: Span::new((), 196..222),
|
||||
pattern: vec![ast::Pattern::Discard {
|
||||
patterns: vec1![ast::Pattern::Discard {
|
||||
name: "_".to_string(),
|
||||
location: Span::new((), 196..197),
|
||||
}],
|
||||
alternative_patterns: vec![],
|
||||
guard: Some(ast::ClauseGuard::And {
|
||||
guard: Some(ast::UntypedClauseGuard::And {
|
||||
location: Span::new((), 201..214),
|
||||
left: Box::new(ast::ClauseGuard::Equals {
|
||||
left: Box::new(ast::UntypedClauseGuard::Equals {
|
||||
location: Span::new((), 201..208),
|
||||
left: Box::new(ast::ClauseGuard::Var {
|
||||
left: Box::new(ast::UntypedClauseGuard::Var {
|
||||
location: Span::new((), 201..202),
|
||||
name: "a".to_string(),
|
||||
tipo: (),
|
||||
}),
|
||||
right: Box::new(ast::ClauseGuard::Constant(ast::Constant::Int {
|
||||
location: Span::new((), 206..208),
|
||||
value: "14".to_string(),
|
||||
})),
|
||||
right: Box::new(ast::UntypedClauseGuard::Constant(
|
||||
ast::Constant::Int {
|
||||
location: Span::new((), 206..208),
|
||||
value: "14".to_string(),
|
||||
},
|
||||
)),
|
||||
}),
|
||||
right: Box::new(ast::ClauseGuard::Not {
|
||||
right: Box::new(ast::UntypedClauseGuard::Not {
|
||||
location: Span::new((), 212..214),
|
||||
value: Box::new(ast::ClauseGuard::Var {
|
||||
value: Box::new(ast::UntypedClauseGuard::Var {
|
||||
location: Span::new((), 213..214),
|
||||
name: "b".to_string(),
|
||||
tipo: (),
|
||||
|
@ -2531,18 +2524,17 @@ fn clause_guards() {
|
|||
name: "Void".to_string(),
|
||||
},
|
||||
},
|
||||
ast::Clause {
|
||||
ast::UntypedClause {
|
||||
location: Span::new((), 227..246),
|
||||
pattern: vec![ast::Pattern::Discard {
|
||||
patterns: vec1![ast::Pattern::Discard {
|
||||
name: "_".to_string(),
|
||||
location: Span::new((), 227..228),
|
||||
}],
|
||||
alternative_patterns: vec![],
|
||||
guard: Some(ast::ClauseGuard::Not {
|
||||
guard: Some(ast::UntypedClauseGuard::Not {
|
||||
location: Span::new((), 232..238),
|
||||
value: Box::new(ast::ClauseGuard::Not {
|
||||
value: Box::new(ast::UntypedClauseGuard::Not {
|
||||
location: Span::new((), 233..238),
|
||||
value: Box::new(ast::ClauseGuard::Var {
|
||||
value: Box::new(ast::UntypedClauseGuard::Var {
|
||||
location: Span::new((), 234..238),
|
||||
tipo: (),
|
||||
name: "True".to_string(),
|
||||
|
@ -2826,14 +2818,14 @@ fn parse_keyword_error() {
|
|||
arguments: vec![],
|
||||
body: expr::UntypedExpr::When {
|
||||
location: Span::new((), 54..110),
|
||||
subjects: vec![expr::UntypedExpr::Var {
|
||||
subject: Box::new(expr::UntypedExpr::Var {
|
||||
location: Span::new((), 59..60),
|
||||
name: "x".to_string(),
|
||||
}],
|
||||
}),
|
||||
clauses: vec![
|
||||
ast::Clause {
|
||||
ast::UntypedClause {
|
||||
location: Span::new((), 72..89),
|
||||
pattern: vec![ast::Pattern::Constructor {
|
||||
patterns: vec1![ast::Pattern::Constructor {
|
||||
is_record: false,
|
||||
location: Span::new((), 72..81),
|
||||
name: "Something".to_string(),
|
||||
|
@ -2843,20 +2835,18 @@ fn parse_keyword_error() {
|
|||
with_spread: false,
|
||||
tipo: (),
|
||||
}],
|
||||
alternative_patterns: vec![],
|
||||
guard: None,
|
||||
then: expr::UntypedExpr::Var {
|
||||
location: Span::new((), 85..89),
|
||||
name: "Void".to_string(),
|
||||
},
|
||||
},
|
||||
ast::Clause {
|
||||
ast::UntypedClause {
|
||||
location: Span::new((), 96..106),
|
||||
pattern: vec![ast::Pattern::Discard {
|
||||
patterns: vec1![ast::Pattern::Discard {
|
||||
name: "_".to_string(),
|
||||
location: Span::new((), 96..97),
|
||||
}],
|
||||
alternative_patterns: vec![],
|
||||
guard: None,
|
||||
then: expr::UntypedExpr::Trace {
|
||||
kind: ast::TraceKind::Error,
|
||||
|
@ -2927,14 +2917,14 @@ fn parse_keyword_todo() {
|
|||
arguments: vec![],
|
||||
body: expr::UntypedExpr::When {
|
||||
location: Span::new((), 53..121),
|
||||
subjects: vec![expr::UntypedExpr::Var {
|
||||
subject: Box::new(expr::UntypedExpr::Var {
|
||||
location: Span::new((), 58..59),
|
||||
name: "x".to_string(),
|
||||
}],
|
||||
}),
|
||||
clauses: vec![
|
||||
ast::Clause {
|
||||
ast::UntypedClause {
|
||||
location: Span::new((), 71..82),
|
||||
pattern: vec![ast::Pattern::Constructor {
|
||||
patterns: vec1![ast::Pattern::Constructor {
|
||||
is_record: false,
|
||||
location: Span::new((), 71..74),
|
||||
name: "Foo".to_string(),
|
||||
|
@ -2944,7 +2934,6 @@ fn parse_keyword_todo() {
|
|||
with_spread: false,
|
||||
tipo: (),
|
||||
}],
|
||||
alternative_patterns: vec![],
|
||||
guard: None,
|
||||
then: expr::UntypedExpr::Trace {
|
||||
kind: ast::TraceKind::Todo,
|
||||
|
@ -2958,9 +2947,9 @@ fn parse_keyword_todo() {
|
|||
}),
|
||||
},
|
||||
},
|
||||
ast::Clause {
|
||||
ast::UntypedClause {
|
||||
location: Span::new((), 89..100),
|
||||
pattern: vec![ast::Pattern::Constructor {
|
||||
patterns: vec1![ast::Pattern::Constructor {
|
||||
is_record: false,
|
||||
location: Span::new((), 89..92),
|
||||
name: "Bar".to_string(),
|
||||
|
@ -2970,20 +2959,18 @@ fn parse_keyword_todo() {
|
|||
with_spread: false,
|
||||
tipo: (),
|
||||
}],
|
||||
alternative_patterns: vec![],
|
||||
guard: None,
|
||||
then: expr::UntypedExpr::Var {
|
||||
location: Span::new((), 96..100),
|
||||
name: "True".to_string(),
|
||||
},
|
||||
},
|
||||
ast::Clause {
|
||||
ast::UntypedClause {
|
||||
location: Span::new((), 107..117),
|
||||
pattern: vec![ast::Pattern::Discard {
|
||||
patterns: vec1![ast::Pattern::Discard {
|
||||
name: "_".to_string(),
|
||||
location: Span::new((), 107..108),
|
||||
}],
|
||||
alternative_patterns: vec![],
|
||||
guard: None,
|
||||
then: expr::UntypedExpr::Var {
|
||||
location: Span::new((), 112..117),
|
||||
|
|
|
@ -315,22 +315,6 @@ From there, you can define 'increment', a function that takes a single argument
|
|||
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(
|
||||
"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()),
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::ast::TypedPattern;
|
||||
use std::{cmp::Ordering, collections::HashMap, sync::Arc};
|
||||
|
||||
use vec1::Vec1;
|
||||
|
@ -5,10 +6,10 @@ use vec1::Vec1;
|
|||
use crate::{
|
||||
ast::{
|
||||
Annotation, Arg, ArgName, AssignmentKind, BinOp, ByteArrayFormatPreference, CallArg,
|
||||
Clause, ClauseGuard, Constant, IfBranch, RecordUpdateSpread, Span, TraceKind, Tracing,
|
||||
TypedArg, TypedCallArg, TypedClause, TypedClauseGuard, TypedIfBranch, TypedMultiPattern,
|
||||
TypedRecordUpdateArg, UnOp, UntypedArg, UntypedClause, UntypedClauseGuard, UntypedIfBranch,
|
||||
UntypedMultiPattern, UntypedPattern, UntypedRecordUpdateArg,
|
||||
ClauseGuard, Constant, IfBranch, RecordUpdateSpread, Span, TraceKind, Tracing, TypedArg,
|
||||
TypedCallArg, TypedClause, TypedClauseGuard, TypedIfBranch, TypedRecordUpdateArg, UnOp,
|
||||
UntypedArg, UntypedClause, UntypedClauseGuard, UntypedIfBranch, UntypedPattern,
|
||||
UntypedRecordUpdateArg,
|
||||
},
|
||||
builtins::{bool, byte_array, function, int, list, string, tuple},
|
||||
expr::{TypedExpr, UntypedExpr},
|
||||
|
@ -22,7 +23,7 @@ use super::{
|
|||
hydrator::Hydrator,
|
||||
pattern::PatternTyper,
|
||||
pipe::PipeTyper,
|
||||
PatternConstructor, RecordAccessor, Type, ValueConstructor, ValueConstructorVariant,
|
||||
RecordAccessor, Type, ValueConstructor, ValueConstructorVariant,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -45,44 +46,24 @@ pub(crate) struct ExprTyper<'a, 'b> {
|
|||
impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||
fn check_when_exhaustiveness(
|
||||
&mut self,
|
||||
subjects_count: usize,
|
||||
subjects: &[Arc<Type>],
|
||||
typed_clauses: &[Clause<TypedExpr, PatternConstructor, Arc<Type>>],
|
||||
subject: &Type,
|
||||
typed_clauses: &[TypedClause],
|
||||
location: Span,
|
||||
) -> Result<(), Vec<String>> {
|
||||
// Because exhaustiveness checking in presence of multiple subjects is similar
|
||||
// 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());
|
||||
let value_typ = collapse_links(Arc::new(subject.clone()));
|
||||
|
||||
// Currently guards in exhaustiveness checking are assumed that they can fail,
|
||||
// so we go through all clauses and pluck out only the patterns
|
||||
// for clauses that don't have guards.
|
||||
let mut patterns = Vec::new();
|
||||
for clause in typed_clauses {
|
||||
if let Clause { guard: None, .. } = clause {
|
||||
// clause.pattern is a list of patterns for all subjects
|
||||
if let Some(pattern) = clause.pattern.get(0) {
|
||||
patterns.push(pattern.clone());
|
||||
}
|
||||
|
||||
// A clause can be built with alternative patterns as well, e.g. `Audio(_) | Text(_) ->`.
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
if let TypedClause {
|
||||
guard: None,
|
||||
pattern,
|
||||
..
|
||||
} = clause
|
||||
{
|
||||
patterns.push(pattern.clone())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -309,10 +290,10 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
|
||||
UntypedExpr::When {
|
||||
location,
|
||||
subjects,
|
||||
subject,
|
||||
clauses,
|
||||
..
|
||||
} => self.infer_when(subjects, clauses, location),
|
||||
} => self.infer_when(*subject, clauses, location),
|
||||
|
||||
UntypedExpr::List {
|
||||
location,
|
||||
|
@ -1093,35 +1074,34 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
fn infer_clause(
|
||||
&mut self,
|
||||
clause: UntypedClause,
|
||||
subjects: &[Arc<Type>],
|
||||
) -> Result<TypedClause, Error> {
|
||||
let Clause {
|
||||
pattern,
|
||||
alternative_patterns,
|
||||
subject: &Type,
|
||||
) -> Result<Vec<TypedClause>, Error> {
|
||||
let UntypedClause {
|
||||
patterns,
|
||||
guard,
|
||||
then,
|
||||
location,
|
||||
} = clause;
|
||||
|
||||
let (guard, then, typed_pattern, typed_alternatives) = self.in_new_scope(|scope| {
|
||||
// Check the types
|
||||
let (typed_pattern, typed_alternatives) =
|
||||
scope.infer_clause_pattern(pattern, alternative_patterns, subjects, &location)?;
|
||||
let (guard, then, typed_patterns) = self.in_new_scope(|scope| {
|
||||
let typed_patterns = scope.infer_clause_pattern(patterns, subject, &location)?;
|
||||
|
||||
let guard = scope.infer_optional_clause_guard(guard)?;
|
||||
|
||||
let then = scope.infer(then)?;
|
||||
|
||||
Ok::<_, Error>((guard, then, typed_pattern, typed_alternatives))
|
||||
Ok::<_, Error>((guard, then, typed_patterns))
|
||||
})?;
|
||||
|
||||
Ok(Clause {
|
||||
location,
|
||||
pattern: typed_pattern,
|
||||
alternative_patterns: typed_alternatives,
|
||||
guard,
|
||||
then,
|
||||
})
|
||||
Ok(typed_patterns
|
||||
.into_iter()
|
||||
.map(|pattern| TypedClause {
|
||||
location,
|
||||
pattern,
|
||||
guard: guard.clone(),
|
||||
then: then.clone(),
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
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(
|
||||
&mut self,
|
||||
pattern: UntypedMultiPattern,
|
||||
alternatives: Vec<UntypedMultiPattern>,
|
||||
subjects: &[Arc<Type>],
|
||||
patterns: Vec1<UntypedPattern>,
|
||||
subject: &Type,
|
||||
location: &Span,
|
||||
) -> Result<(TypedMultiPattern, Vec<TypedMultiPattern>), Error> {
|
||||
) -> Result<Vec<TypedPattern>, Error> {
|
||||
let mut pattern_typer = PatternTyper::new(self.environment, &self.hydrator);
|
||||
|
||||
let typed_pattern = pattern_typer.infer_multi_pattern(pattern, subjects, location)?;
|
||||
|
||||
// Each case clause has one or more patterns that may match the
|
||||
// subject in order for the clause to be selected, so we must type
|
||||
// check every pattern.
|
||||
let mut typed_alternatives = Vec::with_capacity(alternatives.len());
|
||||
|
||||
for m in alternatives {
|
||||
typed_alternatives
|
||||
.push(pattern_typer.infer_alternative_multi_pattern(m, subjects, location)?);
|
||||
let mut typed_patterns = Vec::with_capacity(patterns.len());
|
||||
for (ix, pattern) in patterns.into_iter().enumerate() {
|
||||
if ix == 0 {
|
||||
typed_patterns.push(pattern_typer.infer_pattern(pattern, subject)?);
|
||||
} else {
|
||||
typed_patterns
|
||||
.push(pattern_typer.infer_alternative_pattern(pattern, subject, location)?);
|
||||
}
|
||||
}
|
||||
|
||||
Ok((typed_pattern, typed_alternatives))
|
||||
Ok(typed_patterns)
|
||||
}
|
||||
|
||||
// TODO: extract the type annotation checking into a infer_module_const
|
||||
|
@ -1865,7 +1842,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
|
||||
fn infer_when(
|
||||
&mut self,
|
||||
subjects: Vec<UntypedExpr>,
|
||||
subject: UntypedExpr,
|
||||
clauses: Vec<UntypedClause>,
|
||||
location: Span,
|
||||
) -> Result<TypedExpr, Error> {
|
||||
|
@ -1873,49 +1850,38 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
// that suggests that a `let` binding should be used instead.
|
||||
if clauses.len() == 1 {
|
||||
self.environment.warnings.push(Warning::SingleWhenClause {
|
||||
location: clauses[0].pattern[0].location(),
|
||||
location: clauses[0].patterns[0].location(),
|
||||
sample: UntypedExpr::Assignment {
|
||||
location: Span::empty(),
|
||||
value: Box::new(subjects[0].clone()),
|
||||
pattern: clauses[0].pattern[0].clone(),
|
||||
value: Box::new(subject.clone()),
|
||||
pattern: clauses[0].patterns[0].clone(),
|
||||
kind: AssignmentKind::Let,
|
||||
annotation: None,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
let subjects_count = subjects.len();
|
||||
|
||||
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 typed_subject = self.infer(subject)?;
|
||||
let subject_type = typed_subject.tipo();
|
||||
let return_type = self.new_unbound_var();
|
||||
|
||||
for subject in subjects {
|
||||
let subject = self.infer(subject)?;
|
||||
|
||||
subject_types.push(subject.tipo());
|
||||
|
||||
typed_subjects.push(subject);
|
||||
}
|
||||
|
||||
let mut typed_clauses = Vec::new();
|
||||
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(
|
||||
return_type.clone(),
|
||||
typed_clause.then.tipo(),
|
||||
typed_clause.location(),
|
||||
false,
|
||||
)
|
||||
.map_err(|e| e.case_clause_mismatch())?;
|
||||
|
||||
self.unify(
|
||||
return_type.clone(),
|
||||
typed_clause.then.tipo(),
|
||||
typed_clause.location(),
|
||||
false,
|
||||
)
|
||||
.map_err(|e| e.case_clause_mismatch())?;
|
||||
|
||||
typed_clauses.append(&mut typed_clause.desugarize());
|
||||
typed_clauses.push(typed_clause)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
location,
|
||||
|
@ -1927,7 +1893,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
Ok(TypedExpr::When {
|
||||
location,
|
||||
tipo: return_type,
|
||||
subjects: typed_subjects,
|
||||
subject: Box::new(typed_subject),
|
||||
clauses: typed_clauses,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ use super::{
|
|||
PatternConstructor, Type, ValueConstructorVariant,
|
||||
};
|
||||
use crate::{
|
||||
ast::{CallArg, Pattern, Span, TypedPattern, UntypedMultiPattern, UntypedPattern},
|
||||
ast::{CallArg, Pattern, Span, TypedPattern, UntypedPattern},
|
||||
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,
|
||||
multi_pattern: UntypedMultiPattern,
|
||||
subjects: &[Arc<Type>],
|
||||
pattern: UntypedPattern,
|
||||
subject: &Type,
|
||||
location: &Span,
|
||||
) -> Result<Vec<TypedPattern>, Error> {
|
||||
) -> Result<TypedPattern, Error> {
|
||||
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 {
|
||||
PatternMode::Initial => panic!("Pattern mode switched from Alternative to Initial"),
|
||||
PatternMode::Alternative(assigned)
|
||||
|
@ -123,32 +123,16 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
|
|||
.clone(),
|
||||
})
|
||||
}
|
||||
PatternMode::Alternative(_) => Ok(typed_multi),
|
||||
PatternMode::Alternative(_) => Ok(typed_pattern),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn infer_multi_pattern(
|
||||
pub fn infer_pattern(
|
||||
&mut self,
|
||||
multi_pattern: UntypedMultiPattern,
|
||||
subjects: &[Arc<Type>],
|
||||
location: &Span,
|
||||
) -> Result<Vec<TypedPattern>, Error> {
|
||||
// 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)
|
||||
pattern: UntypedPattern,
|
||||
subject: &Type,
|
||||
) -> Result<TypedPattern, Error> {
|
||||
self.unify(pattern, Arc::new(subject.clone()), None, false)
|
||||
}
|
||||
|
||||
/// When we have an assignment or a case expression we unify the pattern with the
|
||||
|
|
|
@ -20,7 +20,7 @@ use uplc::{
|
|||
use crate::{
|
||||
air::Air,
|
||||
ast::{
|
||||
ArgName, AssignmentKind, BinOp, Clause, Pattern, Span, TypedArg, TypedDataType,
|
||||
ArgName, AssignmentKind, BinOp, Pattern, Span, TypedArg, TypedClause, TypedDataType,
|
||||
TypedFunction, UnOp,
|
||||
},
|
||||
builder::{
|
||||
|
@ -476,13 +476,11 @@ impl<'a> CodeGenerator<'a> {
|
|||
ir_stack.append(&mut pattern_vec);
|
||||
}
|
||||
TypedExpr::When {
|
||||
subjects, clauses, ..
|
||||
subject, clauses, ..
|
||||
} => {
|
||||
let subject_name = format!("__subject_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();
|
||||
if clauses.len() <= 1 {
|
||||
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(&subject, &mut subject_vec, scope.clone());
|
||||
self.build_ir(subject, &mut subject_vec, scope.clone());
|
||||
|
||||
self.assignment_ir(
|
||||
&clauses[0].pattern[0],
|
||||
&clauses[0].pattern,
|
||||
&mut pattern_vec,
|
||||
&mut subject_vec,
|
||||
&subject_tipo,
|
||||
|
@ -508,12 +506,14 @@ impl<'a> CodeGenerator<'a> {
|
|||
ir_stack.append(&mut pattern_vec);
|
||||
ir_stack.append(&mut value_vec);
|
||||
} else {
|
||||
println!("{clauses:?}");
|
||||
// HERE TODO
|
||||
let clauses = if subject_tipo.is_list() {
|
||||
rearrange_clauses(clauses.clone())
|
||||
} else {
|
||||
clauses.clone()
|
||||
};
|
||||
println!("{clauses:?}");
|
||||
|
||||
if let Some((last_clause, clauses)) = clauses.split_last() {
|
||||
let mut pattern_vec = vec![];
|
||||
|
@ -532,7 +532,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
scope.clone(),
|
||||
);
|
||||
|
||||
let last_pattern = &last_clause.pattern[0];
|
||||
let last_pattern = &last_clause.pattern;
|
||||
|
||||
let mut final_scope = scope.clone();
|
||||
|
||||
|
@ -571,7 +571,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
let mut subject_scope = scope.clone();
|
||||
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;
|
||||
scope.push(self.id_gen.next());
|
||||
|
@ -603,7 +603,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
let mut scope = scope;
|
||||
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);
|
||||
|
@ -817,7 +817,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
&mut self,
|
||||
ir_stack: &mut Vec<Air>,
|
||||
clause_properties: &mut ClauseProperties,
|
||||
clauses: &[Clause<TypedExpr, PatternConstructor, Arc<Type>>],
|
||||
clauses: &[TypedClause],
|
||||
subject_type: &Arc<Type>,
|
||||
scope: Vec<u64>,
|
||||
) {
|
||||
|
@ -876,7 +876,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
} => {
|
||||
let subject_name = original_subject_name.clone();
|
||||
self.when_ir(
|
||||
&clause.pattern[0],
|
||||
&clause.pattern,
|
||||
&mut clause_subject_vec,
|
||||
&mut clause_then_vec,
|
||||
subject_type,
|
||||
|
@ -922,16 +922,16 @@ impl<'a> CodeGenerator<'a> {
|
|||
..
|
||||
} => {
|
||||
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())
|
||||
} 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() {
|
||||
(elements.len(), tail.is_some())
|
||||
} else {
|
||||
unreachable!("{:#?}", pattern)
|
||||
}
|
||||
} else {
|
||||
unreachable!("{:#?}", &clause.pattern[0])
|
||||
unreachable!("{:#?}", &clause.pattern)
|
||||
};
|
||||
|
||||
let prev_index = *current_index;
|
||||
|
@ -943,7 +943,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
};
|
||||
|
||||
self.when_ir(
|
||||
&clause.pattern[0],
|
||||
&clause.pattern,
|
||||
&mut clause_subject_vec,
|
||||
&mut clause_then_vec,
|
||||
subject_type,
|
||||
|
@ -955,11 +955,10 @@ impl<'a> CodeGenerator<'a> {
|
|||
None
|
||||
} else {
|
||||
let next_list_size = if let Pattern::List { elements, .. } =
|
||||
&clauses[index + 1].pattern[0]
|
||||
&clauses[index + 1].pattern
|
||||
{
|
||||
elements.len()
|
||||
} else if let Pattern::Assign { pattern, .. } =
|
||||
&clauses[index + 1].pattern[0]
|
||||
} else if let Pattern::Assign { pattern, .. } = &clauses[index + 1].pattern
|
||||
{
|
||||
if let Pattern::List { elements, .. } = pattern.as_ref() {
|
||||
elements.len()
|
||||
|
@ -1008,7 +1007,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
let subject_name = original_subject_name.clone();
|
||||
|
||||
self.when_ir(
|
||||
&clause.pattern[0],
|
||||
&clause.pattern,
|
||||
&mut clause_subject_vec,
|
||||
&mut clause_then_vec,
|
||||
subject_type,
|
||||
|
|
Loading…
Reference in New Issue