iter 22-tidy.5.1: parse_fn rejects duplicate doc/type/params/body clauses
This commit is contained in:
@@ -484,19 +484,58 @@ impl<'a> Parser<'a> {
|
||||
let mut suppress: Vec<Suppress> = Vec::new();
|
||||
loop {
|
||||
match self.peek_head_ident() {
|
||||
Some("doc") => doc = Some(self.parse_doc()?),
|
||||
Some("doc") => {
|
||||
if doc.is_some() {
|
||||
let pos = self.peek().map(|t| t.span.start).unwrap_or(0);
|
||||
return Err(ParseError::Production {
|
||||
production: "fn-def",
|
||||
message: format!(
|
||||
"fn `{name}` has duplicate `(doc ...)` clause"
|
||||
),
|
||||
pos,
|
||||
});
|
||||
}
|
||||
doc = Some(self.parse_doc()?);
|
||||
}
|
||||
Some("suppress") => suppress.push(self.parse_suppress_attr()?),
|
||||
Some("type") => {
|
||||
let t = self.parse_type_attr()?;
|
||||
ty = Some(t);
|
||||
if ty.is_some() {
|
||||
let pos = self.peek().map(|t| t.span.start).unwrap_or(0);
|
||||
return Err(ParseError::Production {
|
||||
production: "fn-def",
|
||||
message: format!(
|
||||
"fn `{name}` has duplicate `(type ...)` clause"
|
||||
),
|
||||
pos,
|
||||
});
|
||||
}
|
||||
ty = Some(self.parse_type_attr()?);
|
||||
}
|
||||
Some("params") => {
|
||||
let p = self.parse_params_attr()?;
|
||||
params = Some(p);
|
||||
if params.is_some() {
|
||||
let pos = self.peek().map(|t| t.span.start).unwrap_or(0);
|
||||
return Err(ParseError::Production {
|
||||
production: "fn-def",
|
||||
message: format!(
|
||||
"fn `{name}` has duplicate `(params ...)` clause"
|
||||
),
|
||||
pos,
|
||||
});
|
||||
}
|
||||
params = Some(self.parse_params_attr()?);
|
||||
}
|
||||
Some("body") => {
|
||||
let b = self.parse_body_attr()?;
|
||||
body = Some(b);
|
||||
if body.is_some() {
|
||||
let pos = self.peek().map(|t| t.span.start).unwrap_or(0);
|
||||
return Err(ParseError::Production {
|
||||
production: "fn-def",
|
||||
message: format!(
|
||||
"fn `{name}` has duplicate `(body ...)` clause"
|
||||
),
|
||||
pos,
|
||||
});
|
||||
}
|
||||
body = Some(self.parse_body_attr()?);
|
||||
}
|
||||
Some(other) => {
|
||||
let pos = self.peek().map(|t| t.span.start).unwrap_or(0);
|
||||
@@ -2260,4 +2299,98 @@ mod tests {
|
||||
};
|
||||
assert_eq!(i.doc.as_deref(), Some("instance for ints"));
|
||||
}
|
||||
|
||||
/// Iter 22-tidy.5: `parse_fn` rejects a duplicate `(doc ...)`
|
||||
/// clause with a `fn-def` production diagnostic naming the
|
||||
/// offending fn. Pre-22-tidy.5, the second clause silently
|
||||
/// overwrote the first; this test pins the strict shape.
|
||||
#[test]
|
||||
fn parse_fn_rejects_duplicate_doc_clause() {
|
||||
let err = parse(
|
||||
r#"
|
||||
(module m
|
||||
(fn f
|
||||
(doc "first")
|
||||
(doc "second")
|
||||
(type (fn-type (params) (ret (con Unit))))
|
||||
(params)
|
||||
(body (do io/print_str "x"))))
|
||||
"#,
|
||||
)
|
||||
.unwrap_err();
|
||||
let msg = format!("{err:?}");
|
||||
assert!(
|
||||
msg.contains("fn `f` has duplicate `(doc ...)` clause"),
|
||||
"expected duplicate-doc diagnostic, got: {msg}"
|
||||
);
|
||||
}
|
||||
|
||||
/// Iter 22-tidy.5: `parse_fn` rejects a duplicate `(type ...)`
|
||||
/// clause with a `fn-def` production diagnostic naming the
|
||||
/// offending fn.
|
||||
#[test]
|
||||
fn parse_fn_rejects_duplicate_type_clause() {
|
||||
let err = parse(
|
||||
r#"
|
||||
(module m
|
||||
(fn f
|
||||
(type (fn-type (params) (ret (con Unit))))
|
||||
(type (fn-type (params) (ret (con Unit))))
|
||||
(params)
|
||||
(body (do io/print_str "x"))))
|
||||
"#,
|
||||
)
|
||||
.unwrap_err();
|
||||
let msg = format!("{err:?}");
|
||||
assert!(
|
||||
msg.contains("fn `f` has duplicate `(type ...)` clause"),
|
||||
"expected duplicate-type diagnostic, got: {msg}"
|
||||
);
|
||||
}
|
||||
|
||||
/// Iter 22-tidy.5: `parse_fn` rejects a duplicate `(params ...)`
|
||||
/// clause with a `fn-def` production diagnostic naming the
|
||||
/// offending fn.
|
||||
#[test]
|
||||
fn parse_fn_rejects_duplicate_params_clause() {
|
||||
let err = parse(
|
||||
r#"
|
||||
(module m
|
||||
(fn f
|
||||
(type (fn-type (params) (ret (con Unit))))
|
||||
(params)
|
||||
(params)
|
||||
(body (do io/print_str "x"))))
|
||||
"#,
|
||||
)
|
||||
.unwrap_err();
|
||||
let msg = format!("{err:?}");
|
||||
assert!(
|
||||
msg.contains("fn `f` has duplicate `(params ...)` clause"),
|
||||
"expected duplicate-params diagnostic, got: {msg}"
|
||||
);
|
||||
}
|
||||
|
||||
/// Iter 22-tidy.5: `parse_fn` rejects a duplicate `(body ...)`
|
||||
/// clause with a `fn-def` production diagnostic naming the
|
||||
/// offending fn.
|
||||
#[test]
|
||||
fn parse_fn_rejects_duplicate_body_clause() {
|
||||
let err = parse(
|
||||
r#"
|
||||
(module m
|
||||
(fn f
|
||||
(type (fn-type (params) (ret (con Unit))))
|
||||
(params)
|
||||
(body (do io/print_str "x"))
|
||||
(body (do io/print_str "y"))))
|
||||
"#,
|
||||
)
|
||||
.unwrap_err();
|
||||
let msg = format!("{err:?}");
|
||||
assert!(
|
||||
msg.contains("fn `f` has duplicate `(body ...)` clause"),
|
||||
"expected duplicate-body diagnostic, got: {msg}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user