diff --git a/crates/aiken-lang/src/ast.rs b/crates/aiken-lang/src/ast.rs
index 750d7cc4..abade95d 100644
--- a/crates/aiken-lang/src/ast.rs
+++ b/crates/aiken-lang/src/ast.rs
@@ -1176,6 +1176,21 @@ impl Pattern {
}
}
+impl UntypedPattern {
+ pub fn true_(location: Span) -> UntypedPattern {
+ UntypedPattern::Constructor {
+ location,
+ name: "True".to_string(),
+ arguments: vec![],
+ constructor: (),
+ with_spread: false,
+ tipo: (),
+ module: None,
+ is_record: false,
+ }
+ }
+}
+
impl TypedPattern {
pub fn find_node<'a>(&'a self, byte_index: usize, value: &Rc) -> Option> {
if !self.location().contains(byte_index) {
@@ -1440,13 +1455,19 @@ impl Default for Bls12_381Point {
pub struct AssignmentPattern {
pub pattern: UntypedPattern,
pub annotation: Option,
+ pub location: Span,
}
impl AssignmentPattern {
- pub fn new(pattern: UntypedPattern, annotation: Option) -> AssignmentPattern {
+ pub fn new(
+ pattern: UntypedPattern,
+ annotation: Option,
+ location: Span,
+ ) -> AssignmentPattern {
Self {
pattern,
annotation,
+ location,
}
}
}
diff --git a/crates/aiken-lang/src/expr.rs b/crates/aiken-lang/src/expr.rs
index b97d608f..0ae888d0 100644
--- a/crates/aiken-lang/src/expr.rs
+++ b/crates/aiken-lang/src/expr.rs
@@ -1300,7 +1300,7 @@ impl UntypedExpr {
}
pub fn lambda(
- names: Vec<(String, Option)>,
+ names: Vec<(String, Span, Option)>,
expressions: Vec,
location: Span,
) -> Self {
@@ -1309,7 +1309,7 @@ impl UntypedExpr {
fn_style: FnStyle::Plain,
arguments: names
.into_iter()
- .map(|(name, annotation)| Arg {
+ .map(|(name, location, annotation)| Arg {
location,
doc: None,
annotation,
diff --git a/crates/aiken-lang/src/format.rs b/crates/aiken-lang/src/format.rs
index a65e55e9..3dfb5944 100644
--- a/crates/aiken-lang/src/format.rs
+++ b/crates/aiken-lang/src/format.rs
@@ -697,6 +697,7 @@ impl<'comments> Formatter<'comments> {
name, module: None, ..
},
annotation,
+ location: _,
} if name == "True"
&& annotation.is_none()
&& kind.is_expect()
@@ -709,6 +710,7 @@ impl<'comments> Formatter<'comments> {
|AssignmentPattern {
pattern,
annotation,
+ location: _,
}| {
self.pop_empty_lines(pattern.location().end);
diff --git a/crates/aiken-lang/src/parser/definition/snapshots/def_test_fail.snap b/crates/aiken-lang/src/parser/definition/snapshots/def_test_fail.snap
index 199199fa..d3b30a4c 100644
--- a/crates/aiken-lang/src/parser/definition/snapshots/def_test_fail.snap
+++ b/crates/aiken-lang/src/parser/definition/snapshots/def_test_fail.snap
@@ -27,6 +27,7 @@ Test(
tipo: (),
},
annotation: None,
+ location: 38..42,
},
],
kind: Expect {
diff --git a/crates/aiken-lang/src/parser/definition/snapshots/function_assignment_only.snap b/crates/aiken-lang/src/parser/definition/snapshots/function_assignment_only.snap
index f7345b59..bb48c17e 100644
--- a/crates/aiken-lang/src/parser/definition/snapshots/function_assignment_only.snap
+++ b/crates/aiken-lang/src/parser/definition/snapshots/function_assignment_only.snap
@@ -32,6 +32,7 @@ Fn(
name: "x",
},
annotation: None,
+ location: 17..18,
},
],
kind: Let {
diff --git a/crates/aiken-lang/src/parser/expr/assignment.rs b/crates/aiken-lang/src/parser/expr/assignment.rs
index 8e3f6b6c..c7960ff0 100644
--- a/crates/aiken-lang/src/parser/expr/assignment.rs
+++ b/crates/aiken-lang/src/parser/expr/assignment.rs
@@ -1,5 +1,5 @@
use crate::{
- ast,
+ ast::{self, Span},
expr::UntypedExpr,
parser::{annotation, error::ParseError, pattern, token::Token},
};
@@ -9,17 +9,7 @@ pub fn let_(
r: Recursive<'_, Token, UntypedExpr, ParseError>,
) -> impl Parser + '_ {
just(Token::Let)
- .ignore_then(
- pattern()
- .then(just(Token::Colon).ignore_then(annotation()).or_not())
- .map(|(pattern, annotation)| ast::AssignmentPattern {
- pattern,
- annotation,
- })
- .separated_by(just(Token::Comma))
- .allow_trailing()
- .at_least(1),
- )
+ .ignore_then(assignment_patterns())
.then(choice((just(Token::Equal), just(Token::LArrow))))
.then(r.clone())
.validate(move |((patterns, kind), value), span, emit| {
@@ -42,20 +32,25 @@ pub fn let_(
})
}
+fn assignment_patterns() -> impl Parser, Error = ParseError> {
+ pattern()
+ .then(just(Token::Colon).ignore_then(annotation()).or_not())
+ .map_with_span(|(pattern, annotation), span| ast::AssignmentPattern {
+ pattern,
+ annotation,
+ location: span,
+ })
+ .separated_by(just(Token::Comma))
+ .allow_trailing()
+ .at_least(1)
+}
+
pub fn expect(
r: Recursive<'_, Token, UntypedExpr, ParseError>,
) -> impl Parser + '_ {
just(Token::Expect)
.ignore_then(
- pattern()
- .then(just(Token::Colon).ignore_then(annotation()).or_not())
- .map(|(pattern, annotation)| ast::AssignmentPattern {
- pattern,
- annotation,
- })
- .separated_by(just(Token::Comma))
- .allow_trailing()
- .at_least(1)
+ assignment_patterns()
.then(choice((just(Token::Equal), just(Token::LArrow))))
.or_not(),
)
@@ -66,22 +61,13 @@ pub fn expect(
}
let (patterns, kind) = opt_pattern.unwrap_or_else(|| {
- (
- vec![ast::AssignmentPattern {
- pattern: ast::UntypedPattern::Constructor {
- is_record: false,
- location: span,
- name: "True".to_string(),
- arguments: vec![],
- module: None,
- constructor: (),
- with_spread: false,
- tipo: (),
- },
- annotation: None,
- }],
- Token::Equal,
- )
+ let filler_true = ast::AssignmentPattern::new(
+ ast::UntypedPattern::true_(span),
+ None,
+ Span::empty(),
+ );
+
+ (vec![filler_true], Token::Equal)
});
let patterns = patterns
diff --git a/crates/aiken-lang/src/parser/expr/snapshots/block_let.snap b/crates/aiken-lang/src/parser/expr/snapshots/block_let.snap
index 0d242c2b..79814a8c 100644
--- a/crates/aiken-lang/src/parser/expr/snapshots/block_let.snap
+++ b/crates/aiken-lang/src/parser/expr/snapshots/block_let.snap
@@ -23,6 +23,7 @@ Assignment {
name: "x",
},
annotation: None,
+ location: 16..17,
},
],
kind: Let {
@@ -53,6 +54,7 @@ Assignment {
name: "b",
},
annotation: None,
+ location: 4..5,
},
],
kind: Let {
diff --git a/crates/aiken-lang/src/parser/expr/snapshots/expect.snap b/crates/aiken-lang/src/parser/expr/snapshots/expect.snap
index 4f1e050a..4588bfd5 100644
--- a/crates/aiken-lang/src/parser/expr/snapshots/expect.snap
+++ b/crates/aiken-lang/src/parser/expr/snapshots/expect.snap
@@ -34,6 +34,7 @@ Assignment {
tipo: (),
},
annotation: None,
+ location: 7..14,
},
],
kind: Expect {
diff --git a/crates/aiken-lang/src/parser/expr/snapshots/expect_bool_sugar.snap b/crates/aiken-lang/src/parser/expr/snapshots/expect_bool_sugar.snap
index 92382eb5..e0e8e104 100644
--- a/crates/aiken-lang/src/parser/expr/snapshots/expect_bool_sugar.snap
+++ b/crates/aiken-lang/src/parser/expr/snapshots/expect_bool_sugar.snap
@@ -33,6 +33,7 @@ Assignment {
tipo: (),
},
annotation: None,
+ location: 0..0,
},
],
kind: Expect {
diff --git a/crates/aiken-lang/src/parser/expr/snapshots/expect_expect_let.snap b/crates/aiken-lang/src/parser/expr/snapshots/expect_expect_let.snap
index 016864c8..98f8b175 100644
--- a/crates/aiken-lang/src/parser/expr/snapshots/expect_expect_let.snap
+++ b/crates/aiken-lang/src/parser/expr/snapshots/expect_expect_let.snap
@@ -23,6 +23,7 @@ Assignment {
name: "a",
},
annotation: None,
+ location: 13..14,
},
],
kind: Let {
@@ -44,6 +45,7 @@ Assignment {
tipo: (),
},
annotation: None,
+ location: 0..0,
},
],
kind: Expect {
diff --git a/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let.snap b/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let.snap
index 21a383d3..f5fa2ed0 100644
--- a/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let.snap
+++ b/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let.snap
@@ -23,6 +23,7 @@ Assignment {
name: "b",
},
annotation: None,
+ location: 14..15,
},
],
kind: Let {
@@ -38,6 +39,7 @@ Assignment {
name: "a",
},
annotation: None,
+ location: 4..5,
},
],
kind: Let {
diff --git a/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let_parens.snap b/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let_parens.snap
index d4a6f3db..b98f6169 100644
--- a/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let_parens.snap
+++ b/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let_parens.snap
@@ -23,6 +23,7 @@ Assignment {
name: "b",
},
annotation: None,
+ location: 14..15,
},
],
kind: Let {
@@ -38,6 +39,7 @@ Assignment {
name: "a",
},
annotation: None,
+ location: 4..5,
},
],
kind: Let {
diff --git a/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let_return.snap b/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let_return.snap
index f0acd435..aa16630d 100644
--- a/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let_return.snap
+++ b/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let_return.snap
@@ -23,6 +23,7 @@ Assignment {
name: "b",
},
annotation: None,
+ location: 16..17,
},
],
kind: Let {
@@ -42,6 +43,7 @@ Assignment {
name: "a",
},
annotation: None,
+ location: 4..5,
},
],
kind: Let {
diff --git a/crates/aiken-lang/src/parser/expr/snapshots/expect_trace_if_false.snap b/crates/aiken-lang/src/parser/expr/snapshots/expect_trace_if_false.snap
index add9e781..cc3515dc 100644
--- a/crates/aiken-lang/src/parser/expr/snapshots/expect_trace_if_false.snap
+++ b/crates/aiken-lang/src/parser/expr/snapshots/expect_trace_if_false.snap
@@ -24,6 +24,7 @@ Assignment {
tipo: (),
},
annotation: None,
+ location: 0..0,
},
],
kind: Expect {
diff --git a/crates/aiken-lang/src/parser/expr/snapshots/function_invoke.snap b/crates/aiken-lang/src/parser/expr/snapshots/function_invoke.snap
index 7d3d16f6..b1e1a4d5 100644
--- a/crates/aiken-lang/src/parser/expr/snapshots/function_invoke.snap
+++ b/crates/aiken-lang/src/parser/expr/snapshots/function_invoke.snap
@@ -34,6 +34,7 @@ Sequence {
name: "x",
},
annotation: None,
+ location: 4..5,
},
],
kind: Let {
@@ -124,6 +125,7 @@ Sequence {
name: "map_add_x",
},
annotation: None,
+ location: 24..33,
},
],
kind: Let {
diff --git a/crates/aiken-lang/src/parser/expr/snapshots/int_numeric_underscore.snap b/crates/aiken-lang/src/parser/expr/snapshots/int_numeric_underscore.snap
index 4b8b0093..ea702270 100644
--- a/crates/aiken-lang/src/parser/expr/snapshots/int_numeric_underscore.snap
+++ b/crates/aiken-lang/src/parser/expr/snapshots/int_numeric_underscore.snap
@@ -21,6 +21,7 @@ Sequence {
name: "i",
},
annotation: None,
+ location: 8..9,
},
],
kind: Let {
@@ -43,6 +44,7 @@ Sequence {
name: "j",
},
annotation: None,
+ location: 28..29,
},
],
kind: Let {
@@ -69,6 +71,7 @@ Sequence {
name: "k",
},
annotation: None,
+ location: 48..49,
},
],
kind: Let {
diff --git a/crates/aiken-lang/src/parser/expr/snapshots/let_bindings.snap b/crates/aiken-lang/src/parser/expr/snapshots/let_bindings.snap
index 5d7430f9..74cd03c8 100644
--- a/crates/aiken-lang/src/parser/expr/snapshots/let_bindings.snap
+++ b/crates/aiken-lang/src/parser/expr/snapshots/let_bindings.snap
@@ -35,6 +35,7 @@ Assignment {
name: "thing",
},
annotation: None,
+ location: 4..9,
},
],
kind: Let {
diff --git a/crates/aiken-lang/src/parser/expr/snapshots/parse_tuple.snap b/crates/aiken-lang/src/parser/expr/snapshots/parse_tuple.snap
index ac27b641..91d9a513 100644
--- a/crates/aiken-lang/src/parser/expr/snapshots/parse_tuple.snap
+++ b/crates/aiken-lang/src/parser/expr/snapshots/parse_tuple.snap
@@ -47,6 +47,7 @@ Sequence {
name: "tuple",
},
annotation: None,
+ location: 4..9,
},
],
kind: Let {
diff --git a/crates/aiken-lang/src/parser/expr/snapshots/parse_tuple2.snap b/crates/aiken-lang/src/parser/expr/snapshots/parse_tuple2.snap
index 9b57ec8a..bc87b56f 100644
--- a/crates/aiken-lang/src/parser/expr/snapshots/parse_tuple2.snap
+++ b/crates/aiken-lang/src/parser/expr/snapshots/parse_tuple2.snap
@@ -34,6 +34,7 @@ Sequence {
name: "a",
},
annotation: None,
+ location: 4..5,
},
],
kind: Let {
diff --git a/crates/aiken-lang/src/parser/expr/when/snapshots/when_basic.snap b/crates/aiken-lang/src/parser/expr/when/snapshots/when_basic.snap
index b1f9628a..929746ae 100644
--- a/crates/aiken-lang/src/parser/expr/when/snapshots/when_basic.snap
+++ b/crates/aiken-lang/src/parser/expr/when/snapshots/when_basic.snap
@@ -92,6 +92,7 @@ When {
name: "amazing",
},
annotation: None,
+ location: 55..62,
},
],
kind: Let {
diff --git a/crates/aiken-lang/src/snapshots/function_ambiguous_sequence.snap b/crates/aiken-lang/src/snapshots/function_ambiguous_sequence.snap
index d6459358..4113a500 100644
--- a/crates/aiken-lang/src/snapshots/function_ambiguous_sequence.snap
+++ b/crates/aiken-lang/src/snapshots/function_ambiguous_sequence.snap
@@ -26,6 +26,7 @@ Module {
name: "a",
},
annotation: None,
+ location: 19..20,
},
],
kind: Let {
@@ -70,6 +71,7 @@ Module {
name: "a",
},
annotation: None,
+ location: 56..57,
},
],
kind: Let {
@@ -125,6 +127,7 @@ Module {
name: "a",
},
annotation: None,
+ location: 93..94,
},
],
kind: Let {
@@ -176,6 +179,7 @@ Module {
name: "a",
},
annotation: None,
+ location: 126..127,
},
],
kind: Let {
diff --git a/crates/aiken-lang/src/snapshots/parse_unicode_offset_1.snap b/crates/aiken-lang/src/snapshots/parse_unicode_offset_1.snap
index dc3f0e3d..8c257e71 100644
--- a/crates/aiken-lang/src/snapshots/parse_unicode_offset_1.snap
+++ b/crates/aiken-lang/src/snapshots/parse_unicode_offset_1.snap
@@ -31,6 +31,7 @@ Module {
name: "x",
},
annotation: None,
+ location: 17..18,
},
],
kind: Let {
diff --git a/crates/aiken-lang/src/snapshots/parse_unicode_offset_2.snap b/crates/aiken-lang/src/snapshots/parse_unicode_offset_2.snap
index 2dec2f89..f4555fe9 100644
--- a/crates/aiken-lang/src/snapshots/parse_unicode_offset_2.snap
+++ b/crates/aiken-lang/src/snapshots/parse_unicode_offset_2.snap
@@ -29,6 +29,7 @@ Module {
name: "x",
},
annotation: None,
+ location: 17..18,
},
],
kind: Let {
diff --git a/crates/aiken-lang/src/tests/check.rs b/crates/aiken-lang/src/tests/check.rs
index 53bc42c0..23501e35 100644
--- a/crates/aiken-lang/src/tests/check.rs
+++ b/crates/aiken-lang/src/tests/check.rs
@@ -1984,3 +1984,27 @@ fn allow_expect_on_var_patterns_that_are_opaque() {
assert!(check(parse(source_code)).is_ok())
}
+
+#[test]
+fn correct_span_for_backpassing_args() {
+ let source_code = r#"
+ fn fold(list: List, acc: b, f: fn(a, b) -> b) -> b {
+ when list is {
+ [] -> acc
+ [x, ..xs] -> fold(xs, f(x, acc), f)
+ }
+ }
+
+ pub fn sum(list: List) -> Int {
+ let a, b <- fold(list, 0)
+
+ a + 1
+ }
+ "#;
+
+ let (warnings, _ast) = check(parse(source_code)).unwrap();
+
+ assert!(
+ matches!(&warnings[0], Warning::UnusedVariable { ref name, location } if name == "b" && location.start == 245 && location.end == 246)
+ );
+}
diff --git a/crates/aiken-lang/src/tipo/expr.rs b/crates/aiken-lang/src/tipo/expr.rs
index f1cedb2a..6ed64c7e 100644
--- a/crates/aiken-lang/src/tipo/expr.rs
+++ b/crates/aiken-lang/src/tipo/expr.rs
@@ -268,6 +268,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
let AssignmentPattern {
pattern,
annotation,
+ location: _,
} = patterns.into_vec().swap_remove(0);
self.infer_assignment(pattern, *value, kind, &annotation, location)
@@ -959,7 +960,8 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
value: UntypedExpr::Assignment {
location,
value: untyped_value.into(),
- patterns: AssignmentPattern::new(untyped_pattern, Some(ann)).into(),
+ patterns: AssignmentPattern::new(untyped_pattern, Some(ann), Span::empty())
+ .into(),
kind,
},
});
@@ -1008,15 +1010,24 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
name: "...".to_string(),
location: Span::empty(),
}),
- patterns: AssignmentPattern::new(untyped_pattern, None)
- .into(),
+ patterns: AssignmentPattern::new(
+ untyped_pattern,
+ None,
+ Span::empty(),
+ )
+ .into(),
kind: AssignmentKind::Let { backpassing: true },
}
}
_ => UntypedExpr::Assignment {
location: Span::empty(),
value: Box::new(untyped_value),
- patterns: AssignmentPattern::new(untyped_pattern, None).into(),
+ patterns: AssignmentPattern::new(
+ untyped_pattern,
+ None,
+ Span::empty(),
+ )
+ .into(),
kind: AssignmentKind::let_(),
},
},
@@ -1725,7 +1736,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
mut continuation: Vec,
) -> UntypedExpr {
let UntypedExpr::Assignment {
- location: assign_location,
+ location: _,
value,
kind,
patterns,
@@ -1750,6 +1761,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
let AssignmentPattern {
pattern,
annotation,
+ location: assignment_pattern_location,
} = assignment_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
@@ -1759,7 +1771,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
Pattern::Var { name, location: _ } | Pattern::Discard { name, location: _ }
if kind.is_let() =>
{
- names.push((name.clone(), annotation));
+ names.push((name.clone(), assignment_pattern_location, annotation));
}
_ => {
let name = format!("{}_{}", ast::BACKPASS_VARIABLE, index);
@@ -1767,13 +1779,18 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
continuation.insert(
0,
UntypedExpr::Assignment {
- location: assign_location,
+ location: assignment_pattern_location,
value: UntypedExpr::Var {
- location: value_location,
+ location: assignment_pattern_location,
name: name.clone(),
}
.into(),
- patterns: AssignmentPattern::new(pattern, annotation.clone()).into(),
+ patterns: AssignmentPattern::new(
+ pattern,
+ annotation.clone(),
+ assignment_pattern_location,
+ )
+ .into(),
// erase backpassing while preserving assignment kind.
kind: match kind {
AssignmentKind::Let { .. } => AssignmentKind::let_(),
@@ -1782,7 +1799,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
},
);
- names.push((name, annotation));
+ names.push((name, assignment_pattern_location, annotation));
}
}
}
@@ -2192,7 +2209,12 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
sample: UntypedExpr::Assignment {
location: Span::empty(),
value: Box::new(subject.clone()),
- patterns: AssignmentPattern::new(clauses[0].patterns[0].clone(), None).into(),
+ patterns: AssignmentPattern::new(
+ clauses[0].patterns[0].clone(),
+ None,
+ Span::empty(),
+ )
+ .into(),
kind: AssignmentKind::let_(),
},
});