fix: spans for backpassing args

closes #882

Co-authored-by: Kasey White <kwhitemsg@gmail.com>
This commit is contained in:
rvcas 2024-03-20 17:26:30 -04:00
parent 8495f98c1d
commit 898ef74457
No known key found for this signature in database
GPG Key ID: C09B64E263F7D68C
25 changed files with 136 additions and 51 deletions

View File

@ -1176,6 +1176,21 @@ impl<A, B> Pattern<A, B> {
}
}
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<Type>) -> Option<Located<'a>> {
if !self.location().contains(byte_index) {
@ -1440,13 +1455,19 @@ impl Default for Bls12_381Point {
pub struct AssignmentPattern {
pub pattern: UntypedPattern,
pub annotation: Option<Annotation>,
pub location: Span,
}
impl AssignmentPattern {
pub fn new(pattern: UntypedPattern, annotation: Option<Annotation>) -> AssignmentPattern {
pub fn new(
pattern: UntypedPattern,
annotation: Option<Annotation>,
location: Span,
) -> AssignmentPattern {
Self {
pattern,
annotation,
location,
}
}
}

View File

@ -1300,7 +1300,7 @@ impl UntypedExpr {
}
pub fn lambda(
names: Vec<(String, Option<Annotation>)>,
names: Vec<(String, Span, Option<Annotation>)>,
expressions: Vec<UntypedExpr>,
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,

View File

@ -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);

View File

@ -27,6 +27,7 @@ Test(
tipo: (),
},
annotation: None,
location: 38..42,
},
],
kind: Expect {

View File

@ -32,6 +32,7 @@ Fn(
name: "x",
},
annotation: None,
location: 17..18,
},
],
kind: Let {

View File

@ -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<Token, UntypedExpr, Error = ParseError> + '_ {
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<Token, Vec<ast::AssignmentPattern>, 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<Token, UntypedExpr, Error = ParseError> + '_ {
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

View File

@ -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 {

View File

@ -34,6 +34,7 @@ Assignment {
tipo: (),
},
annotation: None,
location: 7..14,
},
],
kind: Expect {

View File

@ -33,6 +33,7 @@ Assignment {
tipo: (),
},
annotation: None,
location: 0..0,
},
],
kind: Expect {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -24,6 +24,7 @@ Assignment {
tipo: (),
},
annotation: None,
location: 0..0,
},
],
kind: Expect {

View File

@ -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 {

View File

@ -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 {

View File

@ -35,6 +35,7 @@ Assignment {
name: "thing",
},
annotation: None,
location: 4..9,
},
],
kind: Let {

View File

@ -47,6 +47,7 @@ Sequence {
name: "tuple",
},
annotation: None,
location: 4..9,
},
],
kind: Let {

View File

@ -34,6 +34,7 @@ Sequence {
name: "a",
},
annotation: None,
location: 4..5,
},
],
kind: Let {

View File

@ -92,6 +92,7 @@ When {
name: "amazing",
},
annotation: None,
location: 55..62,
},
],
kind: Let {

View File

@ -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 {

View File

@ -31,6 +31,7 @@ Module {
name: "x",
},
annotation: None,
location: 17..18,
},
],
kind: Let {

View File

@ -29,6 +29,7 @@ Module {
name: "x",
},
annotation: None,
location: 17..18,
},
],
kind: Let {

View File

@ -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<a>, 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>) -> 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)
);
}

View File

@ -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>,
) -> 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_(),
},
});