From 4cb69f85f71d2b70f3f0748f8905579557cec5ff Mon Sep 17 00:00:00 2001 From: Brummel Date: Sun, 10 May 2026 04:35:49 +0200 Subject: [PATCH] iter 22-tidy.5.3: parse_data rejects duplicate doc clause --- crates/ailang-surface/src/parse.rs | 32 ++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/crates/ailang-surface/src/parse.rs b/crates/ailang-surface/src/parse.rs index 2e9af37..ed68f69 100644 --- a/crates/ailang-surface/src/parse.rs +++ b/crates/ailang-surface/src/parse.rs @@ -373,8 +373,17 @@ impl<'a> Parser<'a> { loop { match self.peek_head_ident() { Some("doc") => { - let s = self.parse_doc()?; - doc = Some(s); + if doc.is_some() { + let pos = self.peek().map(|t| t.span.start).unwrap_or(0); + return Err(ParseError::Production { + production: "data-def", + message: format!( + "data `{name}` has duplicate `(doc ...)` clause" + ), + pos, + }); + } + doc = Some(self.parse_doc()?); } Some("ctor") => { ctors.push(self.parse_ctor()?); @@ -2474,4 +2483,23 @@ mod tests { "expected duplicate-body diagnostic, got: {msg}" ); } + + #[test] + fn parse_data_rejects_duplicate_doc_clause() { + let err = parse( + r#" + (module m + (data D + (doc "first") + (doc "second") + (ctor C))) + "#, + ) + .unwrap_err(); + let msg = format!("{err:?}"); + assert!( + msg.contains("data `D` has duplicate `(doc ...)` clause"), + "expected duplicate-doc diagnostic, got: {msg}" + ); + } }