feat(backpassing): implements multi patterns
The main trick here was transforming Assignment to contain `Vec<UntypedPattern, Option<Annotation>>` in a field called patterns. This then meant that I could remove the `pattern` and `annotation` field from `Assignment`. The parser handles `=` and `<-` just fine because in the future `=` with multi patterns will mean some kind of optimization on tuples. But, since we don't have that optimization yet, when someone uses multi patterns with an `=` there will be an error returned from the type checker right where `infer_seq` looks for `backpassing`. From there the rest of the work was in `Project::backpassing` where I only needed to rework some things to work with a list of patterns instead of just one.
This commit is contained in:
parent
f02b9b0f0c
commit
b6b52ba508
|
@ -1782,6 +1782,47 @@ impl Span {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Map the current start and end of the Span to new values.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use aiken_lang::ast::Span;
|
||||||
|
///
|
||||||
|
/// let span = Span { start: 0, end: 1 };
|
||||||
|
///
|
||||||
|
/// let other = span.map(|start, end| (start + 2, end + 4));
|
||||||
|
///
|
||||||
|
/// assert_eq!(other.start, 2);
|
||||||
|
/// assert_eq!(other.end, 5);
|
||||||
|
/// ```
|
||||||
|
pub fn map<F: FnOnce(usize, usize) -> (usize, usize)>(&self, f: F) -> Self {
|
||||||
|
let (start, end) = f(self.start, self.end);
|
||||||
|
|
||||||
|
Self { start, end }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Map the current end of the Span to a new value.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use aiken_lang::ast::Span;
|
||||||
|
///
|
||||||
|
/// let span = Span { start: 0, end: 1 };
|
||||||
|
///
|
||||||
|
/// let other = span.map_end(|end| end + 1);
|
||||||
|
///
|
||||||
|
/// assert_eq!(other.start, 0);
|
||||||
|
/// assert_eq!(other.end, 2);
|
||||||
|
/// ```
|
||||||
|
pub fn map_end<F: FnOnce(usize) -> usize>(&self, f: F) -> Self {
|
||||||
|
Self {
|
||||||
|
start: self.start,
|
||||||
|
end: f(self.end),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn contains(&self, byte_index: usize) -> bool {
|
pub fn contains(&self, byte_index: usize) -> bool {
|
||||||
byte_index >= self.start && byte_index < self.end
|
byte_index >= self.start && byte_index < self.end
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
||||||
Curve, DataType, DataTypeKey, DefinitionLocation, IfBranch, Located, LogicalOpChainKind,
|
Curve, DataType, DataTypeKey, DefinitionLocation, IfBranch, Located, LogicalOpChainKind,
|
||||||
ParsedCallArg, Pattern, RecordConstructorArg, RecordUpdateSpread, Span, TraceKind,
|
ParsedCallArg, Pattern, RecordConstructorArg, RecordUpdateSpread, Span, TraceKind,
|
||||||
TypedAssignmentKind, TypedClause, TypedDataType, TypedRecordUpdateArg, UnOp,
|
TypedAssignmentKind, TypedClause, TypedDataType, TypedRecordUpdateArg, UnOp,
|
||||||
UntypedAssignmentKind, UntypedClause, UntypedRecordUpdateArg,
|
UntypedAssignmentKind, UntypedClause, UntypedPattern, UntypedRecordUpdateArg,
|
||||||
},
|
},
|
||||||
builtins::void,
|
builtins::void,
|
||||||
parser::token::Base,
|
parser::token::Base,
|
||||||
|
@ -518,9 +518,8 @@ pub enum UntypedExpr {
|
||||||
Assignment {
|
Assignment {
|
||||||
location: Span,
|
location: Span,
|
||||||
value: Box<Self>,
|
value: Box<Self>,
|
||||||
pattern: Pattern<(), ()>,
|
patterns: Vec1<(UntypedPattern, Option<Annotation>)>,
|
||||||
kind: UntypedAssignmentKind,
|
kind: UntypedAssignmentKind,
|
||||||
annotation: Option<Annotation>,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
Trace {
|
Trace {
|
||||||
|
@ -1300,22 +1299,25 @@ impl UntypedExpr {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lambda(name: String, expressions: Vec<UntypedExpr>, location: Span) -> Self {
|
pub fn lambda(names: Vec<String>, expressions: Vec<UntypedExpr>, location: Span) -> Self {
|
||||||
Self::Fn {
|
Self::Fn {
|
||||||
location,
|
location,
|
||||||
fn_style: FnStyle::Plain,
|
fn_style: FnStyle::Plain,
|
||||||
arguments: vec![Arg {
|
arguments: names
|
||||||
location,
|
.into_iter()
|
||||||
doc: None,
|
.map(|name| Arg {
|
||||||
annotation: None,
|
|
||||||
tipo: (),
|
|
||||||
arg_name: ArgName::Named {
|
|
||||||
label: name.clone(),
|
|
||||||
name,
|
|
||||||
location,
|
location,
|
||||||
is_validator_param: false,
|
doc: None,
|
||||||
},
|
annotation: None,
|
||||||
}],
|
tipo: (),
|
||||||
|
arg_name: ArgName::Named {
|
||||||
|
label: name.clone(),
|
||||||
|
name,
|
||||||
|
location,
|
||||||
|
is_validator_param: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
body: Self::Sequence {
|
body: Self::Sequence {
|
||||||
location,
|
location,
|
||||||
expressions,
|
expressions,
|
||||||
|
|
|
@ -679,10 +679,9 @@ impl<'comments> Formatter<'comments> {
|
||||||
|
|
||||||
fn assignment<'a>(
|
fn assignment<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
pattern: &'a UntypedPattern,
|
patterns: &'a Vec1<(UntypedPattern, Option<Annotation>)>,
|
||||||
value: &'a UntypedExpr,
|
value: &'a UntypedExpr,
|
||||||
kind: UntypedAssignmentKind,
|
kind: UntypedAssignmentKind,
|
||||||
annotation: &'a Option<Annotation>,
|
|
||||||
) -> Document<'a> {
|
) -> Document<'a> {
|
||||||
let keyword = match kind {
|
let keyword = match kind {
|
||||||
AssignmentKind::Let { .. } => "let",
|
AssignmentKind::Let { .. } => "let",
|
||||||
|
@ -691,26 +690,39 @@ impl<'comments> Formatter<'comments> {
|
||||||
|
|
||||||
let symbol = if kind.is_backpassing() { "<-" } else { "=" };
|
let symbol = if kind.is_backpassing() { "<-" } else { "=" };
|
||||||
|
|
||||||
match pattern {
|
match patterns.first() {
|
||||||
UntypedPattern::Constructor {
|
(
|
||||||
name, module: None, ..
|
UntypedPattern::Constructor {
|
||||||
} if name == "True" && annotation.is_none() && kind.is_expect() => {
|
name, module: None, ..
|
||||||
|
},
|
||||||
|
annotation,
|
||||||
|
) if name == "True"
|
||||||
|
&& annotation.is_none()
|
||||||
|
&& kind.is_expect()
|
||||||
|
&& patterns.len() == 1 =>
|
||||||
|
{
|
||||||
keyword.to_doc().append(self.case_clause_value(value))
|
keyword.to_doc().append(self.case_clause_value(value))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.pop_empty_lines(pattern.location().end);
|
let patterns = patterns.into_iter().map(|(pattern, annotation)| {
|
||||||
|
self.pop_empty_lines(pattern.location().end);
|
||||||
|
|
||||||
let pattern = self.pattern(pattern);
|
let pattern = self.pattern(pattern);
|
||||||
|
|
||||||
let annotation = annotation
|
let annotation = annotation
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|a| ": ".to_doc().append(self.annotation(a)));
|
.map(|a| ": ".to_doc().append(self.annotation(a)));
|
||||||
|
|
||||||
|
pattern.append(annotation).group()
|
||||||
|
});
|
||||||
|
|
||||||
keyword
|
keyword
|
||||||
.to_doc()
|
.to_doc()
|
||||||
.append(" ")
|
.append(break_("", " "))
|
||||||
.append(pattern.append(annotation).group())
|
.append(join(patterns, break_(",", ", ")))
|
||||||
.append(" ")
|
.nest(INDENT)
|
||||||
|
.append(break_(",", ""))
|
||||||
|
.append(break_("", " "))
|
||||||
.append(symbol)
|
.append(symbol)
|
||||||
.append(self.case_clause_value(value))
|
.append(self.case_clause_value(value))
|
||||||
}
|
}
|
||||||
|
@ -907,11 +919,10 @@ impl<'comments> Formatter<'comments> {
|
||||||
|
|
||||||
UntypedExpr::Assignment {
|
UntypedExpr::Assignment {
|
||||||
value,
|
value,
|
||||||
pattern,
|
patterns,
|
||||||
annotation,
|
|
||||||
kind,
|
kind,
|
||||||
..
|
..
|
||||||
} => self.assignment(pattern, value, *kind, annotation),
|
} => self.assignment(patterns, value, *kind),
|
||||||
|
|
||||||
UntypedExpr::Trace {
|
UntypedExpr::Trace {
|
||||||
kind, text, then, ..
|
kind, text, then, ..
|
||||||
|
|
|
@ -14,20 +14,24 @@ Test(
|
||||||
location: 45..50,
|
location: 45..50,
|
||||||
name: "False",
|
name: "False",
|
||||||
},
|
},
|
||||||
pattern: Constructor {
|
patterns: [
|
||||||
is_record: false,
|
(
|
||||||
location: 38..42,
|
Constructor {
|
||||||
name: "True",
|
is_record: false,
|
||||||
arguments: [],
|
location: 38..42,
|
||||||
module: None,
|
name: "True",
|
||||||
constructor: (),
|
arguments: [],
|
||||||
with_spread: false,
|
module: None,
|
||||||
tipo: (),
|
constructor: (),
|
||||||
},
|
with_spread: false,
|
||||||
|
tipo: (),
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Expect {
|
kind: Expect {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
},
|
},
|
||||||
Var {
|
Var {
|
||||||
location: 54..59,
|
location: 54..59,
|
||||||
|
|
|
@ -25,14 +25,18 @@ Fn(
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 17..18,
|
(
|
||||||
name: "x",
|
Var {
|
||||||
},
|
location: 17..18,
|
||||||
|
name: "x",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
},
|
},
|
||||||
doc: None,
|
doc: None,
|
||||||
location: 0..8,
|
location: 0..8,
|
||||||
|
|
|
@ -9,23 +9,30 @@ pub fn let_(
|
||||||
r: Recursive<'_, Token, UntypedExpr, ParseError>,
|
r: Recursive<'_, Token, UntypedExpr, ParseError>,
|
||||||
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
|
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
|
||||||
just(Token::Let)
|
just(Token::Let)
|
||||||
.ignore_then(pattern())
|
.ignore_then(
|
||||||
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
pattern()
|
||||||
|
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
||||||
|
.separated_by(just(Token::Comma))
|
||||||
|
.at_least(1),
|
||||||
|
)
|
||||||
.then(choice((just(Token::Equal), just(Token::LArrow))))
|
.then(choice((just(Token::Equal), just(Token::LArrow))))
|
||||||
.then(r.clone())
|
.then(r.clone())
|
||||||
.validate(move |(((pattern, annotation), kind), value), span, emit| {
|
.validate(move |((patterns, kind), value), span, emit| {
|
||||||
if matches!(value, UntypedExpr::Assignment { .. }) {
|
if matches!(value, UntypedExpr::Assignment { .. }) {
|
||||||
emit(ParseError::invalid_assignment_right_hand_side(span))
|
emit(ParseError::invalid_assignment_right_hand_side(span))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let patterns = patterns
|
||||||
|
.try_into()
|
||||||
|
.expect("We use at_least(1) so this should never be empty");
|
||||||
|
|
||||||
UntypedExpr::Assignment {
|
UntypedExpr::Assignment {
|
||||||
location: span,
|
location: span,
|
||||||
value: Box::new(value),
|
value: Box::new(value),
|
||||||
pattern,
|
patterns,
|
||||||
kind: ast::AssignmentKind::Let {
|
kind: ast::AssignmentKind::Let {
|
||||||
backpassing: kind == Token::LArrow,
|
backpassing: kind == Token::LArrow,
|
||||||
},
|
},
|
||||||
annotation,
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -37,14 +44,20 @@ pub fn expect(
|
||||||
.ignore_then(
|
.ignore_then(
|
||||||
pattern()
|
pattern()
|
||||||
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
||||||
|
.separated_by(just(Token::Comma))
|
||||||
|
.at_least(1)
|
||||||
.then(choice((just(Token::Equal), just(Token::LArrow))))
|
.then(choice((just(Token::Equal), just(Token::LArrow))))
|
||||||
.or_not(),
|
.or_not(),
|
||||||
)
|
)
|
||||||
.then(r.clone())
|
.then(r.clone())
|
||||||
.validate(move |(opt_pattern, value), span, emit| {
|
.validate(move |(opt_pattern, value), span, emit| {
|
||||||
let ((pattern, annotation), kind) = opt_pattern.unwrap_or_else(|| {
|
if matches!(value, UntypedExpr::Assignment { .. }) {
|
||||||
|
emit(ParseError::invalid_assignment_right_hand_side(span))
|
||||||
|
}
|
||||||
|
|
||||||
|
let (patterns, kind) = opt_pattern.unwrap_or_else(|| {
|
||||||
(
|
(
|
||||||
(
|
vec![(
|
||||||
ast::UntypedPattern::Constructor {
|
ast::UntypedPattern::Constructor {
|
||||||
is_record: false,
|
is_record: false,
|
||||||
location: span,
|
location: span,
|
||||||
|
@ -56,23 +69,22 @@ pub fn expect(
|
||||||
tipo: (),
|
tipo: (),
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
),
|
)],
|
||||||
Token::Equal,
|
Token::Equal,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
if matches!(value, UntypedExpr::Assignment { .. }) {
|
let patterns = patterns
|
||||||
emit(ParseError::invalid_assignment_right_hand_side(span))
|
.try_into()
|
||||||
}
|
.expect("We use at_least(1) so this should never be empty");
|
||||||
|
|
||||||
UntypedExpr::Assignment {
|
UntypedExpr::Assignment {
|
||||||
location: span,
|
location: span,
|
||||||
|
patterns,
|
||||||
value: Box::new(value),
|
value: Box::new(value),
|
||||||
pattern,
|
|
||||||
kind: ast::AssignmentKind::Expect {
|
kind: ast::AssignmentKind::Expect {
|
||||||
backpassing: kind == Token::LArrow,
|
backpassing: kind == Token::LArrow,
|
||||||
},
|
},
|
||||||
annotation,
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,14 +16,18 @@ Assignment {
|
||||||
numeric_underscore: false,
|
numeric_underscore: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 16..17,
|
(
|
||||||
name: "x",
|
Var {
|
||||||
},
|
location: 16..17,
|
||||||
|
name: "x",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
},
|
},
|
||||||
BinOp {
|
BinOp {
|
||||||
location: 24..29,
|
location: 24..29,
|
||||||
|
@ -42,12 +46,16 @@ Assignment {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 4..5,
|
(
|
||||||
name: "b",
|
Var {
|
||||||
},
|
location: 4..5,
|
||||||
|
name: "b",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,27 +12,31 @@ Assignment {
|
||||||
name: "something",
|
name: "something",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pattern: Constructor {
|
patterns: [
|
||||||
is_record: false,
|
(
|
||||||
location: 7..14,
|
Constructor {
|
||||||
name: "Some",
|
is_record: false,
|
||||||
arguments: [
|
location: 7..14,
|
||||||
CallArg {
|
name: "Some",
|
||||||
label: None,
|
arguments: [
|
||||||
location: 12..13,
|
CallArg {
|
||||||
value: Var {
|
label: None,
|
||||||
location: 12..13,
|
location: 12..13,
|
||||||
name: "x",
|
value: Var {
|
||||||
},
|
location: 12..13,
|
||||||
|
name: "x",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
module: None,
|
||||||
|
constructor: (),
|
||||||
|
with_spread: false,
|
||||||
|
tipo: (),
|
||||||
},
|
},
|
||||||
],
|
None,
|
||||||
module: None,
|
),
|
||||||
constructor: (),
|
],
|
||||||
with_spread: false,
|
|
||||||
tipo: (),
|
|
||||||
},
|
|
||||||
kind: Expect {
|
kind: Expect {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,18 +20,22 @@ Assignment {
|
||||||
name: "wow",
|
name: "wow",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pattern: Constructor {
|
patterns: [
|
||||||
is_record: false,
|
(
|
||||||
location: 0..29,
|
Constructor {
|
||||||
name: "True",
|
is_record: false,
|
||||||
arguments: [],
|
location: 0..29,
|
||||||
module: None,
|
name: "True",
|
||||||
constructor: (),
|
arguments: [],
|
||||||
with_spread: false,
|
module: None,
|
||||||
tipo: (),
|
constructor: (),
|
||||||
},
|
with_spread: false,
|
||||||
|
tipo: (),
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Expect {
|
kind: Expect {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,29 +16,37 @@ Assignment {
|
||||||
numeric_underscore: false,
|
numeric_underscore: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 13..14,
|
(
|
||||||
name: "a",
|
Var {
|
||||||
},
|
location: 13..14,
|
||||||
|
name: "a",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
pattern: Constructor {
|
patterns: [
|
||||||
is_record: false,
|
(
|
||||||
location: 0..21,
|
Constructor {
|
||||||
name: "True",
|
is_record: false,
|
||||||
arguments: [],
|
location: 0..21,
|
||||||
module: None,
|
name: "True",
|
||||||
constructor: (),
|
arguments: [],
|
||||||
with_spread: false,
|
module: None,
|
||||||
tipo: (),
|
constructor: (),
|
||||||
},
|
with_spread: false,
|
||||||
|
tipo: (),
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Expect {
|
kind: Expect {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,23 +16,31 @@ Assignment {
|
||||||
numeric_underscore: false,
|
numeric_underscore: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 14..15,
|
(
|
||||||
name: "b",
|
Var {
|
||||||
},
|
location: 14..15,
|
||||||
|
name: "b",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 4..5,
|
(
|
||||||
name: "a",
|
Var {
|
||||||
},
|
location: 4..5,
|
||||||
|
name: "a",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,23 +16,31 @@ Assignment {
|
||||||
numeric_underscore: false,
|
numeric_underscore: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 14..15,
|
(
|
||||||
name: "b",
|
Var {
|
||||||
},
|
location: 14..15,
|
||||||
|
name: "b",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 4..5,
|
(
|
||||||
name: "a",
|
Var {
|
||||||
},
|
location: 4..5,
|
||||||
|
name: "a",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,14 +16,18 @@ Assignment {
|
||||||
numeric_underscore: false,
|
numeric_underscore: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 16..17,
|
(
|
||||||
name: "b",
|
Var {
|
||||||
},
|
location: 16..17,
|
||||||
|
name: "b",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
},
|
},
|
||||||
Var {
|
Var {
|
||||||
location: 25..26,
|
location: 25..26,
|
||||||
|
@ -31,12 +35,16 @@ Assignment {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 4..5,
|
(
|
||||||
name: "a",
|
Var {
|
||||||
},
|
location: 4..5,
|
||||||
|
name: "a",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,18 +11,22 @@ Assignment {
|
||||||
name: "foo",
|
name: "foo",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pattern: Constructor {
|
patterns: [
|
||||||
is_record: false,
|
(
|
||||||
location: 0..11,
|
Constructor {
|
||||||
name: "True",
|
is_record: false,
|
||||||
arguments: [],
|
location: 0..11,
|
||||||
module: None,
|
name: "True",
|
||||||
constructor: (),
|
arguments: [],
|
||||||
with_spread: false,
|
module: None,
|
||||||
tipo: (),
|
constructor: (),
|
||||||
},
|
with_spread: false,
|
||||||
|
tipo: (),
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Expect {
|
kind: Expect {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,14 +27,18 @@ Sequence {
|
||||||
},
|
},
|
||||||
location: 8..18,
|
location: 8..18,
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 4..5,
|
(
|
||||||
name: "x",
|
Var {
|
||||||
},
|
location: 4..5,
|
||||||
|
name: "x",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
},
|
},
|
||||||
Assignment {
|
Assignment {
|
||||||
location: 20..65,
|
location: 20..65,
|
||||||
|
@ -113,14 +117,18 @@ Sequence {
|
||||||
},
|
},
|
||||||
return_annotation: None,
|
return_annotation: None,
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 24..33,
|
(
|
||||||
name: "map_add_x",
|
Var {
|
||||||
},
|
location: 24..33,
|
||||||
|
name: "map_add_x",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
},
|
},
|
||||||
Call {
|
Call {
|
||||||
arguments: [
|
arguments: [
|
||||||
|
|
|
@ -14,14 +14,18 @@ Sequence {
|
||||||
numeric_underscore: true,
|
numeric_underscore: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 8..9,
|
(
|
||||||
name: "i",
|
Var {
|
||||||
},
|
location: 8..9,
|
||||||
|
name: "i",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
},
|
},
|
||||||
Assignment {
|
Assignment {
|
||||||
location: 24..41,
|
location: 24..41,
|
||||||
|
@ -32,14 +36,18 @@ Sequence {
|
||||||
numeric_underscore: true,
|
numeric_underscore: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 28..29,
|
(
|
||||||
name: "j",
|
Var {
|
||||||
},
|
location: 28..29,
|
||||||
|
name: "j",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
},
|
},
|
||||||
Assignment {
|
Assignment {
|
||||||
location: 44..59,
|
location: 44..59,
|
||||||
|
@ -54,14 +62,18 @@ Sequence {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 48..49,
|
(
|
||||||
name: "k",
|
Var {
|
||||||
},
|
location: 48..49,
|
||||||
|
name: "k",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,12 +28,16 @@ Assignment {
|
||||||
],
|
],
|
||||||
tail: None,
|
tail: None,
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 4..9,
|
(
|
||||||
name: "thing",
|
Var {
|
||||||
},
|
location: 4..9,
|
||||||
|
name: "thing",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,14 +40,18 @@ Sequence {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 4..9,
|
(
|
||||||
name: "tuple",
|
Var {
|
||||||
},
|
location: 4..9,
|
||||||
|
name: "tuple",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
},
|
},
|
||||||
BinOp {
|
BinOp {
|
||||||
location: 25..70,
|
location: 25..70,
|
||||||
|
|
|
@ -27,14 +27,18 @@ Sequence {
|
||||||
},
|
},
|
||||||
location: 8..15,
|
location: 8..15,
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 4..5,
|
(
|
||||||
name: "a",
|
Var {
|
||||||
},
|
location: 4..5,
|
||||||
|
name: "a",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
},
|
},
|
||||||
Tuple {
|
Tuple {
|
||||||
location: 16..23,
|
location: 16..23,
|
||||||
|
|
|
@ -85,14 +85,18 @@ When {
|
||||||
numeric_underscore: false,
|
numeric_underscore: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 55..62,
|
(
|
||||||
name: "amazing",
|
Var {
|
||||||
},
|
location: 55..62,
|
||||||
|
name: "amazing",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
},
|
},
|
||||||
Var {
|
Var {
|
||||||
location: 71..78,
|
location: 71..78,
|
||||||
|
|
|
@ -19,14 +19,18 @@ Module {
|
||||||
location: 23..26,
|
location: 23..26,
|
||||||
name: "bar",
|
name: "bar",
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 19..20,
|
(
|
||||||
name: "a",
|
Var {
|
||||||
},
|
location: 19..20,
|
||||||
|
name: "a",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
},
|
},
|
||||||
UInt {
|
UInt {
|
||||||
location: 30..32,
|
location: 30..32,
|
||||||
|
@ -59,14 +63,18 @@ Module {
|
||||||
location: 60..63,
|
location: 60..63,
|
||||||
name: "bar",
|
name: "bar",
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 56..57,
|
(
|
||||||
name: "a",
|
Var {
|
||||||
},
|
location: 56..57,
|
||||||
|
name: "a",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
},
|
},
|
||||||
UInt {
|
UInt {
|
||||||
location: 67..69,
|
location: 67..69,
|
||||||
|
@ -110,14 +118,18 @@ Module {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 93..94,
|
(
|
||||||
name: "a",
|
Var {
|
||||||
},
|
location: 93..94,
|
||||||
|
name: "a",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
},
|
},
|
||||||
doc: None,
|
doc: None,
|
||||||
location: 74..84,
|
location: 74..84,
|
||||||
|
@ -157,14 +169,18 @@ Module {
|
||||||
},
|
},
|
||||||
location: 130..137,
|
location: 130..137,
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 126..127,
|
(
|
||||||
name: "a",
|
Var {
|
||||||
},
|
location: 126..127,
|
||||||
|
name: "a",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
},
|
},
|
||||||
BinOp {
|
BinOp {
|
||||||
location: 141..153,
|
location: 141..153,
|
||||||
|
|
|
@ -24,14 +24,18 @@ Module {
|
||||||
],
|
],
|
||||||
preferred_format: Utf8String,
|
preferred_format: Utf8String,
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 17..18,
|
(
|
||||||
name: "x",
|
Var {
|
||||||
},
|
location: 17..18,
|
||||||
|
name: "x",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
},
|
},
|
||||||
Var {
|
Var {
|
||||||
location: 29..30,
|
location: 29..30,
|
||||||
|
|
|
@ -22,14 +22,18 @@ Module {
|
||||||
],
|
],
|
||||||
preferred_format: Utf8String,
|
preferred_format: Utf8String,
|
||||||
},
|
},
|
||||||
pattern: Var {
|
patterns: [
|
||||||
location: 17..18,
|
(
|
||||||
name: "x",
|
Var {
|
||||||
},
|
location: 17..18,
|
||||||
|
name: "x",
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
kind: Let {
|
kind: Let {
|
||||||
backpassing: false,
|
backpassing: false,
|
||||||
},
|
},
|
||||||
annotation: None,
|
|
||||||
},
|
},
|
||||||
Var {
|
Var {
|
||||||
location: 27..28,
|
location: 27..28,
|
||||||
|
|
|
@ -1383,6 +1383,74 @@ fn backpassing_expect_type_mismatch() {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn backpassing_multi_args() {
|
||||||
|
let source_code = r#"
|
||||||
|
fn fold(list: List<a>, init: b, then: fn(a, b) -> b) -> b {
|
||||||
|
when list is {
|
||||||
|
[] -> init
|
||||||
|
[x, ..rest] -> fold(rest, then(x, init), then)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn backpassing() -> Int {
|
||||||
|
let elem, acc <- fold([1, 2, 3], 0)
|
||||||
|
|
||||||
|
elem + acc
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
assert!(check(parse(source_code)).is_ok())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn backpassing_multi_args_expect() {
|
||||||
|
let source_code = r#"
|
||||||
|
pub type Bar {
|
||||||
|
Foo(Int)
|
||||||
|
Wow(Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold(list: List<a>, init: b, then: fn(a, b) -> b) -> b {
|
||||||
|
when list is {
|
||||||
|
[] -> init
|
||||||
|
[x, ..rest] -> fold(rest, then(x, init), then)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn backpassing() -> Bar {
|
||||||
|
expect Foo(elem), Wow(acc) <- fold([Foo(1), Foo(2), Foo(3)], Wow(0))
|
||||||
|
|
||||||
|
Wow(elem + acc)
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
assert!(matches!(check(parse(source_code)), Ok((warnings, _)) if warnings.is_empty()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn backpassing_multi_args_using_equals() {
|
||||||
|
let source_code = r#"
|
||||||
|
fn fold(list: List<a>, init: b, then: fn(a, b) -> b) -> b {
|
||||||
|
when list is {
|
||||||
|
[] -> init
|
||||||
|
[x, ..rest] -> fold(rest, then(x, init), then)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn backpassing() -> Int {
|
||||||
|
let elem, acc = fold([1, 2, 3], 0, fn(elem, acc) { elem + acc })
|
||||||
|
|
||||||
|
elem + acc
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
assert!(matches!(
|
||||||
|
check(parse(source_code)),
|
||||||
|
Err((_, Error::UnexpectedMultiPatternAssignment { .. }))
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn trace_if_false_ko() {
|
fn trace_if_false_ko() {
|
||||||
let source_code = r#"
|
let source_code = r#"
|
||||||
|
|
|
@ -707,6 +707,19 @@ Perhaps, try the following:
|
||||||
with_spread: bool,
|
with_spread: bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
#[error("I discovered a regular let assignment with multiple patterns.\n")]
|
||||||
|
#[diagnostic(code("unexpected::multi_pattern_assignment"))]
|
||||||
|
#[diagnostic(help(
|
||||||
|
"Did you mean to use backpassing syntax with {}?",
|
||||||
|
"<-".if_supports_color(Stdout, |s| s.purple())
|
||||||
|
))]
|
||||||
|
UnexpectedMultiPatternAssignment {
|
||||||
|
#[label("unexpected")]
|
||||||
|
location: Span,
|
||||||
|
#[label("<-")]
|
||||||
|
arrow: Span,
|
||||||
|
},
|
||||||
|
|
||||||
#[error("I tripped over some unknown labels in a pattern or function.\n")]
|
#[error("I tripped over some unknown labels in a pattern or function.\n")]
|
||||||
#[diagnostic(code("unknown::labels"))]
|
#[diagnostic(code("unknown::labels"))]
|
||||||
UnknownLabels(#[related] Vec<UnknownLabels>),
|
UnknownLabels(#[related] Vec<UnknownLabels>),
|
||||||
|
@ -1031,6 +1044,7 @@ impl ExtraData for Error {
|
||||||
| Error::ValidatorImported { .. }
|
| Error::ValidatorImported { .. }
|
||||||
| Error::IncorrectTestArity { .. }
|
| Error::IncorrectTestArity { .. }
|
||||||
| Error::GenericLeftAtBoundary { .. }
|
| Error::GenericLeftAtBoundary { .. }
|
||||||
|
| Error::UnexpectedMultiPatternAssignment { .. }
|
||||||
| Error::ValidatorMustReturnBool { .. } => None,
|
| Error::ValidatorMustReturnBool { .. } => None,
|
||||||
|
|
||||||
Error::UnknownType { name, .. }
|
Error::UnknownType { name, .. }
|
||||||
|
|
|
@ -262,12 +262,17 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
|
|
||||||
UntypedExpr::Assignment {
|
UntypedExpr::Assignment {
|
||||||
location,
|
location,
|
||||||
pattern,
|
patterns,
|
||||||
value,
|
value,
|
||||||
kind,
|
kind,
|
||||||
annotation,
|
|
||||||
..
|
..
|
||||||
} => self.infer_assignment(pattern, *value, kind, &annotation, location),
|
} => {
|
||||||
|
// at this point due to backpassing rewrites,
|
||||||
|
// patterns is guaranteed to have one item
|
||||||
|
let (pattern, annotation) = patterns.into_vec().swap_remove(0);
|
||||||
|
|
||||||
|
self.infer_assignment(pattern, *value, kind, &annotation, location)
|
||||||
|
}
|
||||||
|
|
||||||
UntypedExpr::Trace {
|
UntypedExpr::Trace {
|
||||||
location,
|
location,
|
||||||
|
@ -340,7 +345,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
location,
|
location,
|
||||||
value,
|
value,
|
||||||
op,
|
op,
|
||||||
} => self.infer_un_op(location, value, op),
|
} => self.infer_un_op(location, *value, op),
|
||||||
|
|
||||||
UntypedExpr::TraceIfFalse { value, location } => {
|
UntypedExpr::TraceIfFalse { value, location } => {
|
||||||
self.infer_trace_if_false(*value, location)
|
self.infer_trace_if_false(*value, location)
|
||||||
|
@ -663,10 +668,10 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
fn infer_un_op(
|
fn infer_un_op(
|
||||||
&mut self,
|
&mut self,
|
||||||
location: Span,
|
location: Span,
|
||||||
value: Box<UntypedExpr>,
|
value: UntypedExpr,
|
||||||
op: UnOp,
|
op: UnOp,
|
||||||
) -> Result<TypedExpr, Error> {
|
) -> Result<TypedExpr, Error> {
|
||||||
let value = self.infer(*value)?;
|
let value = self.infer(value)?;
|
||||||
|
|
||||||
let tipo = match op {
|
let tipo = match op {
|
||||||
UnOp::Not => bool(),
|
UnOp::Not => bool(),
|
||||||
|
@ -949,19 +954,20 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
)?
|
)?
|
||||||
} else {
|
} else {
|
||||||
if value_is_data && !untyped_pattern.is_var() && !untyped_pattern.is_discard() {
|
if value_is_data && !untyped_pattern.is_var() && !untyped_pattern.is_discard() {
|
||||||
|
let ann = Annotation::Constructor {
|
||||||
|
location: Span::empty(),
|
||||||
|
module: None,
|
||||||
|
name: "Type".to_string(),
|
||||||
|
arguments: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
return Err(Error::CastDataNoAnn {
|
return Err(Error::CastDataNoAnn {
|
||||||
location,
|
location,
|
||||||
value: UntypedExpr::Assignment {
|
value: UntypedExpr::Assignment {
|
||||||
location,
|
location,
|
||||||
value: untyped_value.into(),
|
value: untyped_value.into(),
|
||||||
pattern: untyped_pattern,
|
patterns: Vec1::new((untyped_pattern, Some(ann))),
|
||||||
kind,
|
kind,
|
||||||
annotation: Some(Annotation::Constructor {
|
|
||||||
location: Span::empty(),
|
|
||||||
module: None,
|
|
||||||
name: "Type".to_string(),
|
|
||||||
arguments: vec![],
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1007,17 +1013,15 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
name: "...".to_string(),
|
name: "...".to_string(),
|
||||||
location: Span::empty(),
|
location: Span::empty(),
|
||||||
}),
|
}),
|
||||||
pattern: untyped_pattern,
|
patterns: Vec1::new((untyped_pattern, None)),
|
||||||
kind: AssignmentKind::Let { backpassing: true },
|
kind: AssignmentKind::Let { backpassing: true },
|
||||||
annotation: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => UntypedExpr::Assignment {
|
_ => UntypedExpr::Assignment {
|
||||||
location: Span::empty(),
|
location: Span::empty(),
|
||||||
value: Box::new(untyped_value),
|
value: Box::new(untyped_value),
|
||||||
pattern: untyped_pattern,
|
patterns: Vec1::new((untyped_pattern, None)),
|
||||||
kind: AssignmentKind::let_(),
|
kind: AssignmentKind::let_(),
|
||||||
annotation: None,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1721,17 +1725,20 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
PipeTyper::infer(self, expressions)
|
PipeTyper::infer(self, expressions)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn backpass(&mut self, breakpoint: UntypedExpr, continuation: Vec<UntypedExpr>) -> UntypedExpr {
|
fn backpass(
|
||||||
let (value, pattern, annotation, kind, assign_location) = match breakpoint {
|
&mut self,
|
||||||
UntypedExpr::Assignment {
|
breakpoint: UntypedExpr,
|
||||||
location,
|
mut continuation: Vec<UntypedExpr>,
|
||||||
value,
|
) -> UntypedExpr {
|
||||||
pattern,
|
let UntypedExpr::Assignment {
|
||||||
annotation,
|
location: assign_location,
|
||||||
kind,
|
value,
|
||||||
..
|
kind,
|
||||||
} => (value, pattern, annotation, kind, location),
|
patterns,
|
||||||
_ => unreachable!("backpass misuse: breakpoint isn't an Assignment ?!"),
|
..
|
||||||
|
} = breakpoint
|
||||||
|
else {
|
||||||
|
unreachable!("backpass misuse: breakpoint isn't an Assignment ?!");
|
||||||
};
|
};
|
||||||
|
|
||||||
let value_location = value.location();
|
let value_location = value.location();
|
||||||
|
@ -1744,33 +1751,41 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
.unwrap_or_else(|| value_location.end),
|
.unwrap_or_else(|| value_location.end),
|
||||||
};
|
};
|
||||||
|
|
||||||
// In case where we have a Pattern that isn't simply a let-binding to a name, we do insert an extra let-binding
|
let mut names = Vec::new();
|
||||||
// in front of the continuation sequence. This is because we do not support patterns in function argument
|
|
||||||
// (which is perhaps something we should support?).
|
for (index, (pattern, annotation)) in patterns.into_iter().enumerate() {
|
||||||
let (name, continuation) = match pattern {
|
// In case where we have a Pattern that isn't simply a let-binding to a name, we do insert an extra let-binding
|
||||||
Pattern::Var { name, .. } | Pattern::Discard { name, .. } if kind.is_let() => {
|
// in front of the continuation sequence. This is because we do not support patterns in function argument
|
||||||
(name.clone(), continuation)
|
// (which is perhaps something we should support?).
|
||||||
|
match pattern {
|
||||||
|
Pattern::Var { name, .. } | Pattern::Discard { name, .. } if kind.is_let() => {
|
||||||
|
names.push(name.clone());
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let name = format!("{}_{}", ast::BACKPASS_VARIABLE, index);
|
||||||
|
|
||||||
|
continuation.insert(
|
||||||
|
0,
|
||||||
|
UntypedExpr::Assignment {
|
||||||
|
location: assign_location,
|
||||||
|
value: UntypedExpr::Var {
|
||||||
|
location: value_location,
|
||||||
|
name: name.clone(),
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
patterns: Vec1::new((pattern, annotation)),
|
||||||
|
// erase backpassing while preserving assignment kind.
|
||||||
|
kind: match kind {
|
||||||
|
AssignmentKind::Let { .. } => AssignmentKind::let_(),
|
||||||
|
AssignmentKind::Expect { .. } => AssignmentKind::expect(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
names.push(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
}
|
||||||
let mut with_assignment = vec![UntypedExpr::Assignment {
|
|
||||||
location: assign_location,
|
|
||||||
value: UntypedExpr::Var {
|
|
||||||
location: value_location,
|
|
||||||
name: ast::BACKPASS_VARIABLE.to_string(),
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
pattern,
|
|
||||||
// Erase backpassing while preserving assignment kind.
|
|
||||||
kind: match kind {
|
|
||||||
AssignmentKind::Let { .. } => AssignmentKind::let_(),
|
|
||||||
AssignmentKind::Expect { .. } => AssignmentKind::expect(),
|
|
||||||
},
|
|
||||||
annotation,
|
|
||||||
}];
|
|
||||||
with_assignment.extend(continuation);
|
|
||||||
(ast::BACKPASS_VARIABLE.to_string(), with_assignment)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match *value {
|
match *value {
|
||||||
UntypedExpr::Call { fun, arguments, .. } => {
|
UntypedExpr::Call { fun, arguments, .. } => {
|
||||||
|
@ -1779,7 +1794,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
new_arguments.push(CallArg {
|
new_arguments.push(CallArg {
|
||||||
location: call_location,
|
location: call_location,
|
||||||
label: None,
|
label: None,
|
||||||
value: UntypedExpr::lambda(name, continuation, call_location),
|
value: UntypedExpr::lambda(names, continuation, call_location),
|
||||||
});
|
});
|
||||||
|
|
||||||
UntypedExpr::Call {
|
UntypedExpr::Call {
|
||||||
|
@ -1811,7 +1826,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
arguments: vec![CallArg {
|
arguments: vec![CallArg {
|
||||||
location: call_location,
|
location: call_location,
|
||||||
label: None,
|
label: None,
|
||||||
value: UntypedExpr::lambda(name, continuation, call_location),
|
value: UntypedExpr::lambda(names, continuation, call_location),
|
||||||
}],
|
}],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1838,7 +1853,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
arguments: vec![CallArg {
|
arguments: vec![CallArg {
|
||||||
location: call_location,
|
location: call_location,
|
||||||
label: None,
|
label: None,
|
||||||
value: UntypedExpr::lambda(name, continuation, call_location),
|
value: UntypedExpr::lambda(names, continuation, call_location),
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1857,10 +1872,28 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
UntypedExpr::Assignment { kind, .. } if kind.is_backpassing() => {
|
UntypedExpr::Assignment { kind, .. } if kind.is_backpassing() => {
|
||||||
breakpoint = Some(expression);
|
breakpoint = Some(expression);
|
||||||
}
|
}
|
||||||
|
UntypedExpr::Assignment {
|
||||||
|
patterns, location, ..
|
||||||
|
} if patterns.len() > 1 => {
|
||||||
|
return Err(Error::UnexpectedMultiPatternAssignment {
|
||||||
|
arrow: patterns
|
||||||
|
.last()
|
||||||
|
.0
|
||||||
|
.location()
|
||||||
|
.map(|_, c_end| (c_end + 1, c_end + 1)),
|
||||||
|
location: patterns[1..]
|
||||||
|
.iter()
|
||||||
|
.map(|(p, _)| p.location())
|
||||||
|
.reduce(|acc, loc| acc.union(loc))
|
||||||
|
.unwrap_or(location)
|
||||||
|
.map_end(|current| current - 1),
|
||||||
|
});
|
||||||
|
}
|
||||||
_ => prefix.push(expression),
|
_ => prefix.push(expression),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(breakpoint) = breakpoint {
|
if let Some(breakpoint) = breakpoint {
|
||||||
prefix.push(self.backpass(breakpoint, suffix));
|
prefix.push(self.backpass(breakpoint, suffix));
|
||||||
return self.infer_seq(location, prefix);
|
return self.infer_seq(location, prefix);
|
||||||
|
@ -2149,9 +2182,8 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
sample: UntypedExpr::Assignment {
|
sample: UntypedExpr::Assignment {
|
||||||
location: Span::empty(),
|
location: Span::empty(),
|
||||||
value: Box::new(subject.clone()),
|
value: Box::new(subject.clone()),
|
||||||
pattern: clauses[0].patterns[0].clone(),
|
patterns: Vec1::new((clauses[0].patterns[0].clone(), None)),
|
||||||
kind: AssignmentKind::let_(),
|
kind: AssignmentKind::let_(),
|
||||||
annotation: None,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue