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 { impl TypedPattern {
pub fn find_node<'a>(&'a self, byte_index: usize, value: &Rc<Type>) -> Option<Located<'a>> { pub fn find_node<'a>(&'a self, byte_index: usize, value: &Rc<Type>) -> Option<Located<'a>> {
if !self.location().contains(byte_index) { if !self.location().contains(byte_index) {
@ -1440,13 +1455,19 @@ impl Default for Bls12_381Point {
pub struct AssignmentPattern { pub struct AssignmentPattern {
pub pattern: UntypedPattern, pub pattern: UntypedPattern,
pub annotation: Option<Annotation>, pub annotation: Option<Annotation>,
pub location: Span,
} }
impl AssignmentPattern { impl AssignmentPattern {
pub fn new(pattern: UntypedPattern, annotation: Option<Annotation>) -> AssignmentPattern { pub fn new(
pattern: UntypedPattern,
annotation: Option<Annotation>,
location: Span,
) -> AssignmentPattern {
Self { Self {
pattern, pattern,
annotation, annotation,
location,
} }
} }
} }

View File

@ -1300,7 +1300,7 @@ impl UntypedExpr {
} }
pub fn lambda( pub fn lambda(
names: Vec<(String, Option<Annotation>)>, names: Vec<(String, Span, Option<Annotation>)>,
expressions: Vec<UntypedExpr>, expressions: Vec<UntypedExpr>,
location: Span, location: Span,
) -> Self { ) -> Self {
@ -1309,7 +1309,7 @@ impl UntypedExpr {
fn_style: FnStyle::Plain, fn_style: FnStyle::Plain,
arguments: names arguments: names
.into_iter() .into_iter()
.map(|(name, annotation)| Arg { .map(|(name, location, annotation)| Arg {
location, location,
doc: None, doc: None,
annotation, annotation,

View File

@ -697,6 +697,7 @@ impl<'comments> Formatter<'comments> {
name, module: None, .. name, module: None, ..
}, },
annotation, annotation,
location: _,
} if name == "True" } if name == "True"
&& annotation.is_none() && annotation.is_none()
&& kind.is_expect() && kind.is_expect()
@ -709,6 +710,7 @@ impl<'comments> Formatter<'comments> {
|AssignmentPattern { |AssignmentPattern {
pattern, pattern,
annotation, annotation,
location: _,
}| { }| {
self.pop_empty_lines(pattern.location().end); self.pop_empty_lines(pattern.location().end);

View File

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

View File

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

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
ast, ast::{self, Span},
expr::UntypedExpr, expr::UntypedExpr,
parser::{annotation, error::ParseError, pattern, token::Token}, parser::{annotation, error::ParseError, pattern, token::Token},
}; };
@ -9,17 +9,7 @@ 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( .ignore_then(assignment_patterns())
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),
)
.then(choice((just(Token::Equal), just(Token::LArrow)))) .then(choice((just(Token::Equal), just(Token::LArrow))))
.then(r.clone()) .then(r.clone())
.validate(move |((patterns, kind), value), span, emit| { .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( pub fn expect(
r: Recursive<'_, Token, UntypedExpr, ParseError>, r: Recursive<'_, Token, UntypedExpr, ParseError>,
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ { ) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
just(Token::Expect) just(Token::Expect)
.ignore_then( .ignore_then(
pattern() assignment_patterns()
.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)
.then(choice((just(Token::Equal), just(Token::LArrow)))) .then(choice((just(Token::Equal), just(Token::LArrow))))
.or_not(), .or_not(),
) )
@ -66,22 +61,13 @@ pub fn expect(
} }
let (patterns, kind) = opt_pattern.unwrap_or_else(|| { let (patterns, kind) = opt_pattern.unwrap_or_else(|| {
( let filler_true = ast::AssignmentPattern::new(
vec![ast::AssignmentPattern { ast::UntypedPattern::true_(span),
pattern: ast::UntypedPattern::Constructor { None,
is_record: false, Span::empty(),
location: span, );
name: "True".to_string(),
arguments: vec![], (vec![filler_true], Token::Equal)
module: None,
constructor: (),
with_spread: false,
tipo: (),
},
annotation: None,
}],
Token::Equal,
)
}); });
let patterns = patterns let patterns = patterns

View File

@ -23,6 +23,7 @@ Assignment {
name: "x", name: "x",
}, },
annotation: None, annotation: None,
location: 16..17,
}, },
], ],
kind: Let { kind: Let {
@ -53,6 +54,7 @@ Assignment {
name: "b", name: "b",
}, },
annotation: None, annotation: None,
location: 4..5,
}, },
], ],
kind: Let { kind: Let {

View File

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

View File

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

View File

@ -23,6 +23,7 @@ Assignment {
name: "a", name: "a",
}, },
annotation: None, annotation: None,
location: 13..14,
}, },
], ],
kind: Let { kind: Let {
@ -44,6 +45,7 @@ Assignment {
tipo: (), tipo: (),
}, },
annotation: None, annotation: None,
location: 0..0,
}, },
], ],
kind: Expect { kind: Expect {

View File

@ -23,6 +23,7 @@ Assignment {
name: "b", name: "b",
}, },
annotation: None, annotation: None,
location: 14..15,
}, },
], ],
kind: Let { kind: Let {
@ -38,6 +39,7 @@ Assignment {
name: "a", name: "a",
}, },
annotation: None, annotation: None,
location: 4..5,
}, },
], ],
kind: Let { kind: Let {

View File

@ -23,6 +23,7 @@ Assignment {
name: "b", name: "b",
}, },
annotation: None, annotation: None,
location: 14..15,
}, },
], ],
kind: Let { kind: Let {
@ -38,6 +39,7 @@ Assignment {
name: "a", name: "a",
}, },
annotation: None, annotation: None,
location: 4..5,
}, },
], ],
kind: Let { kind: Let {

View File

@ -23,6 +23,7 @@ Assignment {
name: "b", name: "b",
}, },
annotation: None, annotation: None,
location: 16..17,
}, },
], ],
kind: Let { kind: Let {
@ -42,6 +43,7 @@ Assignment {
name: "a", name: "a",
}, },
annotation: None, annotation: None,
location: 4..5,
}, },
], ],
kind: Let { kind: Let {

View File

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

View File

@ -34,6 +34,7 @@ Sequence {
name: "x", name: "x",
}, },
annotation: None, annotation: None,
location: 4..5,
}, },
], ],
kind: Let { kind: Let {
@ -124,6 +125,7 @@ Sequence {
name: "map_add_x", name: "map_add_x",
}, },
annotation: None, annotation: None,
location: 24..33,
}, },
], ],
kind: Let { kind: Let {

View File

@ -21,6 +21,7 @@ Sequence {
name: "i", name: "i",
}, },
annotation: None, annotation: None,
location: 8..9,
}, },
], ],
kind: Let { kind: Let {
@ -43,6 +44,7 @@ Sequence {
name: "j", name: "j",
}, },
annotation: None, annotation: None,
location: 28..29,
}, },
], ],
kind: Let { kind: Let {
@ -69,6 +71,7 @@ Sequence {
name: "k", name: "k",
}, },
annotation: None, annotation: None,
location: 48..49,
}, },
], ],
kind: Let { kind: Let {

View File

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

View File

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

View File

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

View File

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

View File

@ -26,6 +26,7 @@ Module {
name: "a", name: "a",
}, },
annotation: None, annotation: None,
location: 19..20,
}, },
], ],
kind: Let { kind: Let {
@ -70,6 +71,7 @@ Module {
name: "a", name: "a",
}, },
annotation: None, annotation: None,
location: 56..57,
}, },
], ],
kind: Let { kind: Let {
@ -125,6 +127,7 @@ Module {
name: "a", name: "a",
}, },
annotation: None, annotation: None,
location: 93..94,
}, },
], ],
kind: Let { kind: Let {
@ -176,6 +179,7 @@ Module {
name: "a", name: "a",
}, },
annotation: None, annotation: None,
location: 126..127,
}, },
], ],
kind: Let { kind: Let {

View File

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

View File

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

View File

@ -1984,3 +1984,27 @@ fn allow_expect_on_var_patterns_that_are_opaque() {
assert!(check(parse(source_code)).is_ok()) 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 { let AssignmentPattern {
pattern, pattern,
annotation, annotation,
location: _,
} = patterns.into_vec().swap_remove(0); } = patterns.into_vec().swap_remove(0);
self.infer_assignment(pattern, *value, kind, &annotation, location) self.infer_assignment(pattern, *value, kind, &annotation, location)
@ -959,7 +960,8 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
value: UntypedExpr::Assignment { value: UntypedExpr::Assignment {
location, location,
value: untyped_value.into(), value: untyped_value.into(),
patterns: AssignmentPattern::new(untyped_pattern, Some(ann)).into(), patterns: AssignmentPattern::new(untyped_pattern, Some(ann), Span::empty())
.into(),
kind, kind,
}, },
}); });
@ -1008,7 +1010,11 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
name: "...".to_string(), name: "...".to_string(),
location: Span::empty(), location: Span::empty(),
}), }),
patterns: AssignmentPattern::new(untyped_pattern, None) patterns: AssignmentPattern::new(
untyped_pattern,
None,
Span::empty(),
)
.into(), .into(),
kind: AssignmentKind::Let { backpassing: true }, kind: AssignmentKind::Let { backpassing: true },
} }
@ -1016,7 +1022,12 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
_ => UntypedExpr::Assignment { _ => UntypedExpr::Assignment {
location: Span::empty(), location: Span::empty(),
value: Box::new(untyped_value), value: Box::new(untyped_value),
patterns: AssignmentPattern::new(untyped_pattern, None).into(), patterns: AssignmentPattern::new(
untyped_pattern,
None,
Span::empty(),
)
.into(),
kind: AssignmentKind::let_(), kind: AssignmentKind::let_(),
}, },
}, },
@ -1725,7 +1736,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
mut continuation: Vec<UntypedExpr>, mut continuation: Vec<UntypedExpr>,
) -> UntypedExpr { ) -> UntypedExpr {
let UntypedExpr::Assignment { let UntypedExpr::Assignment {
location: assign_location, location: _,
value, value,
kind, kind,
patterns, patterns,
@ -1750,6 +1761,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
let AssignmentPattern { let AssignmentPattern {
pattern, pattern,
annotation, annotation,
location: assignment_pattern_location,
} = assignment_pattern; } = 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 // 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: _ } Pattern::Var { name, location: _ } | Pattern::Discard { name, location: _ }
if kind.is_let() => if kind.is_let() =>
{ {
names.push((name.clone(), annotation)); names.push((name.clone(), assignment_pattern_location, annotation));
} }
_ => { _ => {
let name = format!("{}_{}", ast::BACKPASS_VARIABLE, index); let name = format!("{}_{}", ast::BACKPASS_VARIABLE, index);
@ -1767,13 +1779,18 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
continuation.insert( continuation.insert(
0, 0,
UntypedExpr::Assignment { UntypedExpr::Assignment {
location: assign_location, location: assignment_pattern_location,
value: UntypedExpr::Var { value: UntypedExpr::Var {
location: value_location, location: assignment_pattern_location,
name: name.clone(), name: name.clone(),
} }
.into(), .into(),
patterns: AssignmentPattern::new(pattern, annotation.clone()).into(), patterns: AssignmentPattern::new(
pattern,
annotation.clone(),
assignment_pattern_location,
)
.into(),
// erase backpassing while preserving assignment kind. // erase backpassing while preserving assignment kind.
kind: match kind { kind: match kind {
AssignmentKind::Let { .. } => AssignmentKind::let_(), 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 { sample: UntypedExpr::Assignment {
location: Span::empty(), location: Span::empty(),
value: Box::new(subject.clone()), 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_(), kind: AssignmentKind::let_(),
}, },
}); });