From 14a990ae46e7cfe85b2114775518851e4f81e82d Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Tue, 12 Dec 2023 13:02:19 -0800 Subject: [PATCH 1/6] Parser recovery rework --- Cargo.lock | 102 +-- Cargo.toml | 2 +- crates/hir/src/lower/parse.rs | 6 +- crates/parser2/Cargo.toml | 2 + crates/parser2/src/ast/attr.rs | 2 +- crates/parser2/src/ast/expr.rs | 5 +- crates/parser2/src/ast/item.rs | 3 +- crates/parser2/src/ast/param.rs | 8 +- crates/parser2/src/ast/pat.rs | 2 +- crates/parser2/src/ast/path.rs | 2 +- crates/parser2/src/ast/stmt.rs | 4 +- crates/parser2/src/ast/types.rs | 2 +- crates/parser2/src/lib.rs | 53 +- crates/parser2/src/parser/attr.rs | 126 ++-- crates/parser2/src/parser/expr.rs | 235 +++---- crates/parser2/src/parser/expr_atom.rs | 261 +++---- crates/parser2/src/parser/func.rs | 203 +++--- crates/parser2/src/parser/item.rs | 511 +++++++------- crates/parser2/src/parser/lit.rs | 16 +- crates/parser2/src/parser/mod.rs | 645 +++++++++++++----- crates/parser2/src/parser/param.rs | 473 +++++++------ crates/parser2/src/parser/pat.rs | 138 ++-- crates/parser2/src/parser/path.rs | 22 +- crates/parser2/src/parser/stmt.rs | 111 +-- crates/parser2/src/parser/struct_.rs | 114 ++-- crates/parser2/src/parser/type_.rs | 110 +-- crates/parser2/src/parser/use_tree.rs | 81 ++- crates/parser2/src/syntax_kind.rs | 89 +++ .../test_files/error_recovery/exprs/call.snap | 28 +- .../test_files/error_recovery/exprs/if_.fe | 12 +- .../test_files/error_recovery/exprs/if_.snap | 101 +-- .../error_recovery/exprs/match_.snap | 8 +- .../error_recovery/exprs/method.snap | 21 +- .../error_recovery/items/const_.snap | 17 +- .../test_files/error_recovery/items/enum_.fe | 4 +- .../error_recovery/items/enum_.snap | 165 +++-- .../error_recovery/items/extern_.fe | 6 +- .../error_recovery/items/extern_.snap | 92 +-- .../test_files/error_recovery/items/func.snap | 41 +- .../error_recovery/items/impl_.snap | 10 +- .../error_recovery/items/impl_trait.fe | 6 +- .../error_recovery/items/impl_trait.snap | 35 +- .../error_recovery/items/struct_.snap | 6 +- .../error_recovery/items/trait_.snap | 28 +- .../error_recovery/items/type_.snap | 5 +- .../test_files/error_recovery/stmts/for_.snap | 22 +- .../test_files/syntax_node/items/enums.fe | 4 +- .../test_files/syntax_node/items/enums.snap | 326 ++++----- .../test_files/syntax_node/items/func.fe | 4 +- .../test_files/syntax_node/items/func.snap | 178 +++-- .../test_files/syntax_node/items/impl.snap | 12 +- .../syntax_node/items/impl_trait.fe | 6 +- .../syntax_node/items/impl_trait.snap | 231 ++++--- .../test_files/syntax_node/items/trait.snap | 20 +- .../syntax_node/structs/generics.fe | 6 +- .../syntax_node/structs/generics.snap | 469 ++++++------- crates/parser2/tests/test_runner.rs | 8 +- .../name_resolution/path_invalid_domain.fe | 2 +- .../name_resolution/path_invalid_domain.snap | 2 +- .../name_resolution/path_missing_generics.fe | 6 +- .../path_missing_generics.snap | 2 +- crates/uitest/fixtures/parser/array.snap | 6 - crates/uitest/fixtures/parser/call.snap | 6 - crates/uitest/fixtures/parser/func.snap | 16 +- crates/uitest/fixtures/parser/match_.snap | 10 +- crates/uitest/fixtures/parser/struct_.snap | 22 +- .../parser/struct_field_missing_comma.snap | 4 +- .../fixtures/parser/struct_missing_body.snap | 8 +- crates/uitest/fixtures/parser/trait_.snap | 48 +- crates/uitest/fixtures/parser/type_.snap | 12 +- 70 files changed, 2894 insertions(+), 2449 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4c1f38447b..67cafd12ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -84,9 +84,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.72" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" [[package]] name = "arc-swap" @@ -304,7 +304,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.50", ] [[package]] @@ -724,7 +724,7 @@ checksum = "48016319042fb7c87b78d2993084a831793a897a5cd1a2a67cab9d1eeb4b7d76" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.50", ] [[package]] @@ -1079,7 +1079,7 @@ dependencies = [ "salsa-2022", "smallvec", "strum 0.25.0", - "strum_macros 0.25.2", + "strum_macros 0.25.3", ] [[package]] @@ -1149,7 +1149,7 @@ dependencies = [ "glob", "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.50", ] [[package]] @@ -1204,6 +1204,8 @@ dependencies = [ "logos", "rowan", "rustc-hash", + "smallvec", + "unwrap-infallible", "wasm-bindgen", "wasm-bindgen-test", ] @@ -1272,9 +1274,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -1457,9 +1459,9 @@ checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1710,9 +1712,9 @@ dependencies = [ [[package]] name = "lsp-server" -version = "0.7.2" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ea9ae5a5082ca3b6ae824fc7666cd206b99168a4d4c769ad8fe9cc740df6a6" +checksum = "248f65b78f6db5d8e1b1604b4098a28b43d21a8eb1deeca22b1c421b276c7095" dependencies = [ "crossbeam-channel", "log", @@ -1722,9 +1724,9 @@ dependencies = [ [[package]] name = "lsp-types" -version = "0.94.0" +version = "0.94.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b63735a13a1f9cd4f4835223d828ed9c2e35c8c5e61837774399f558b6a1237" +checksum = "c66bfd44a06ae10647fe3f8214762e9369fd4248df1350924b4ef9e770a85ea1" dependencies = [ "bitflags", "serde", @@ -1945,18 +1947,18 @@ checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" [[package]] name = "patricia_tree" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "457d51c8a92e0fe2c45cd1abf6c64e5be012097756462f956483f3149fcd9649" +checksum = "1c8e0b346244f1606d39ec7c47046286cbdcc6553dbdf25b3b9550d5e026f2ed" dependencies = [ "bitflags", ] [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "petgraph" @@ -2064,9 +2066,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -2097,9 +2099,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quote" -version = "1.0.32" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -2594,9 +2596,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.176" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76dc28c9523c5d70816e393136b86d48909cfb27cecaa902d338c19ed47164dc" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] @@ -2613,20 +2615,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.176" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e7b8c5dc823e3b90651ff1d3808419cd14e5ad76de04feaf37da114e7a306f" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.50", ] [[package]] name = "serde_json" -version = "1.0.96" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", @@ -2635,13 +2637,13 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.15" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e168eaaf71e8f9bd6037feb05190485708e019f4fd87d161b3c0a0d37daf85e5" +checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.50", ] [[package]] @@ -2692,9 +2694,9 @@ checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf" [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "smol_str" @@ -2747,7 +2749,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" dependencies = [ - "strum_macros 0.25.2", + "strum_macros 0.25.3", ] [[package]] @@ -2765,15 +2767,15 @@ dependencies = [ [[package]] name = "strum_macros" -version = "0.25.2" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" dependencies = [ "heck 0.4.1", "proc-macro2", "quote", "rustversion", - "syn 2.0.27", + "syn 2.0.50", ] [[package]] @@ -2808,9 +2810,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.27" +version = "2.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" +checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" dependencies = [ "proc-macro2", "quote", @@ -2870,7 +2872,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.50", ] [[package]] @@ -2975,9 +2977,9 @@ checksum = "ccb97dac3243214f8d8507998906ca3e2e0b900bf9bf4870477f125b82e68f6e" [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" @@ -2987,9 +2989,9 @@ checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] @@ -3006,11 +3008,17 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +[[package]] +name = "unwrap-infallible" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "151ac09978d3c2862c4e39b557f4eceee2cc72150bc4cb4f16abf061b6e381fb" + [[package]] name = "url" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", diff --git a/Cargo.toml b/Cargo.toml index 82d38453cd..aad1e95a79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,4 +7,4 @@ opt-level = 3 [profile.dev] # Speeds up the build. May need to diable for debugging. -debug = 0 +debug = 1 diff --git a/crates/hir/src/lower/parse.rs b/crates/hir/src/lower/parse.rs index c1e6fed2df..81deadeb6f 100644 --- a/crates/hir/src/lower/parse.rs +++ b/crates/hir/src/lower/parse.rs @@ -41,13 +41,13 @@ impl DiagnosticVoucher for ParserError { fn to_complete(&self, _db: &dyn SpannedHirDb) -> CompleteDiagnostic { let error_code = self.error_code(); - let span = Span::new(self.file, self.error.range, SpanKind::Original); + let span = Span::new(self.file, self.error.range(), SpanKind::Original); CompleteDiagnostic::new( Severity::Error, - self.error.msg.clone(), + self.error.msg(), vec![SubDiagnostic::new( LabelStyle::Primary, - self.error.msg.clone(), + self.error.msg(), Some(span), )], vec![], diff --git a/crates/parser2/Cargo.toml b/crates/parser2/Cargo.toml index cef56961c5..f2c4c5d5ad 100644 --- a/crates/parser2/Cargo.toml +++ b/crates/parser2/Cargo.toml @@ -15,6 +15,8 @@ logos = "0.12.1" rustc-hash = "1.1.0" lazy_static = "1.4.0" derive_more = "0.99" +smallvec = { version = "1.11.2", features = ["union"] } +unwrap-infallible = "0.1.5" [dev-dependencies] fe-compiler-test-utils = { path = "../test-utils" } diff --git a/crates/parser2/src/ast/attr.rs b/crates/parser2/src/ast/attr.rs index 82942f6d26..314f82473a 100644 --- a/crates/parser2/src/ast/attr.rs +++ b/crates/parser2/src/ast/attr.rs @@ -137,7 +137,7 @@ mod tests { fn parse_attr_list(source: &str) -> AttrList { let lexer = Lexer::new(source); let mut parser = Parser::new(lexer); - parser.parse(AttrListScope::default(), None); + parser.parse(AttrListScope::default()).unwrap(); AttrList::cast(parser.finish_to_node().0).unwrap() } diff --git a/crates/parser2/src/ast/expr.rs b/crates/parser2/src/ast/expr.rs index 0fda11b039..b3f6dd1dfa 100644 --- a/crates/parser2/src/ast/expr.rs +++ b/crates/parser2/src/ast/expr.rs @@ -536,7 +536,7 @@ pub enum ArithBinOp { BitAnd(SyntaxToken), /// `|` BitOr(SyntaxToken), - /// `^` + /// `^` BitXor(SyntaxToken), } impl ArithBinOp { @@ -674,7 +674,7 @@ mod tests { { let lexer = Lexer::new(source); let mut parser = Parser::new(lexer); - crate::parser::expr::parse_expr(&mut parser); + crate::parser::expr::parse_expr(&mut parser).unwrap(); Expr::cast(parser.finish_to_node().0) .unwrap() .kind() @@ -913,6 +913,7 @@ mod tests { let if_expr: IfExpr = parse_expr("if { true } { return } else { continue }"); if let ExprKind::Block(stmts) = if_expr.cond().unwrap().kind() { + dbg!(&stmts); assert!(matches!( stmts.into_iter().next().unwrap().kind(), crate::ast::StmtKind::Expr(_) diff --git a/crates/parser2/src/ast/item.rs b/crates/parser2/src/ast/item.rs index 7d578cf451..a97315bbc6 100644 --- a/crates/parser2/src/ast/item.rs +++ b/crates/parser2/src/ast/item.rs @@ -475,7 +475,7 @@ mod tests { let lexer = Lexer::new(source); let mut parser = Parser::new(lexer); - parser.parse(ItemListScope::default(), None); + let _ = parser.parse(ItemListScope::default()); let (node, errs) = parser.finish_to_node(); for e in errs { eprintln!("{:?}", e); @@ -729,6 +729,7 @@ mod tests { let u: Use = parse_item(source); let use_tree = u.use_tree().unwrap(); let mut count = 0; + dbg!(use_tree.path().unwrap()); for segment in use_tree.path().unwrap() { match count { 0 => { diff --git a/crates/parser2/src/ast/param.rs b/crates/parser2/src/ast/param.rs index 936d27bbd1..a8aa0bb45e 100644 --- a/crates/parser2/src/ast/param.rs +++ b/crates/parser2/src/ast/param.rs @@ -452,21 +452,21 @@ mod tests { fn parse_generic_params(source: &str) -> GenericParamList { let lexer = Lexer::new(source); let mut parser = Parser::new(lexer); - parser.parse(GenericParamListScope::default(), None); + parser.parse(GenericParamListScope::default()).unwrap(); GenericParamList::cast(parser.finish_to_node().0).unwrap() } fn parse_generic_arg(source: &str) -> GenericArgList { let lexer = Lexer::new(source); let mut parser = Parser::new(lexer); - parser.parse(GenericArgListScope::default(), None); + parser.parse(GenericArgListScope::default()).unwrap(); GenericArgList::cast(parser.finish_to_node().0).unwrap() } fn parse_where_clause(source: &str) -> WhereClause { let lexer = Lexer::new(source); let mut parser = Parser::new(lexer); - parser.parse(WhereClauseScope::default(), None); + parser.parse(WhereClauseScope::default()).unwrap(); WhereClause::cast(parser.finish_to_node().0).unwrap() } @@ -548,7 +548,7 @@ mod tests { #[test] #[wasm_bindgen_test] fn where_clause() { - let source = r#"where + let source = r#"where T: Trait + Trait2 *U: Trait3 (T, U): Trait4 + Trait5 diff --git a/crates/parser2/src/ast/pat.rs b/crates/parser2/src/ast/pat.rs index 09ba246aa7..73a8c0bc16 100644 --- a/crates/parser2/src/ast/pat.rs +++ b/crates/parser2/src/ast/pat.rs @@ -186,7 +186,7 @@ mod tests { { let lexer = Lexer::new(source); let mut parser = Parser::new(lexer); - crate::parser::pat::parse_pat(&mut parser); + crate::parser::pat::parse_pat(&mut parser).unwrap(); Pat::cast(parser.finish_to_node().0) .unwrap() .kind() diff --git a/crates/parser2/src/ast/path.rs b/crates/parser2/src/ast/path.rs index 2b02a4723f..caf8ed09ee 100644 --- a/crates/parser2/src/ast/path.rs +++ b/crates/parser2/src/ast/path.rs @@ -79,7 +79,7 @@ mod tests { fn parse_path(source: &str) -> Path { let lexer = Lexer::new(source); let mut parser = Parser::new(lexer); - parser.parse(PathScope::default(), None); + parser.parse(PathScope::default()).unwrap(); Path::cast(parser.finish_to_node().0).unwrap() } diff --git a/crates/parser2/src/ast/stmt.rs b/crates/parser2/src/ast/stmt.rs index 7ae89c645a..44a488e8fa 100644 --- a/crates/parser2/src/ast/stmt.rs +++ b/crates/parser2/src/ast/stmt.rs @@ -171,7 +171,7 @@ mod tests { { let lexer = Lexer::new(source); let mut parser = Parser::new(lexer); - crate::parser::stmt::parse_stmt(&mut parser, None); + crate::parser::stmt::parse_stmt(&mut parser).unwrap(); Stmt::cast(parser.finish_to_node().0) .unwrap() .kind() @@ -218,7 +218,7 @@ mod tests { let source = r#" while { x } { bar - } + } "#; let while_stmt: WhileStmt = parse_stmt(source); diff --git a/crates/parser2/src/ast/types.rs b/crates/parser2/src/ast/types.rs index 2a7b17ac72..1bae4db190 100644 --- a/crates/parser2/src/ast/types.rs +++ b/crates/parser2/src/ast/types.rs @@ -142,7 +142,7 @@ mod tests { { let lexer = Lexer::new(source); let mut parser = parser::Parser::new(lexer); - parser::type_::parse_type(&mut parser, None); + let _ = parser::type_::parse_type(&mut parser, None); Type::cast(parser.finish_to_node().0) .unwrap() .kind() diff --git a/crates/parser2/src/lib.rs b/crates/parser2/src/lib.rs index a142970bcf..3176dfee05 100644 --- a/crates/parser2/src/lib.rs +++ b/crates/parser2/src/lib.rs @@ -4,6 +4,8 @@ pub mod parser; pub mod syntax_kind; pub mod syntax_node; +use rowan::TextSize; +use smallvec::SmallVec; pub use syntax_kind::SyntaxKind; pub use syntax_node::{FeLang, GreenNode, NodeOrToken, SyntaxNode, SyntaxToken, TextRange}; @@ -14,7 +16,7 @@ pub fn parse_source_file(text: &str) -> (GreenNode, Vec) { let mut parser = parser::Parser::new(lexer); let checkpoint = parser.enter(RootScope::default(), None); - parser.parse(parser::ItemListScope::default(), None); + let _ = parser.parse(parser::ItemListScope::default()); parser.leave(checkpoint); let (node, errs) = parser.finish(); @@ -23,10 +25,49 @@ pub fn parse_source_file(text: &str) -> (GreenNode, Vec) { /// An parse error which is accumulated in the [`parser::Parser`] while parsing. #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ParseError { - /// An error message. - pub msg: String, +pub enum ParseError { + Expected(SmallVec<[SyntaxKind; 2]>, Option, TextSize), + Unexpected(TextRange), - /// A range of the error. - pub range: TextRange, + Msg(String, TextRange), +} + +impl ParseError { + pub fn expected(tokens: &[SyntaxKind], msg: Option<&str>, pos: TextSize) -> Self { + ParseError::Expected( + SmallVec::from_slice(tokens), + msg.map(|s| s.to_string()), + pos, + ) + } + + pub fn msg(&self) -> String { + match self { + ParseError::Expected(_, Some(msg), _) => msg.clone(), + ParseError::Expected(tokens, None, _) => { + if tokens.len() == 1 { + return format!("expected {}", tokens[0].describe()); + } + + let mut s = "expected ".to_string(); + let mut delim = ""; + for (i, t) in tokens.iter().enumerate() { + s.push_str(delim); + s.push_str(t.describe()); + + delim = if i + 2 == tokens.len() { " or " } else { ", " }; + } + s + } + ParseError::Unexpected(_) => "unexpected syntax".into(), + ParseError::Msg(m, _) => m.clone(), + } + } + + pub fn range(&self) -> TextRange { + match self { + ParseError::Expected(_, _, pos) => TextRange::empty(*pos), + ParseError::Unexpected(r) | ParseError::Msg(_, r) => *r, + } + } } diff --git a/crates/parser2/src/parser/attr.rs b/crates/parser2/src/parser/attr.rs index 883032283c..19286d5820 100644 --- a/crates/parser2/src/parser/attr.rs +++ b/crates/parser2/src/parser/attr.rs @@ -1,12 +1,19 @@ -use super::{define_scope, token_stream::TokenStream, Checkpoint, Parser}; +use std::convert::Infallible; +use unwrap_infallible::UnwrapInfallible; + +use super::{ + define_scope, parse_list, token_stream::TokenStream, Checkpoint, ErrProof, Parser, Recovery, +}; use crate::SyntaxKind; -pub(super) fn parse_attr_list(parser: &mut Parser) -> Option { +pub(super) fn parse_attr_list( + parser: &mut Parser, +) -> Result, Recovery> { if let Some(SyntaxKind::DocComment) | Some(SyntaxKind::Pound) = parser.current_kind() { - Some(parser.parse(AttrListScope::default(), None).1) + parser.parse_cp(AttrListScope::default(), None).map(Some) } else { - None + Ok(None) } } @@ -18,21 +25,26 @@ define_scope! { ) } impl super::Parse for AttrListScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { loop { parser.set_newline_as_trivia(true); match parser.current_kind() { - Some(SyntaxKind::Pound) => parser.parse(AttrScope::default(), None), - Some(SyntaxKind::DocComment) => parser.parse(DocCommentAttrScope::default(), None), + Some(SyntaxKind::Pound) => { + parser.parse(AttrScope::default())?; + } + Some(SyntaxKind::DocComment) => parser + .parse(DocCommentAttrScope::default()) + .unwrap_infallible(), _ => break, }; parser.set_newline_as_trivia(false); - parser.bump_or_recover( - SyntaxKind::Newline, - "expected newline after Attribute", - None, - ) + if parser.find(SyntaxKind::Newline, None)? { + parser.bump(); + } } + Ok(()) } } @@ -42,18 +54,25 @@ define_scope! { Inheritance } impl super::Parse for AttrScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.set_newline_as_trivia(false); parser.bump_expected(SyntaxKind::Pound); - parser.with_recovery_tokens( - |parser| { - parser.bump_or_recover(SyntaxKind::Ident, "expected attribute name", None); - }, - &[SyntaxKind::LParen], - ); + + parser.set_scope_recovery_stack(&[SyntaxKind::LParen]); + if parser.find( + SyntaxKind::Ident, + Some("expected an attribute name after `#`"), + )? { + parser.bump() + } if parser.current_kind() == Some(SyntaxKind::LParen) { - parser.parse(AttrArgListScope::default(), None); + parser.pop_recovery_stack(); + parser.parse(AttrArgListScope::default()) + } else { + Ok(()) } } } @@ -61,53 +80,43 @@ impl super::Parse for AttrScope { define_scope! { AttrArgListScope, AttrArgList, - Override( - RParen - ) + Override(Comma, RParen) } impl super::Parse for AttrArgListScope { - fn parse(&mut self, parser: &mut Parser) { - parser.bump_expected(SyntaxKind::LParen); - if parser.bump_if(SyntaxKind::RParen) { - return; - } - - parser.with_next_expected_tokens( - |parser| parser.parse(AttrArgScope::default(), None), - &[SyntaxKind::Comma, SyntaxKind::RParen], - ); - while parser.bump_if(SyntaxKind::Comma) { - parser.with_next_expected_tokens( - |parser| parser.parse(AttrArgScope::default(), None), - &[SyntaxKind::Comma, SyntaxKind::RParen], - ); - } + type Error = Recovery; - parser.bump_or_recover(SyntaxKind::RParen, "expected `)`", None); + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parse_list( + parser, + false, + (SyntaxKind::LParen, SyntaxKind::RParen), + |parser| parser.parse(AttrArgScope::default()), + ) } } define_scope! { AttrArgScope, AttrArg, - Override( - Comma, - RParen - ) + Inheritance } impl super::Parse for AttrArgScope { - fn parse(&mut self, parser: &mut Parser) { - parser.with_next_expected_tokens( - |parser| parser.bump_or_recover(SyntaxKind::Ident, "Expected `key: value`", None), - &[SyntaxKind::Colon], - ); - - parser.with_next_expected_tokens( - |parser| parser.bump_or_recover(SyntaxKind::Colon, "Expected `key: value`", None), - &[SyntaxKind::Ident], - ); - - parser.bump_or_recover(SyntaxKind::Ident, "Expected `key: value`", None); + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + let msg = Some("expected attribute argument in the form `key: value`"); + + parser.set_scope_recovery_stack(&[SyntaxKind::Ident, SyntaxKind::Colon]); + if parser.find_and_pop(SyntaxKind::Ident, msg)? { + parser.bump(); + } + if parser.find_and_pop(SyntaxKind::Colon, msg)? { + parser.bump(); + } + if parser.find(SyntaxKind::Ident, msg)? { + parser.bump(); + } + Ok(()) } } @@ -117,8 +126,11 @@ define_scope! { Inheritance } impl super::Parse for DocCommentAttrScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Infallible; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::DocComment); parser.bump_if(SyntaxKind::Newline); + Ok(()) } } diff --git a/crates/parser2/src/parser/expr.rs b/crates/parser2/src/parser/expr.rs index 1a86d67016..53862fe2ea 100644 --- a/crates/parser2/src/parser/expr.rs +++ b/crates/parser2/src/parser/expr.rs @@ -1,18 +1,23 @@ +use std::convert::Infallible; +use unwrap_infallible::UnwrapInfallible; + use super::{ define_scope, expr_atom, param::{CallArgListScope, GenericArgListScope}, - token_stream::{LexicalToken, TokenStream}, - Checkpoint, Parser, + token_stream::TokenStream, + Checkpoint, ErrProof, Parser, Recovery, }; use crate::SyntaxKind; /// Parses expression. -pub fn parse_expr(parser: &mut Parser) -> bool { +pub fn parse_expr(parser: &mut Parser) -> Result<(), Recovery> { parse_expr_with_min_bp(parser, 0, true) } /// Parses expression except for `struct` initialization expression. -pub fn parse_expr_no_struct(parser: &mut Parser) -> bool { +pub fn parse_expr_no_struct( + parser: &mut Parser, +) -> Result<(), Recovery> { parse_expr_with_min_bp(parser, 0, false) } @@ -26,11 +31,8 @@ fn parse_expr_with_min_bp( parser: &mut Parser, min_bp: u8, allow_struct_init: bool, -) -> bool { - let (ok, checkpoint) = parse_expr_atom(parser, allow_struct_init); - if !ok { - return false; - } +) -> Result<(), Recovery> { + let checkpoint = parse_expr_atom(parser, allow_struct_init)?; loop { let is_trivia = parser.set_newline_as_trivia(true); @@ -46,12 +48,15 @@ fn parse_expr_with_min_bp( Some(_) => { match kind { SyntaxKind::LBracket => { - parser.parse(IndexExprScope::default(), Some(checkpoint)); + parser.parse_cp(IndexExprScope::default(), Some(checkpoint))?; continue; } SyntaxKind::LParen => { - if parser.parse(CallExprScope::default(), Some(checkpoint)).0 { + if parser + .parse_cp(CallExprScope::default(), Some(checkpoint)) + .is_ok() + { continue; } } @@ -59,7 +64,7 @@ fn parse_expr_with_min_bp( // `expr()`. SyntaxKind::Lt => { if is_call_expr(parser) { - parser.parse(CallExprScope::default(), Some(checkpoint)); + parser.parse_cp(CallExprScope::default(), Some(checkpoint))?; continue; } } @@ -67,7 +72,7 @@ fn parse_expr_with_min_bp( // `expr.method()` SyntaxKind::Dot => { if is_method_call(parser) { - parser.parse(MethodExprScope::default(), Some(checkpoint)); + parser.parse_cp(MethodExprScope::default(), Some(checkpoint))?; continue; } } @@ -82,41 +87,35 @@ fn parse_expr_with_min_bp( break; } - let (ok, _) = if kind == SyntaxKind::Dot { - parser.parse(FieldExprScope::default(), Some(checkpoint)) + if kind == SyntaxKind::Dot { + parser.parse_cp(FieldExprScope::default(), Some(checkpoint)) } else if is_assign(parser) { - parser.parse(AssignExprScope::default(), Some(checkpoint)) + parser.parse_cp(AssignExprScope::default(), Some(checkpoint)) } else if is_aug_assign(parser) { - parser.parse(AugAssignExprScope::default(), Some(checkpoint)) + parser.parse_cp(AugAssignExprScope::default(), Some(checkpoint)) } else { - parser.parse(BinExprScope::default(), Some(checkpoint)) - }; - - if !ok { - return false; - } - + parser.parse_cp(BinExprScope::default(), Some(checkpoint)) + }?; continue; } break; } - true + Ok(()) } fn parse_expr_atom( parser: &mut Parser, allow_struct_init: bool, -) -> (bool, Checkpoint) { +) -> Result> { match parser.current_kind() { Some(kind) if prefix_binding_power(kind).is_some() => { - parser.parse(UnExprScope::default(), None) + parser.parse_cp(UnExprScope::default(), None) } Some(_) => expr_atom::parse_expr_atom(parser, allow_struct_init), - None => { - parser.error_and_recover("expected expression", None); - (false, parser.checkpoint()) - } + None => parser + .error_and_recover("expected expression") + .map(|_| parser.checkpoint()), } } @@ -216,161 +215,170 @@ fn infix_binding_power(parser: &mut Parser) -> Option<(u8, u8 define_scope! { UnExprScope, UnExpr, Inheritance } impl super::Parse for UnExprScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.set_newline_as_trivia(false); let kind = parser.current_kind().unwrap(); let bp = prefix_binding_power(kind).unwrap(); parser.bump(); - parse_expr_with_min_bp(parser, bp, true); + parse_expr_with_min_bp(parser, bp, true) } } define_scope! { BinExprScope, BinExpr, Inheritance } impl super::Parse for BinExprScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.set_newline_as_trivia(false); let (_, rbp) = infix_binding_power(parser).unwrap(); bump_bin_op(parser); - parse_expr_with_min_bp(parser, rbp, false); + parse_expr_with_min_bp(parser, rbp, false) } } define_scope! { AugAssignExprScope, AugAssignExpr, Inheritance } impl super::Parse for AugAssignExprScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.set_newline_as_trivia(false); let (_, rbp) = infix_binding_power(parser).unwrap(); bump_aug_assign_op(parser); - parse_expr_with_min_bp(parser, rbp, false); + parse_expr_with_min_bp(parser, rbp, false) } } define_scope! { AssignExprScope, AssignExpr, Inheritance } impl super::Parse for AssignExprScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.set_newline_as_trivia(false); let (_, rbp) = infix_binding_power(parser).unwrap(); parser.bump_expected(SyntaxKind::Eq); - parse_expr_with_min_bp(parser, rbp, true); + parse_expr_with_min_bp(parser, rbp, true) } } -define_scope! { IndexExprScope, IndexExpr, Override(RBracket) } +define_scope! { IndexExprScope, IndexExpr, Override(RBracket, Newline) } impl super::Parse for IndexExprScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.set_newline_as_trivia(false); parser.bump_expected(SyntaxKind::LBracket); - parser.with_next_expected_tokens(parse_expr, &[SyntaxKind::RBracket]); - parser.bump_or_recover(SyntaxKind::RBracket, "expected `]`", None); + parse_expr(parser)?; + + if parser.find( + SyntaxKind::RBracket, + Some("missing closing `]` in index expression"), + )? { + parser.bump(); + } + Ok(()) } } define_scope! { CallExprScope, CallExpr, Inheritance } impl super::Parse for CallExprScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.set_newline_as_trivia(false); + + parser.set_scope_recovery_stack(&[SyntaxKind::LParen]); if parser.current_kind() == Some(SyntaxKind::Lt) { - parser.with_next_expected_tokens( - |parser| { - parser.parse(GenericArgListScope::default(), None); - }, - &[SyntaxKind::LParen], - ); + parser.parse(GenericArgListScope::default())?; } - if parser.current_kind() != Some(SyntaxKind::LParen) { - parser.error_and_recover("expected `(`", None); - return; + if parser.find_and_pop(SyntaxKind::LParen, None)? { + parser.parse(CallArgListScope::default())?; } - parser.parse(CallArgListScope::default(), None); + Ok(()) } } define_scope! { MethodExprScope, MethodCallExpr, Inheritance } impl super::Parse for MethodExprScope { - fn parse(&mut self, parser: &mut Parser) { - let is_trivia = parser.set_newline_as_trivia(true); - parser.bump_expected(SyntaxKind::Dot); + type Error = Recovery; - parser.bump_or_recover(SyntaxKind::Ident, "expected identifier", None); + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parser.bump_expected(SyntaxKind::Dot); + parser.set_newline_as_trivia(false); - parser.with_next_expected_tokens( - |parser| { - if parser.current_kind() == Some(SyntaxKind::Lt) { - parser.parse(GenericArgListScope::default(), None); - } - }, - &[SyntaxKind::LParen], - ); + parser.set_scope_recovery_stack(&[SyntaxKind::Ident, SyntaxKind::Lt, SyntaxKind::LParen]); + if parser.find_and_pop(SyntaxKind::Ident, None)? { + parser.bump(); + } - if parser.current_kind() != Some(SyntaxKind::LParen) { - parser.error_and_recover("expected `(`", None); - parser.set_newline_as_trivia(is_trivia); - return; + parser.pop_recovery_stack(); + if parser.current_kind() == Some(SyntaxKind::Lt) { + parser.parse(GenericArgListScope::default())?; } - parser.set_newline_as_trivia(is_trivia); - parser.parse(CallArgListScope::default(), None); + if parser.find_and_pop(SyntaxKind::LParen, None)? { + parser.parse(CallArgListScope::default())?; + } + Ok(()) } } define_scope! { FieldExprScope, FieldExpr, Inheritance } impl super::Parse for FieldExprScope { - fn parse(&mut self, parser: &mut Parser) { - let is_trivia = parser.set_newline_as_trivia(true); - parser.bump_expected(SyntaxKind::Dot); + type Error = Recovery; - match parser.current_token() { - Some(token) if token.syntax_kind() == SyntaxKind::Ident => { - parser.bump(); - } - Some(token) if token.syntax_kind() == SyntaxKind::Int => { - let text = token.text(); - if !text.chars().all(|c| c.is_ascii_digit()) { - parser - .error_and_recover("expected integer decimal literal without prefix", None); - return; - } - parser.bump(); - } - _ => { - parser.error_and_recover("expected identifier or integer literal", None); - } - } + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parser.bump_expected(SyntaxKind::Dot); - parser.set_newline_as_trivia(is_trivia); + parser.expect(&[SyntaxKind::Ident, SyntaxKind::Int], None)?; + parser.bump(); + Ok(()) } } define_scope! { pub(super) LShiftScope, LShift, Inheritance } impl super::Parse for LShiftScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Infallible; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::Lt); parser.bump_expected(SyntaxKind::Lt); + Ok(()) } } define_scope! { pub(super) RShiftScope, RShift, Inheritance } impl super::Parse for RShiftScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Infallible; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::Gt); parser.bump_expected(SyntaxKind::Gt); + Ok(()) } } define_scope! { pub(super) LtEqScope, LtEq, Inheritance } impl super::Parse for LtEqScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Infallible; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::Lt); parser.bump_expected(SyntaxKind::Eq); + Ok(()) } } define_scope! { pub(super) GtEqScope, GtEq, Inheritance } impl super::Parse for GtEqScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Infallible; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::Gt); parser.bump_expected(SyntaxKind::Eq); + Ok(()) } } @@ -414,18 +422,18 @@ fn bump_bin_op(parser: &mut Parser) { match parser.current_kind() { Some(SyntaxKind::Lt) => { if is_lshift(parser) { - parser.parse(LShiftScope::default(), None); + parser.parse(LShiftScope::default()).unwrap_infallible(); } else if is_lt_eq(parser) { - parser.parse(LtEqScope::default(), None); + parser.parse(LtEqScope::default()).unwrap_infallible(); } else { parser.bump(); } } Some(SyntaxKind::Gt) => { if is_rshift(parser) { - parser.parse(RShiftScope::default(), None); + parser.parse(RShiftScope::default()).unwrap_infallible(); } else if is_gt_eq(parser) { - parser.parse(GtEqScope::default(), None); + parser.parse(GtEqScope::default()).unwrap_infallible(); } else { parser.bump(); } @@ -445,12 +453,12 @@ fn bump_aug_assign_op(parser: &mut Parser) -> bool { true } (Some(Lt), Some(Lt), Some(Eq)) => { - parser.parse(LShiftScope::default(), None); + parser.parse(LShiftScope::default()).unwrap_infallible(); parser.bump_expected(SyntaxKind::Eq); true } (Some(Gt), Some(Gt), Some(Eq)) => { - parser.parse(RShiftScope::default(), None); + parser.parse(RShiftScope::default()).unwrap_infallible(); parser.bump_expected(SyntaxKind::Eq); true } @@ -464,43 +472,42 @@ fn is_call_expr(parser: &mut Parser) -> bool { let mut is_call = true; if parser.current_kind() == Some(SyntaxKind::Lt) { - is_call &= parser.parse(GenericArgListScope::default(), None).0; + // xxx `call` error recovery test: "without error" should only apply to base scope + is_call &= parser.parses_without_error(GenericArgListScope::default()) } if parser.current_kind() != Some(SyntaxKind::LParen) { false } else { - is_call && parser.parse(CallArgListScope::default(), None).0 + is_call && parser.parses_without_error(CallArgListScope::default()) } }) } fn is_method_call(parser: &mut Parser) -> bool { - parser.dry_run(|parser| { - let is_trivia = parser.set_newline_as_trivia(true); + let is_trivia = parser.set_newline_as_trivia(true); + let res = parser.dry_run(|parser| { if !parser.bump_if(SyntaxKind::Dot) { - parser.set_newline_as_trivia(is_trivia); return false; } if !parser.bump_if(SyntaxKind::Ident) { - parser.set_newline_as_trivia(is_trivia); return false; } if parser.current_kind() == Some(SyntaxKind::Lt) - && !parser.parse(GenericArgListScope::default(), None).0 + && !parser.parses_without_error(GenericArgListScope::default()) { - parser.set_newline_as_trivia(is_trivia); return false; } if parser.current_kind() != Some(SyntaxKind::LParen) { - parser.set_newline_as_trivia(is_trivia); false } else { parser.set_newline_as_trivia(is_trivia); - parser.parse(CallArgListScope::default(), None).0 + parser.parses_without_error(CallArgListScope::default()) } - }) + }); + parser.set_newline_as_trivia(is_trivia); + res } diff --git a/crates/parser2/src/parser/expr_atom.rs b/crates/parser2/src/parser/expr_atom.rs index 52fa229b1f..586f1934ad 100644 --- a/crates/parser2/src/parser/expr_atom.rs +++ b/crates/parser2/src/parser/expr_atom.rs @@ -1,3 +1,5 @@ +use std::convert::Infallible; + use rowan::Checkpoint; use crate::{ @@ -9,31 +11,32 @@ use super::{ define_scope, expr::{parse_expr, parse_expr_no_struct}, item::ItemScope, - parse_pat, + parse_list, parse_pat, stmt::parse_stmt, token_stream::TokenStream, - Parser, + ErrProof, Parser, Recovery, }; pub(super) fn parse_expr_atom( parser: &mut Parser, allow_record_init: bool, -) -> (bool, Checkpoint) { +) -> Result> { use SyntaxKind::*; match parser.current_kind() { - Some(IfKw) => parser.parse(IfExprScope::default(), None), - Some(MatchKw) => parser.parse(MatchExprScope::default(), None), - Some(LBrace) => parser.parse(BlockExprScope::default(), None), - Some(LParen) => parser.parse(ParenScope::default(), None), - Some(LBracket) => parser.parse(ArrayScope::default(), None), - Some(kind) if lit::is_lit(kind) => parser.parse(LitExprScope::default(), None), + Some(IfKw) => parser.parse_cp(IfExprScope::default(), None), + Some(MatchKw) => parser.parse_cp(MatchExprScope::default(), None), + Some(LBrace) => parser.parse_cp(BlockExprScope::default(), None), + Some(LParen) => parser.parse_cp(ParenScope::default(), None), + Some(LBracket) => parser.parse_cp(ArrayScope::default(), None), + Some(kind) if lit::is_lit(kind) => parser + .parse_cp(LitExprScope::default(), None) + .map_err(|e| e.into()), Some(kind) if path::is_path_segment(kind) => { - parser.parse(PathExprScope::new(allow_record_init), None) - } - _ => { - parser.error_and_recover("expected expression", None); - (false, parser.checkpoint()) + parser.parse_cp(PathExprScope::new(allow_record_init), None) } + _ => parser + .error_and_recover("expected expression") // xxx + .map(|()| parser.checkpoint()), } } @@ -52,7 +55,9 @@ define_scope! { ) } impl super::Parse for BlockExprScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::LBrace); loop { @@ -67,198 +72,189 @@ impl super::Parse for BlockExprScope { .map(SyntaxKind::is_item_head) .unwrap_or_default() { - parser.parse(ItemScope::default(), None); + parser.parse(ItemScope::default())?; continue; } - if !parse_stmt(parser, None) { - continue; - } + parse_stmt(parser)?; parser.set_newline_as_trivia(false); - if !parser.bump_if(SyntaxKind::Newline) - && parser.current_kind() != Some(SyntaxKind::RBrace) - { - parser.error_and_recover("expected newline after statement", None); - parser.bump_if(SyntaxKind::Newline); - } + parser.expect(&[SyntaxKind::Newline, SyntaxKind::RBrace], None)?; + parser.bump_if(SyntaxKind::Newline); } - if !parser.bump_if(SyntaxKind::RBrace) { - parser.error_and_bump_until("expected `}`", None, SyntaxKind::RBrace); - parser.bump_if(SyntaxKind::RBrace); + if parser.find(SyntaxKind::RBrace, Some("missing closing `}` for block"))? { + parser.bump(); } + Ok(()) } } define_scope! { IfExprScope, IfExpr, Inheritance } impl super::Parse for IfExprScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::IfKw); - parser.with_next_expected_tokens(parse_expr_no_struct, &[SyntaxKind::LBrace]); + parser.set_scope_recovery_stack(&[SyntaxKind::LBrace, SyntaxKind::ElseKw]); + parse_expr_no_struct(parser)?; - if parser.current_kind() != Some(SyntaxKind::LBrace) { - parser.error_and_recover("expected `{`", None); - return; + if parser.find_and_pop(SyntaxKind::LBrace, Some("missing `if` body"))? { + parser.parse(BlockExprScope::default())?; } - parser.parse(BlockExprScope::default(), None); if parser.current_kind() == Some(SyntaxKind::ElseKw) { - parser.bump_expected(SyntaxKind::ElseKw); - - parser.with_recovery_tokens( - |parser| { - if matches!( - parser.current_kind(), - Some(SyntaxKind::LBrace | SyntaxKind::IfKw) - ) { - parse_expr(parser); - } else { - parser.error_and_recover("expected `{` or `if` after `else`", None); - } - }, - &[SyntaxKind::LBrace, SyntaxKind::IfKw], - ); + parser.bump(); + + parser.expect(&[SyntaxKind::LBrace, SyntaxKind::IfKw], None)?; + parse_expr(parser)?; } + Ok(()) } } define_scope! { MatchExprScope, MatchExpr, Inheritance } impl super::Parse for MatchExprScope { - fn parse(&mut self, parser: &mut Parser) { - parser.bump_expected(SyntaxKind::MatchKw); + type Error = Recovery; - parser.with_next_expected_tokens(parse_expr_no_struct, &[SyntaxKind::LBrace]); + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parser.bump_expected(SyntaxKind::MatchKw); - if parser.current_kind() != Some(SyntaxKind::LBrace) { - parser.error_and_recover("expected `{`", None); - return; + parse_expr_no_struct(parser)?; + if parser.find(SyntaxKind::LBrace, None)? { + dbg!(parser.current_kind()); + parser.parse(MatchArmListScope::default())?; } - parser.parse(MatchArmListScope::default(), None); + Ok(()) } } define_scope! { MatchArmListScope, MatchArmList, Override(SyntaxKind::Newline, SyntaxKind::RBrace) } impl super::Parse for MatchArmListScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::LBrace); loop { parser.set_newline_as_trivia(true); - if parser.current_kind() == Some(SyntaxKind::RBrace) || parser.current_kind().is_none() - { + if parser.current_kind() == Some(SyntaxKind::RBrace) { break; } - parser.parse(MatchArmScope::default(), None); - + parser.parse(MatchArmScope::default())?; parser.set_newline_as_trivia(false); - if parser.current_kind() != Some(SyntaxKind::RBrace) { - parser.bump_or_recover( - SyntaxKind::Newline, - "expected newline after match arm", - None, - ); + + parser.expect(&[SyntaxKind::Newline, SyntaxKind::RBrace], None)?; + if !parser.bump_if(SyntaxKind::Newline) { + break; } } - - parser.bump_or_recover(SyntaxKind::RBrace, "expected `}`", None); + parser.bump_expected(SyntaxKind::RBrace); + Ok(()) } } define_scope! { MatchArmScope, MatchArm, Inheritance } impl super::Parse for MatchArmScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.set_newline_as_trivia(false); - parser.with_next_expected_tokens(parse_pat, &[SyntaxKind::FatArrow]); - parser.bump_or_recover(SyntaxKind::FatArrow, "expected `=>`", None); + parser.set_scope_recovery_stack(&[SyntaxKind::FatArrow]); + parse_pat(parser)?; - parser.with_next_expected_tokens(parse_expr, &[SyntaxKind::RBrace, SyntaxKind::Newline]); + if parser.find_and_pop(SyntaxKind::FatArrow, None)? { + parser.bump(); + } + parse_expr(parser) } } define_scope! { pub(crate) LitExprScope, LitExpr, Inheritance } impl super::Parse for LitExprScope { - fn parse(&mut self, parser: &mut Parser) { - parser.parse(lit::LitScope::default(), None); + type Error = Infallible; + + /// Caller is expected to verify that the next token is a literal. + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parser.parse(lit::LitScope::default()) } } define_scope! { PathExprScope{ allow_record_init: bool }, PathExpr, Inheritance } impl super::Parse for PathExprScope { - fn parse(&mut self, parser: &mut Parser) { - parser.with_recovery_tokens( - |parser| parser.parse(path::PathScope::default(), None), - &[SyntaxKind::LBrace], - ); + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + // xxx "expected an expression"? + parser.or_recover(|p| p.parse(path::PathScope::default()))?; + if parser.current_kind() == Some(SyntaxKind::LBrace) && self.allow_record_init { self.set_kind(SyntaxKind::RecordInitExpr); - parser.parse(RecordFieldListScope::default(), None); + parser.parse(RecordFieldListScope::default())?; } + Ok(()) } } define_scope! { RecordFieldListScope, RecordFieldList, Override(RBrace, Comma) } impl super::Parse for RecordFieldListScope { - fn parse(&mut self, parser: &mut Parser) { - parser.bump_expected(SyntaxKind::LBrace); - - if parser.bump_if(SyntaxKind::RBrace) { - return; - } - - parser.with_next_expected_tokens( - |parser| parser.parse(RecordFieldScope::default(), None), - &[SyntaxKind::RBrace, SyntaxKind::Comma], - ); - - while parser.bump_if(SyntaxKind::Comma) { - parser.with_next_expected_tokens( - |parser| { - parser.parse(RecordFieldScope::default(), None); - }, - &[SyntaxKind::RBrace, SyntaxKind::Comma], - ) - } - - parser.bump_or_recover(SyntaxKind::RBrace, "expected `}`", None); + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parse_list( + parser, + true, + (SyntaxKind::LBrace, SyntaxKind::RBrace), + |parser| parser.parse(RecordFieldScope::default()), + ) } } define_scope! { RecordFieldScope, RecordField, Inheritance } impl super::Parse for RecordFieldScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.set_newline_as_trivia(false); parser.bump_if(SyntaxKind::Ident); if parser.bump_if(SyntaxKind::Colon) { - parse_expr(parser); + parse_expr(parser)?; } + Ok(()) } } define_scope! { ParenScope, ParenExpr, Override(RParen, Comma) } impl super::Parse for ParenScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::LParen); - let is_trivia = parser.set_newline_as_trivia(true); if parser.bump_if(SyntaxKind::RParen) { self.set_kind(SyntaxKind::TupleExpr); - parser.set_newline_as_trivia(is_trivia); - return; + return Ok(()); } - parser.with_next_expected_tokens(parse_expr, &[SyntaxKind::RParen, SyntaxKind::Comma]); - while parser.bump_if(SyntaxKind::Comma) { - self.set_kind(SyntaxKind::TupleExpr); - parser.with_next_expected_tokens(parse_expr, &[SyntaxKind::RParen, SyntaxKind::Comma]); - } + loop { + if parser.bump_if(SyntaxKind::RParen) { + return Ok(()); + } + parse_expr(parser)?; + parser.expect(&[SyntaxKind::RParen, SyntaxKind::Comma], None)?; - parser.bump_or_recover(SyntaxKind::RParen, "expected `)`", None); - parser.set_newline_as_trivia(is_trivia); + if parser.bump_if(SyntaxKind::Comma) { + self.set_kind(SyntaxKind::TupleExpr); + continue; + } + break; + } + parser.bump_expected(SyntaxKind::RParen); + Ok(()) } } @@ -268,34 +264,45 @@ define_scope! { Override(RBracket, Comma, SemiColon) } impl super::Parse for ArrayScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::LBracket); if parser.bump_if(SyntaxKind::RBracket) { - return; + return Ok(()); } - parser.with_next_expected_tokens( - parse_expr, + parse_expr(parser)?; + parser.expect( &[ SyntaxKind::SemiColon, SyntaxKind::Comma, SyntaxKind::RBracket, ], - ); + None, + )?; if parser.bump_if(SyntaxKind::SemiColon) { self.set_kind(SyntaxKind::ArrayRepExpr); - parser.with_next_expected_tokens(parse_expr, &[SyntaxKind::RBracket]); + parse_expr(parser)?; } else { while parser.bump_if(SyntaxKind::Comma) { - parser.with_next_expected_tokens( - parse_expr, - &[SyntaxKind::Comma, SyntaxKind::RBracket], - ); + if parser.bump_if(SyntaxKind::RBracket) { + return Ok(()); + } + + parse_expr(parser)?; + parser.expect(&[SyntaxKind::Comma, SyntaxKind::RBracket], None)?; } } - parser.bump_or_recover(SyntaxKind::RBracket, "expected `]`", None); + if parser.find( + SyntaxKind::RBracket, + Some("missing closing `]` in array definition"), + )? { + parser.bump(); + } + Ok(()) } } diff --git a/crates/parser2/src/parser/func.rs b/crates/parser2/src/parser/func.rs index 1843ac6c79..6af9f122da 100644 --- a/crates/parser2/src/parser/func.rs +++ b/crates/parser2/src/parser/func.rs @@ -6,7 +6,7 @@ use super::{ param::{parse_generic_params_opt, parse_where_clause_opt, FuncParamListScope}, token_stream::TokenStream, type_::parse_type, - Parser, + ErrProof, Parser, Recovery, }; define_scope! { @@ -31,7 +31,9 @@ impl Default for FuncDefScope { } impl super::Parse for FuncScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::FnKw); match self.fn_def_scope { @@ -43,129 +45,100 @@ impl super::Parse for FuncScope { } } -fn parse_normal_fn_def_impl(parser: &mut Parser, allow_self: bool) { - parser.with_next_expected_tokens( - |parser| { - parser.bump_or_recover( - SyntaxKind::Ident, - "expected ident for the function name", - None, - ) - }, - &[ - SyntaxKind::Lt, - SyntaxKind::LParen, - SyntaxKind::Arrow, - SyntaxKind::WhereKw, - SyntaxKind::LBrace, - ], - ); - - parser.with_next_expected_tokens( - |parser| parse_generic_params_opt(parser, false), - &[ - SyntaxKind::LParen, - SyntaxKind::WhereKw, - SyntaxKind::Arrow, - SyntaxKind::LBrace, - ], - ); - - parser.with_next_expected_tokens( - |parser| { - if parser.current_kind() == Some(SyntaxKind::LParen) { - parser.parse(FuncParamListScope::new(allow_self), None); - } else { - parser.error_and_recover("expected `(` for the function arguments", None); - } - }, - &[SyntaxKind::Arrow, SyntaxKind::WhereKw, SyntaxKind::LBrace], - ); - - parser.with_next_expected_tokens( - |parser| { - if parser.bump_if(SyntaxKind::Arrow) { - parse_type(parser, None); - } - }, - &[SyntaxKind::LBrace, SyntaxKind::WhereKw], - ); - parser.with_next_expected_tokens(parse_where_clause_opt, &[SyntaxKind::LBrace]); +fn parse_normal_fn_def_impl( + parser: &mut Parser, + allow_self: bool, +) -> Result<(), Recovery> { + // xxx check where newlines are allowed + + parser.set_scope_recovery_stack(&[ + SyntaxKind::Ident, + SyntaxKind::Lt, + SyntaxKind::LParen, + SyntaxKind::Arrow, + SyntaxKind::WhereKw, + SyntaxKind::LBrace, + ]); + + if parser.find_and_pop(SyntaxKind::Ident, None)? { + parser.bump(); + } - if parser.current_kind() == Some(SyntaxKind::LBrace) { - parser.parse(BlockExprScope::default(), None); - } else { - parser.error_and_recover("function body is required", None) + parser.expect_and_pop_recovery_stack()?; + parse_generic_params_opt(parser, false)?; + + if parser.find_and_pop(SyntaxKind::LParen, None)? { + parser.parse(FuncParamListScope::new(allow_self))?; + } + + parser.expect_and_pop_recovery_stack()?; + if parser.bump_if(SyntaxKind::Arrow) { + parse_type(parser, None)?; + } + + parser.expect_and_pop_recovery_stack()?; + parse_where_clause_opt(parser)?; + + if parser.find_and_pop(SyntaxKind::LBrace, None)? { + parser.parse(BlockExprScope::default())?; } + Ok(()) } -fn parse_trait_fn_def_impl(parser: &mut Parser) { - parser.with_next_expected_tokens( - |parser| { - parser.bump_or_recover( - SyntaxKind::Ident, - "expected ident for the function name", - None, - ) - }, - &[SyntaxKind::Lt, SyntaxKind::LParen], - ); - - parser.with_next_expected_tokens( - |parser| parse_generic_params_opt(parser, false), - &[SyntaxKind::LParen], - ); - - parser.with_recovery_tokens( - |parser| { - if parser.current_kind() == Some(SyntaxKind::LParen) { - parser.parse(FuncParamListScope::new(true), None); - } else { - parser.error_and_recover("expected `(` for the function arguments", None); - } - }, - &[SyntaxKind::LBrace, SyntaxKind::Arrow, SyntaxKind::WhereKw], - ); - - parser.with_recovery_tokens( - |parser| { - if parser.bump_if(SyntaxKind::Arrow) { - parse_type(parser, None); - } - }, - &[SyntaxKind::LBrace, SyntaxKind::WhereKw], - ); - parser.with_recovery_tokens(parse_where_clause_opt, &[SyntaxKind::LBrace]); +fn parse_trait_fn_def_impl( + parser: &mut Parser, +) -> Result<(), Recovery> { + parser.set_scope_recovery_stack(&[ + SyntaxKind::Ident, + SyntaxKind::Lt, + SyntaxKind::LParen, + SyntaxKind::Arrow, + SyntaxKind::WhereKw, + SyntaxKind::LBrace, + ]); + + if parser.find_and_pop(SyntaxKind::Ident, None)? { + parser.bump(); + } + + parser.expect_and_pop_recovery_stack()?; + parse_generic_params_opt(parser, false)?; + + if parser.find_and_pop(SyntaxKind::LParen, None)? { + parser.parse(FuncParamListScope::new(true))?; + } + + parser.pop_recovery_stack(); + if parser.bump_if(SyntaxKind::Arrow) { + parse_type(parser, None)?; + } + + parser.pop_recovery_stack(); + parse_where_clause_opt(parser)?; if parser.current_kind() == Some(SyntaxKind::LBrace) { - parser.parse(BlockExprScope::default(), None); + parser.parse(BlockExprScope::default())?; } + Ok(()) } -fn parse_extern_fn_def_impl(parser: &mut Parser) { - parser.with_next_expected_tokens( - |parser| { - parser.bump_or_recover( - SyntaxKind::Ident, - "expected identifier for the function name", - None, - ) - }, - &[SyntaxKind::LParen], - ); - - parser.with_recovery_tokens( - |parser| { - if parser.current_kind() == Some(SyntaxKind::LParen) { - parser.parse(FuncParamListScope::default(), None); - } else { - parser.error_and_recover("expected `(` for the function arguments", None); - } - }, - &[SyntaxKind::Arrow], - ); +fn parse_extern_fn_def_impl( + parser: &mut Parser, +) -> Result<(), Recovery> { + parser.set_scope_recovery_stack(&[SyntaxKind::Ident, SyntaxKind::LParen, SyntaxKind::Arrow]); + if parser.find_and_pop(SyntaxKind::Ident, None)? { + parser.bump(); + } + + if parser.find_and_pop(SyntaxKind::LParen, None)? { + parser.parse(FuncParamListScope::new(true))?; + } + + parser.pop_recovery_stack(); if parser.bump_if(SyntaxKind::Arrow) { - parse_type(parser, None); + parse_type(parser, None)?; } + + Ok(()) } diff --git a/crates/parser2/src/parser/item.rs b/crates/parser2/src/parser/item.rs index 35f5458015..d0c9a415be 100644 --- a/crates/parser2/src/parser/item.rs +++ b/crates/parser2/src/parser/item.rs @@ -1,4 +1,6 @@ -use std::{cell::Cell, rc::Rc}; +use std::{cell::Cell, convert::Infallible, rc::Rc}; + +use unwrap_infallible::UnwrapInfallible; use crate::{parser::func::FuncScope, SyntaxKind}; @@ -7,11 +9,12 @@ use super::{ expr::parse_expr, func::FuncDefScope, param::{parse_generic_params_opt, parse_where_clause_opt, TraitRefScope}, + parse_list, struct_::RecordFieldDefListScope, token_stream::{LexicalToken, TokenStream}, type_::{parse_type, TupleTypeScope}, use_tree::UseTreeScope, - Parser, + ErrProof, Parser, Recovery, }; define_scope! { @@ -37,7 +40,9 @@ define_scope! { ) } impl super::Parse for ItemListScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { use crate::SyntaxKind::*; if self.inside_mod { @@ -51,13 +56,14 @@ impl super::Parse for ItemListScope { } if parser.current_kind().is_none() { if self.inside_mod { - parser.error("expected `}` to close the module"); + parser.error("`}` to close the module"); } break; } - parser.parse(ItemScope::default(), None); + parser.parse(ItemScope::default())?; } + Ok(()) } } @@ -68,14 +74,16 @@ define_scope! { Inheritance } impl super::Parse for ItemScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { use crate::SyntaxKind::*; - let mut checkpoint = attr::parse_attr_list(parser); + let mut checkpoint = attr::parse_attr_list(parser)?; let modifier_scope = ItemModifierScope::default(); let modifier = match parser.current_kind() { Some(kind) if kind.is_modifier_head() => { - let (_, modifier_checkpoint) = parser.parse(modifier_scope.clone(), None); + let modifier_checkpoint = parser.parse_cp(modifier_scope.clone(), None).unwrap(); checkpoint.get_or_insert(modifier_checkpoint); modifier_scope.kind.get() } @@ -83,7 +91,7 @@ impl super::Parse for ItemScope { }; if modifier.is_unsafe() && parser.current_kind() != Some(FnKw) { - parser.error("expected `fn` after `unsafe` keyword"); + parser.error("expected `fn` after `unsafe` keyword"); // xxx } else if modifier.is_pub() && matches!(parser.current_kind(), Some(ImplKw | ExternKw)) { let error_msg = format!( "`pub` can't be used for `{}`", @@ -93,51 +101,31 @@ impl super::Parse for ItemScope { } match parser.current_kind() { - Some(ModKw) => { - parser.parse(ModScope::default(), checkpoint); - } - Some(FnKw) => { - parser.parse(FuncScope::default(), checkpoint); - } - Some(StructKw) => { - parser.parse(super::struct_::StructScope::default(), checkpoint); - } - Some(ContractKw) => { - parser.parse(ContractScope::default(), checkpoint); - } - Some(EnumKw) => { - parser.parse(EnumScope::default(), checkpoint); - } - Some(TraitKw) => { - parser.parse(TraitScope::default(), checkpoint); - } - Some(ImplKw) => { - parser.parse(ImplScope::default(), checkpoint); - } - Some(UseKw) => { - parser.parse(UseScope::default(), checkpoint); - } - Some(ConstKw) => { - parser.parse(ConstScope::default(), checkpoint); - } - Some(ExternKw) => { - parser.parse(ExternScope::default(), checkpoint); - } - Some(TypeKw) => { - parser.parse(TypeAliasScope::default(), checkpoint); - } - tok => { - parser.error_and_recover(&format! {"expected item: but got {tok:?}"}, checkpoint) - } - } + Some(ModKw) => parser.parse_cp(ModScope::default(), checkpoint), + Some(FnKw) => parser.parse_cp(FuncScope::default(), checkpoint), + Some(StructKw) => parser.parse_cp(super::struct_::StructScope::default(), checkpoint), + Some(ContractKw) => parser.parse_cp(ContractScope::default(), checkpoint), + Some(EnumKw) => parser.parse_cp(EnumScope::default(), checkpoint), + Some(TraitKw) => parser.parse_cp(TraitScope::default(), checkpoint), + Some(ImplKw) => parser.parse_cp(ImplScope::default(), checkpoint), + Some(UseKw) => parser.parse_cp(UseScope::default(), checkpoint), + Some(ConstKw) => parser.parse_cp(ConstScope::default(), checkpoint), + Some(ExternKw) => parser.parse_cp(ExternScope::default(), checkpoint), + Some(TypeKw) => parser.parse_cp(TypeAliasScope::default(), checkpoint), + tok => parser + .error_and_recover(&format! {"expected item: but got {tok:?}"}) + .map(|_| checkpoint.unwrap_or_else(|| parser.checkpoint())), + }?; parser.set_newline_as_trivia(false); if parser.current_kind().is_some() && !parser.bump_if(SyntaxKind::Newline) { + // xxx parser.bump_or_recover( SyntaxKind::Newline, "expected newline after item definition", - checkpoint, ) + } else { + Ok(()) } } } @@ -148,7 +136,9 @@ define_scope! { Inheritance } impl super::Parse for ItemModifierScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Infallible; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { let mut modifier_kind = ModifierKind::None; loop { @@ -170,6 +160,7 @@ impl super::Parse for ItemModifierScope { _ => break, } } + Ok(()) } } @@ -217,339 +208,321 @@ impl ModifierKind { define_scope! { ModScope, Mod, Inheritance } impl super::Parse for ModScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::ModKw); - parser.with_next_expected_tokens( - |parser| { - parser.bump_or_recover( - SyntaxKind::Ident, - "expected identifier for the module name", - None, - ) - }, - &[SyntaxKind::LBrace], - ); - if parser.current_kind() == Some(SyntaxKind::LBrace) { - parser.parse(ItemListScope::new(true), None); - } else { - parser.error_and_recover("expected contract field definition", None); + + parser.set_scope_recovery_stack(&[SyntaxKind::Ident, SyntaxKind::LBrace]); + + if parser.find_and_pop(SyntaxKind::Ident, None)? { + parser.bump(); } + if parser.find_and_pop(SyntaxKind::LBrace, Some("`mod` body"))? { + parser.parse(ItemListScope::new(true))?; + } + Ok(()) } } define_scope! { ContractScope, Contract, Inheritance } impl super::Parse for ContractScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::ContractKw); - parser.with_next_expected_tokens( - |parser| { - parser.bump_or_recover( - SyntaxKind::Ident, - "expected identifier for the contract name", - None, - ) - }, - &[SyntaxKind::LBrace], - ); - - if parser.current_kind() == Some(SyntaxKind::LBrace) { - parser.parse(RecordFieldDefListScope::default(), None); - } else { - parser.error_and_recover("expected contract field definition", None); + parser.set_scope_recovery_stack(&[SyntaxKind::Ident, SyntaxKind::LBrace]); + + if parser.find_and_pop(SyntaxKind::Ident, None)? { + parser.bump(); + } + if parser.find_and_pop(SyntaxKind::LBrace, Some("contract field definition"))? { + parser.parse(RecordFieldDefListScope::default())?; } + Ok(()) } } define_scope! { EnumScope, Enum, Inheritance } impl super::Parse for EnumScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::EnumKw); - parser.with_next_expected_tokens( - |parser| { - parser.bump_or_recover( - SyntaxKind::Ident, - "expected identifier for the enum name", - None, - ); - }, - &[SyntaxKind::Lt, SyntaxKind::LBrace, SyntaxKind::WhereKw], - ); - - parser.with_next_expected_tokens( - |parser| parse_generic_params_opt(parser, false), - &[SyntaxKind::LBrace, SyntaxKind::WhereKw], - ); - - parser.with_next_expected_tokens(parse_where_clause_opt, &[SyntaxKind::LBrace]); - - if parser.current_kind() != Some(SyntaxKind::LBrace) { - parser.error_and_recover("expected enum body", None); - return; + parser.set_scope_recovery_stack(&[ + SyntaxKind::Ident, + SyntaxKind::Lt, + SyntaxKind::WhereKw, + SyntaxKind::LBrace, + ]); + + if parser.find_and_pop(SyntaxKind::Ident, None)? { + parser.bump(); } - parser.parse(VariantDefListScope::default(), None); - } -} + parser.pop_recovery_stack(); + parse_generic_params_opt(parser, false)?; -define_scope! { VariantDefListScope, VariantDefList, Override(RBrace, Newline) } -impl super::Parse for VariantDefListScope { - fn parse(&mut self, parser: &mut Parser) { - parser.bump_expected(SyntaxKind::LBrace); - parser.set_newline_as_trivia(true); - - loop { - if parser.current_kind() == Some(SyntaxKind::RBrace) || parser.current_kind().is_none() - { - break; - } - parser.parse(VariantDefScope::default(), None); + parser.pop_recovery_stack(); + parse_where_clause_opt(parser)?; - if !parser.bump_if(SyntaxKind::Comma) - && parser.current_kind() != Some(SyntaxKind::RBrace) - { - parser.error("expected comma after enum variant definition"); - } + if parser.find_and_pop(SyntaxKind::LBrace, Some("enum body definition"))? { + parser.parse(VariantDefListScope::default())?; } + Ok(()) + } +} - parser.bump_or_recover( - SyntaxKind::RBrace, - "expected the closing brace of the enum definition", - None, - ); +define_scope! { VariantDefListScope, VariantDefList, Override(Comma, RBrace) } +impl super::Parse for VariantDefListScope { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parse_list( + parser, + true, + (SyntaxKind::LBrace, SyntaxKind::RBrace), + |parser| parser.parse(VariantDefScope::default()), + ) } } define_scope! { VariantDefScope, VariantDef, Inheritance } impl super::Parse for VariantDefScope { - fn parse(&mut self, parser: &mut Parser) { - parser.bump_or_recover( - SyntaxKind::Ident, - "expected ident for the variant name", - None, - ); + type Error = Recovery; + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + // xxx check for keywords when bumping ident + parser.bump_or_recover(SyntaxKind::Ident, "expected ident for the variant name")?; if parser.current_kind() == Some(SyntaxKind::LParen) { - parser.parse(TupleTypeScope::default(), None); + parser.parse(TupleTypeScope::default())?; } else if parser.current_kind() == Some(SyntaxKind::LBrace) { - parser.parse(RecordFieldDefListScope::default(), None); + parser.parse(RecordFieldDefListScope::default())?; } + Ok(()) } } define_scope! { TraitScope, Trait, Inheritance } impl super::Parse for TraitScope { - fn parse(&mut self, parser: &mut Parser) { - parser.bump_expected(SyntaxKind::TraitKw); + type Error = Recovery; + + // xxx add TraitSignature syntax kind - parser.bump_or_recover( + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parser.bump_expected(SyntaxKind::TraitKw); + parser.set_scope_recovery_stack(&[ SyntaxKind::Ident, - "expected identifier for the trait name", - None, - ); + SyntaxKind::Lt, + SyntaxKind::Colon, + SyntaxKind::WhereKw, + SyntaxKind::LBrace, + ]); + if parser.find_and_pop( + SyntaxKind::Ident, + Some("expected identifier for the trait name"), + )? { + parser.bump(); + } - parser.with_next_expected_tokens( - |parser| parse_generic_params_opt(parser, false), - &[SyntaxKind::LBrace, SyntaxKind::WhereKw, SyntaxKind::Colon], - ); + parser.expect_and_pop_recovery_stack()?; + parse_generic_params_opt(parser, false)?; + parser.expect_and_pop_recovery_stack()?; if parser.current_kind() == Some(SyntaxKind::Colon) { - parser.with_next_expected_tokens( - |parser| { - parser.parse(SuperTraitListScope::default(), None); - }, - &[SyntaxKind::LBrace, SyntaxKind::WhereKw], - ); + parser.parse(SuperTraitListScope::default())?; } - parser.with_next_expected_tokens(parse_where_clause_opt, &[SyntaxKind::LBrace]); + parser.expect_and_pop_recovery_stack()?; + parse_where_clause_opt(parser)?; - if parser.current_kind() != Some(SyntaxKind::LBrace) { - parser.error_and_recover("expected trait body", None); - return; + if parser.find(SyntaxKind::LBrace, Some("missing trait body"))? { + parser.parse(TraitItemListScope::default())?; } - - parser.parse(TraitItemListScope::default(), None); + Ok(()) } } -define_scope! {SuperTraitListScope, SuperTraitList, Inheritance(Plus)} +define_scope! {SuperTraitListScope, SuperTraitList, Inheritance(Plus)} // xxx remove Plus? impl super::Parse for SuperTraitListScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::Colon); - parser.parse(TraitRefScope::default(), None); + parser.parse(TraitRefScope::default())?; while parser.bump_if(SyntaxKind::Plus) { - parser.parse(TraitRefScope::default(), None); + parser.parse(TraitRefScope::default())?; } + Ok(()) } } define_scope! { TraitItemListScope, TraitItemList, Override(RBrace, Newline, FnKw) } impl super::Parse for TraitItemListScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parse_fn_item_block(parser, false, FuncDefScope::TraitDef) } } -define_scope! { ImplScope, Impl, Inheritance } +define_scope! { ImplScope, Impl, Override(ForKw, LBrace) } impl super::Parse for ImplScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::ImplKw); - parser.with_recovery_tokens( - |parser| parse_generic_params_opt(parser, false), - &[SyntaxKind::LBrace, SyntaxKind::WhereKw, SyntaxKind::ForKw], - ); + + parse_generic_params_opt(parser, false)?; let is_impl_trait = parser.dry_run(|parser| { - parser.with_next_expected_tokens( - |parser| parse_type(parser, None), - &[SyntaxKind::LBrace, SyntaxKind::WhereKw, SyntaxKind::ForKw], - ); + // xxx reconsider, with new changes to parses_without_error + // We don't use `parses_without_error` here, because it's too strict; + // we only care whether the token after the trait/type is `for`. + let _ = parse_type(parser, None); parser.bump_if(SyntaxKind::ForKw) }); if is_impl_trait { self.set_kind(SyntaxKind::ImplTrait); - parser.with_next_expected_tokens( - |parser| { - parser.parse(TraitRefScope::default(), None); - }, - &[SyntaxKind::ForKw], - ); + parser.set_scope_recovery_stack(&[ + SyntaxKind::ForKw, + SyntaxKind::WhereKw, + SyntaxKind::LBrace, + ]); + + parser.parse(TraitRefScope::default())?; + parser.pop_recovery_stack(); parser.bump_expected(SyntaxKind::ForKw); - parser.with_next_expected_tokens( - |parser| { - parse_type(parser, None); - }, - &[SyntaxKind::LBrace, SyntaxKind::WhereKw], - ); } else { - parser.with_next_expected_tokens( - |parser| { - parse_type(parser, None); - }, - &[SyntaxKind::LBrace, SyntaxKind::WhereKw], - ) + parser.set_scope_recovery_stack(&[SyntaxKind::WhereKw, SyntaxKind::LBrace]); } - parser.with_next_expected_tokens(parse_where_clause_opt, &[SyntaxKind::LBrace]); - if parser.current_kind() != Some(SyntaxKind::LBrace) { - parser.error_and_recover("expected impl body", None); - return; - } + parse_type(parser, None)?; - if is_impl_trait { - parser.parse(ImplTraitItemListScope::default(), None); - } else { - parser.parse(ImplItemListScope::default(), None); + parser.expect_and_pop_recovery_stack()?; + parse_where_clause_opt(parser)?; + + if parser.find_and_pop(SyntaxKind::LBrace, Some("impl body"))? { + if is_impl_trait { + parser.parse(ImplTraitItemListScope::default())?; + } else { + parser.parse(ImplItemListScope::default())?; + } } + Ok(()) } } define_scope! { ImplTraitItemListScope, ImplTraitItemList, Override(RBrace, FnKw) } impl super::Parse for ImplTraitItemListScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parse_fn_item_block(parser, false, FuncDefScope::Impl) } } define_scope! { ImplItemListScope, ImplItemList, Override(RBrace, FnKw) } impl super::Parse for ImplItemListScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parse_fn_item_block(parser, true, FuncDefScope::Impl) } } define_scope! { UseScope, Use, Inheritance } impl super::Parse for UseScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::UseKw); - parser.parse(UseTreeScope::default(), None); + parser.parse(UseTreeScope::default()) } } define_scope! { ConstScope, Const, Inheritance } impl super::Parse for ConstScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::ConstKw); parser.set_newline_as_trivia(false); + parser.set_scope_recovery_stack(&[SyntaxKind::Ident, SyntaxKind::Colon, SyntaxKind::Eq]); - parser.with_next_expected_tokens( - |parser| parser.bump_or_recover(SyntaxKind::Ident, "expected identifier", None), - &[SyntaxKind::Colon, SyntaxKind::Eq], - ); - - parser.with_next_expected_tokens( - |parser| { - if parser.bump_if(SyntaxKind::Colon) { - parse_type(parser, None); - } else { - parser.error_and_recover("expected type annotation for `const`", None); - } - }, - &[SyntaxKind::Eq], - ); - - if parser.bump_if(SyntaxKind::Eq) { - parse_expr(parser); - } else { - parser.error_and_recover("expected `=` for const value definition", None); + if parser.find_and_pop(SyntaxKind::Ident, None)? { + parser.bump(); + } + if parser.find_and_pop(SyntaxKind::Colon, None)? { + parser.bump(); + parse_type(parser, None)?; } + if parser.find_and_pop( + SyntaxKind::Eq, + Some("expected `=` for const value definition"), + )? { + parser.bump(); + parse_expr(parser)?; + } + Ok(()) } } define_scope! { ExternScope, Extern, Inheritance } impl super::Parse for ExternScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::ExternKw); - if parser.current_kind() != Some(SyntaxKind::LBrace) { - parser.error_and_recover("expected extern block", None) + parser.set_scope_recovery_stack(&[SyntaxKind::LBrace]); + if parser.find(SyntaxKind::LBrace, Some("missing `extern` body"))? { + parser.parse(ExternItemListScope::default())?; } - - parser.parse(ExternItemListScope::default(), None); + Ok(()) } } -define_scope! { ExternItemListScope, ExternItemList, Override(RBrace, PubKw, UnsafeKw, FnKw) } +define_scope! { ExternItemListScope, ExternItemList, Override(PubKw, UnsafeKw, FnKw) } impl super::Parse for ExternItemListScope { - fn parse(&mut self, parser: &mut Parser) { - parse_fn_item_block(parser, true, FuncDefScope::Extern); + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parse_fn_item_block(parser, true, FuncDefScope::Extern) } } define_scope! { TypeAliasScope, TypeAlias, Inheritance } impl super::Parse for TypeAliasScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.set_newline_as_trivia(false); parser.bump_expected(SyntaxKind::TypeKw); - parser.with_next_expected_tokens( - |parser| { - parser.bump_or_recover( - SyntaxKind::Ident, - "expected identifier for type alias name", - None, - ); - }, - &[SyntaxKind::Lt, SyntaxKind::Eq], - ); - - parser.with_next_expected_tokens( - |parser| { - parse_generic_params_opt(parser, true); - }, - &[SyntaxKind::Eq], - ); - - if !parser.bump_if(SyntaxKind::Eq) { - parser.error_and_recover("expected `=` for type alias definition", None); - return; + parser.set_scope_recovery_stack(&[SyntaxKind::Ident, SyntaxKind::Lt, SyntaxKind::Eq]); + if parser.find_and_pop( + SyntaxKind::Ident, + Some("expected identifier for type alias name"), + )? { + parser.bump(); } - parse_type(parser, None); + parser.pop_recovery_stack(); + parse_generic_params_opt(parser, true)?; + + if parser.find_and_pop( + SyntaxKind::Eq, + Some("expected `=` for type alias definition"), + )? { + parser.bump(); + parse_type(parser, None)?; + } + Ok(()) } } @@ -562,7 +535,7 @@ fn parse_fn_item_block( parser: &mut Parser, allow_modifier: bool, fn_def_scope: FuncDefScope, -) { +) -> Result<(), Recovery> { parser.bump_expected(SyntaxKind::LBrace); loop { parser.set_newline_as_trivia(true); @@ -570,7 +543,7 @@ fn parse_fn_item_block( break; } - let mut checkpoint = attr::parse_attr_list(parser); + let mut checkpoint = attr::parse_attr_list(parser)?; let is_modifier = |kind: Option| match kind { Some(kind) => kind.is_modifier_head(), @@ -579,7 +552,9 @@ fn parse_fn_item_block( if is_modifier(parser.current_kind()) { if allow_modifier { - let (_, modifier_checkpoint) = parser.parse(ItemModifierScope::default(), None); + let modifier_checkpoint = parser + .parse_cp(ItemModifierScope::default(), None) + .unwrap_infallible(); checkpoint.get_or_insert(modifier_checkpoint); } else { while is_modifier(parser.current_kind()) { @@ -590,22 +565,20 @@ fn parse_fn_item_block( match parser.current_kind() { Some(SyntaxKind::FnKw) => { - parser.parse(FuncScope::new(fn_def_scope), checkpoint); + parser.parse_cp(FuncScope::new(fn_def_scope), checkpoint)?; + + parser.set_newline_as_trivia(false); + parser.expect( + &[SyntaxKind::Newline, SyntaxKind::RBrace], + Some("expected newline after item definition"), + )?; } _ => { - parser.error_msg_on_current_token("only `fn` is allowed in this block"); - parser.recover(checkpoint); + let proof = parser.error_msg_on_current_token("only `fn` is allowed in this block"); + parser.try_recover().map_err(|r| r.add_err_proof(proof))?; } } - - parser.set_newline_as_trivia(false); - if !matches!( - parser.current_kind(), - Some(SyntaxKind::RBrace | SyntaxKind::Newline) - ) { - parser.error_and_recover("expected newline after item definition", None) - } } - parser.bump_or_recover(SyntaxKind::RBrace, "expected `}` to close the block", None); + parser.bump_or_recover(SyntaxKind::RBrace, "expected `}` to close the block") } diff --git a/crates/parser2/src/parser/lit.rs b/crates/parser2/src/parser/lit.rs index a9a3c43ca9..f0b5717c35 100644 --- a/crates/parser2/src/parser/lit.rs +++ b/crates/parser2/src/parser/lit.rs @@ -1,3 +1,5 @@ +use std::convert::Infallible; + use crate::SyntaxKind; use super::{define_scope, token_stream::TokenStream, Parser}; @@ -8,13 +10,13 @@ define_scope! { Inheritance } impl super::Parse for LitScope { - fn parse(&mut self, parser: &mut Parser) { - match parser.current_kind() { - Some(kind) if is_lit(kind) => { - parser.bump(); - } - _ => parser.error_and_recover("expected literal", None), - } + type Error = Infallible; + + /// Caller is expected to verify that the next token is a literal. + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + assert!(is_lit(parser.current_kind().unwrap())); + parser.bump(); + Ok(()) } } diff --git a/crates/parser2/src/parser/mod.rs b/crates/parser2/src/parser/mod.rs index 87672d1eb0..5c340d42e8 100644 --- a/crates/parser2/src/parser/mod.rs +++ b/crates/parser2/src/parser/mod.rs @@ -1,7 +1,9 @@ -use std::collections::VecDeque; +use std::{collections::VecDeque, convert::Infallible}; pub(crate) use item::ItemListScope; + use rustc_hash::{FxHashMap, FxHashSet}; +use smallvec::SmallVec; use self::token_stream::{BackTrackableTokenStream, LexicalToken, TokenStream}; use crate::{syntax_node::SyntaxNode, GreenNode, ParseError, SyntaxKind, TextRange}; @@ -34,9 +36,8 @@ pub struct Parser { builder: rowan::GreenNodeBuilder<'static>, /// The second element holds `is_newline_trivia` of the parent. - parents: Vec<(Box, bool)>, + parents: Vec, errors: Vec, - is_err: bool, next_trivias: VecDeque, /// if `is_newline_trivia` is `true`, `Newline` is also regarded as a trivia @@ -44,11 +45,10 @@ pub struct Parser { is_newline_trivia: bool, current_pos: rowan::TextSize, + end_of_prev_token: rowan::TextSize, /// The dry run states which holds the each state of the parser when it /// enters dry run mode. dry_run_states: Vec>, - - auxiliary_recovery_set: FxHashMap, } impl Parser { @@ -59,12 +59,11 @@ impl Parser { builder: rowan::GreenNodeBuilder::new(), parents: Vec::new(), errors: Vec::new(), - is_err: false, current_pos: rowan::TextSize::from(0), + end_of_prev_token: rowan::TextSize::from(0), is_newline_trivia: true, next_trivias: VecDeque::new(), dry_run_states: Vec::new(), - auxiliary_recovery_set: FxHashMap::default(), } } @@ -73,6 +72,36 @@ impl Parser { self.peek_non_trivia() } + // xxx doc + pub fn current_token_range(&mut self) -> Option { + let mut start = self.current_pos; + if !self.is_newline_trivia { + for tok in &self.next_trivias { + if tok.syntax_kind() == SyntaxKind::Newline { + return Some(TextRange::new(start, start + tok.text_size())); + } + start += tok.text_size(); + } + } + + while let Some(next) = self.stream.peek().map(|tok| tok.syntax_kind()) { + if self.is_trivia(next) { + let next = self.stream.next().unwrap(); + start += next.text_size(); + + self.next_trivias.push_back(next); + continue; + } else { + return Some(TextRange::new( + start, + start + self.stream.peek().unwrap().text_size(), + )); + } + } + + None + } + /// Returns the current non-trivia token kind of the parser. pub fn current_kind(&mut self) -> Option { self.current_token().map(|tok| tok.syntax_kind()) @@ -101,6 +130,69 @@ impl Parser { (SyntaxNode::new_root(green_node), errors) } + pub fn set_scope_recovery_stack(&mut self, tokens: &[SyntaxKind]) { + let rec = self.scope_aux_recovery(); + rec.clear(); + rec.extend(tokens.iter().rev().copied()); + } + + pub fn pop_recovery_stack(&mut self) { + self.scope_aux_recovery().pop(); + } + + fn scope_aux_recovery(&mut self) -> &mut SmallVec<[SyntaxKind; 4]> { + &mut self.parents.last_mut().unwrap().aux_recovery_tokens + } + + pub fn expect_and_pop_recovery_stack(&mut self) -> Result<(), Recovery> { + let current = self.current_kind(); + let r = if current.is_some() && self.scope_aux_recovery().contains(¤t.unwrap()) { + Ok(()) + } else { + let pos = self.current_pos; + let (index, unexpected) = self.recover(None); + let proof = if unexpected.is_some() { + ErrProof(()) + } else { + let err = ParseError::expected(self.scope_aux_recovery(), None, pos); + self.add_error(err) + }; + self.allow_local_recovery(Err(Recovery(index, proof))) + }; + self.pop_recovery_stack(); + r + } + + // xxx + pub fn expect( + &mut self, + expected: &[SyntaxKind], + msg: Option<&str>, + ) -> Result<(), Recovery> { + let current = self.current_kind(); + + let aux = self.scope_aux_recovery(); + let truncate_to = aux.len(); + aux.extend_from_slice(expected); + + let res = if current.is_some() && aux.contains(¤t.unwrap()) { + Ok(()) + } else { + let pos = self.current_pos; + let (index, unexpected) = self.recover(None); + let proof = if unexpected.is_some() { + ErrProof(()) + } else { + self.add_error(ParseError::expected(expected, msg, pos)) + }; + self.pop_recovery_stack(); + self.allow_local_recovery(Err(Recovery(index, proof))) + }; + self.scope_aux_recovery().truncate(truncate_to); + + res + } + /// Adds the `recovery_tokens` as a temporary recovery token set. /// These tokens are used as a recovery token set in addition to scope's /// recovery token set. @@ -111,51 +203,13 @@ impl Parser { where F: FnOnce(&mut Self) -> R, { - for token in recovery_tokens { - self.add_recovery_token(*token); - } - + let truncate_to = self.scope_aux_recovery().len(); + self.scope_aux_recovery().extend_from_slice(recovery_tokens); let r = f(self); - - for token in recovery_tokens { - self.remove_recovery_token(*token); - } - + self.scope_aux_recovery().truncate(truncate_to); r } - /// Adds `expected_tokens` as a temporary recovery token set, the invokes - /// the `f` closure. If the `f` closure fails to parse, - /// `expected_tokens` are also used as a recovery token set in addition to - /// scope's recovery token set. - /// - /// If `current_token()` is not in `expected_tokens` after `f` returns, an - /// error is reported and try to recover with `expected_tokens` and scope's - /// recovery token set. - pub fn with_next_expected_tokens(&mut self, f: F, expected_tokens: &[SyntaxKind]) -> R - where - F: FnOnce(&mut Self) -> R, - { - for token in expected_tokens { - self.add_recovery_token(*token); - } - - let r = f(self); - - if self.current_kind().is_some() - && expected_tokens - .iter() - .all(|token| *token != self.current_kind().unwrap()) - { - self.recover(None); - } - - for token in expected_tokens { - self.remove_recovery_token(*token); - } - - r - } /// Invoke the scope to parse. The scope is wrapped up by the node specified /// by the scope. /// @@ -170,17 +224,69 @@ impl Parser { /// `true`. otherwise, the first element is `false`. /// * The second element of the return value is the checkpoint of the start /// of the node. - pub fn parse(&mut self, mut scope: T, checkpoint: Option) -> (bool, Checkpoint) + pub fn parse_cp( + &mut self, + mut scope: T, + checkpoint: Option, + ) -> Result + // xxx checkpoint handling where - T: Parse + 'static, + T: Parse + 'static, + E: XxxRecoveryThing, { - let mut is_err = std::mem::take(&mut self.is_err); let checkpoint = self.enter(scope.clone(), checkpoint); let start_checkpoint = self.checkpoint(); - scope.parse(self); + let res = scope.parse(self); + self.leave(checkpoint); + let res = self.allow_local_recovery(res); + res.map(|_| start_checkpoint) + } + + pub fn parse(&mut self, scope: T) -> Result<(), E> + where + T: Parse + 'static, + E: XxxRecoveryThing, + { + self.parse_cp(scope, None).map(|_| ()) + } + + // xxx do we ever want to use this? + pub fn parses_without_error(&mut self, mut scope: T) -> bool + where + T: Parse + 'static, + E: XxxRecoveryThing, + { + debug_assert!(self.is_dry_run()); + let checkpoint = self.enter(scope.clone(), None); + let r = scope.parse(self); + let is_err = self.leave(checkpoint); + r.is_ok() && !is_err + } + + // xxx remove? + pub fn parse_or_recover(&mut self, mut scope: T) -> Result<(), Recovery> + where + T: Parse + 'static, + { + let checkpoint = self.enter(scope.clone(), None); + let res = scope.parse(self); self.leave(checkpoint); - std::mem::swap(&mut self.is_err, &mut is_err); - (!is_err, start_checkpoint) + if let Err(err) = res { + let proof = self.add_error(err); + self.try_recover().map_err(|r| r.add_err_proof(proof))?; + } + Ok(()) + } + + pub fn or_recover(&mut self, f: F) -> Result<(), Recovery> + where + F: FnOnce(&mut Self) -> Result<(), ParseError>, + { + if let Err(err) = f(self) { + let proof = self.add_error(err); + self.try_recover().map_err(|r| r.add_err_proof(proof))?; + } + Ok(()) } #[doc(hidden)] @@ -195,7 +301,9 @@ impl Parser { if !self.parents.is_empty() { self.bump_trivias(); } - self.parents.push((Box::new(scope), self.is_newline_trivia)); + // xxx don't push current scope onto parents stack + self.parents + .push(ScopeEntry::new(Box::new(scope), self.is_newline_trivia)); // `is_newline_trivia` is always `true` when entering a scope. self.is_newline_trivia = true; checkpoint.unwrap_or_else(|| self.checkpoint()) @@ -203,10 +311,11 @@ impl Parser { #[doc(hidden)] /// Leave the scope and wrap up the checkpoint by the scope's node. + /// Returns `is_err` value for exited scope. // NOTE: This method is limited to testing and internal usage. - pub fn leave(&mut self, checkpoint: Checkpoint) { - let (scope, is_newline_trivia) = self.parents.pop().unwrap(); - self.is_newline_trivia = is_newline_trivia; + pub fn leave(&mut self, checkpoint: Checkpoint) -> bool { + let scope = self.parents.pop().unwrap(); + self.is_newline_trivia = scope.is_newline_trivia; // Ensure the trailing trivias are added to the current node if the current // scope is the root. @@ -216,9 +325,20 @@ impl Parser { if !self.is_dry_run() { self.builder - .start_node_at(checkpoint, scope.syntax_kind().into()); + .start_node_at(checkpoint, scope.scope.syntax_kind().into()); self.builder.finish_node(); } + scope.is_err + } + + pub fn add_error(&mut self, err: ParseError) -> ErrProof { + eprintln!( + "add_error: {err:?} {}", + std::backtrace::Backtrace::capture() + ); + self.parents.last_mut().unwrap().is_err = true; + self.errors.push(err); + ErrProof(()) } /// Add `msg` as an error to the error list, then bumps consecutive tokens @@ -228,33 +348,27 @@ impl Parser { /// node. /// * If checkpoint is `None`, the current branch is wrapped up by an error /// node. - pub fn error_and_recover(&mut self, msg: &str, checkpoint: Option) { - self.error(msg); - self.recover(checkpoint); + pub fn error_and_recover(&mut self, msg: &str) -> Result<(), Recovery> { + let proof = self.add_error(ParseError::Msg( + msg.into(), + TextRange::empty(self.end_of_prev_token), + )); + self.try_recover().map_err(|r| r.add_err_proof(proof)) } - /// Add `msg` as an error to the error list, then bumps consecutive tokens - /// until a `tok` is found or the end of the file is reached. - /// - /// * If checkpoint is `Some`, the marked branch is wrapped up by an error - /// node. - /// * If checkpoint is `None`, the current branch is wrapped up by an error - /// node. - pub fn error_and_bump_until( + // xxx check uses of error_and_recover + pub fn recover_and_error_if_no_skipped_tokens( &mut self, msg: &str, - checkpoint: Option, - kind: SyntaxKind, - ) { - let err_scope = self.error(msg); - let checkpoint = self.enter(err_scope, checkpoint); - loop { - if self.current_kind() == Some(kind) || self.current_kind().is_none() { - break; - } - self.bump() + ) -> Result<(), Recovery> { + let (index, unexpected) = self.recover(None); + if unexpected.is_none() { + self.add_error(ParseError::Msg( + msg.into(), + TextRange::empty(self.current_pos), + )); } - self.leave(checkpoint); + self.allow_local_recovery(Err(Recovery(index, ErrProof(())))) } /// Runs the parser in the dry run mode. @@ -268,10 +382,9 @@ impl Parser { self.stream.set_bt_point(); self.dry_run_states.push(DryRunState { pos: self.current_pos, + end_of_prev_token: self.end_of_prev_token, err_num: self.errors.len(), next_trivias: self.next_trivias.clone(), - auxiliary_recovery_set: self.auxiliary_recovery_set.clone(), - is_err: self.is_err, }); let r = f(self); @@ -281,9 +394,8 @@ impl Parser { let state = self.dry_run_states.pop().unwrap(); self.errors.truncate(state.err_num); self.current_pos = state.pos; + self.end_of_prev_token = state.end_of_prev_token; self.next_trivias = state.next_trivias; - self.auxiliary_recovery_set = state.auxiliary_recovery_set; - self.is_err = state.is_err; r } @@ -294,6 +406,7 @@ impl Parser { self.bump_trivias(); self.bump_raw(); + self.end_of_prev_token = self.current_pos; } /// Bumps the current token if the current token is the `expected` kind. @@ -301,7 +414,7 @@ impl Parser { /// # Panics /// Panics If the current token is not the `expected` kind. pub fn bump_expected(&mut self, expected: SyntaxKind) { - assert_eq!(self.current_kind(), Some(expected)); + assert_eq!(self.current_kind(), Some(expected), "expected {expected:?}"); self.bump(); } @@ -316,53 +429,88 @@ impl Parser { } } - /// Consumes tokens until a recovery token is found, and reports an error on any - /// unexpected tokens. - pub fn recover(&mut self, checkpoint: Option) { - let mut recovery_set: FxHashSet = FxHashSet::default(); - let mut scope_index = self.parents.len() - 1; - loop { - match self - .parents - .get(scope_index) - .map(|scope| scope.0.recovery_method()) - { - Some(RecoveryMethod::Inheritance(set)) => { - recovery_set.extend(set.iter()); - if scope_index == 0 { - break; - } - scope_index -= 1; - } - Some(RecoveryMethod::Override(set)) => { - recovery_set.extend(set.iter()); - break; - } + pub fn find( + &mut self, + kind: SyntaxKind, + msg: Option<&str>, + ) -> Result> { + self.scope_aux_recovery().push(kind); + self.find_and_pop(kind, msg) + } - None => break, + pub fn find_and_pop( + &mut self, + kind: SyntaxKind, + msg: Option<&str>, + ) -> Result> { + debug_assert_eq!(self.scope_aux_recovery().last(), Some(&kind)); + + let r = if self.current_kind() == Some(kind) { + Ok(true) + } else { + let pos = self.current_pos; + let r = self.try_recover(); + if self.current_kind() == Some(kind) { + Ok(true) + } else { + let proof = self.add_error(ParseError::expected(&[kind], msg, pos)); + r.map(|_| false).map_err(|rec| rec.add_err_proof(proof)) } - } + }; + self.scope_aux_recovery().pop(); + r + } - if !self.is_newline_trivia { - self.add_recovery_token(SyntaxKind::Newline); + pub fn try_recover(&mut self) -> Result<(), Recovery<()>> { + let (index, _) = self.recover(None); + self.allow_local_recovery(Err(Recovery(index, ()))) + } + + // xxx remove checkpoint arg? + /// Consumes tokens until a recovery token is found, and reports an error on any + /// unexpected tokens. + /// Returns the index of the scope that matched the recovery token. + fn recover( + &mut self, + checkpoint: Option, + ) -> (Option, Option) { + if !self.is_dry_run() { + eprintln!( + "recover! {:?} {:?} scopes: {:#?}", + self.current_kind(), + self.current_token().map(|t| t.text().to_string()), + self.parents + ); } let mut unexpected = None; let mut open_brackets_in_error = FxHashMap::default(); + let mut match_scope_index = None; while let Some(kind) = self.current_kind() { if kind.is_open_bracket_kind() { *open_brackets_in_error.entry(kind).or_insert(0) += 1; + } else if let Some(open_bracket) = kind.corresponding_open_bracket_kind() { + if open_brackets_in_error.get(&open_bracket).unwrap_or(&0) != &0 { + *open_brackets_in_error.get_mut(&open_bracket).unwrap() -= 1; + } } - if recovery_set.contains(&kind) || self.auxiliary_recovery_set.contains_key(&kind) { - if let Some(open_bracket) = kind.corresponding_open_bracket_kind() { - if open_brackets_in_error.get(&open_bracket).unwrap_or(&0) != &0 { - *open_brackets_in_error.get_mut(&open_bracket).unwrap() -= 1; - } else { - break; - } - } else { - break; + + if let Some((scope_index, _)) = self + .parents + .iter() + .enumerate() + .rev() + .find(|(_i, scope)| scope.is_recovery_match(kind)) + { + match_scope_index = Some(scope_index); + if !self.is_dry_run() { + eprintln!( + "recovered at {scope_index} on {kind:?}, {:#?}", + self.parents[scope_index] + ); } + break; } + if unexpected.is_none() { if !self.parents.is_empty() { self.bump_trivias(); @@ -372,26 +520,46 @@ impl Parser { checkpoint.unwrap_or_else(|| self.checkpoint()), )); } + if !self.is_dry_run() { + eprintln!( + "skipping {kind:?} {:?}", + self.current_token().unwrap().text() + ); + } self.bump(); } - if !self.is_newline_trivia { - self.remove_recovery_token(SyntaxKind::Newline); - } - if let Some((start_pos, checkpoint)) = unexpected { - self.is_err = true; if !self.is_dry_run() { self.builder .start_node_at(checkpoint, SyntaxKind::Error.into()); self.builder.finish_node(); - self.errors.push(ParseError { - range: TextRange::new(start_pos, self.current_pos), - msg: "unexpected syntax".to_string(), - }); + self.add_error(ParseError::Unexpected(TextRange::new( + start_pos, + self.current_pos, + ))); } } + + eprintln!("{}", std::backtrace::Backtrace::capture()); + ( + match_scope_index.map(ScopeIndex), + unexpected.map(|(start_pos, _)| start_pos), + ) + } + + // xxx + fn allow_local_recovery(&self, r: Result<(), E>) -> Result<(), E> { + match r { + Ok(()) => Ok(()), + Err(e) if e.is_local_recovery(self) => Ok(()), + _ => r, + } + } + + fn is_current_scope(&self, index: ScopeIndex) -> bool { + index.0 + 1 == self.parents.len() } /// Bumps the current token if the current token is the `expected` kind. @@ -401,11 +569,15 @@ impl Parser { &mut self, expected: SyntaxKind, msg: &str, - checkpoint: Option, - ) { + ) -> Result<(), Recovery> { if !self.bump_if(expected) { - self.error(msg); - self.recover(checkpoint); + let proof = self.add_error(ParseError::Msg( + msg.into(), + TextRange::empty(self.current_pos), + )); + self.try_recover().map_err(|r| r.add_err_proof(proof)) + } else { + Ok(()) } } @@ -496,21 +668,17 @@ impl Parser { } /// Add the `msg` to the error list, at `current_pos`. - fn error(&mut self, msg: &str) -> ErrorScope { - self.is_err = true; + fn error(&mut self, msg: &str) -> ErrProof { let pos = self.current_pos; - self.errors.push(ParseError { - range: TextRange::new(pos, pos), - msg: msg.to_string(), - }); - ErrorScope::default() + self.errors + .push(ParseError::Msg(msg.into(), TextRange::new(pos, pos))); + ErrProof(()) } /// Add the `msg` to the error list, on `current_token()`. /// Bumps trivias. - fn error_msg_on_current_token(&mut self, msg: &str) { + fn error_msg_on_current_token(&mut self, msg: &str) -> ErrProof { self.bump_trivias(); - self.is_err = true; let start = self.current_pos; let end = if let Some(current_token) = self.current_token() { start + current_token.text_size() @@ -518,24 +686,21 @@ impl Parser { start }; - self.errors.push(ParseError { - range: TextRange::new(start, end), - msg: msg.to_string(), - }); + self.add_error(ParseError::Msg(msg.into(), TextRange::new(start, end))) } + // xxx remove this or error_msg_on_current_token /// Wrap the current token in a `SyntaxKind::Error`, and add `msg` to the error list. fn unexpected_token_error(&mut self, msg: &str, checkpoint: Option) { let checkpoint = self.enter(ErrorScope::default(), checkpoint); - self.is_err = true; let start_pos = self.current_pos; self.bump(); - self.errors.push(ParseError { - range: TextRange::new(start_pos, self.current_pos), - msg: msg.to_string(), - }); + self.add_error(ParseError::Msg( + msg.into(), + TextRange::new(start_pos, self.current_pos), + )); self.leave(checkpoint); } @@ -547,19 +712,6 @@ impl Parser { fn is_trivia(&self, kind: SyntaxKind) -> bool { kind.is_trivia() || (self.is_newline_trivia && kind == SyntaxKind::Newline) } - - fn add_recovery_token(&mut self, token: SyntaxKind) { - *self.auxiliary_recovery_set.entry(token).or_insert(0) += 1; - } - - fn remove_recovery_token(&mut self, token: SyntaxKind) { - if let Some(num) = self.auxiliary_recovery_set.get_mut(&token) { - *num -= 1; - } - if self.auxiliary_recovery_set.get(&token) == Some(&0) { - self.auxiliary_recovery_set.remove(&token); - } - } } pub trait ParsingScope { @@ -570,18 +722,63 @@ pub trait ParsingScope { } pub trait Parse: ParsingScope + Clone { + type Error; + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error>; +} + +pub trait ParseInfalible: ParsingScope + Clone { fn parse(&mut self, parser: &mut Parser); } +#[derive(Debug, Copy, Clone)] +pub struct ScopeIndex(usize); +#[derive(Debug, Copy, Clone)] +pub struct Recovery(Option, T); +impl Recovery<()> { + pub fn add_err_proof(self, proof: ErrProof) -> Recovery { + Recovery(self.0, proof) + } +} + +#[derive(Debug)] +pub struct ErrProof(()); + +impl From for Recovery { + fn from(_value: Infallible) -> Self { + unreachable!() + } +} + +impl From> for Recovery<()> { + fn from(r: Recovery) -> Self { + Recovery(r.0, ()) + } +} + +pub trait XxxRecoveryThing { + fn is_local_recovery(&self, _parser: &Parser) -> bool { + false + } +} +impl XxxRecoveryThing for ParseError {} +impl XxxRecoveryThing for Infallible {} +impl XxxRecoveryThing for Recovery { + fn is_local_recovery(&self, parser: &Parser) -> bool { + self.0 + .as_ref() + .map(|i| parser.is_current_scope(*i)) + .unwrap_or(false) + } +} + struct DryRunState { /// The text position is the position when the dry run started. pos: rowan::TextSize, + end_of_prev_token: rowan::TextSize, /// The number of errors when the dry run started. err_num: usize, /// The stored trivias when the dry run started. next_trivias: VecDeque, - auxiliary_recovery_set: FxHashMap, - is_err: bool, } /// Represents the recovery method of the current scope. @@ -603,6 +800,46 @@ impl RecoveryMethod { fn override_(tokens: &[SyntaxKind]) -> Self { Self::Override(tokens.iter().copied().collect()) } + + fn recovery_set(&self) -> &FxHashSet { + match self { + RecoveryMethod::Inheritance(set) => set, + RecoveryMethod::Override(set) => set, + } + } +} + +struct ScopeEntry { + scope: Box, + is_newline_trivia: bool, + is_err: bool, + aux_recovery_tokens: SmallVec<[SyntaxKind; 4]>, +} +impl ScopeEntry { + fn new(scope: Box, is_newline_trivia: bool) -> Self { + Self { + scope, + is_newline_trivia, + is_err: false, + aux_recovery_tokens: SmallVec::new(), + } + } + + fn is_recovery_match(&self, kind: SyntaxKind) -> bool { + self.scope.recovery_method().recovery_set().contains(&kind) + || self.aux_recovery_tokens.contains(&kind) + } +} + +impl std::fmt::Debug for ScopeEntry { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ScopeEntry") + .field("scope", &self.scope.syntax_kind()) + .field("is_newline_trivia", &self.is_newline_trivia) + .field("is_err", &self.is_err) + .field("aux_recovery_tokens", &self.aux_recovery_tokens) + .finish() + } } trait TextSize { @@ -726,3 +963,77 @@ macro_rules! define_scope_struct { use define_scope; #[doc(hidden)] use define_scope_struct; + +// xxx move +/// Parse a comma-separated list of elements, with trailing commas allowed. +/// Panics if `parser.current_kind() != Some(brackets.0)` +fn parse_list( + parser: &mut Parser, + newline_delim: bool, + brackets: (SyntaxKind, SyntaxKind), + element: F, +) -> Result<(), Recovery> +where + F: Fn(&mut Parser) -> Result<(), Recovery>, +{ + parser.bump_expected(brackets.0); + + loop { + if parser.bump_if(brackets.1) { + return Ok(()); + } + element(parser)?; + + dbg!(parser.current_token().map(|t| t.text().to_string())); + if parser.current_kind() != Some(SyntaxKind::Comma) + && parser.current_kind() != Some(brackets.1) + { + // Recover gracefully if list elements are separated by newline instead of comma + let nt = parser.set_newline_as_trivia(false); + let newline = parser.current_kind() == Some(SyntaxKind::Newline) || { + parser.with_recovery_tokens( + |parser| { + // xxx clean + let pos = parser.current_pos; + let (index, unexpected) = parser.recover(None); + if unexpected.is_none() { + parser.add_error(ParseError::expected( + &[brackets.1, SyntaxKind::Comma], + None, + pos, + )); + } + parser.allow_local_recovery(Err(Recovery(index, ErrProof(())))) + }, + &[SyntaxKind::Newline, SyntaxKind::Comma, brackets.1], + )?; + parser.current_kind() == Some(SyntaxKind::Newline) + }; + parser.set_newline_as_trivia(nt); + + if newline { + dbg!(newline_delim); + parser.add_error(ParseError::expected( + &[brackets.1, SyntaxKind::Comma], + None, + parser.current_pos, + )); + if !newline_delim { + return Ok(()); + } + } else { + parser.expect(&[brackets.1, SyntaxKind::Comma], None)?; + if !parser.bump_if(SyntaxKind::Comma) { + break; + } + } + } else if !parser.bump_if(SyntaxKind::Comma) { + dbg!("2", parser.current_kind()); + parser.expect(&[brackets.1], None)?; + break; + } + } + parser.bump_expected(brackets.1); + + Ok(()) +} diff --git a/crates/parser2/src/parser/param.rs b/crates/parser2/src/parser/param.rs index 428b664c3a..10af889769 100644 --- a/crates/parser2/src/parser/param.rs +++ b/crates/parser2/src/parser/param.rs @@ -1,13 +1,16 @@ -use crate::SyntaxKind; +use std::convert::Infallible; + +use crate::{ParseError, SyntaxKind}; use super::{ define_scope, expr::parse_expr, expr_atom::{BlockExprScope, LitExprScope}, + parse_list, path::PathScope, token_stream::TokenStream, type_::{is_type_start, parse_type}, - Parser, + ErrProof, Parser, Recovery, }; define_scope! { @@ -16,24 +19,15 @@ define_scope! { Override(RParen, Comma) } impl super::Parse for FuncParamListScope { - fn parse(&mut self, parser: &mut Parser) { - parser.bump_expected(SyntaxKind::LParen); - if parser.bump_if(SyntaxKind::RParen) { - return; - } - - parser.with_next_expected_tokens( - |parser| parser.parse(FnParamScope::new(self.allow_self), None), - &[SyntaxKind::Comma, SyntaxKind::RParen], - ); - while parser.bump_if(SyntaxKind::Comma) { - parser.with_next_expected_tokens( - |parser| parser.parse(FnParamScope::new(false), None), - &[SyntaxKind::Comma, SyntaxKind::RParen], - ); - } - - parser.bump_or_recover(SyntaxKind::RParen, "expected closing `)`", None); + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parse_list( + parser, + false, + (SyntaxKind::LParen, SyntaxKind::RParen), + |parser| parser.parse(FnParamScope::new(self.allow_self)), + ) } } @@ -43,120 +37,124 @@ define_scope! { Inheritance } impl super::Parse for FnParamScope { - fn parse(&mut self, parser: &mut Parser) { - parser.bump_if(SyntaxKind::MutKw); + type Error = Recovery; - if !self.allow_self && parser.current_kind() == Some(SyntaxKind::SelfKw) { - parser.error_and_recover("self is not allowed here", None); - return; - } - - let is_self = parser.with_recovery_tokens( - |parser| match parser.current_kind() { - Some(SyntaxKind::SelfKw) => { - if self.allow_self { - parser.bump_expected(SyntaxKind::SelfKw); - true - } else { - unreachable!() - } + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parser.bump_if(SyntaxKind::MutKw); + parser.expect( + &[ + SyntaxKind::SelfKw, + SyntaxKind::Ident, + SyntaxKind::Underscore, + ], + None, + )?; + + match parser.current_kind() { + Some(SyntaxKind::SelfKw) => { + if !self.allow_self { + parser.error_msg_on_current_token("`self` is not allowed here"); } - Some(SyntaxKind::Ident | SyntaxKind::Underscore) => parser - .with_next_expected_tokens( - |parser| { - parser.bump(); - if !parser.bump_if(SyntaxKind::Ident) { - parser.bump_if(SyntaxKind::Underscore); - } - false - }, - &[SyntaxKind::Colon], - ), - _ => { - parser.error_and_recover("expected identifier for argument name", None); - false + parser.bump_expected(SyntaxKind::SelfKw); + if parser.bump_if(SyntaxKind::Colon) { + parse_type(parser, None)?; } - }, - &[SyntaxKind::Colon], - ); - - if is_self { - if parser.bump_if(SyntaxKind::Colon) { - parse_type(parser, None); } - } else { - parser.bump_or_recover(SyntaxKind::Colon, "expected `:` after argument name", None); - parse_type(parser, None); - } + Some(SyntaxKind::Ident | SyntaxKind::Underscore) => { + parser.bump(); + + parser.expect( + &[SyntaxKind::Ident, SyntaxKind::Underscore, SyntaxKind::Colon], + None, + )?; + if !parser.bump_if(SyntaxKind::Ident) { + parser.bump_if(SyntaxKind::Underscore); + } + if parser.find( + SyntaxKind::Colon, + Some("missing type bound for fn parameter"), + )? { + parser.bump(); + parse_type(parser, None)?; + } + } + _ => unreachable!(), // only reachable if a recovery token is added + }; + Ok(()) } } define_scope! { pub(crate) GenericParamListScope {disallow_trait_bound: bool}, GenericParamList, - Override(Gt) + Override(Comma, Gt) } impl super::Parse for GenericParamListScope { - fn parse(&mut self, parser: &mut Parser) { - parser.bump_expected(SyntaxKind::Lt); - if parser.bump_if(SyntaxKind::Gt) { - return; - } + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parse_list(parser, false, (SyntaxKind::Lt, SyntaxKind::Gt), |parser| { + parser.expect( + &[SyntaxKind::Ident, SyntaxKind::ConstKw, SyntaxKind::Gt], + None, + )?; + match parser.current_kind() { + Some(SyntaxKind::ConstKw) => parser.parse(ConstGenericParamScope::default()), + Some(SyntaxKind::Ident) => { + parser.parse(TypeGenericParamScope::new(self.disallow_trait_bound)) + } + Some(SyntaxKind::Gt) => Ok(()), + _ => unreachable!(), + } + }) + } +} - parser.parse(GenericParamScope::new(self.disallow_trait_bound), None); - while parser.bump_if(SyntaxKind::Comma) { - parser.parse(GenericParamScope::new(self.disallow_trait_bound), None); +define_scope! { + ConstGenericParamScope, + ConstGenericParam, + Inheritance +} +impl super::Parse for ConstGenericParamScope { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parser.set_newline_as_trivia(false); + parser.bump_expected(SyntaxKind::ConstKw); + + parser.set_scope_recovery_stack(&[SyntaxKind::Ident, SyntaxKind::Colon]); + if parser.find_and_pop(SyntaxKind::Ident, None)? { + parser.bump(); + } + if parser.find_and_pop(SyntaxKind::Colon, None)? { + parser.bump(); + parse_type(parser, None)?; } - parser.bump_or_recover(SyntaxKind::Gt, "expected closing `>`", None); + // parse trait bound even though it's not allowed (checked in hir) + if parser.current_kind() == Some(SyntaxKind::Colon) { + parser.parse(TypeBoundListScope::new(true))?; + } + Ok(()) } } define_scope! { - GenericParamScope {disallow_trait_bound: bool}, + TypeGenericParamScope {disallow_trait_bound: bool}, TypeGenericParam, - Inheritance(Comma) + Inheritance } -impl super::Parse for GenericParamScope { - fn parse(&mut self, parser: &mut Parser) { - parser.set_newline_as_trivia(false); - let is_const = parser.bump_if(SyntaxKind::ConstKw); - if is_const { - self.set_kind(SyntaxKind::ConstGenericParam); - } - parser.with_next_expected_tokens( - |parser| { - if is_const { - parser.with_next_expected_tokens( - |parser| { - if !parser.bump_if(SyntaxKind::Ident) { - parser.error_and_recover("expected const parameter", None); - } - }, - &[SyntaxKind::Colon], - ); - - if !parser.bump_if(SyntaxKind::Colon) { - parser.error_and_recover("expected `:` after const parameter", None); - return; - } - parse_type(parser, None); +impl super::Parse for TypeGenericParamScope { + type Error = Recovery; - parser.set_newline_as_trivia(true); - } else { - if !parser.bump_if(SyntaxKind::Ident) { - parser.error_and_recover("expected type parameter", None); - } - - if parser.current_kind() == Some(SyntaxKind::Colon) { - parser.parse(TypeBoundListScope::new(self.disallow_trait_bound), None); - } + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parser.set_newline_as_trivia(false); + parser.bump_expected(SyntaxKind::Ident); - parser.set_newline_as_trivia(true); - } - }, - &[SyntaxKind::Comma, SyntaxKind::Gt], - ); + if parser.current_kind() == Some(SyntaxKind::Colon) { + parser.parse(TypeBoundListScope::new(self.disallow_trait_bound))?; + } + Ok(()) } } @@ -166,14 +164,17 @@ define_scope! { Inheritance(Plus) } impl super::Parse for TypeBoundListScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::Colon); - parser.parse(TypeBoundScope::new(self.disallow_trait_bound), None); + parser.parse(TypeBoundScope::new(self.disallow_trait_bound))?; while parser.current_kind() == Some(SyntaxKind::Plus) { parser.bump_expected(SyntaxKind::Plus); - parser.parse(TypeBoundScope::new(self.disallow_trait_bound), None); + parser.parse(TypeBoundScope::new(self.disallow_trait_bound))?; } + Ok(()) } } @@ -183,41 +184,49 @@ define_scope! { Inheritance } impl super::Parse for TypeBoundScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { let is_type_kind = matches!( parser.current_kind(), Some(SyntaxKind::LParen | SyntaxKind::Star) ); if is_type_kind { - parse_kind_bound(parser); + parse_kind_bound(parser) } else { if self.disallow_trait_bound { - parser.error_and_recover("trait bounds are not allowed here", None); - return; + return parser.error_and_recover("trait bounds are not allowed here"); } - parser.parse(TraitRefScope::default(), None); + parser.parse(TraitRefScope::default()) } } } -fn parse_kind_bound(parser: &mut Parser) { +fn parse_kind_bound(parser: &mut Parser) -> Result<(), Recovery> { let checkpoint = parser.checkpoint(); let is_newline_trivia = parser.set_newline_as_trivia(false); + parser.expect(&[SyntaxKind::Star, SyntaxKind::LParen], None)?; + if parser.bump_if(SyntaxKind::LParen) { - parse_kind_bound(parser); - parser.bump_or_recover(SyntaxKind::RParen, "expected closing `)`", None); + parse_kind_bound(parser)?; + if parser.find(SyntaxKind::RParen, None)? { + parser.bump(); + } } else if parser.current_kind() == Some(SyntaxKind::Star) { - parser.parse(KindBoundMonoScope::default(), None); + parser.parse(KindBoundMonoScope::default())?; } else { - parser.error_and_recover("expected `*` or `(`", None); + // guaranteed by `expected`, unless other recovery + // other tokens are added to the current scope + unreachable!(); } if parser.current_kind() == Some(SyntaxKind::Arrow) { - parser.parse(KindBoundAbsScope::default(), checkpoint.into()); + parser.parse_cp(KindBoundAbsScope::default(), checkpoint.into())?; } parser.set_newline_as_trivia(is_newline_trivia); + Ok(()) } define_scope! { @@ -226,8 +235,11 @@ define_scope! { Inheritance } impl super::Parse for KindBoundMonoScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Infallible; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::Star); + Ok(()) } } @@ -237,9 +249,11 @@ define_scope! { Inheritance } impl super::Parse for KindBoundAbsScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::Arrow); - parse_kind_bound(parser); + parse_kind_bound(parser) } } @@ -249,11 +263,20 @@ define_scope! { Inheritance } impl super::Parse for TraitRefScope { - fn parse(&mut self, parser: &mut Parser) { - parser.parse(PathScope::default(), None); + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + // xxx add test that triggers this + parser.or_recover(|parser| { + parser.parse(PathScope::default()).map_err(|_| { + ParseError::expected(&[SyntaxKind::TraitRef], None, parser.current_pos) + }) + })?; + if parser.current_kind() == Some(SyntaxKind::Lt) { - parser.parse(GenericArgListScope::default(), None); + parser.parse(GenericArgListScope::default())?; } + Ok(()) } } @@ -263,143 +286,167 @@ define_scope! { Override(Gt, Comma) } impl super::Parse for GenericArgListScope { - fn parse(&mut self, parser: &mut Parser) { - parser.bump_expected(SyntaxKind::Lt); + type Error = Recovery; - if parser.bump_if(SyntaxKind::Gt) { - return; - } - - parser.parse(GenericArgScope::default(), None); - while parser.bump_if(SyntaxKind::Comma) { - parser.parse(GenericArgScope::default(), None); - } - - parser.bump_or_recover(SyntaxKind::Gt, "expected closing `>`", None); + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parse_list(parser, false, (SyntaxKind::Lt, SyntaxKind::Gt), |parser| { + parser.parse(GenericArgScope::default()) + }) } } define_scope! { GenericArgScope, TypeGenericArg, - Inheritance + Override() } impl super::Parse for GenericArgScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.set_newline_as_trivia(false); - parser.with_next_expected_tokens( - |parser| { - match parser.current_kind() { - Some(SyntaxKind::LBrace) => { - self.set_kind(SyntaxKind::ConstGenericArg); - parser.parse(BlockExprScope::default(), None); - } + match parser.current_kind() { + Some(SyntaxKind::LBrace) => { + self.set_kind(SyntaxKind::ConstGenericArg); + parser.parse(BlockExprScope::default())?; + } - Some(kind) if kind.is_literal_leaf() => { - self.set_kind(SyntaxKind::ConstGenericArg); - parser.parse(LitExprScope::default(), None); - } + Some(kind) if kind.is_literal_leaf() => { + self.set_kind(SyntaxKind::ConstGenericArg); + parser.parse(LitExprScope::default())?; + } - _ => { - parse_type(parser, None); - if parser.current_kind() == Some(SyntaxKind::Colon) { - parser.error_and_recover("type bounds are not allowed here", None); - } - } + _ => { + parse_type(parser, None)?; + if parser.current_kind() == Some(SyntaxKind::Colon) { + parser.error_and_recover("type bounds are not allowed here")?; } - parser.set_newline_as_trivia(true); - }, - &[SyntaxKind::Comma, SyntaxKind::Gt], - ); + } + } + Ok(()) } } define_scope! { pub(crate) CallArgListScope, CallArgList, Override(RParen, Comma) } impl super::Parse for CallArgListScope { - fn parse(&mut self, parser: &mut Parser) { - parser.bump_expected(SyntaxKind::LParen); - - if parser.bump_if(SyntaxKind::RParen) { - return; - } - - parser.parse(CallArgScope::default(), None); - while parser.bump_if(SyntaxKind::Comma) { - parser.parse(CallArgScope::default(), None); - } - - parser.bump_or_recover(SyntaxKind::RParen, "expected closing `)`", None); + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parse_list( + parser, + false, + (SyntaxKind::LParen, SyntaxKind::RParen), + |parser| parser.parse(CallArgScope::default()), + ) } } -define_scope! { CallArgScope, CallArg, Inheritance } +define_scope! { CallArgScope, CallArg, Override(Comma, RParen) } impl super::Parse for CallArgScope { - fn parse(&mut self, parser: &mut Parser) { - parser.with_next_expected_tokens( - |parser| { - parser.set_newline_as_trivia(false); - let has_label = parser.dry_run(|parser| { - parser.bump_if(SyntaxKind::Ident) && parser.bump_if(SyntaxKind::Colon) - }); - - if has_label { - parser.bump_expected(SyntaxKind::Ident); - parser.bump_expected(SyntaxKind::Colon); - } - parse_expr(parser); - parser.set_newline_as_trivia(true); - }, - &[SyntaxKind::Comma, SyntaxKind::RParen], - ); + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parser.set_newline_as_trivia(false); + let has_label = parser.dry_run(|parser| { + parser.bump_if(SyntaxKind::Ident) && parser.bump_if(SyntaxKind::Colon) + }); + + if has_label { + parser.bump_expected(SyntaxKind::Ident); + parser.bump_expected(SyntaxKind::Colon); + } + parse_expr(parser)?; + Ok(()) } } define_scope! { pub(crate) WhereClauseScope, WhereClause, Inheritance(Newline) } impl super::Parse for WhereClauseScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::WhereKw); + let mut pred_count = 0; + loop { parser.set_newline_as_trivia(true); match parser.current_kind() { Some(kind) if is_type_start(kind) => { - parser.parse(WherePredicateScope::default(), None); + parser.parse(WherePredicateScope::default())?; + pred_count += 1; } _ => break, } + + if !parser.bump_if(SyntaxKind::Comma) { + if parser.current_kind().is_some() && is_type_start(parser.current_kind().unwrap()) + { + parser.set_newline_as_trivia(false); + let newline = parser.current_kind() == Some(SyntaxKind::Newline); + parser.set_newline_as_trivia(true); + + if newline { + parser.add_error(ParseError::expected( + &[SyntaxKind::Comma], + None, + parser.current_pos, + )); + } else if parser.find(SyntaxKind::Comma, None)? { + parser.bump(); + } else { + break; + } + } + } } + if pred_count == 0 { + parser.error("`where` clause requires one or more type constraints"); + } + Ok(()) } } define_scope! { pub(crate) WherePredicateScope, WherePredicate, Inheritance } impl super::Parse for WherePredicateScope { - fn parse(&mut self, parser: &mut Parser) { - parse_type(parser, None); - parser.set_newline_as_trivia(false); + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parse_type(parser, None)?; + if parser.current_kind() == Some(SyntaxKind::Colon) { - parser.parse(TypeBoundListScope::default(), None); - if !parser.bump_if(SyntaxKind::Newline) { - parser.error_and_recover("expected newline after type bounds", None); - } + parser.parse(TypeBoundListScope::default())?; } else { - parser.error_and_recover("expected `:` for type bounds", None); + parser.add_error(ParseError::expected( + &[SyntaxKind::Colon], + Some("missing type bound in `where` clause"), + parser.current_pos, + )); } + Ok(()) } } -pub(crate) fn parse_where_clause_opt(parser: &mut Parser) { +pub(crate) fn parse_where_clause_opt( + parser: &mut Parser, +) -> Result<(), Recovery> { let newline_as_trivia = parser.set_newline_as_trivia(true); - if parser.current_kind() == Some(SyntaxKind::WhereKw) { - parser.parse(WhereClauseScope::default(), None); - } + let r = if parser.current_kind() == Some(SyntaxKind::WhereKw) { + parser.parse(WhereClauseScope::default()) + } else { + Ok(()) + }; parser.set_newline_as_trivia(newline_as_trivia); + r } pub(crate) fn parse_generic_params_opt( parser: &mut Parser, disallow_trait_bound: bool, -) { +) -> Result<(), Recovery> { if parser.current_kind() == Some(SyntaxKind::Lt) { - parser.parse(GenericParamListScope::new(disallow_trait_bound), None); + parser.parse(GenericParamListScope::new(disallow_trait_bound)) + } else { + Ok(()) } } diff --git a/crates/parser2/src/parser/pat.rs b/crates/parser2/src/parser/pat.rs index 3a9fe1ee1c..3cb964f981 100644 --- a/crates/parser2/src/parser/pat.rs +++ b/crates/parser2/src/parser/pat.rs @@ -1,13 +1,16 @@ -use super::{define_scope, path::PathScope, token_stream::TokenStream, Parser}; +use std::convert::Infallible; + +use super::{define_scope, path::PathScope, token_stream::TokenStream, ErrProof, Parser, Recovery}; use crate::{ parser::{ lit::{is_lit, LitScope}, + parse_list, token_stream::LexicalToken, }, - SyntaxKind, + ParseError, SyntaxKind, }; -pub fn parse_pat(parser: &mut Parser) -> bool { +pub fn parse_pat(parser: &mut Parser) -> Result<(), Recovery> { use SyntaxKind::*; parser.bump_trivias(); let checkpoint = parser.checkpoint(); @@ -34,123 +37,146 @@ pub fn parse_pat(parser: &mut Parser) -> bool { } } - let success = match parser.current_kind() { - Some(Underscore) => parser.parse(WildCardPatScope::default(), Some(checkpoint)), - Some(Dot2) => parser.parse(RestPatScope::default(), Some(checkpoint)), - Some(LParen) => parser.parse(TuplePatScope::default(), Some(checkpoint)), - Some(kind) if is_lit(kind) => parser.parse(LitPatScope::default(), Some(checkpoint)), - _ => parser.parse(PathPatScope::default(), Some(checkpoint)), - } - .0; + match parser.current_kind() { + Some(Underscore) => parser + .parse_cp(WildCardPatScope::default(), Some(checkpoint)) + .unwrap(), + Some(Dot2) => parser + .parse_cp(RestPatScope::default(), Some(checkpoint)) + .unwrap(), + Some(LParen) => parser.parse_cp(TuplePatScope::default(), Some(checkpoint))?, + Some(kind) if is_lit(kind) => parser + .parse_cp(LitPatScope::default(), Some(checkpoint)) + .unwrap(), + _ => parser.parse_cp(PathPatScope::default(), Some(checkpoint))?, + }; if parser.current_kind() == Some(SyntaxKind::Pipe) { - parser.parse(OrPatScope::default(), Some(checkpoint)).0 && success - } else { - success + parser.parse_cp(OrPatScope::default(), Some(checkpoint))?; } + Ok(()) } define_scope! { WildCardPatScope, WildCardPat, Inheritance(SyntaxKind::Pipe) } impl super::Parse for WildCardPatScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Infallible; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.set_newline_as_trivia(false); parser.bump_expected(SyntaxKind::Underscore); + Ok(()) } } define_scope! { RestPatScope, RestPat, Inheritance } impl super::Parse for RestPatScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Infallible; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.set_newline_as_trivia(false); parser.bump_expected(SyntaxKind::Dot2); + Ok(()) } } define_scope! { LitPatScope, LitPat, Inheritance(SyntaxKind::Pipe) } impl super::Parse for LitPatScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Infallible; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.set_newline_as_trivia(false); - parser.parse(LitScope::default(), None); + parser.parse(LitScope::default()) } } define_scope! { TuplePatScope, TuplePat, Inheritance } impl super::Parse for TuplePatScope { - fn parse(&mut self, parser: &mut Parser) { - parser.parse(TuplePatElemListScope::default(), None); + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parser.parse(TuplePatElemListScope::default()) } } -define_scope! { TuplePatElemListScope, TuplePatElemList, Override(RParen) } +define_scope! { TuplePatElemListScope, TuplePatElemList, Override(RParen, Comma) } impl super::Parse for TuplePatElemListScope { - fn parse(&mut self, parser: &mut Parser) { - parser.bump_expected(SyntaxKind::LParen); - if parser.bump_if(SyntaxKind::RParen) { - return; - } - - parser.with_next_expected_tokens(parse_pat, &[SyntaxKind::RParen, SyntaxKind::Comma]); - while parser.bump_if(SyntaxKind::Comma) { - parser.with_next_expected_tokens(parse_pat, &[SyntaxKind::RParen, SyntaxKind::Comma]); - } - - parser.bump_or_recover(SyntaxKind::RParen, "expected `)`", None); + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parse_list( + parser, + false, + (SyntaxKind::LParen, SyntaxKind::RParen), + parse_pat, + ) } } define_scope! { PathPatScope, PathPat, Inheritance(Pipe) } impl super::Parse for PathPatScope { - fn parse(&mut self, parser: &mut Parser) { - if !parser.parse(PathScope::default(), None).0 { - return; - } + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parser.or_recover(|p| { + p.parse(PathScope::default()).map_err(|e| { + ParseError::expected( + &[SyntaxKind::PathPat], + Some("expected a pattern"), + e.range().start(), + ) + }) + })?; parser.set_newline_as_trivia(false); if parser.current_kind() == Some(SyntaxKind::LParen) { self.set_kind(SyntaxKind::PathTuplePat); - parser.parse(TuplePatElemListScope::default(), None); + parser.parse(TuplePatElemListScope::default()) } else if parser.current_kind() == Some(SyntaxKind::LBrace) { self.set_kind(SyntaxKind::RecordPat); - parser.parse(RecordPatFieldListScope::default(), None); + parser.parse(RecordPatFieldListScope::default()) + } else { + Ok(()) } } } define_scope! { RecordPatFieldListScope, RecordPatFieldList, Override(Comma, RBrace) } impl super::Parse for RecordPatFieldListScope { - fn parse(&mut self, parser: &mut Parser) { - parser.bump_expected(SyntaxKind::LBrace); - if parser.bump_if(SyntaxKind::RBrace) { - return; - } - - parser.parse(RecordPatFieldScope::default(), None); - while parser.bump_if(SyntaxKind::Comma) { - parser.parse(RecordPatFieldScope::default(), None); - } - - parser.bump_or_recover(SyntaxKind::RBrace, "expected `}`", None); + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parse_list( + parser, + true, + (SyntaxKind::LBrace, SyntaxKind::RBrace), + |parser| parser.parse(RecordPatFieldScope::default()), + ) } } -define_scope! { RecordPatFieldScope, RecordPatField, Override(Comma, RBrace) } +define_scope! { RecordPatFieldScope, RecordPatField, Inheritance } impl super::Parse for RecordPatFieldScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { let has_label = parser.dry_run(|parser| { + // parser.bump_if(SyntaxKind::Ident) && parser.bump_if(SyntaxKind::Colon) }); if has_label { parser.bump_expected(SyntaxKind::Ident); parser.bump_expected(SyntaxKind::Colon); } - parser.with_next_expected_tokens(parse_pat, &[SyntaxKind::Comma, SyntaxKind::RBrace]); + parse_pat(parser) } } define_scope! { OrPatScope, OrPat, Inheritance(SyntaxKind::Pipe) } impl super::Parse for OrPatScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::Pipe); - parse_pat(parser); + parse_pat(parser) } } diff --git a/crates/parser2/src/parser/path.rs b/crates/parser2/src/parser/path.rs index 85c84edc5c..8ed45ce55f 100644 --- a/crates/parser2/src/parser/path.rs +++ b/crates/parser2/src/parser/path.rs @@ -1,4 +1,4 @@ -use crate::SyntaxKind; +use crate::{ParseError, SyntaxKind}; use super::{define_scope, token_stream::TokenStream, Parser}; @@ -9,12 +9,15 @@ define_scope! { Inheritance(Colon2) } impl super::Parse for PathScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = ParseError; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.set_newline_as_trivia(false); - parser.parse(PathSegmentScope::default(), None); + parser.parse(PathSegmentScope::default())?; while parser.bump_if(SyntaxKind::Colon2) { - parser.parse(PathSegmentScope::default(), None); + parser.parse(PathSegmentScope::default())?; } + Ok(()) } } @@ -24,12 +27,19 @@ define_scope! { Inheritance } impl super::Parse for PathSegmentScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = ParseError; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { match parser.current_kind() { Some(kind) if is_path_segment(kind) => { parser.bump(); + Ok(()) } - _ => parser.error_and_recover("expected path segment", None), + _ => Err(ParseError::expected( + &[SyntaxKind::PathSegment], + None, + parser.current_pos, + )), } } } diff --git a/crates/parser2/src/parser/stmt.rs b/crates/parser2/src/parser/stmt.rs index 2d416920e1..affd4c8ba4 100644 --- a/crates/parser2/src/parser/stmt.rs +++ b/crates/parser2/src/parser/stmt.rs @@ -1,3 +1,5 @@ +use std::convert::Infallible; + use crate::SyntaxKind; use super::{ @@ -7,115 +9,130 @@ use super::{ pat::parse_pat, token_stream::TokenStream, type_::parse_type, - Checkpoint, Parser, + ErrProof, Parser, Recovery, }; -pub fn parse_stmt(parser: &mut Parser, checkpoint: Option) -> bool { +pub fn parse_stmt(parser: &mut Parser) -> Result<(), Recovery> { use SyntaxKind::*; match parser.current_kind() { - Some(LetKw) => parser.parse(LetStmtScope::default(), checkpoint), - Some(ForKw) => parser.parse(ForStmtScope::default(), checkpoint), - Some(WhileKw) => parser.parse(WhileStmtScope::default(), checkpoint), - Some(ContinueKw) => parser.parse(ContinueStmtScope::default(), checkpoint), - Some(BreakKw) => parser.parse(BreakStmtScope::default(), checkpoint), - Some(ReturnKw) => parser.parse(ReturnStmtScope::default(), checkpoint), - _ => parser.parse(ExprStmtScope::default(), checkpoint), + Some(LetKw) => parser.parse(LetStmtScope::default()), + Some(ForKw) => parser.parse(ForStmtScope::default()), + Some(WhileKw) => parser.parse(WhileStmtScope::default()), + Some(ContinueKw) => parser + .parse(ContinueStmtScope::default()) + .map_err(|e| e.into()), + Some(BreakKw) => parser + .parse(BreakStmtScope::default()) + .map_err(|e| e.into()), + Some(ReturnKw) => parser.parse(ReturnStmtScope::default()), + _ => parser.parse(ExprStmtScope::default()), } - .0 } define_scope! { LetStmtScope, LetStmt, Inheritance } impl super::Parse for LetStmtScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::LetKw); parser.set_newline_as_trivia(false); - if !parse_pat(parser) { - parser.error_and_recover("expected pattern", None); - return; - } + parse_pat(parser)?; // xxx "expected pattern" error msg + if parser.current_kind() == Some(SyntaxKind::Colon) { parser.bump_expected(SyntaxKind::Colon); - parse_type(parser, None); + parse_type(parser, None)?; } if parser.bump_if(SyntaxKind::Eq) { - parse_expr(parser); + parse_expr(parser)?; } + Ok(()) } } define_scope! { ForStmtScope, ForStmt, Inheritance } impl super::Parse for ForStmtScope { - fn parse(&mut self, parser: &mut Parser) { - parser.bump_expected(SyntaxKind::ForKw); + type Error = Recovery; - parser.with_recovery_tokens(parse_pat, &[SyntaxKind::InKw, SyntaxKind::LBrace]); + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parser.bump_expected(SyntaxKind::ForKw); - parser.with_next_expected_tokens( - |p| { - if !p.bump_if(SyntaxKind::InKw) { - p.error("expected `in` keyword"); - } + parser.set_scope_recovery_stack(&[SyntaxKind::InKw, SyntaxKind::LBrace]); + parse_pat(parser)?; - parse_expr_no_struct(p); - }, - &[SyntaxKind::LBrace], - ); + if parser.find_and_pop(SyntaxKind::InKw, None)? { + parser.bump(); + } + parse_expr_no_struct(parser)?; - if parser.current_kind() != Some(SyntaxKind::LBrace) { - parser.error_and_recover("expected block", None); - return; + if parser.find_and_pop(SyntaxKind::LBrace, None)? { + parser.parse(BlockExprScope::default())?; } - parser.parse(BlockExprScope::default(), None); + Ok(()) } } define_scope! { WhileStmtScope, WhileStmt, Inheritance } impl super::Parse for WhileStmtScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::WhileKw); - parser.with_next_expected_tokens(parse_expr_no_struct, &[SyntaxKind::LBrace]); + parser.set_scope_recovery_stack(&[SyntaxKind::LBrace]); + parse_expr_no_struct(parser)?; - if parser.current_kind() != Some(SyntaxKind::LBrace) { - parser.error_and_recover("expected block", None); - return; + if parser.find_and_pop(SyntaxKind::LBrace, None)? { + parser.parse(BlockExprScope::default())?; } - parser.parse(BlockExprScope::default(), None); + Ok(()) } } define_scope! { ContinueStmtScope, ContinueStmt, Inheritance } impl super::Parse for ContinueStmtScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Infallible; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::ContinueKw); + Ok(()) } } define_scope! { BreakStmtScope, BreakStmt, Inheritance } impl super::Parse for BreakStmtScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Infallible; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::BreakKw); + Ok(()) } } define_scope! { ReturnStmtScope, ReturnStmt, Inheritance } impl super::Parse for ReturnStmtScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::ReturnKw); parser.set_newline_as_trivia(false); - let has_val = parser.dry_run(parse_expr); - if has_val { - parse_expr(parser); + if !matches!( + parser.current_kind(), + None | Some(SyntaxKind::Newline | SyntaxKind::RBrace) + ) { + parse_expr(parser)?; } + Ok(()) } } define_scope! { ExprStmtScope, ExprStmt, Inheritance } impl super::Parse for ExprStmtScope { - fn parse(&mut self, parser: &mut Parser) { - parse_expr(parser); + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parse_expr(parser) } } diff --git a/crates/parser2/src/parser/struct_.rs b/crates/parser2/src/parser/struct_.rs index 3729f0dc1b..c958c50769 100644 --- a/crates/parser2/src/parser/struct_.rs +++ b/crates/parser2/src/parser/struct_.rs @@ -5,9 +5,10 @@ use super::{ define_scope, func::FuncScope, param::{parse_generic_params_opt, parse_where_clause_opt}, + parse_list, token_stream::TokenStream, type_::parse_type, - Parser, + ErrProof, Parser, Recovery, }; define_scope! { @@ -16,30 +17,32 @@ define_scope! { Inheritance } impl super::Parse for StructScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::StructKw); - parser.with_next_expected_tokens( - |parser| { - if !parser.bump_if(SyntaxKind::Ident) { - parser.error_and_recover("expected ident for the struct name", None) - } - }, - &[SyntaxKind::Lt, SyntaxKind::LBrace, SyntaxKind::WhereKw], - ); - - parser.with_next_expected_tokens( - |parser| parse_generic_params_opt(parser, false), - &[SyntaxKind::LBrace, SyntaxKind::WhereKw], - ); - - parser.with_next_expected_tokens(parse_where_clause_opt, &[SyntaxKind::LBrace]); - - if parser.current_kind() == Some(SyntaxKind::LBrace) { - parser.parse(RecordFieldDefListScope::default(), None); - } else { - parser.error_and_recover("expected struct field definition", None); + parser.set_scope_recovery_stack(&[ + SyntaxKind::Ident, + SyntaxKind::Lt, + SyntaxKind::WhereKw, + SyntaxKind::LBrace, + ]); + + if parser.find_and_pop(SyntaxKind::Ident, None)? { + parser.bump(); + } + + parser.expect_and_pop_recovery_stack()?; + parse_generic_params_opt(parser, false)?; + + parser.expect_and_pop_recovery_stack()?; + parse_where_clause_opt(parser)?; + + if parser.find_and_pop(SyntaxKind::LBrace, Some("struct field definition"))? { + parser.parse(RecordFieldDefListScope::default())?; } + Ok(()) } } @@ -48,34 +51,20 @@ define_scope! { RecordFieldDefList, Override( RBrace, + Comma, Newline ) } impl super::Parse for RecordFieldDefListScope { - fn parse(&mut self, parser: &mut Parser) { - parser.bump_expected(SyntaxKind::LBrace); - parser.set_newline_as_trivia(true); - - loop { - if parser.current_kind() == Some(SyntaxKind::RBrace) || parser.current_kind().is_none() - { - break; - } - - parser.parse(RecordFieldDefScope::default(), None); - - if !parser.bump_if(SyntaxKind::Comma) - && parser.current_kind() != Some(SyntaxKind::RBrace) - { - parser.error("expected comma after field definition"); - } - } + type Error = Recovery; - parser.bump_or_recover( - SyntaxKind::RBrace, - "expected the closing brace of the struct definition", - None, - ); + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parse_list( + parser, + true, + (SyntaxKind::LBrace, SyntaxKind::RBrace), + |parser| parser.parse(RecordFieldDefScope::default()), + ) } } @@ -85,9 +74,11 @@ define_scope! { Inheritance } impl super::Parse for RecordFieldDefScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.set_newline_as_trivia(false); - parse_attr_list(parser); + parse_attr_list(parser)?; parser.bump_if(SyntaxKind::PubKw); // Since the Fe-V2 doesn't support method definition in a struct, we add an @@ -101,26 +92,21 @@ impl super::Parse for RecordFieldDefScope { if parser.current_kind() == Some(SyntaxKind::FnKw) { parser.error_msg_on_current_token("function definition in struct is not allowed"); let checkpoint = parser.enter(super::ErrorScope::new(), None); - parser.parse(FuncScope::default(), None); + parser.parse(FuncScope::default())?; parser.leave(checkpoint); - return; + return Ok(()); + } + + parser.set_scope_recovery_stack(&[SyntaxKind::Colon]); + + if parser.find(SyntaxKind::Ident, Some("expected a field name"))? { + parser.bump(); } - parser.with_next_expected_tokens( - |parser| { - if !parser.bump_if(SyntaxKind::Ident) { - parser.error_and_recover("expected ident for the field name", None); - } - }, - &[SyntaxKind::Colon], - ); - if parser.bump_if(SyntaxKind::Colon) { - parser.with_next_expected_tokens( - |parser| parse_type(parser, None), - &[SyntaxKind::Comma, SyntaxKind::Newline, SyntaxKind::RBrace], - ); - } else { - parser.error_and_recover("expected `name: type` for the field definition", None); + if parser.find(SyntaxKind::Colon, Some("missing field type"))? { + parser.bump(); + parse_type(parser, None).map(|_| ())?; } + Ok(()) } } diff --git a/crates/parser2/src/parser/type_.rs b/crates/parser2/src/parser/type_.rs index a931d24a7c..1f05ffa8ad 100644 --- a/crates/parser2/src/parser/type_.rs +++ b/crates/parser2/src/parser/type_.rs @@ -1,23 +1,26 @@ -use crate::SyntaxKind; +use crate::{ParseError, SyntaxKind}; use super::{ define_scope, expr::parse_expr, param::GenericArgListScope, + parse_list, path::{is_path_segment, PathScope}, token_stream::TokenStream, - Checkpoint, Parser, + Checkpoint, ErrProof, Parser, Recovery, }; -pub fn parse_type(parser: &mut Parser, checkpoint: Option) -> bool { +pub fn parse_type( + parser: &mut Parser, + checkpoint: Option, +) -> Result> { match parser.current_kind() { - Some(SyntaxKind::Star) => parser.parse(PtrTypeScope::default(), checkpoint), - Some(SyntaxKind::SelfTypeKw) => parser.parse(SelfTypeScope::new(), checkpoint), - Some(SyntaxKind::LParen) => parser.parse(TupleTypeScope::default(), checkpoint), - Some(SyntaxKind::LBracket) => parser.parse(ArrayTypeScope::default(), checkpoint), - _ => parser.parse(PathTypeScope::default(), checkpoint), + Some(SyntaxKind::Star) => parser.parse_cp(PtrTypeScope::default(), checkpoint), + Some(SyntaxKind::SelfTypeKw) => parser.parse_cp(SelfTypeScope::new(), checkpoint), + Some(SyntaxKind::LParen) => parser.parse_cp(TupleTypeScope::default(), checkpoint), + Some(SyntaxKind::LBracket) => parser.parse_cp(ArrayTypeScope::default(), checkpoint), + _ => parser.parse_cp(PathTypeScope::default(), checkpoint), } - .0 } pub(crate) fn is_type_start(kind: SyntaxKind) -> bool { @@ -32,38 +35,44 @@ pub(crate) fn is_type_start(kind: SyntaxKind) -> bool { define_scope!(PtrTypeScope, PtrType, Inheritance); impl super::Parse for PtrTypeScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.set_newline_as_trivia(false); parser.bump_expected(SyntaxKind::Star); - parse_type(parser, None); + parse_type(parser, None).map(|_| ()) } } define_scope!(pub(crate) PathTypeScope , PathType, Inheritance); impl super::Parse for PathTypeScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.set_newline_as_trivia(false); - if !parser.parse(PathScope::default(), None).0 { - return; - } + + parser.or_recover(|p| { + p.parse(PathScope::default()).map_err(|_| { + ParseError::expected(&[SyntaxKind::PathType], None, p.end_of_prev_token) + }) + })?; if parser.current_kind() == Some(SyntaxKind::Lt) { - parser.parse(GenericArgListScope::default(), None); + parser.parse(GenericArgListScope::default())?; } + Ok(()) } } define_scope!(pub(super) SelfTypeScope, SelfType, Inheritance); impl super::Parse for SelfTypeScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.set_newline_as_trivia(false); - if !parser.bump_if(SyntaxKind::SelfTypeKw) { - parser.error_and_recover("expected `Self` type here", None); - return; - } + parser.bump_expected(SyntaxKind::SelfTypeKw); if parser.current_kind() == Some(SyntaxKind::Lt) { - parser.parse(GenericArgListScope::default(), None); + parser.parse(GenericArgListScope::default())?; } + Ok(()) } } define_scope! { @@ -75,54 +84,45 @@ define_scope! { ) } impl super::Parse for TupleTypeScope { - fn parse(&mut self, parser: &mut Parser) { - parser.set_newline_as_trivia(false); - parser.bump_expected(SyntaxKind::LParen); - if parser.bump_if(SyntaxKind::RParen) { - return; - } - parser.set_newline_as_trivia(true); - - parse_type(parser, None); - while parser.bump_if(SyntaxKind::Comma) { - parse_type(parser, None); - } - - if !parser.bump_if(SyntaxKind::RParen) { - // If the close paren is missing, we want to recover on a newline, - // so we have to explicitly set newlines to be non-trivia. - parser.set_newline_as_trivia(false); - parser.error_and_recover("expected `)`", None); - parser.set_newline_as_trivia(true); - parser.bump_if(SyntaxKind::RParen); - } + type Error = Recovery; + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parse_list( + parser, + false, + (SyntaxKind::LParen, SyntaxKind::RParen), + |parser| { + parse_type(parser, None)?; + Ok(()) + }, + ) } } define_scope! { ArrayTypeScope, ArrayType, - Override(RBracket) + Inheritance } impl super::Parse for ArrayTypeScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.set_newline_as_trivia(false); parser.bump_expected(SyntaxKind::LBracket); - parser - .with_next_expected_tokens(|parser| parse_type(parser, None), &[SyntaxKind::SemiColon]); + parser.set_scope_recovery_stack(&[SyntaxKind::SemiColon, SyntaxKind::RBracket]); + + parse_type(parser, None)?; - if !parser.bump_if(SyntaxKind::SemiColon) { - parser.error_and_recover("expected `;`", None); - parser.bump_if(SyntaxKind::LBracket); - return; + if parser.find_and_pop(SyntaxKind::SemiColon, None)? { + parser.bump(); } - parse_expr(parser); + parse_expr(parser)?; - if !parser.bump_if(SyntaxKind::RBracket) { - parser.error_and_recover("expected closing `]`", None); - parser.bump_if(SyntaxKind::RBracket); + if parser.find_and_pop(SyntaxKind::RBracket, None)? { + parser.bump(); } + Ok(()) } } diff --git a/crates/parser2/src/parser/use_tree.rs b/crates/parser2/src/parser/use_tree.rs index 58c09c8e92..7302fca0fb 100644 --- a/crates/parser2/src/parser/use_tree.rs +++ b/crates/parser2/src/parser/use_tree.rs @@ -1,8 +1,8 @@ use std::{cell::Cell, rc::Rc}; -use crate::{parser::path::is_path_segment, SyntaxKind}; +use crate::{parser::path::is_path_segment, ParseError, SyntaxKind, TextRange}; -use super::{define_scope, token_stream::TokenStream, Parser}; +use super::{define_scope, parse_list, token_stream::TokenStream, ErrProof, Parser, Recovery}; define_scope! { pub(crate) UseTreeScope, @@ -10,15 +10,16 @@ define_scope! { Inheritance } impl super::Parse for UseTreeScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = Recovery; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.set_newline_as_trivia(false); if let Some(SyntaxKind::LBrace) = parser.current_kind() { - parser.parse(UseTreeListScope::default(), None); - return; + return parser.parse(UseTreeListScope::default()); } let use_path_scope = UsePathScope::default(); - parser.parse(use_path_scope.clone(), None); + parser.parse_or_recover(use_path_scope.clone())?; let is_glob = use_path_scope.is_glob.get(); if parser.current_kind() == Some(SyntaxKind::AsKw) { @@ -26,20 +27,21 @@ impl super::Parse for UseTreeScope { parser.error_msg_on_current_token("can't use `as` with `*`"); } if parser.current_kind() == Some(SyntaxKind::AsKw) { - parser.parse(UseTreeAliasScope::default(), None); + parser.parse_or_recover(UseTreeAliasScope::default())?; } - return; + return Ok(()); } if !parser.bump_if(SyntaxKind::Colon2) { - return; + return Ok(()); } if parser.current_kind() == Some(SyntaxKind::LBrace) { if is_glob { parser.error_msg_on_current_token("can't use `*` with `{}`"); } - parser.parse(UseTreeListScope::default(), None); + parser.parse(UseTreeListScope::default())?; } + Ok(()) } } @@ -49,25 +51,15 @@ define_scope! { Override(Comma, RBrace) } impl super::Parse for UseTreeListScope { - fn parse(&mut self, parser: &mut Parser) { - parser.bump_expected(SyntaxKind::LBrace); - parser.with_next_expected_tokens( - |parser| { - parser.parse(UseTreeScope::default(), None); - }, - &[SyntaxKind::RBrace, SyntaxKind::Comma], - ); - - while parser.bump_if(SyntaxKind::Comma) { - parser.with_next_expected_tokens( - |parser| { - parser.parse(UseTreeScope::default(), None); - }, - &[SyntaxKind::RBrace, SyntaxKind::Comma], - ); - } + type Error = Recovery; - parser.bump_or_recover(SyntaxKind::RBrace, "expected `}`", None); + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { + parse_list( + parser, + true, + (SyntaxKind::LBrace, SyntaxKind::RBrace), + |parser| parser.parse(UseTreeScope::default()), + ) } } @@ -77,14 +69,16 @@ define_scope! { Inheritance(Colon2) } impl super::Parse for UsePathScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = ParseError; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.set_newline_as_trivia(false); - parser.parse(UsePathSegmentScope::default(), None); + parser.parse(UsePathSegmentScope::default())?; loop { let is_path_segment = parser.dry_run(|parser| { parser.bump_if(SyntaxKind::Colon2) - && parser.parse(UsePathSegmentScope::default(), None).0 + && parser.parses_without_error(UsePathSegmentScope::default()) }); if is_path_segment { if self.is_glob.get() { @@ -93,11 +87,12 @@ impl super::Parse for UsePathScope { parser.bump_expected(SyntaxKind::Colon2); self.is_glob .set(parser.current_kind() == Some(SyntaxKind::Star)); - parser.parse(UsePathSegmentScope::default(), None); + parser.parse(UsePathSegmentScope::default())?; } else { break; } } + Ok(()) } } @@ -107,15 +102,21 @@ define_scope! { Inheritance } impl super::Parse for UsePathSegmentScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = ParseError; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { match parser.current_kind() { Some(kind) if is_use_path_segment(kind) => { parser.bump(); } _ => { - parser.error_and_recover("expected identifier or `self`", None); + return Err(ParseError::Msg( + "expected identifier or `self`".into(), + TextRange::empty(parser.current_pos), + )); } } + Ok(()) } } @@ -125,15 +126,23 @@ define_scope! { Inheritance } impl super::Parse for UseTreeAliasScope { - fn parse(&mut self, parser: &mut Parser) { + type Error = ParseError; + + fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.set_newline_as_trivia(false); parser.bump_expected(SyntaxKind::AsKw); match parser.current_kind() { Some(SyntaxKind::Ident) => parser.bump_expected(SyntaxKind::Ident), Some(SyntaxKind::Underscore) => parser.bump_expected(SyntaxKind::Underscore), - _ => parser.error_and_recover("expected identifier or `_`", None), + _ => { + return Err(ParseError::Msg( + "expected identifier or `_`".into(), + TextRange::empty(parser.current_pos), + )) + } }; + Ok(()) } } diff --git a/crates/parser2/src/syntax_kind.rs b/crates/parser2/src/syntax_kind.rs index 4b0792e56b..cf97d6ab89 100644 --- a/crates/parser2/src/syntax_kind.rs +++ b/crates/parser2/src/syntax_kind.rs @@ -435,6 +435,8 @@ pub enum SyntaxKind { /// `` GenericParamList, + /// fn foo(t: T) -> U + FuncSignature, /// `(x: i32, _ y: mut i32)` FuncParamList, @@ -517,6 +519,93 @@ impl SyntaxKind { | SyntaxKind::ExternKw ) } + + // xxx + /// Panics if `self` is not a token kind + pub fn describe(self) -> &'static str { + match self { + SyntaxKind::Newline => "newline", + SyntaxKind::Ident => "identifier", + SyntaxKind::Int => "integer", + SyntaxKind::String => "string literal", + SyntaxKind::LParen => "`(`", + SyntaxKind::RParen => "`)`", + SyntaxKind::LBrace => "`{`", + SyntaxKind::RBrace => "`}`", + SyntaxKind::LBracket => "`[`", + SyntaxKind::RBracket => "`]`", + SyntaxKind::Colon => "`:`", + SyntaxKind::Colon2 => "`::`", + SyntaxKind::SemiColon => "`;`", + SyntaxKind::Dot => "`.`", + SyntaxKind::Dot2 => "`..`", + SyntaxKind::Comma => "`,`", + SyntaxKind::Arrow => "`->`", + SyntaxKind::FatArrow => "`=>`", + SyntaxKind::Underscore => "`_`", + SyntaxKind::Pound => "`#`", + SyntaxKind::Plus => "`+`", + SyntaxKind::Minus => "`-`", + SyntaxKind::Star => "`*`", + SyntaxKind::Star2 => "`**`", + SyntaxKind::Slash => "`/`", + SyntaxKind::Percent => "`%`", + SyntaxKind::Tilde => "`~`", + SyntaxKind::Not => "`!`", + SyntaxKind::Hat => "`^`", + SyntaxKind::Amp => "`&`", + SyntaxKind::Amp2 => "`&&`", + SyntaxKind::Pipe => "`|`", + SyntaxKind::Pipe2 => "`||`", + SyntaxKind::Lt => "`<`", + SyntaxKind::Gt => "`>`", + SyntaxKind::Eq => "``", + SyntaxKind::Eq2 => "``", + SyntaxKind::NotEq => "``", + SyntaxKind::AsKw => "`as`", + SyntaxKind::TrueKw => "`true`", + SyntaxKind::FalseKw => "`false`", + SyntaxKind::BreakKw => "`break`", + SyntaxKind::ContinueKw => "`continue`", + SyntaxKind::ContractKw => "`contract`", + SyntaxKind::FnKw => "`fn`", + SyntaxKind::ModKw => "`mod`", + SyntaxKind::ConstKw => "`const`", + SyntaxKind::IfKw => "`if`", + SyntaxKind::ElseKw => "`else`", + SyntaxKind::MatchKw => "`match`", + SyntaxKind::ForKw => "`for`", + SyntaxKind::InKw => "`in`", + SyntaxKind::WhereKw => "`where`", + SyntaxKind::WhileKw => "`while`", + SyntaxKind::PubKw => "`pub`", + SyntaxKind::ReturnKw => "`return`", + SyntaxKind::SelfKw => "`self`", + SyntaxKind::SelfTypeKw => "`Self`", + SyntaxKind::StructKw => "`struct`", + SyntaxKind::EnumKw => "`enum`", + SyntaxKind::TraitKw => "`trait`", + SyntaxKind::ImplKw => "`impl`", + SyntaxKind::TypeKw => "`type`", + SyntaxKind::LetKw => "`let`", + SyntaxKind::MutKw => "`mut`", + SyntaxKind::UseKw => "`use`", + SyntaxKind::ExternKw => "`extern`", + SyntaxKind::UnsafeKw => "`unsafe`", + SyntaxKind::IngotKw => "`ingot`", + SyntaxKind::SuperKw => "`super`", + SyntaxKind::LShift => "`<<`", + SyntaxKind::RShift => "`>>`", + SyntaxKind::LtEq => "`<=`", + SyntaxKind::GtEq => "`>=`", + + SyntaxKind::PathType => "a type name", + SyntaxKind::TraitRef => "a trait name", + SyntaxKind::PathSegment => "a path segment", + SyntaxKind::PathPat => "a pattern", + _ => unimplemented!(), + } + } } impl From for rowan::SyntaxKind { diff --git a/crates/parser2/test_files/error_recovery/exprs/call.snap b/crates/parser2/test_files/error_recovery/exprs/call.snap index f6369fd7a7..dea6f8e5f8 100644 --- a/crates/parser2/test_files/error_recovery/exprs/call.snap +++ b/crates/parser2/test_files/error_recovery/exprs/call.snap @@ -18,24 +18,24 @@ Root@0..40 Ident@4..5 "x" Comma@5..6 "," WhiteSpace@6..7 " " - CallArg@7..10 + CallArg@7..8 PathExpr@7..8 Path@7..8 PathSegment@7..8 Ident@7..8 "y" - WhiteSpace@8..9 " " - Error@9..10 - Ident@9..10 "a" + WhiteSpace@8..9 " " + Error@9..10 + Ident@9..10 "a" Comma@10..11 "," WhiteSpace@11..12 " " - CallArg@12..15 + CallArg@12..13 PathExpr@12..13 Path@12..13 PathSegment@12..13 Ident@12..13 "z" - WhiteSpace@13..14 " " - Error@14..15 - SemiColon@14..15 ";" + WhiteSpace@13..14 " " + Error@14..15 + SemiColon@14..15 ";" RParen@15..16 ")" Newline@16..18 "\n\n" CallExpr@18..39 @@ -52,20 +52,16 @@ Root@0..40 Ident@22..25 "i32" Comma@25..26 "," WhiteSpace@26..27 " " - TypeGenericArg@27..30 + TypeGenericArg@27..28 PathType@27..28 Path@27..28 PathSegment@27..28 Ident@27..28 "T" - WhiteSpace@28..29 " " - Error@29..30 - Ident@29..30 "E" + WhiteSpace@28..29 " " + Error@29..30 + Ident@29..30 "E" Comma@30..31 "," WhiteSpace@31..32 " " - TypeGenericArg@32..32 - PathType@32..32 - Path@32..32 - PathSegment@32..32 Gt@32..33 ">" CallArgList@33..39 LParen@33..34 "(" diff --git a/crates/parser2/test_files/error_recovery/exprs/if_.fe b/crates/parser2/test_files/error_recovery/exprs/if_.fe index cb68659d3d..5b9f9b43fa 100644 --- a/crates/parser2/test_files/error_recovery/exprs/if_.fe +++ b/crates/parser2/test_files/error_recovery/exprs/if_.fe @@ -1,14 +1,14 @@ -if x y { +if a b { } -if x { +if c { -} else x {} +} else d {} -if x { } else x if x { } else { } +if e { } else f if g { } else { } -if x { - 10 +if h { + 10 else { 1 } diff --git a/crates/parser2/test_files/error_recovery/exprs/if_.snap b/crates/parser2/test_files/error_recovery/exprs/if_.snap index 34feb493dc..c40a18cfd6 100644 --- a/crates/parser2/test_files/error_recovery/exprs/if_.snap +++ b/crates/parser2/test_files/error_recovery/exprs/if_.snap @@ -3,30 +3,30 @@ source: crates/parser2/tests/error_recovery.rs expression: node input_file: crates/parser2/test_files/error_recovery/exprs/if_.fe --- -Root@0..101 +Root@0..97 IfExpr@0..10 IfKw@0..2 "if" WhiteSpace@2..3 " " PathExpr@3..4 Path@3..4 PathSegment@3..4 - Ident@3..4 "x" + Ident@3..4 "a" WhiteSpace@4..5 " " Error@5..6 - Ident@5..6 "y" + Ident@5..6 "b" WhiteSpace@6..7 " " BlockExpr@7..10 LBrace@7..8 "{" Newline@8..9 "\n" RBrace@9..10 "}" Newline@10..12 "\n\n" - IfExpr@12..28 + IfExpr@12..31 IfKw@12..14 "if" WhiteSpace@14..15 " " PathExpr@15..16 Path@15..16 PathSegment@15..16 - Ident@15..16 "x" + Ident@15..16 "c" WhiteSpace@16..17 " " BlockExpr@17..21 LBrace@17..18 "{" @@ -36,19 +36,19 @@ Root@0..101 ElseKw@22..26 "else" WhiteSpace@26..27 " " Error@27..28 - Ident@27..28 "x" - WhiteSpace@28..29 " " - BlockExpr@29..31 - LBrace@29..30 "{" - RBrace@30..31 "}" + Ident@27..28 "d" + WhiteSpace@28..29 " " + BlockExpr@29..31 + LBrace@29..30 "{" + RBrace@30..31 "}" Newline@31..33 "\n\n" - IfExpr@33..48 + IfExpr@33..66 IfKw@33..35 "if" WhiteSpace@35..36 " " PathExpr@36..37 Path@36..37 PathSegment@36..37 - Ident@36..37 "x" + Ident@36..37 "e" WhiteSpace@37..38 " " BlockExpr@38..41 LBrace@38..39 "{" @@ -58,37 +58,37 @@ Root@0..101 ElseKw@42..46 "else" WhiteSpace@46..47 " " Error@47..48 - Ident@47..48 "x" - WhiteSpace@48..49 " " - IfExpr@49..66 - IfKw@49..51 "if" - WhiteSpace@51..52 " " - PathExpr@52..53 - Path@52..53 - PathSegment@52..53 - Ident@52..53 "x" - WhiteSpace@53..54 " " - BlockExpr@54..57 - LBrace@54..55 "{" - WhiteSpace@55..56 " " - RBrace@56..57 "}" - WhiteSpace@57..58 " " - ElseKw@58..62 "else" - WhiteSpace@62..63 " " - BlockExpr@63..66 - LBrace@63..64 "{" - WhiteSpace@64..65 " " - RBrace@65..66 "}" + Ident@47..48 "f" + WhiteSpace@48..49 " " + IfExpr@49..66 + IfKw@49..51 "if" + WhiteSpace@51..52 " " + PathExpr@52..53 + Path@52..53 + PathSegment@52..53 + Ident@52..53 "g" + WhiteSpace@53..54 " " + BlockExpr@54..57 + LBrace@54..55 "{" + WhiteSpace@55..56 " " + RBrace@56..57 "}" + WhiteSpace@57..58 " " + ElseKw@58..62 "else" + WhiteSpace@62..63 " " + BlockExpr@63..66 + LBrace@63..64 "{" + WhiteSpace@64..65 " " + RBrace@65..66 "}" Newline@66..68 "\n\n" - IfExpr@68..101 + IfExpr@68..96 IfKw@68..70 "if" WhiteSpace@70..71 " " PathExpr@71..72 Path@71..72 PathSegment@71..72 - Ident@71..72 "x" + Ident@71..72 "h" WhiteSpace@72..73 " " - BlockExpr@73..101 + BlockExpr@73..82 LBrace@73..74 "{" Newline@74..75 "\n" WhiteSpace@75..79 " " @@ -96,18 +96,19 @@ Root@0..101 LitExpr@79..81 Lit@79..81 Int@79..81 "10" - WhiteSpace@81..85 " " - Newline@85..86 "\n" - ExprStmt@86..100 - Error@86..100 - ElseKw@86..90 "else" - WhiteSpace@90..91 " " - LBrace@91..92 "{" - Newline@92..93 "\n" - WhiteSpace@93..97 " " - Int@97..98 "1" - Newline@98..99 "\n" - RBrace@99..100 "}" - Newline@100..101 "\n" - Error@101..101 + Newline@81..82 "\n" + ExprStmt@82..82 + ElseKw@82..86 "else" + WhiteSpace@86..87 " " + BlockExpr@87..96 + LBrace@87..88 "{" + Newline@88..89 "\n" + WhiteSpace@89..93 " " + ExprStmt@93..94 + LitExpr@93..94 + Lit@93..94 + Int@93..94 "1" + Newline@94..95 "\n" + RBrace@95..96 "}" + Newline@96..97 "\n" diff --git a/crates/parser2/test_files/error_recovery/exprs/match_.snap b/crates/parser2/test_files/error_recovery/exprs/match_.snap index 89d7442001..6a6e366e58 100644 --- a/crates/parser2/test_files/error_recovery/exprs/match_.snap +++ b/crates/parser2/test_files/error_recovery/exprs/match_.snap @@ -58,7 +58,7 @@ Root@0..94 WhiteSpace@53..54 " " Newline@54..55 "\n" WhiteSpace@55..58 " " - MatchArm@58..79 + MatchArm@58..77 PathTuplePat@58..70 Path@58..61 PathSegment@58..61 @@ -85,9 +85,9 @@ Root@0..94 LitExpr@73..77 Lit@73..77 TrueKw@73..77 "true" - WhiteSpace@77..78 " " - Error@78..79 - Ident@78..79 "x" + WhiteSpace@77..78 " " + Error@78..79 + Ident@78..79 "x" Newline@79..80 "\n" WhiteSpace@80..83 " " MatchArm@83..91 diff --git a/crates/parser2/test_files/error_recovery/exprs/method.snap b/crates/parser2/test_files/error_recovery/exprs/method.snap index c102ef6f2b..984d5bafbd 100644 --- a/crates/parser2/test_files/error_recovery/exprs/method.snap +++ b/crates/parser2/test_files/error_recovery/exprs/method.snap @@ -23,19 +23,15 @@ Root@0..78 Ident@13..16 "i32" Comma@16..17 "," WhiteSpace@17..18 " " - TypeGenericArg@18..23 + TypeGenericArg@18..21 PathType@18..21 Path@18..21 PathSegment@18..21 Ident@18..21 "u32" - WhiteSpace@21..22 " " - Error@22..23 - Ident@22..23 "T" + WhiteSpace@21..22 " " + Error@22..23 + Ident@22..23 "T" Comma@23..24 "," - TypeGenericArg@24..24 - PathType@24..24 - Path@24..24 - PathSegment@24..24 Gt@24..25 ">" CallArgList@25..31 LParen@25..26 "(" @@ -69,15 +65,14 @@ Root@0..78 Int@44..45 "1" Comma@45..46 "," WhiteSpace@46..47 " " - CallArg@47..50 + CallArg@47..48 LitExpr@47..48 Lit@47..48 Int@47..48 "2" - WhiteSpace@48..49 " " - Error@49..50 - Ident@49..50 "E" + WhiteSpace@48..49 " " + Error@49..50 + Ident@49..50 "E" Comma@50..51 "," - CallArg@51..51 RParen@51..52 ")" Newline@52..54 "\n\n" MethodCallExpr@54..78 diff --git a/crates/parser2/test_files/error_recovery/items/const_.snap b/crates/parser2/test_files/error_recovery/items/const_.snap index 6790a63299..a82e34328d 100644 --- a/crates/parser2/test_files/error_recovery/items/const_.snap +++ b/crates/parser2/test_files/error_recovery/items/const_.snap @@ -18,7 +18,7 @@ Root@0..44 Int@10..12 "10" Newline@12..14 "\n\n" Item@14..29 - Const@14..26 + Const@14..29 ConstKw@14..19 "const" WhiteSpace@19..20 " " Ident@20..21 "X" @@ -28,8 +28,9 @@ Root@0..44 Path@23..26 PathSegment@23..26 Ident@23..26 "i32" - WhiteSpace@26..27 " " - Newline@27..29 "\n\n" + WhiteSpace@26..27 " " + Error@27..29 + Newline@27..29 "\n\n" Item@29..44 Const@29..44 ConstKw@29..34 "const" @@ -38,11 +39,11 @@ Root@0..44 Colon@36..37 ":" WhiteSpace@37..38 " " PathType@38..40 - Path@38..40 - PathSegment@38..40 - Error@38..40 - RBracket@38..39 "]" - InvalidToken@39..40 "@" + Path@38..38 + PathSegment@38..38 + Error@38..40 + RBracket@38..39 "]" + InvalidToken@39..40 "@" WhiteSpace@40..41 " " Eq@41..42 "=" WhiteSpace@42..43 " " diff --git a/crates/parser2/test_files/error_recovery/items/enum_.fe b/crates/parser2/test_files/error_recovery/items/enum_.fe index 3d2ff26e76..0e85c5b496 100644 --- a/crates/parser2/test_files/error_recovery/items/enum_.fe +++ b/crates/parser2/test_files/error_recovery/items/enum_.fe @@ -1,11 +1,11 @@ pub enum MyEnum { X(u32, T A - Y(T, u32) A + Y(T, u32) B Z } -pub enum MyEnum2 +pub enum MyEnum2 where T: * -> (* -> * U: * -> * diff --git a/crates/parser2/test_files/error_recovery/items/enum_.snap b/crates/parser2/test_files/error_recovery/items/enum_.snap index a931adb74d..968cd001f0 100644 --- a/crates/parser2/test_files/error_recovery/items/enum_.snap +++ b/crates/parser2/test_files/error_recovery/items/enum_.snap @@ -3,8 +3,8 @@ source: crates/parser2/tests/error_recovery.rs expression: node input_file: crates/parser2/test_files/error_recovery/items/enum_.fe --- -Root@0..151 - ItemList@0..151 +Root@0..150 + ItemList@0..150 Item@0..65 Enum@0..63 ItemModifier@0..3 @@ -59,8 +59,8 @@ Root@0..151 Ident@49..52 "u32" RParen@52..53 ")" WhiteSpace@53..54 " " - VariantDef@54..55 - Ident@54..55 "A" + Error@54..55 + Ident@54..55 "B" Newline@55..56 "\n" WhiteSpace@56..60 " " VariantDef@60..61 @@ -68,8 +68,8 @@ Root@0..151 Newline@61..62 "\n" RBrace@62..63 "}" Newline@63..65 "\n\n" - Item@65..151 - Enum@65..150 + Item@65..150 + Enum@65..149 ItemModifier@65..68 PubKw@65..68 "pub" WhiteSpace@68..69 " " @@ -85,81 +85,80 @@ Root@0..151 TypeGenericParam@85..86 Ident@85..86 "U" Gt@86..87 ">" - WhiteSpace@87..88 " " - Newline@88..89 "\n" - WhereClause@89..129 - WhereKw@89..94 "where" - Newline@94..95 "\n" - WhiteSpace@95..99 " " - WherePredicate@99..115 - PathType@99..100 - Path@99..100 - PathSegment@99..100 - Ident@99..100 "T" - TypeBoundList@100..114 - Colon@100..101 ":" - WhiteSpace@101..102 " " - TypeBound@102..114 - KindBoundAbs@102..114 - KindBoundMono@102..103 - Star@102..103 "*" - WhiteSpace@103..104 " " - Arrow@104..106 "->" - WhiteSpace@106..107 " " - LParen@107..108 "(" - KindBoundAbs@108..114 - KindBoundMono@108..109 - Star@108..109 "*" - WhiteSpace@109..110 " " - Arrow@110..112 "->" - WhiteSpace@112..113 " " - KindBoundMono@113..114 - Star@113..114 "*" - Newline@114..115 "\n" - WhiteSpace@115..119 " " - WherePredicate@119..129 - PathType@119..120 - Path@119..120 - PathSegment@119..120 - Ident@119..120 "U" - TypeBoundList@120..128 - Colon@120..121 ":" - WhiteSpace@121..122 " " - TypeBound@122..128 - KindBoundAbs@122..128 - KindBoundMono@122..123 - Star@122..123 "*" - WhiteSpace@123..124 " " - Arrow@124..126 "->" - WhiteSpace@126..127 " " - KindBoundMono@127..128 - Star@127..128 "*" - Newline@128..129 "\n" - VariantDefList@129..150 - LBrace@129..130 "{" - Newline@130..131 "\n" - WhiteSpace@131..135 " " - VariantDef@135..139 - Ident@135..136 "T" - TupleType@136..139 - LParen@136..137 "(" - PathType@137..138 - Path@137..138 - PathSegment@137..138 - Ident@137..138 "t" - RParen@138..139 ")" - Newline@139..140 "\n" - WhiteSpace@140..144 " " - VariantDef@144..148 - Ident@144..145 "U" - TupleType@145..148 - LParen@145..146 "(" - PathType@146..147 - Path@146..147 - PathSegment@146..147 - Ident@146..147 "U" - RParen@147..148 ")" - Newline@148..149 "\n" - RBrace@149..150 "}" - Newline@150..151 "\n" + Newline@87..88 "\n" + WhereClause@88..127 + WhereKw@88..93 "where" + Newline@93..94 "\n" + WhiteSpace@94..98 " " + WherePredicate@98..113 + PathType@98..99 + Path@98..99 + PathSegment@98..99 + Ident@98..99 "T" + TypeBoundList@99..113 + Colon@99..100 ":" + WhiteSpace@100..101 " " + TypeBound@101..113 + KindBoundAbs@101..113 + KindBoundMono@101..102 + Star@101..102 "*" + WhiteSpace@102..103 " " + Arrow@103..105 "->" + WhiteSpace@105..106 " " + LParen@106..107 "(" + KindBoundAbs@107..113 + KindBoundMono@107..108 + Star@107..108 "*" + WhiteSpace@108..109 " " + Arrow@109..111 "->" + WhiteSpace@111..112 " " + KindBoundMono@112..113 + Star@112..113 "*" + Newline@113..114 "\n" + WhiteSpace@114..118 " " + WherePredicate@118..127 + PathType@118..119 + Path@118..119 + PathSegment@118..119 + Ident@118..119 "U" + TypeBoundList@119..127 + Colon@119..120 ":" + WhiteSpace@120..121 " " + TypeBound@121..127 + KindBoundAbs@121..127 + KindBoundMono@121..122 + Star@121..122 "*" + WhiteSpace@122..123 " " + Arrow@123..125 "->" + WhiteSpace@125..126 " " + KindBoundMono@126..127 + Star@126..127 "*" + Newline@127..128 "\n" + VariantDefList@128..149 + LBrace@128..129 "{" + Newline@129..130 "\n" + WhiteSpace@130..134 " " + VariantDef@134..138 + Ident@134..135 "T" + TupleType@135..138 + LParen@135..136 "(" + PathType@136..137 + Path@136..137 + PathSegment@136..137 + Ident@136..137 "t" + RParen@137..138 ")" + Newline@138..139 "\n" + WhiteSpace@139..143 " " + VariantDef@143..147 + Ident@143..144 "U" + TupleType@144..147 + LParen@144..145 "(" + PathType@145..146 + Path@145..146 + PathSegment@145..146 + Ident@145..146 "U" + RParen@146..147 ")" + Newline@147..148 "\n" + RBrace@148..149 "}" + Newline@149..150 "\n" diff --git a/crates/parser2/test_files/error_recovery/items/extern_.fe b/crates/parser2/test_files/error_recovery/items/extern_.fe index 12b50f7186..d33068b690 100644 --- a/crates/parser2/test_files/error_recovery/items/extern_.fe +++ b/crates/parser2/test_files/error_recovery/items/extern_.fe @@ -1,6 +1,8 @@ extern { - pub unsafe fn Foo(x: *usize) - + pub unsafe fn Foo + + pub fn bar() + struct Foo { pub unsafe fn foo() diff --git a/crates/parser2/test_files/error_recovery/items/extern_.snap b/crates/parser2/test_files/error_recovery/items/extern_.snap index 8547a5fc96..5f7fbf7824 100644 --- a/crates/parser2/test_files/error_recovery/items/extern_.snap +++ b/crates/parser2/test_files/error_recovery/items/extern_.snap @@ -3,17 +3,17 @@ source: crates/parser2/tests/error_recovery.rs expression: node input_file: crates/parser2/test_files/error_recovery/items/extern_.fe --- -Root@0..90 - ItemList@0..90 - Item@0..90 - Extern@0..90 +Root@0..93 + ItemList@0..93 + Item@0..54 + Extern@0..54 ExternKw@0..6 "extern" WhiteSpace@6..7 " " - ExternItemList@7..90 + ExternItemList@7..54 LBrace@7..8 "{" Newline@8..9 "\n" WhiteSpace@9..13 " " - Func@13..41 + Func@13..30 ItemModifier@13..23 PubKw@13..16 "pub" WhiteSpace@16..17 " " @@ -22,43 +22,45 @@ Root@0..90 FnKw@24..26 "fn" WhiteSpace@26..27 " " Ident@27..30 "Foo" - FuncParamList@30..41 - LParen@30..31 "(" - FnParam@31..40 - Ident@31..32 "x" - Colon@32..33 ":" - WhiteSpace@33..34 " " - PtrType@34..40 - Star@34..35 "*" - PathType@35..40 - Path@35..40 - PathSegment@35..40 - Ident@35..40 "usize" - RParen@40..41 ")" - Newline@41..42 "\n" - WhiteSpace@42..46 " " - Newline@46..47 "\n" - WhiteSpace@47..51 " " - Error@51..63 - StructKw@51..57 "struct" - WhiteSpace@57..58 " " - Ident@58..61 "Foo" - WhiteSpace@61..62 " " - LBrace@62..63 "{" - Newline@63..65 "\n\n" - WhiteSpace@65..69 " " - Func@69..88 - ItemModifier@69..79 - PubKw@69..72 "pub" - WhiteSpace@72..73 " " - UnsafeKw@73..79 "unsafe" - WhiteSpace@79..80 " " - FnKw@80..82 "fn" - WhiteSpace@82..83 " " - Ident@83..86 "foo" - FuncParamList@86..88 - LParen@86..87 "(" - RParen@87..88 ")" - Newline@88..89 "\n" - RBrace@89..90 "}" + Newline@30..32 "\n\n" + WhiteSpace@32..36 " " + Func@36..48 + ItemModifier@36..39 + PubKw@36..39 "pub" + WhiteSpace@39..40 " " + FnKw@40..42 "fn" + WhiteSpace@42..43 " " + Ident@43..46 "bar" + FuncParamList@46..48 + LParen@46..47 "(" + RParen@47..48 ")" + Newline@48..50 "\n\n" + WhiteSpace@50..54 " " + Item@54..75 + Struct@54..75 + StructKw@54..60 "struct" + WhiteSpace@60..61 " " + Ident@61..64 "Foo" + WhiteSpace@64..65 " " + RecordFieldDefList@65..75 + LBrace@65..66 "{" + Newline@66..68 "\n\n" + WhiteSpace@68..72 " " + RecordFieldDef@72..75 + PubKw@72..75 "pub" + WhiteSpace@75..76 " " + Item@76..93 + Func@76..93 + ItemModifier@76..82 + UnsafeKw@76..82 "unsafe" + WhiteSpace@82..83 " " + FnKw@83..85 "fn" + WhiteSpace@85..86 " " + Ident@86..89 "foo" + FuncParamList@89..91 + LParen@89..90 "(" + RParen@90..91 ")" + Newline@91..92 "\n" + Error@92..93 + RBrace@92..93 "}" diff --git a/crates/parser2/test_files/error_recovery/items/func.snap b/crates/parser2/test_files/error_recovery/items/func.snap index 9c9c2cd676..af1583e0ab 100644 --- a/crates/parser2/test_files/error_recovery/items/func.snap +++ b/crates/parser2/test_files/error_recovery/items/func.snap @@ -40,10 +40,10 @@ Root@0..133 FnParam@26..38 Underscore@26..27 "_" WhiteSpace@27..28 " " - Error@28..33 + Error@28..31 MutKw@28..31 "mut" - WhiteSpace@31..32 " " - Ident@32..33 "y" + WhiteSpace@31..32 " " + Ident@32..33 "y" Colon@33..34 ":" WhiteSpace@34..35 " " PathType@35..38 @@ -73,10 +73,10 @@ Root@0..133 WhiteSpace@54..55 " " Ident@55..56 "u" WhiteSpace@56..57 " " - WhereClause@57..74 + WhereClause@57..72 WhereKw@57..62 "where" WhiteSpace@62..63 " " - WherePredicate@63..74 + WherePredicate@63..72 PathType@63..64 Path@63..64 PathSegment@63..64 @@ -89,8 +89,8 @@ Root@0..133 Path@66..72 PathSegment@66..72 Ident@66..72 "Trait2" - WhiteSpace@72..73 " " - Newline@73..74 "\n" + WhiteSpace@72..73 " " + Newline@73..74 "\n" BlockExpr@74..78 LBrace@74..75 "{" Newline@75..77 "\n\n" @@ -103,15 +103,20 @@ Root@0..133 Ident@83..86 "foo" GenericParamList@86..98 Lt@86..87 "<" - TypeGenericParam@87..98 - Error@87..98 - Lt@87..88 "<" - Lt@88..89 "<" - Ident@89..90 "T" + Error@87..89 + Lt@87..88 "<" + Lt@88..89 "<" + TypeGenericParam@89..97 + Ident@89..90 "T" + TypeBoundList@90..97 Colon@90..91 ":" WhiteSpace@91..92 " " - Ident@92..97 "Trait" - Gt@97..98 ">" + TypeBound@92..97 + TraitRef@92..97 + Path@92..97 + PathSegment@92..97 + Ident@92..97 "Trait" + Gt@97..98 ">" FuncParamList@98..106 LParen@98..99 "(" FnParam@99..105 @@ -125,10 +130,10 @@ Root@0..133 RParen@105..106 ")" Newline@106..107 "\n" WhiteSpace@107..111 " " - WhereClause@111..128 + WhereClause@111..126 WhereKw@111..116 "where" WhiteSpace@116..117 " " - WherePredicate@117..128 + WherePredicate@117..126 PathType@117..118 Path@117..118 PathSegment@117..118 @@ -141,8 +146,8 @@ Root@0..133 Path@120..126 PathSegment@120..126 Ident@120..126 "Trait2" - WhiteSpace@126..127 " " - Newline@127..128 "\n" + WhiteSpace@126..127 " " + Newline@127..128 "\n" BlockExpr@128..132 LBrace@128..129 "{" Newline@129..131 "\n\n" diff --git a/crates/parser2/test_files/error_recovery/items/impl_.snap b/crates/parser2/test_files/error_recovery/items/impl_.snap index be69f26108..fc151f4e6b 100644 --- a/crates/parser2/test_files/error_recovery/items/impl_.snap +++ b/crates/parser2/test_files/error_recovery/items/impl_.snap @@ -28,10 +28,10 @@ Root@0..56 PathType@17..17 Path@17..17 PathSegment@17..17 - WhereClause@17..34 + WhereClause@17..33 WhereKw@17..22 "where" WhiteSpace@22..23 " " - WherePredicate@23..34 + WherePredicate@23..33 PathType@23..24 Path@23..24 PathSegment@23..24 @@ -44,7 +44,7 @@ Root@0..56 Path@26..33 PathSegment@26..33 Ident@26..33 "Integer" - Newline@33..34 "\n" + Newline@33..34 "\n" ImplItemList@34..37 LBrace@34..35 "{" WhiteSpace@35..36 " " @@ -67,10 +67,6 @@ Root@0..56 Ident@48..49 "T" Comma@49..50 "," WhiteSpace@50..51 " " - TypeGenericArg@51..51 - PathType@51..51 - Path@51..51 - PathSegment@51..51 Gt@51..52 ">" Newline@52..53 "\n" ImplItemList@53..56 diff --git a/crates/parser2/test_files/error_recovery/items/impl_trait.fe b/crates/parser2/test_files/error_recovery/items/impl_trait.fe index 19ceebbdb9..b38ce032ff 100644 --- a/crates/parser2/test_files/error_recovery/items/impl_trait.fe +++ b/crates/parser2/test_files/error_recovery/items/impl_trait.fe @@ -1,5 +1,5 @@ -impl X for Y for B" WhiteSpace@14..15 " " ForKw@15..18 "for" @@ -37,7 +37,7 @@ Root@0..90 PathType@19..22 Path@19..20 PathSegment@19..20 - Ident@19..20 "Y" + Ident@19..20 "B" GenericArgList@20..22 Lt@20..21 "<" TypeGenericArg@21..22 @@ -74,7 +74,7 @@ Root@0..90 TraitRef@43..49 Path@43..44 PathSegment@43..44 - Ident@43..44 "X" + Ident@43..44 "C" GenericArgList@44..49 Lt@44..45 "<" TypeGenericArg@45..46 @@ -95,7 +95,7 @@ Root@0..90 PathType@54..57 Path@54..55 PathSegment@54..55 - Ident@54..55 "Y" + Ident@54..55 "D" GenericArgList@55..57 Lt@55..56 "<" TypeGenericArg@56..57 @@ -126,25 +126,22 @@ Root@0..90 RBrace@70..71 "}" Newline@71..73 "\n\n" Item@73..90 - ImplTrait@73..90 + Impl@73..81 ImplKw@73..77 "impl" WhiteSpace@77..78 " " - TraitRef@78..79 + PathType@78..79 Path@78..79 PathSegment@78..79 - Ident@78..79 "X" + Ident@78..79 "E" WhiteSpace@79..80 " " Error@80..81 InvalidToken@80..81 "@" - WhiteSpace@81..82 " " + WhiteSpace@81..82 " " + Error@82..90 ForKw@82..85 "for" WhiteSpace@85..86 " " - PathType@86..87 - Path@86..87 - PathSegment@86..87 - Ident@86..87 "Y" + Ident@86..87 "F" WhiteSpace@87..88 " " - ImplTraitItemList@88..90 - LBrace@88..89 "{" - RBrace@89..90 "}" + LBrace@88..89 "{" + RBrace@89..90 "}" diff --git a/crates/parser2/test_files/error_recovery/items/struct_.snap b/crates/parser2/test_files/error_recovery/items/struct_.snap index c1e8787114..cddf79090e 100644 --- a/crates/parser2/test_files/error_recovery/items/struct_.snap +++ b/crates/parser2/test_files/error_recovery/items/struct_.snap @@ -20,7 +20,7 @@ Root@0..160 TypeGenericParam@14..15 Ident@14..15 "U" Newline@15..16 "\n" - WhereClause@16..40 + WhereClause@16..39 WhereKw@16..21 "where" WhiteSpace@21..22 " " WherePredicate@22..23 @@ -31,7 +31,7 @@ Root@0..160 WhiteSpace@23..24 " " Newline@24..25 "\n" WhiteSpace@25..31 " " - WherePredicate@31..40 + WherePredicate@31..39 PathType@31..32 Path@31..32 PathSegment@31..32 @@ -44,7 +44,7 @@ Root@0..160 Path@34..39 PathSegment@34..39 Ident@34..39 "Trait" - Newline@39..40 "\n" + Newline@39..40 "\n" WhiteSpace@40..44 " " Newline@44..45 "\n" RecordFieldDefList@45..74 diff --git a/crates/parser2/test_files/error_recovery/items/trait_.snap b/crates/parser2/test_files/error_recovery/items/trait_.snap index 453cb4fd1c..4768468b2e 100644 --- a/crates/parser2/test_files/error_recovery/items/trait_.snap +++ b/crates/parser2/test_files/error_recovery/items/trait_.snap @@ -19,7 +19,6 @@ Root@0..133 TypeGenericParam@13..14 Ident@13..14 "Y" Comma@14..15 "," - TypeGenericParam@15..15 Gt@15..16 ">" TraitItemList@16..18 LBrace@16..17 "{" @@ -30,18 +29,17 @@ Root@0..133 TraitKw@20..25 "trait" WhiteSpace@25..26 " " Ident@26..29 "Bar" - GenericParamList@29..33 + GenericParamList@29..32 Lt@29..30 "<" TypeGenericParam@30..31 Ident@30..31 "Y" Comma@31..32 "," - WhiteSpace@32..33 " " - TypeGenericParam@33..33 + WhiteSpace@32..33 " " TraitItemList@33..35 LBrace@33..34 "{" RBrace@34..35 "}" Newline@35..37 "\n\n" - Item@37..53 + Item@37..51 Trait@37..51 TraitKw@37..42 "trait" WhiteSpace@42..43 " " @@ -52,9 +50,8 @@ Root@0..133 Ident@47..48 "T" Comma@48..49 "," WhiteSpace@49..50 " " - TypeGenericParam@50..50 Gt@50..51 ">" - Newline@51..53 "\n\n" + Newline@51..53 "\n\n" Item@53..87 Trait@53..85 TraitKw@53..58 "trait" @@ -69,7 +66,6 @@ Root@0..133 TypeGenericParam@66..67 Ident@66..67 "T" Comma@67..68 "," - TypeGenericParam@68..68 Gt@68..69 ">" WhiteSpace@69..70 " " WhereClause@70..82 @@ -100,10 +96,10 @@ Root@0..133 Ident@93..96 "Bar" GenericParamList@96..108 Lt@96..97 "<" - TypeGenericParam@97..99 - Error@97..99 - Lt@97..98 "<" - Ident@98..99 "Y" + Error@97..98 + Lt@97..98 "<" + TypeGenericParam@98..99 + Ident@98..99 "Y" Comma@99..100 "," WhiteSpace@100..101 " " TypeGenericParam@101..107 @@ -120,10 +116,10 @@ Root@0..133 WhiteSpace@108..110 " " Newline@110..111 "\n" WhiteSpace@111..115 " " - WhereClause@115..129 + WhereClause@115..127 WhereKw@115..120 "where" WhiteSpace@120..121 " " - WherePredicate@121..129 + WherePredicate@121..127 PathType@121..122 Path@121..122 PathSegment@121..122 @@ -136,8 +132,8 @@ Root@0..133 Path@124..127 PathSegment@124..127 Ident@124..127 "Add" - WhiteSpace@127..128 " " - Newline@128..129 "\n" + WhiteSpace@127..128 " " + Newline@128..129 "\n" TraitItemList@129..133 LBrace@129..130 "{" Newline@130..132 "\n\n" diff --git a/crates/parser2/test_files/error_recovery/items/type_.snap b/crates/parser2/test_files/error_recovery/items/type_.snap index 2b16a62168..d5292f1c34 100644 --- a/crates/parser2/test_files/error_recovery/items/type_.snap +++ b/crates/parser2/test_files/error_recovery/items/type_.snap @@ -10,13 +10,12 @@ Root@0..72 TypeKw@0..4 "type" WhiteSpace@4..5 " " Ident@5..11 "Result" - GenericParamList@11..15 + GenericParamList@11..14 Lt@11..12 "<" TypeGenericParam@12..13 Ident@12..13 "T" Comma@13..14 "," - WhiteSpace@14..15 " " - TypeGenericParam@15..15 + WhiteSpace@14..15 " " Eq@15..16 "=" WhiteSpace@16..17 " " PathType@17..29 diff --git a/crates/parser2/test_files/error_recovery/stmts/for_.snap b/crates/parser2/test_files/error_recovery/stmts/for_.snap index f143788693..bd08005e3d 100644 --- a/crates/parser2/test_files/error_recovery/stmts/for_.snap +++ b/crates/parser2/test_files/error_recovery/stmts/for_.snap @@ -16,10 +16,8 @@ Root@0..71 PathSegment@6..7 Ident@6..7 "i" WhiteSpace@7..8 " " - PathExpr@8..11 - Path@8..11 - PathSegment@8..11 - Ident@8..11 "arr" + Error@8..11 + Ident@8..11 "arr" WhiteSpace@11..12 " " BlockExpr@12..15 LBrace@12..13 "{" @@ -48,10 +46,10 @@ Root@0..71 ForKw@33..36 "for" WhiteSpace@36..37 " " PathPat@37..38 - Path@37..38 - PathSegment@37..38 - Error@37..38 - InvalidToken@37..38 "@" + Path@37..37 + PathSegment@37..37 + Error@37..38 + InvalidToken@37..38 "@" WhiteSpace@38..39 " " InKw@39..41 "in" WhiteSpace@41..42 " " @@ -68,10 +66,10 @@ Root@0..71 ForKw@50..53 "for" WhiteSpace@53..54 " " PathPat@54..55 - Path@54..55 - PathSegment@54..55 - Error@54..55 - InvalidToken@54..55 "@" + Path@54..54 + PathSegment@54..54 + Error@54..55 + InvalidToken@54..55 "@" WhiteSpace@55..56 " " InKw@56..58 "in" WhiteSpace@58..59 " " diff --git a/crates/parser2/test_files/syntax_node/items/enums.fe b/crates/parser2/test_files/syntax_node/items/enums.fe index f7e6b035ff..f341d285b6 100644 --- a/crates/parser2/test_files/syntax_node/items/enums.fe +++ b/crates/parser2/test_files/syntax_node/items/enums.fe @@ -26,8 +26,8 @@ where Foo::Bar: Trait enum HKTEnum *, U, V, W> where - U: (* -> *) -> * - V: * -> * -> (* -> *) + U: (* -> *) -> *, + V: * -> * -> (* -> *), W: * -> * -> * -> * { Foo(U) diff --git a/crates/parser2/test_files/syntax_node/items/enums.snap b/crates/parser2/test_files/syntax_node/items/enums.snap index 164b75ef26..734018e9f4 100644 --- a/crates/parser2/test_files/syntax_node/items/enums.snap +++ b/crates/parser2/test_files/syntax_node/items/enums.snap @@ -3,8 +3,8 @@ source: crates/parser2/tests/syntax_node.rs expression: node input_file: crates/parser2/test_files/syntax_node/items/enums.fe --- -Root@0..491 - ItemList@0..491 +Root@0..493 + ItemList@0..493 Item@0..15 Enum@0..13 EnumKw@0..4 "enum" @@ -118,10 +118,10 @@ Root@0..491 Gt@155..156 ">" Newline@156..157 "\n" WhiteSpace@157..161 " " - WhereClause@161..176 + WhereClause@161..175 WhereKw@161..166 "where" WhiteSpace@166..167 " " - WherePredicate@167..176 + WherePredicate@167..175 PathType@167..168 Path@167..168 PathSegment@167..168 @@ -134,7 +134,7 @@ Root@0..491 Path@170..175 PathSegment@170..175 Ident@170..175 "Clone" - Newline@175..176 "\n" + Newline@175..176 "\n" VariantDefList@176..202 LBrace@176..177 "{" Newline@177..178 "\n" @@ -205,10 +205,10 @@ Root@0..491 Ident@243..246 "Div" Gt@246..247 ">" Newline@247..248 "\n" - WhereClause@248..273 + WhereClause@248..272 WhereKw@248..253 "where" WhiteSpace@253..254 " " - WherePredicate@254..273 + WherePredicate@254..272 PathType@254..265 Path@254..262 PathSegment@254..257 @@ -232,7 +232,7 @@ Root@0..491 Path@267..272 PathSegment@267..272 Ident@267..272 "Trait" - Newline@272..273 "\n" + Newline@272..273 "\n" VariantDefList@273..306 LBrace@273..274 "{" Newline@274..275 "\n" @@ -262,8 +262,8 @@ Root@0..491 Newline@304..305 "\n" RBrace@305..306 "}" Newline@306..308 "\n\n" - Item@308..434 - Enum@308..432 + Item@308..436 + Enum@308..434 EnumKw@308..312 "enum" WhiteSpace@312..313 " " Ident@313..320 "HKTEnum" @@ -297,11 +297,11 @@ Root@0..491 Ident@338..339 "W" Gt@339..340 ">" Newline@340..341 "\n" - WhereClause@341..415 + WhereClause@341..416 WhereKw@341..346 "where" Newline@346..347 "\n" WhiteSpace@347..350 " " - WherePredicate@350..367 + WherePredicate@350..366 PathType@350..351 Path@350..351 PathSegment@350..351 @@ -326,156 +326,158 @@ Root@0..491 WhiteSpace@364..365 " " KindBoundMono@365..366 Star@365..366 "*" - Newline@366..367 "\n" - WhiteSpace@367..370 " " - WherePredicate@370..392 - PathType@370..371 - Path@370..371 - PathSegment@370..371 - Ident@370..371 "V" - TypeBoundList@371..391 - Colon@371..372 ":" - WhiteSpace@372..373 " " - TypeBound@373..391 - KindBoundAbs@373..391 - KindBoundMono@373..374 - Star@373..374 "*" - WhiteSpace@374..375 " " - Arrow@375..377 "->" - KindBoundAbs@377..391 - WhiteSpace@377..378 " " - KindBoundMono@378..379 - Star@378..379 "*" - WhiteSpace@379..380 " " - Arrow@380..382 "->" - WhiteSpace@382..383 " " - LParen@383..384 "(" - KindBoundAbs@384..390 - KindBoundMono@384..385 - Star@384..385 "*" - WhiteSpace@385..386 " " - Arrow@386..388 "->" - WhiteSpace@388..389 " " - KindBoundMono@389..390 - Star@389..390 "*" - RParen@390..391 ")" - Newline@391..392 "\n" - WhiteSpace@392..395 " " - WherePredicate@395..415 - PathType@395..396 - Path@395..396 - PathSegment@395..396 - Ident@395..396 "W" - TypeBoundList@396..414 - Colon@396..397 ":" - WhiteSpace@397..398 " " - TypeBound@398..414 - KindBoundAbs@398..414 - KindBoundMono@398..399 - Star@398..399 "*" - WhiteSpace@399..400 " " - Arrow@400..402 "->" - KindBoundAbs@402..414 - WhiteSpace@402..403 " " - KindBoundMono@403..404 - Star@403..404 "*" + Comma@366..367 "," + Newline@367..368 "\n" + WhiteSpace@368..371 " " + WherePredicate@371..392 + PathType@371..372 + Path@371..372 + PathSegment@371..372 + Ident@371..372 "V" + TypeBoundList@372..392 + Colon@372..373 ":" + WhiteSpace@373..374 " " + TypeBound@374..392 + KindBoundAbs@374..392 + KindBoundMono@374..375 + Star@374..375 "*" + WhiteSpace@375..376 " " + Arrow@376..378 "->" + KindBoundAbs@378..392 + WhiteSpace@378..379 " " + KindBoundMono@379..380 + Star@379..380 "*" + WhiteSpace@380..381 " " + Arrow@381..383 "->" + WhiteSpace@383..384 " " + LParen@384..385 "(" + KindBoundAbs@385..391 + KindBoundMono@385..386 + Star@385..386 "*" + WhiteSpace@386..387 " " + Arrow@387..389 "->" + WhiteSpace@389..390 " " + KindBoundMono@390..391 + Star@390..391 "*" + RParen@391..392 ")" + Comma@392..393 "," + Newline@393..394 "\n" + WhiteSpace@394..397 " " + WherePredicate@397..416 + PathType@397..398 + Path@397..398 + PathSegment@397..398 + Ident@397..398 "W" + TypeBoundList@398..416 + Colon@398..399 ":" + WhiteSpace@399..400 " " + TypeBound@400..416 + KindBoundAbs@400..416 + KindBoundMono@400..401 + Star@400..401 "*" + WhiteSpace@401..402 " " + Arrow@402..404 "->" + KindBoundAbs@404..416 WhiteSpace@404..405 " " - Arrow@405..407 "->" - KindBoundAbs@407..414 - WhiteSpace@407..408 " " - KindBoundMono@408..409 - Star@408..409 "*" + KindBoundMono@405..406 + Star@405..406 "*" + WhiteSpace@406..407 " " + Arrow@407..409 "->" + KindBoundAbs@409..416 WhiteSpace@409..410 " " - Arrow@410..412 "->" - WhiteSpace@412..413 " " - KindBoundMono@413..414 - Star@413..414 "*" - Newline@414..415 "\n" - VariantDefList@415..432 - LBrace@415..416 "{" - Newline@416..417 "\n" - WhiteSpace@417..421 " " - VariantDef@421..430 - Ident@421..424 "Foo" - TupleType@424..430 - LParen@424..425 "(" - PathType@425..429 - Path@425..426 - PathSegment@425..426 - Ident@425..426 "U" - GenericArgList@426..429 - Lt@426..427 "<" - TypeGenericArg@427..428 - PathType@427..428 - Path@427..428 - PathSegment@427..428 - Ident@427..428 "T" - Gt@428..429 ">" - RParen@429..430 ")" - Newline@430..431 "\n" - RBrace@431..432 "}" - Newline@432..434 "\n\n" - Item@434..491 - Enum@434..490 - EnumKw@434..438 "enum" - WhiteSpace@438..439 " " - Ident@439..449 "SingleLine" - WhiteSpace@449..450 " " - VariantDefList@450..490 - LBrace@450..451 "{" - WhiteSpace@451..452 " " - VariantDef@452..453 - Ident@452..453 "A" - Comma@453..454 "," - WhiteSpace@454..455 " " - VariantDef@455..456 - Ident@455..456 "B" - Comma@456..457 "," - WhiteSpace@457..458 " " - VariantDef@458..477 - Ident@458..459 "C" - WhiteSpace@459..460 " " - RecordFieldDefList@460..477 - LBrace@460..461 "{" - WhiteSpace@461..462 " " - RecordFieldDef@462..468 - Ident@462..463 "x" - Colon@463..464 ":" - WhiteSpace@464..465 " " - PathType@465..468 - Path@465..468 - PathSegment@465..468 - Ident@465..468 "i32" - Comma@468..469 "," - WhiteSpace@469..470 " " - RecordFieldDef@470..475 - Ident@470..471 "y" - Colon@471..472 ":" - WhiteSpace@472..473 " " - PathType@473..475 - Path@473..475 - PathSegment@473..475 - Ident@473..475 "u8" - WhiteSpace@475..476 " " - RBrace@476..477 "}" - Comma@477..478 "," - WhiteSpace@478..479 " " - VariantDef@479..488 - Ident@479..480 "D" - TupleType@480..488 - LParen@480..481 "(" - PathType@481..483 - Path@481..483 - PathSegment@481..483 - Ident@481..483 "i8" - Comma@483..484 "," - WhiteSpace@484..485 " " - PathType@485..487 - Path@485..487 - PathSegment@485..487 - Ident@485..487 "i8" - RParen@487..488 ")" - WhiteSpace@488..489 " " - RBrace@489..490 "}" - Newline@490..491 "\n" + KindBoundMono@410..411 + Star@410..411 "*" + WhiteSpace@411..412 " " + Arrow@412..414 "->" + WhiteSpace@414..415 " " + KindBoundMono@415..416 + Star@415..416 "*" + Newline@416..417 "\n" + VariantDefList@417..434 + LBrace@417..418 "{" + Newline@418..419 "\n" + WhiteSpace@419..423 " " + VariantDef@423..432 + Ident@423..426 "Foo" + TupleType@426..432 + LParen@426..427 "(" + PathType@427..431 + Path@427..428 + PathSegment@427..428 + Ident@427..428 "U" + GenericArgList@428..431 + Lt@428..429 "<" + TypeGenericArg@429..430 + PathType@429..430 + Path@429..430 + PathSegment@429..430 + Ident@429..430 "T" + Gt@430..431 ">" + RParen@431..432 ")" + Newline@432..433 "\n" + RBrace@433..434 "}" + Newline@434..436 "\n\n" + Item@436..493 + Enum@436..492 + EnumKw@436..440 "enum" + WhiteSpace@440..441 " " + Ident@441..451 "SingleLine" + WhiteSpace@451..452 " " + VariantDefList@452..492 + LBrace@452..453 "{" + WhiteSpace@453..454 " " + VariantDef@454..455 + Ident@454..455 "A" + Comma@455..456 "," + WhiteSpace@456..457 " " + VariantDef@457..458 + Ident@457..458 "B" + Comma@458..459 "," + WhiteSpace@459..460 " " + VariantDef@460..479 + Ident@460..461 "C" + WhiteSpace@461..462 " " + RecordFieldDefList@462..479 + LBrace@462..463 "{" + WhiteSpace@463..464 " " + RecordFieldDef@464..470 + Ident@464..465 "x" + Colon@465..466 ":" + WhiteSpace@466..467 " " + PathType@467..470 + Path@467..470 + PathSegment@467..470 + Ident@467..470 "i32" + Comma@470..471 "," + WhiteSpace@471..472 " " + RecordFieldDef@472..477 + Ident@472..473 "y" + Colon@473..474 ":" + WhiteSpace@474..475 " " + PathType@475..477 + Path@475..477 + PathSegment@475..477 + Ident@475..477 "u8" + WhiteSpace@477..478 " " + RBrace@478..479 "}" + Comma@479..480 "," + WhiteSpace@480..481 " " + VariantDef@481..490 + Ident@481..482 "D" + TupleType@482..490 + LParen@482..483 "(" + PathType@483..485 + Path@483..485 + PathSegment@483..485 + Ident@483..485 "i8" + Comma@485..486 "," + WhiteSpace@486..487 " " + PathType@487..489 + Path@487..489 + PathSegment@487..489 + Ident@487..489 "i8" + RParen@489..490 ")" + WhiteSpace@490..491 " " + RBrace@491..492 "}" + Newline@492..493 "\n" diff --git a/crates/parser2/test_files/syntax_node/items/func.fe b/crates/parser2/test_files/syntax_node/items/func.fe index c8d6f445f6..c727427859 100644 --- a/crates/parser2/test_files/syntax_node/items/func.fe +++ b/crates/parser2/test_files/syntax_node/items/func.fe @@ -11,9 +11,9 @@ fn baz(from sender: address, mut to recipient: address, _ val: u256, _ _: u256) } fn generics1(t: T, u: Option) -> T - where Result: Trait + where Result: Trait, Option: Clone - + { t } diff --git a/crates/parser2/test_files/syntax_node/items/func.snap b/crates/parser2/test_files/syntax_node/items/func.snap index 88833e5dfb..c1c5235f6e 100644 --- a/crates/parser2/test_files/syntax_node/items/func.snap +++ b/crates/parser2/test_files/syntax_node/items/func.snap @@ -3,8 +3,8 @@ source: crates/parser2/tests/syntax_node.rs expression: node input_file: crates/parser2/test_files/syntax_node/items/func.fe --- -Root@0..361 - ItemList@0..361 +Root@0..351 + ItemList@0..351 Item@0..32 Func@0..30 ItemModifier@0..3 @@ -159,8 +159,8 @@ Root@0..361 Newline@176..177 "\n" RBrace@177..178 "}" Newline@178..180 "\n\n" - Item@180..308 - Func@180..306 + Item@180..298 + Func@180..296 FnKw@180..182 "fn" WhiteSpace@182..183 " " Ident@183..192 "generics1" @@ -219,10 +219,10 @@ Root@0..361 Ident@229..230 "T" Newline@230..231 "\n" WhiteSpace@231..235 " " - WhereClause@235..286 + WhereClause@235..285 WhereKw@235..240 "where" WhiteSpace@240..241 " " - WherePredicate@241..259 + WherePredicate@241..257 PathType@241..250 Path@241..247 PathSegment@241..247 @@ -243,10 +243,10 @@ Root@0..361 Path@252..257 PathSegment@252..257 Ident@252..257 "Trait" - WhiteSpace@257..258 " " - Newline@258..259 "\n" + Comma@257..258 "," + Newline@258..259 "\n" WhiteSpace@259..269 " " - WherePredicate@269..286 + WherePredicate@269..285 PathType@269..278 Path@269..275 PathSegment@269..275 @@ -267,85 +267,83 @@ Root@0..361 Path@280..285 PathSegment@280..285 Ident@280..285 "Clone" - Newline@285..286 "\n" - WhiteSpace@286..296 " " - Newline@296..297 "\n" - BlockExpr@297..306 - LBrace@297..298 "{" - Newline@298..299 "\n" - WhiteSpace@299..303 " " - ExprStmt@303..304 - PathExpr@303..304 - Path@303..304 - PathSegment@303..304 - Ident@303..304 "t" - Newline@304..305 "\n" - RBrace@305..306 "}" - Newline@306..308 "\n\n" - Item@308..361 - Func@308..361 - FnKw@308..310 "fn" - WhiteSpace@310..311 " " - Ident@311..315 "decl" - GenericParamList@315..321 - Lt@315..316 "<" - TypeGenericParam@316..317 - Ident@316..317 "T" - Comma@317..318 "," - WhiteSpace@318..319 " " - TypeGenericParam@319..320 - Ident@319..320 "U" - Gt@320..321 ">" - FuncParamList@321..340 - LParen@321..322 "(" - FnParam@322..339 - Ident@322..323 "t" - Colon@323..324 ":" - WhiteSpace@324..325 " " - PathType@325..339 - Path@325..333 - PathSegment@325..333 - Ident@325..333 "MyStruct" - GenericArgList@333..339 - Lt@333..334 "<" - TypeGenericArg@334..335 - PathType@334..335 - Path@334..335 - PathSegment@334..335 - Ident@334..335 "T" - Comma@335..336 "," - WhiteSpace@336..337 " " - TypeGenericArg@337..338 - PathType@337..338 - Path@337..338 - PathSegment@337..338 - Ident@337..338 "U" - Gt@338..339 ">" - RParen@339..340 ")" - WhiteSpace@340..341 " " - Arrow@341..343 "->" - WhiteSpace@343..344 " " - PathType@344..358 - Path@344..350 - PathSegment@344..350 - Ident@344..350 "Result" - GenericArgList@350..358 - Lt@350..351 "<" - TypeGenericArg@351..352 - PathType@351..352 - Path@351..352 - PathSegment@351..352 - Ident@351..352 "T" - Comma@352..353 "," - WhiteSpace@353..354 " " - TypeGenericArg@354..357 - PathType@354..357 - Path@354..357 - PathSegment@354..357 - Ident@354..357 "Err" - Gt@357..358 ">" - WhiteSpace@358..359 " " - BlockExpr@359..361 - LBrace@359..360 "{" - RBrace@360..361 "}" + Newline@285..287 "\n\n" + BlockExpr@287..296 + LBrace@287..288 "{" + Newline@288..289 "\n" + WhiteSpace@289..293 " " + ExprStmt@293..294 + PathExpr@293..294 + Path@293..294 + PathSegment@293..294 + Ident@293..294 "t" + Newline@294..295 "\n" + RBrace@295..296 "}" + Newline@296..298 "\n\n" + Item@298..351 + Func@298..351 + FnKw@298..300 "fn" + WhiteSpace@300..301 " " + Ident@301..305 "decl" + GenericParamList@305..311 + Lt@305..306 "<" + TypeGenericParam@306..307 + Ident@306..307 "T" + Comma@307..308 "," + WhiteSpace@308..309 " " + TypeGenericParam@309..310 + Ident@309..310 "U" + Gt@310..311 ">" + FuncParamList@311..330 + LParen@311..312 "(" + FnParam@312..329 + Ident@312..313 "t" + Colon@313..314 ":" + WhiteSpace@314..315 " " + PathType@315..329 + Path@315..323 + PathSegment@315..323 + Ident@315..323 "MyStruct" + GenericArgList@323..329 + Lt@323..324 "<" + TypeGenericArg@324..325 + PathType@324..325 + Path@324..325 + PathSegment@324..325 + Ident@324..325 "T" + Comma@325..326 "," + WhiteSpace@326..327 " " + TypeGenericArg@327..328 + PathType@327..328 + Path@327..328 + PathSegment@327..328 + Ident@327..328 "U" + Gt@328..329 ">" + RParen@329..330 ")" + WhiteSpace@330..331 " " + Arrow@331..333 "->" + WhiteSpace@333..334 " " + PathType@334..348 + Path@334..340 + PathSegment@334..340 + Ident@334..340 "Result" + GenericArgList@340..348 + Lt@340..341 "<" + TypeGenericArg@341..342 + PathType@341..342 + Path@341..342 + PathSegment@341..342 + Ident@341..342 "T" + Comma@342..343 "," + WhiteSpace@343..344 " " + TypeGenericArg@344..347 + PathType@344..347 + Path@344..347 + PathSegment@344..347 + Ident@344..347 "Err" + Gt@347..348 ">" + WhiteSpace@348..349 " " + BlockExpr@349..351 + LBrace@349..350 "{" + RBrace@350..351 "}" diff --git a/crates/parser2/test_files/syntax_node/items/impl.snap b/crates/parser2/test_files/syntax_node/items/impl.snap index 002a709caa..c984174c5e 100644 --- a/crates/parser2/test_files/syntax_node/items/impl.snap +++ b/crates/parser2/test_files/syntax_node/items/impl.snap @@ -136,10 +136,10 @@ Root@0..272 Gt@152..153 ">" WhiteSpace@153..154 " " Newline@154..155 "\n" - WhereClause@155..175 + WhereClause@155..174 WhereKw@155..160 "where" WhiteSpace@160..161 " " - WherePredicate@161..175 + WherePredicate@161..174 PathType@161..167 Path@161..164 PathSegment@161..164 @@ -160,7 +160,7 @@ Root@0..272 Path@169..174 PathSegment@169..174 Ident@169..174 "Clone" - Newline@174..175 "\n" + Newline@174..175 "\n" ImplItemList@175..272 LBrace@175..176 "{" Newline@176..177 "\n" @@ -208,10 +208,10 @@ Root@0..272 WhiteSpace@212..213 " " Newline@213..214 "\n" WhiteSpace@214..222 " " - WhereClause@222..236 + WhereClause@222..235 WhereKw@222..227 "where" WhiteSpace@227..228 " " - WherePredicate@228..236 + WherePredicate@228..235 PathType@228..229 Path@228..229 PathSegment@228..229 @@ -224,7 +224,7 @@ Root@0..272 Path@231..235 PathSegment@231..235 Ident@231..235 "Copy" - Newline@235..236 "\n" + Newline@235..236 "\n" WhiteSpace@236..240 " " BlockExpr@240..270 LBrace@240..241 "{" diff --git a/crates/parser2/test_files/syntax_node/items/impl_trait.fe b/crates/parser2/test_files/syntax_node/items/impl_trait.fe index 99e2b4fd20..dfd87c9005 100644 --- a/crates/parser2/test_files/syntax_node/items/impl_trait.fe +++ b/crates/parser2/test_files/syntax_node/items/impl_trait.fe @@ -4,8 +4,8 @@ impl Trait for F { } } -impl Trait for F -where T: Clone +impl Trait for F +where T: Clone, U: Bar { fn foo>(t: T) { @@ -13,7 +13,7 @@ where T: Clone } } -impl Trait for F +impl Trait for F where U: Bar { fn foo>(t: T) { diff --git a/crates/parser2/test_files/syntax_node/items/impl_trait.snap b/crates/parser2/test_files/syntax_node/items/impl_trait.snap index b792987ec3..aaa6cb9c8e 100644 --- a/crates/parser2/test_files/syntax_node/items/impl_trait.snap +++ b/crates/parser2/test_files/syntax_node/items/impl_trait.snap @@ -3,8 +3,8 @@ source: crates/parser2/tests/syntax_node.rs expression: node input_file: crates/parser2/test_files/syntax_node/items/impl_trait.fe --- -Root@0..335 - ItemList@0..335 +Root@0..334 + ItemList@0..334 Item@0..69 ImplTrait@0..67 ImplKw@0..4 "impl" @@ -117,27 +117,27 @@ Root@0..335 PathSegment@98..99 Ident@98..99 "T" Gt@99..100 ">" - WhiteSpace@100..101 " " - Newline@101..102 "\n" - WhereClause@102..130 - WhereKw@102..107 "where" - WhiteSpace@107..108 " " - WherePredicate@108..117 - PathType@108..109 - Path@108..109 - PathSegment@108..109 - Ident@108..109 "T" - TypeBoundList@109..116 - Colon@109..110 ":" - WhiteSpace@110..111 " " - TypeBound@111..116 - TraitRef@111..116 - Path@111..116 - PathSegment@111..116 - Ident@111..116 "Clone" - Newline@116..117 "\n" + Newline@100..101 "\n" + WhereClause@101..129 + WhereKw@101..106 "where" + WhiteSpace@106..107 " " + WherePredicate@107..115 + PathType@107..108 + Path@107..108 + PathSegment@107..108 + Ident@107..108 "T" + TypeBoundList@108..115 + Colon@108..109 ":" + WhiteSpace@109..110 " " + TypeBound@110..115 + TraitRef@110..115 + Path@110..115 + PathSegment@110..115 + Ident@110..115 "Clone" + Comma@115..116 "," + Newline@116..117 "\n" WhiteSpace@117..123 " " - WherePredicate@123..130 + WherePredicate@123..129 PathType@123..124 Path@123..124 PathSegment@123..124 @@ -150,7 +150,7 @@ Root@0..335 Path@126..129 PathSegment@126..129 Ident@126..129 "Bar" - Newline@129..130 "\n" + Newline@129..130 "\n" ImplTraitItemList@130..205 LBrace@130..131 "{" Newline@131..132 "\n" @@ -224,8 +224,8 @@ Root@0..335 Newline@203..204 "\n" RBrace@204..205 "}" Newline@205..207 "\n\n" - Item@207..335 - ImplTrait@207..335 + Item@207..334 + ImplTrait@207..334 ImplKw@207..211 "impl" GenericParamList@211..224 Lt@211..212 "<" @@ -279,95 +279,94 @@ Root@0..335 PathSegment@243..244 Ident@243..244 "U" Gt@244..245 ">" - WhiteSpace@245..246 " " - Newline@246..247 "\n" - WhereClause@247..260 - WhereKw@247..252 "where" - WhiteSpace@252..253 " " - WherePredicate@253..260 - PathType@253..254 - Path@253..254 - PathSegment@253..254 - Ident@253..254 "U" - TypeBoundList@254..259 - Colon@254..255 ":" - WhiteSpace@255..256 " " - TypeBound@256..259 - TraitRef@256..259 - Path@256..259 - PathSegment@256..259 - Ident@256..259 "Bar" - Newline@259..260 "\n" - ImplTraitItemList@260..335 - LBrace@260..261 "{" - Newline@261..262 "\n" - WhiteSpace@262..266 " " - Func@266..333 - FnKw@266..268 "fn" - WhiteSpace@268..269 " " - Ident@269..272 "foo" - GenericParamList@272..290 - Lt@272..273 "<" - TypeGenericParam@273..289 - Ident@273..274 "T" - TypeBoundList@274..289 - Colon@274..275 ":" - WhiteSpace@275..276 " " - TypeBound@276..289 - TraitRef@276..289 - Path@276..286 - PathSegment@276..286 - Ident@276..286 "OtherTrait" - GenericArgList@286..289 - Lt@286..287 "<" - TypeGenericArg@287..288 - PathType@287..288 - Path@287..288 - PathSegment@287..288 - Ident@287..288 "U" - Gt@288..289 ">" - Gt@289..290 ">" - FuncParamList@290..296 - LParen@290..291 "(" - FnParam@291..295 - Ident@291..292 "t" - Colon@292..293 ":" - WhiteSpace@293..294 " " - PathType@294..295 - Path@294..295 - PathSegment@294..295 - Ident@294..295 "T" - RParen@295..296 ")" - WhiteSpace@296..297 " " - BlockExpr@297..333 - LBrace@297..298 "{" - Newline@298..299 "\n" - WhiteSpace@299..307 " " - ExprStmt@307..327 - CallExpr@307..327 - PathExpr@307..319 - Path@307..319 - PathSegment@307..319 - Ident@307..319 "do_something" - GenericArgList@319..324 - Lt@319..320 "<" - TypeGenericArg@320..323 - PathType@320..323 - Path@320..323 - PathSegment@320..323 - Ident@320..323 "i32" - Gt@323..324 ">" - CallArgList@324..327 - LParen@324..325 "(" - CallArg@325..326 - PathExpr@325..326 - Path@325..326 - PathSegment@325..326 - Ident@325..326 "t" - RParen@326..327 ")" - Newline@327..328 "\n" - WhiteSpace@328..332 " " - RBrace@332..333 "}" - Newline@333..334 "\n" - RBrace@334..335 "}" + Newline@245..246 "\n" + WhereClause@246..258 + WhereKw@246..251 "where" + WhiteSpace@251..252 " " + WherePredicate@252..258 + PathType@252..253 + Path@252..253 + PathSegment@252..253 + Ident@252..253 "U" + TypeBoundList@253..258 + Colon@253..254 ":" + WhiteSpace@254..255 " " + TypeBound@255..258 + TraitRef@255..258 + Path@255..258 + PathSegment@255..258 + Ident@255..258 "Bar" + Newline@258..259 "\n" + ImplTraitItemList@259..334 + LBrace@259..260 "{" + Newline@260..261 "\n" + WhiteSpace@261..265 " " + Func@265..332 + FnKw@265..267 "fn" + WhiteSpace@267..268 " " + Ident@268..271 "foo" + GenericParamList@271..289 + Lt@271..272 "<" + TypeGenericParam@272..288 + Ident@272..273 "T" + TypeBoundList@273..288 + Colon@273..274 ":" + WhiteSpace@274..275 " " + TypeBound@275..288 + TraitRef@275..288 + Path@275..285 + PathSegment@275..285 + Ident@275..285 "OtherTrait" + GenericArgList@285..288 + Lt@285..286 "<" + TypeGenericArg@286..287 + PathType@286..287 + Path@286..287 + PathSegment@286..287 + Ident@286..287 "U" + Gt@287..288 ">" + Gt@288..289 ">" + FuncParamList@289..295 + LParen@289..290 "(" + FnParam@290..294 + Ident@290..291 "t" + Colon@291..292 ":" + WhiteSpace@292..293 " " + PathType@293..294 + Path@293..294 + PathSegment@293..294 + Ident@293..294 "T" + RParen@294..295 ")" + WhiteSpace@295..296 " " + BlockExpr@296..332 + LBrace@296..297 "{" + Newline@297..298 "\n" + WhiteSpace@298..306 " " + ExprStmt@306..326 + CallExpr@306..326 + PathExpr@306..318 + Path@306..318 + PathSegment@306..318 + Ident@306..318 "do_something" + GenericArgList@318..323 + Lt@318..319 "<" + TypeGenericArg@319..322 + PathType@319..322 + Path@319..322 + PathSegment@319..322 + Ident@319..322 "i32" + Gt@322..323 ">" + CallArgList@323..326 + LParen@323..324 "(" + CallArg@324..325 + PathExpr@324..325 + Path@324..325 + PathSegment@324..325 + Ident@324..325 "t" + RParen@325..326 ")" + Newline@326..327 "\n" + WhiteSpace@327..331 " " + RBrace@331..332 "}" + Newline@332..333 "\n" + RBrace@333..334 "}" diff --git a/crates/parser2/test_files/syntax_node/items/trait.snap b/crates/parser2/test_files/syntax_node/items/trait.snap index 3e14ddc27e..60cb70e803 100644 --- a/crates/parser2/test_files/syntax_node/items/trait.snap +++ b/crates/parser2/test_files/syntax_node/items/trait.snap @@ -203,7 +203,7 @@ Root@0..652 LBrace@209..210 "{" Newline@210..211 "\n" WhiteSpace@211..215 " " - Func@215..270 + Func@215..269 FnKw@215..217 "fn" WhiteSpace@217..218 " " Ident@218..221 "add" @@ -230,10 +230,10 @@ Root@0..652 WhiteSpace@245..246 " " Newline@246..247 "\n" WhiteSpace@247..255 " " - WhereClause@255..270 + WhereClause@255..269 WhereKw@255..260 "where" WhiteSpace@260..261 " " - WherePredicate@261..270 + WherePredicate@261..269 PathType@261..264 Path@261..264 PathSegment@261..264 @@ -246,7 +246,7 @@ Root@0..652 Path@266..269 PathSegment@266..269 Ident@266..269 "Sub" - Newline@269..270 "\n" + Newline@269..270 "\n" RBrace@270..271 "}" Newline@271..274 "\n\n\n" Item@274..357 @@ -333,10 +333,10 @@ Root@0..652 WhiteSpace@374..375 " " Newline@375..376 "\n" WhiteSpace@376..380 " " - WhereClause@380..409 + WhereClause@380..408 WhereKw@380..385 "where" WhiteSpace@385..386 " " - WherePredicate@386..409 + WherePredicate@386..408 PathType@386..387 Path@386..387 PathSegment@386..387 @@ -357,7 +357,7 @@ Root@0..652 Path@403..408 PathSegment@403..408 Ident@403..408 "Clone" - Newline@408..409 "\n" + Newline@408..409 "\n" ImplItemList@409..592 LBrace@409..410 "{" Newline@410..411 "\n" @@ -521,10 +521,10 @@ Root@0..652 Gt@631..632 ">" WhiteSpace@632..633 " " Newline@633..634 "\n" - WhereClause@634..650 + WhereClause@634..649 WhereKw@634..639 "where" WhiteSpace@639..640 " " - WherePredicate@640..650 + WherePredicate@640..649 PathType@640..641 Path@640..641 PathSegment@640..641 @@ -545,7 +545,7 @@ Root@0..652 PathSegment@647..648 Ident@647..648 "T" Gt@648..649 ">" - Newline@649..650 "\n" + Newline@649..650 "\n" TraitItemList@650..652 LBrace@650..651 "{" RBrace@651..652 "}" diff --git a/crates/parser2/test_files/syntax_node/structs/generics.fe b/crates/parser2/test_files/syntax_node/structs/generics.fe index af3c862084..2b1483bcfb 100644 --- a/crates/parser2/test_files/syntax_node/structs/generics.fe +++ b/crates/parser2/test_files/syntax_node/structs/generics.fe @@ -20,9 +20,9 @@ pub struct StructWithGenericParam3< T, U: bar::Trait > where - T: Trait1 + Trait2 - Option: Trait1 + Trait2 - Result: Trait2 + Trait3 + T: Trait1 + Trait2, + Option: Trait1 + Trait2, + Result: Trait2 + Trait3, { x: S, y: T, diff --git a/crates/parser2/test_files/syntax_node/structs/generics.snap b/crates/parser2/test_files/syntax_node/structs/generics.snap index eae9111356..b714a4ad32 100644 --- a/crates/parser2/test_files/syntax_node/structs/generics.snap +++ b/crates/parser2/test_files/syntax_node/structs/generics.snap @@ -3,8 +3,8 @@ source: crates/parser2/tests/syntax_node.rs expression: node input_file: crates/parser2/test_files/syntax_node/structs/generics.fe --- -Root@0..560 - ItemList@0..560 +Root@0..563 + ItemList@0..563 Item@0..78 Struct@0..76 ItemModifier@0..3 @@ -154,8 +154,8 @@ Root@0..560 Newline@188..189 "\n" RBrace@189..190 "}" Newline@190..192 "\n\n" - Item@192..413 - Struct@192..411 + Item@192..416 + Struct@192..414 ItemModifier@192..195 PubKw@192..195 "pub" WhiteSpace@195..196 " " @@ -214,11 +214,11 @@ Root@0..560 Newline@284..285 "\n" Gt@285..286 ">" WhiteSpace@286..287 " " - WhereClause@287..378 + WhereClause@287..380 WhereKw@287..292 "where" Newline@292..293 "\n" WhiteSpace@293..297 " " - WherePredicate@297..316 + WherePredicate@297..315 PathType@297..298 Path@297..298 PathSegment@297..298 @@ -239,243 +239,246 @@ Root@0..560 Path@309..315 PathSegment@309..315 Ident@309..315 "Trait2" - Newline@315..316 "\n" - WhiteSpace@316..320 " " - WherePredicate@320..347 - PathType@320..329 - Path@320..326 - PathSegment@320..326 - Ident@320..326 "Option" - GenericArgList@326..329 - Lt@326..327 "<" - TypeGenericArg@327..328 - PathType@327..328 - Path@327..328 - PathSegment@327..328 - Ident@327..328 "T" - Gt@328..329 ">" - TypeBoundList@329..346 - Colon@329..330 ":" - WhiteSpace@330..331 " " - TypeBound@331..337 - TraitRef@331..337 - Path@331..337 - PathSegment@331..337 - Ident@331..337 "Trait1" - WhiteSpace@337..338 " " - Plus@338..339 "+" - WhiteSpace@339..340 " " - TypeBound@340..346 - TraitRef@340..346 - Path@340..346 - PathSegment@340..346 - Ident@340..346 "Trait2" - Newline@346..347 "\n" - WhiteSpace@347..351 " " - WherePredicate@351..378 - PathType@351..360 - Path@351..357 - PathSegment@351..357 - Ident@351..357 "Result" - GenericArgList@357..360 - Lt@357..358 "<" - TypeGenericArg@358..359 - PathType@358..359 - Path@358..359 - PathSegment@358..359 - Ident@358..359 "U" - Gt@359..360 ">" - TypeBoundList@360..377 - Colon@360..361 ":" - WhiteSpace@361..362 " " - TypeBound@362..368 - TraitRef@362..368 - Path@362..368 - PathSegment@362..368 - Ident@362..368 "Trait2" - WhiteSpace@368..369 " " - Plus@369..370 "+" + Comma@315..316 "," + Newline@316..317 "\n" + WhiteSpace@317..321 " " + WherePredicate@321..347 + PathType@321..330 + Path@321..327 + PathSegment@321..327 + Ident@321..327 "Option" + GenericArgList@327..330 + Lt@327..328 "<" + TypeGenericArg@328..329 + PathType@328..329 + Path@328..329 + PathSegment@328..329 + Ident@328..329 "T" + Gt@329..330 ">" + TypeBoundList@330..347 + Colon@330..331 ":" + WhiteSpace@331..332 " " + TypeBound@332..338 + TraitRef@332..338 + Path@332..338 + PathSegment@332..338 + Ident@332..338 "Trait1" + WhiteSpace@338..339 " " + Plus@339..340 "+" + WhiteSpace@340..341 " " + TypeBound@341..347 + TraitRef@341..347 + Path@341..347 + PathSegment@341..347 + Ident@341..347 "Trait2" + Comma@347..348 "," + Newline@348..349 "\n" + WhiteSpace@349..353 " " + WherePredicate@353..379 + PathType@353..362 + Path@353..359 + PathSegment@353..359 + Ident@353..359 "Result" + GenericArgList@359..362 + Lt@359..360 "<" + TypeGenericArg@360..361 + PathType@360..361 + Path@360..361 + PathSegment@360..361 + Ident@360..361 "U" + Gt@361..362 ">" + TypeBoundList@362..379 + Colon@362..363 ":" + WhiteSpace@363..364 " " + TypeBound@364..370 + TraitRef@364..370 + Path@364..370 + PathSegment@364..370 + Ident@364..370 "Trait2" WhiteSpace@370..371 " " - TypeBound@371..377 - TraitRef@371..377 - Path@371..377 - PathSegment@371..377 - Ident@371..377 "Trait3" - Newline@377..378 "\n" - RecordFieldDefList@378..411 - LBrace@378..379 "{" - Newline@379..380 "\n" - WhiteSpace@380..384 " " - RecordFieldDef@384..388 - Ident@384..385 "x" - Colon@385..386 ":" - WhiteSpace@386..387 " " - PathType@387..388 - Path@387..388 - PathSegment@387..388 - Ident@387..388 "S" - Comma@388..389 "," - Newline@389..390 "\n" - WhiteSpace@390..394 " " - RecordFieldDef@394..398 - Ident@394..395 "y" - Colon@395..396 ":" - WhiteSpace@396..397 " " - PathType@397..398 - Path@397..398 - PathSegment@397..398 - Ident@397..398 "T" - Comma@398..399 "," - Newline@399..400 "\n" - WhiteSpace@400..404 " " - RecordFieldDef@404..408 - Ident@404..405 "z" - Colon@405..406 ":" - WhiteSpace@406..407 " " - PathType@407..408 - Path@407..408 - PathSegment@407..408 - Ident@407..408 "U" - Comma@408..409 "," - Newline@409..410 "\n" - RBrace@410..411 "}" - Newline@411..413 "\n\n" - Item@413..560 - Struct@413..560 - ItemModifier@413..416 - PubKw@413..416 "pub" - WhiteSpace@416..417 " " - StructKw@417..423 "struct" - WhiteSpace@423..424 " " - Ident@424..429 "MyArr" - GenericParamList@429..466 - Lt@429..430 "<" - TypeGenericParam@430..446 - Ident@430..431 "T" - TypeBoundList@431..446 - Colon@431..432 ":" - WhiteSpace@432..433 " " - TypeBound@433..446 - TraitRef@433..446 - Path@433..446 - PathSegment@433..436 - Ident@433..436 "std" - Colon2@436..438 "::" - PathSegment@438..441 - Ident@438..441 "ops" - Colon2@441..443 "::" - PathSegment@443..446 - Ident@443..446 "Add" - Comma@446..447 "," - WhiteSpace@447..448 " " - TypeGenericParam@448..449 - Ident@448..449 "U" + Plus@371..372 "+" + WhiteSpace@372..373 " " + TypeBound@373..379 + TraitRef@373..379 + Path@373..379 + PathSegment@373..379 + Ident@373..379 "Trait3" + Comma@379..380 "," + Newline@380..381 "\n" + RecordFieldDefList@381..414 + LBrace@381..382 "{" + Newline@382..383 "\n" + WhiteSpace@383..387 " " + RecordFieldDef@387..391 + Ident@387..388 "x" + Colon@388..389 ":" + WhiteSpace@389..390 " " + PathType@390..391 + Path@390..391 + PathSegment@390..391 + Ident@390..391 "S" + Comma@391..392 "," + Newline@392..393 "\n" + WhiteSpace@393..397 " " + RecordFieldDef@397..401 + Ident@397..398 "y" + Colon@398..399 ":" + WhiteSpace@399..400 " " + PathType@400..401 + Path@400..401 + PathSegment@400..401 + Ident@400..401 "T" + Comma@401..402 "," + Newline@402..403 "\n" + WhiteSpace@403..407 " " + RecordFieldDef@407..411 + Ident@407..408 "z" + Colon@408..409 ":" + WhiteSpace@409..410 " " + PathType@410..411 + Path@410..411 + PathSegment@410..411 + Ident@410..411 "U" + Comma@411..412 "," + Newline@412..413 "\n" + RBrace@413..414 "}" + Newline@414..416 "\n\n" + Item@416..563 + Struct@416..563 + ItemModifier@416..419 + PubKw@416..419 "pub" + WhiteSpace@419..420 " " + StructKw@420..426 "struct" + WhiteSpace@426..427 " " + Ident@427..432 "MyArr" + GenericParamList@432..469 + Lt@432..433 "<" + TypeGenericParam@433..449 + Ident@433..434 "T" + TypeBoundList@434..449 + Colon@434..435 ":" + WhiteSpace@435..436 " " + TypeBound@436..449 + TraitRef@436..449 + Path@436..449 + PathSegment@436..439 + Ident@436..439 "std" + Colon2@439..441 "::" + PathSegment@441..444 + Ident@441..444 "ops" + Colon2@444..446 "::" + PathSegment@446..449 + Ident@446..449 "Add" Comma@449..450 "," WhiteSpace@450..451 " " - ConstGenericParam@451..465 - ConstKw@451..456 "const" - WhiteSpace@456..457 " " - Ident@457..458 "N" - Colon@458..459 ":" + TypeGenericParam@451..452 + Ident@451..452 "U" + Comma@452..453 "," + WhiteSpace@453..454 " " + ConstGenericParam@454..468 + ConstKw@454..459 "const" WhiteSpace@459..460 " " - PathType@460..465 - Path@460..465 - PathSegment@460..465 - Ident@460..465 "usize" - Gt@465..466 ">" - Newline@466..467 "\n" - WhiteSpace@467..471 " " - WhereClause@471..515 - WhereKw@471..476 "where" - Newline@476..477 "\n" - WhiteSpace@477..485 " " - WherePredicate@485..515 - TupleType@485..491 - LParen@485..486 "(" - PathType@486..487 - Path@486..487 - PathSegment@486..487 - Ident@486..487 "T" - Comma@487..488 "," - WhiteSpace@488..489 " " + Ident@460..461 "N" + Colon@461..462 ":" + WhiteSpace@462..463 " " + PathType@463..468 + Path@463..468 + PathSegment@463..468 + Ident@463..468 "usize" + Gt@468..469 ">" + Newline@469..470 "\n" + WhiteSpace@470..474 " " + WhereClause@474..517 + WhereKw@474..479 "where" + Newline@479..480 "\n" + WhiteSpace@480..488 " " + WherePredicate@488..517 + TupleType@488..494 + LParen@488..489 "(" PathType@489..490 Path@489..490 PathSegment@489..490 - Ident@489..490 "U" - RParen@490..491 ")" - TypeBoundList@491..514 - Colon@491..492 ":" - WhiteSpace@492..493 " " - TypeBound@493..498 - TraitRef@493..498 - Path@493..498 - PathSegment@493..498 - Ident@493..498 "Trait" - WhiteSpace@498..499 " " - Plus@499..500 "+" - WhiteSpace@500..501 " " - TypeBound@501..514 - TraitRef@501..514 - Path@501..506 - PathSegment@501..506 - Ident@501..506 "Trait" - GenericArgList@506..514 - Lt@506..507 "<" - TypeGenericArg@507..510 - PathType@507..510 - Path@507..510 - PathSegment@507..510 - Ident@507..510 "i32" - Comma@510..511 "," - WhiteSpace@511..512 " " - TypeGenericArg@512..513 - PathType@512..513 - Path@512..513 - PathSegment@512..513 - Ident@512..513 "Y" - Gt@513..514 ">" - Newline@514..515 "\n" - RecordFieldDefList@515..560 - LBrace@515..516 "{" - Newline@516..517 "\n" - WhiteSpace@517..521 " " - RecordFieldDef@521..536 - Ident@521..528 "__inner" - Colon@528..529 ":" - WhiteSpace@529..530 " " - ArrayType@530..536 - LBracket@530..531 "[" - PathType@531..532 - Path@531..532 - PathSegment@531..532 - Ident@531..532 "T" - SemiColon@532..533 ";" - WhiteSpace@533..534 " " - PathExpr@534..535 + Ident@489..490 "T" + Comma@490..491 "," + WhiteSpace@491..492 " " + PathType@492..493 + Path@492..493 + PathSegment@492..493 + Ident@492..493 "U" + RParen@493..494 ")" + TypeBoundList@494..517 + Colon@494..495 ":" + WhiteSpace@495..496 " " + TypeBound@496..501 + TraitRef@496..501 + Path@496..501 + PathSegment@496..501 + Ident@496..501 "Trait" + WhiteSpace@501..502 " " + Plus@502..503 "+" + WhiteSpace@503..504 " " + TypeBound@504..517 + TraitRef@504..517 + Path@504..509 + PathSegment@504..509 + Ident@504..509 "Trait" + GenericArgList@509..517 + Lt@509..510 "<" + TypeGenericArg@510..513 + PathType@510..513 + Path@510..513 + PathSegment@510..513 + Ident@510..513 "i32" + Comma@513..514 "," + WhiteSpace@514..515 " " + TypeGenericArg@515..516 + PathType@515..516 + Path@515..516 + PathSegment@515..516 + Ident@515..516 "Y" + Gt@516..517 ">" + Newline@517..518 "\n" + RecordFieldDefList@518..563 + LBrace@518..519 "{" + Newline@519..520 "\n" + WhiteSpace@520..524 " " + RecordFieldDef@524..539 + Ident@524..531 "__inner" + Colon@531..532 ":" + WhiteSpace@532..533 " " + ArrayType@533..539 + LBracket@533..534 "[" + PathType@534..535 Path@534..535 PathSegment@534..535 - Ident@534..535 "N" - RBracket@535..536 "]" - Comma@536..537 "," - Newline@537..538 "\n" - WhiteSpace@538..542 " " - RecordFieldDef@542..558 - Ident@542..550 "__inner2" - Colon@550..551 ":" - WhiteSpace@551..552 " " - TupleType@552..558 - LParen@552..553 "(" - PathType@553..554 - Path@553..554 - PathSegment@553..554 - Ident@553..554 "T" - Comma@554..555 "," - WhiteSpace@555..556 " " + Ident@534..535 "T" + SemiColon@535..536 ";" + WhiteSpace@536..537 " " + PathExpr@537..538 + Path@537..538 + PathSegment@537..538 + Ident@537..538 "N" + RBracket@538..539 "]" + Comma@539..540 "," + Newline@540..541 "\n" + WhiteSpace@541..545 " " + RecordFieldDef@545..561 + Ident@545..553 "__inner2" + Colon@553..554 ":" + WhiteSpace@554..555 " " + TupleType@555..561 + LParen@555..556 "(" PathType@556..557 Path@556..557 PathSegment@556..557 - Ident@556..557 "U" - RParen@557..558 ")" - Newline@558..559 "\n" - RBrace@559..560 "}" + Ident@556..557 "T" + Comma@557..558 "," + WhiteSpace@558..559 " " + PathType@559..560 + Path@559..560 + PathSegment@559..560 + Ident@559..560 "U" + RParen@560..561 ")" + Newline@561..562 "\n" + RBrace@562..563 "}" diff --git a/crates/parser2/tests/test_runner.rs b/crates/parser2/tests/test_runner.rs index 6bbc56b8fd..ac763c48d6 100644 --- a/crates/parser2/tests/test_runner.rs +++ b/crates/parser2/tests/test_runner.rs @@ -30,7 +30,7 @@ impl TestRunner { /// Constructs a test runner for parsing a list of expressions. pub fn item_list(should_success: bool) -> Self { fn parse(parser: &mut Parser) { - parser.parse(ItemListScope::default(), None); + parser.parse(ItemListScope::default()); } Self::new(parse, should_success) @@ -44,7 +44,7 @@ impl TestRunner { bump_newlines(parser); while parser.current_kind().is_some() { bump_newlines(parser); - parse_stmt(parser, None); + parse_stmt(parser); bump_newlines(parser); } } @@ -90,14 +90,14 @@ impl TestRunner { let (cst, errors) = parser.finish_to_node(); for error in &errors { - println!("{}@{:?}", error.msg, error.range); + println!("{}@{:?}", error.msg(), error.range()); } if self.should_success { assert! {errors.is_empty()} } else { assert! {!errors.is_empty()} } - assert!(input == cst.to_string()); + assert_eq!(input, cst.to_string()); cst } diff --git a/crates/uitest/fixtures/name_resolution/path_invalid_domain.fe b/crates/uitest/fixtures/name_resolution/path_invalid_domain.fe index b8878f34a5..4aaaa62a87 100644 --- a/crates/uitest/fixtures/name_resolution/path_invalid_domain.fe +++ b/crates/uitest/fixtures/name_resolution/path_invalid_domain.fe @@ -10,7 +10,7 @@ pub trait MyTWithGenerics {} use MyE::Var pub enum MyE2 -where T: MyE +where T: MyE, U: MyTWithGenerics { Variant(MyC), diff --git a/crates/uitest/fixtures/name_resolution/path_invalid_domain.snap b/crates/uitest/fixtures/name_resolution/path_invalid_domain.snap index 4472ba2904..61d63973b1 100644 --- a/crates/uitest/fixtures/name_resolution/path_invalid_domain.snap +++ b/crates/uitest/fixtures/name_resolution/path_invalid_domain.snap @@ -33,7 +33,7 @@ error[2-0006]: expected type item here error[2-0007]: expected trait item here ┌─ path_invalid_domain.fe:13:10 │ -13 │ where T: MyE +13 │ where T: MyE, │ ^^^ expected trait here, but found enum `MyE` diff --git a/crates/uitest/fixtures/name_resolution/path_missing_generics.fe b/crates/uitest/fixtures/name_resolution/path_missing_generics.fe index 227c302381..97da56729d 100644 --- a/crates/uitest/fixtures/name_resolution/path_missing_generics.fe +++ b/crates/uitest/fixtures/name_resolution/path_missing_generics.fe @@ -1,9 +1,9 @@ pub trait Trait {} pub struct MyS - where T: Trait - U: Trait - Z: Trait + where T: Trait, + U: Trait, + Z: Trait, { t: T, u: U, diff --git a/crates/uitest/fixtures/name_resolution/path_missing_generics.snap b/crates/uitest/fixtures/name_resolution/path_missing_generics.snap index f83007a3c1..5e677041ad 100644 --- a/crates/uitest/fixtures/name_resolution/path_missing_generics.snap +++ b/crates/uitest/fixtures/name_resolution/path_missing_generics.snap @@ -6,7 +6,7 @@ input_file: crates/uitest/fixtures/name_resolution/path_missing_generics.fe error[2-0002]: `Z` is not found ┌─ path_missing_generics.fe:6:11 │ -6 │ Z: Trait +6 │ Z: Trait, │ ^ `Z` is not found error[2-0002]: `Z` is not found diff --git a/crates/uitest/fixtures/parser/array.snap b/crates/uitest/fixtures/parser/array.snap index ded5f3a520..d7e1b55303 100644 --- a/crates/uitest/fixtures/parser/array.snap +++ b/crates/uitest/fixtures/parser/array.snap @@ -9,10 +9,4 @@ error[1-0001]: unexpected syntax 2 │ [1, 2 a, 3] │ ^ unexpected syntax -error[1-0001]: expected expression - ┌─ array.fe:3:7 - │ -3 │ [1, 2,] - │ ^ expected expression - diff --git a/crates/uitest/fixtures/parser/call.snap b/crates/uitest/fixtures/parser/call.snap index b723e6fad7..349b3acb40 100644 --- a/crates/uitest/fixtures/parser/call.snap +++ b/crates/uitest/fixtures/parser/call.snap @@ -21,10 +21,4 @@ error[1-0001]: unexpected syntax 4 │ foo(x, y) │ ^ unexpected syntax -error[1-0001]: expected path segment - ┌─ call.fe:4:15 - │ -4 │ foo(x, y) - │ ^ expected path segment - diff --git a/crates/uitest/fixtures/parser/func.snap b/crates/uitest/fixtures/parser/func.snap index 871bfeb3fb..1d09f337b4 100644 --- a/crates/uitest/fixtures/parser/func.snap +++ b/crates/uitest/fixtures/parser/func.snap @@ -13,7 +13,7 @@ error[1-0001]: unexpected syntax ┌─ func.fe:1:29 │ 1 │ fn foo>(x: i32, _ mut y: u32, z: u32) -> T, u where T: Trait2 - │ ^^^^^ unexpected syntax + │ ^^^ unexpected syntax error[1-0001]: unexpected syntax ┌─ func.fe:1:54 @@ -21,22 +21,10 @@ error[1-0001]: unexpected syntax 1 │ fn foo>(x: i32, _ mut y: u32, z: u32) -> T, u where T: Trait2 │ ^^^ unexpected syntax -error[1-0001]: expected type parameter - ┌─ func.fe:6:8 - │ -6 │ fn foo<<(x: i32) - │ ^ expected type parameter - error[1-0001]: unexpected syntax ┌─ func.fe:6:8 │ 6 │ fn foo<<(x: i32) - │ ^^^^^^^^^^^ unexpected syntax - -error[1-0001]: expected closing `>` - ┌─ func.fe:6:19 - │ -6 │ fn foo<<(x: i32) - │ ^ expected closing `>` + │ ^^ unexpected syntax diff --git a/crates/uitest/fixtures/parser/match_.snap b/crates/uitest/fixtures/parser/match_.snap index d22fb5865e..6e8f2ce149 100644 --- a/crates/uitest/fixtures/parser/match_.snap +++ b/crates/uitest/fixtures/parser/match_.snap @@ -15,17 +15,11 @@ error[1-0001]: expected `=>` 4 │ Bar │ ^ expected `=>` -error[1-0001]: expected expression - ┌─ match_.fe:4:7 - │ -4 │ Bar - │ ^ expected expression - -error[1-0001]: expected path segment +error[1-0001]: expected pattern ┌─ match_.fe:8:16 │ 8 │ Foo(i, j, => true x - │ ^ expected path segment + │ ^ expected pattern error[1-0001]: expected `)` ┌─ match_.fe:8:16 diff --git a/crates/uitest/fixtures/parser/struct_.snap b/crates/uitest/fixtures/parser/struct_.snap index 505701d973..2fc4443c29 100644 --- a/crates/uitest/fixtures/parser/struct_.snap +++ b/crates/uitest/fixtures/parser/struct_.snap @@ -3,17 +3,17 @@ source: crates/uitest/tests/parser.rs expression: diags input_file: crates/uitest/fixtures/parser/struct_.fe --- -error[1-0001]: expected ident for the struct name +error[1-0001]: expected identifier ┌─ struct_.fe:1:11 │ 1 │ pub struct` +error[1-0001]: expected `>` or `,` ┌─ struct_.fe:1:16 │ 1 │ pub struct` + │ ^ expected `>` or `,` error[1-0001]: expected `:` for type bounds ┌─ struct_.fe:2:8 @@ -21,17 +21,23 @@ error[1-0001]: expected `:` for type bounds 2 │ where T │ ^ expected `:` for type bounds +error[1-0001]: expected `,` + ┌─ struct_.fe:2:8 + │ +2 │ where T + │ ^ expected `,` + error[1-0001]: expected `name: type` for the field definition ┌─ struct_.fe:6:8 │ 6 │ foo │ ^ expected `name: type` for the field definition -error[1-0001]: expected comma after field definition +error[1-0001]: expected `}` or `,` ┌─ struct_.fe:6:8 │ 6 │ foo - │ ^ expected comma after field definition + │ ^ expected `}` or `,` error[1-0001]: function definition in struct is not allowed ┌─ struct_.fe:11:9 @@ -39,10 +45,10 @@ error[1-0001]: function definition in struct is not allowed 11 │ pub fn foo() -> i32 { │ ^^ function definition in struct is not allowed -error[1-0001]: expected comma after field definition +error[1-0001]: expected `}` or `,` ┌─ struct_.fe:13:6 │ 13 │ } - │ ^ expected comma after field definition + │ ^ expected `}` or `,` diff --git a/crates/uitest/fixtures/parser/struct_field_missing_comma.snap b/crates/uitest/fixtures/parser/struct_field_missing_comma.snap index e5b1bdc3c0..12ccdb42ac 100644 --- a/crates/uitest/fixtures/parser/struct_field_missing_comma.snap +++ b/crates/uitest/fixtures/parser/struct_field_missing_comma.snap @@ -3,10 +3,10 @@ source: crates/uitest/tests/parser.rs expression: diags input_file: crates/uitest/fixtures/parser/struct_field_missing_comma.fe --- -error[1-0001]: expected comma after field definition +error[1-0001]: expected `}` or `,` ┌─ struct_field_missing_comma.fe:2:10 │ 2 │ x: u8 - │ ^ expected comma after field definition + │ ^ expected `}` or `,` diff --git a/crates/uitest/fixtures/parser/struct_missing_body.snap b/crates/uitest/fixtures/parser/struct_missing_body.snap index 30983f0e10..02a04799f0 100644 --- a/crates/uitest/fixtures/parser/struct_missing_body.snap +++ b/crates/uitest/fixtures/parser/struct_missing_body.snap @@ -3,16 +3,16 @@ source: crates/uitest/tests/parser.rs expression: diags input_file: crates/uitest/fixtures/parser/struct_missing_body.fe --- -error[1-0001]: expected struct field definition +error[1-0001]: expected `{`, `where` or `<` ┌─ struct_missing_body.fe:2:9 │ 2 │ struct S - │ ^ expected struct field definition + │ ^ expected `{`, `where` or `<` -error[1-0001]: expected struct field definition +error[1-0001]: expected `{` or `where` ┌─ struct_missing_body.fe:4:12 │ 4 │ struct T - │ ^ expected struct field definition + │ ^ expected `{` or `where` diff --git a/crates/uitest/fixtures/parser/trait_.snap b/crates/uitest/fixtures/parser/trait_.snap index 72e8a4d13b..919f4a05da 100644 --- a/crates/uitest/fixtures/parser/trait_.snap +++ b/crates/uitest/fixtures/parser/trait_.snap @@ -3,58 +3,22 @@ source: crates/uitest/tests/parser.rs expression: diags input_file: crates/uitest/fixtures/parser/trait_.fe --- -error[1-0001]: expected type parameter - ┌─ trait_.fe:1:16 - │ -1 │ trait Foo{} - │ ^ expected type parameter - -error[1-0001]: expected type parameter - ┌─ trait_.fe:3:14 - │ -3 │ trait Bar` - ┌─ trait_.fe:3:14 +error[1-0001]: expected identifier, `const` or `>` + ┌─ trait_.fe:3:13 │ 3 │ trait Bar` - -error[1-0001]: expected type parameter - ┌─ trait_.fe:5:14 - │ -5 │ trait Bar - │ ^ expected type parameter + │ ^ expected identifier, `const` or `>` -error[1-0001]: expected trait body +error[1-0001]: expected `{`, `where` or `:` ┌─ trait_.fe:5:15 │ 5 │ trait Bar - │ ^ expected trait body - -error[1-0001]: expected type parameter - ┌─ trait_.fe:7:16 - │ -7 │ trait Bar where T: Add {} - │ ^ expected type parameter - -error[1-0001]: expected newline after type bounds - ┌─ trait_.fe:7:30 - │ -7 │ trait Bar where T: Add {} - │ ^ expected newline after type bounds - -error[1-0001]: expected type parameter - ┌─ trait_.fe:9:11 - │ -9 │ trait Bar< - │ ^ expected type parameter + │ ^ expected `{`, `where` or `:` error[1-0001]: unexpected syntax ┌─ trait_.fe:9:11 │ 9 │ trait Bar< - │ ^^ unexpected syntax + │ ^ unexpected syntax diff --git a/crates/uitest/fixtures/parser/type_.snap b/crates/uitest/fixtures/parser/type_.snap index adbfa1c23d..07d2723c3e 100644 --- a/crates/uitest/fixtures/parser/type_.snap +++ b/crates/uitest/fixtures/parser/type_.snap @@ -3,16 +3,10 @@ source: crates/uitest/tests/parser.rs expression: diags input_file: crates/uitest/fixtures/parser/type_.fe --- -error[1-0001]: expected type parameter - ┌─ type_.fe:1:16 +error[1-0001]: expected identifier, `const` or `>` + ┌─ type_.fe:1:15 │ 1 │ type Result - │ ^ expected type parameter - -error[1-0001]: expected closing `>` - ┌─ type_.fe:1:16 - │ -1 │ type Result - │ ^ expected closing `>` + │ ^ expected identifier, `const` or `>` From ff27aaec98fb678c5ebd9e2c05019c4678724f86 Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Wed, 6 Mar 2024 22:22:05 -0800 Subject: [PATCH 2/6] Better parser error message headers (ExpectedKind enum) --- crates/hir/src/lower/parse.rs | 2 +- crates/hir/src/visitor.rs | 8 +- crates/parser2/src/ast/expr.rs | 1 - crates/parser2/src/ast/item.rs | 1 - crates/parser2/src/lib.rs | 66 +++++- crates/parser2/src/parser/attr.rs | 24 ++- crates/parser2/src/parser/expr.rs | 51 +++-- crates/parser2/src/parser/expr_atom.rs | 52 +++-- crates/parser2/src/parser/func.rs | 27 ++- crates/parser2/src/parser/item.rs | 149 +++++++------ crates/parser2/src/parser/mod.rs | 194 +++++------------ crates/parser2/src/parser/param.rs | 116 ++++++---- crates/parser2/src/parser/pat.rs | 11 +- crates/parser2/src/parser/path.rs | 2 +- crates/parser2/src/parser/stmt.rs | 18 +- crates/parser2/src/parser/struct_.rs | 17 +- crates/parser2/src/parser/type_.rs | 13 +- crates/parser2/src/parser/use_tree.rs | 13 +- crates/parser2/src/syntax_kind.rs | 203 +++++++++++++++++- .../error_recovery/items/const_.snap | 13 +- .../error_recovery/items/enum_.snap | 10 +- .../test_files/error_recovery/items/func.snap | 10 +- .../error_recovery/items/impl_.snap | 4 +- .../error_recovery/items/impl_trait.snap | 25 ++- .../error_recovery/items/struct_.snap | 4 +- .../error_recovery/items/trait_.snap | 12 +- .../error_recovery/items/type_.snap | 10 +- .../test_files/error_recovery/items/use_.snap | 8 +- .../test_files/error_recovery/stmts/for_.snap | 6 +- .../test_files/syntax_node/exprs/block.snap | 12 +- .../test_files/syntax_node/items/const.snap | 10 +- .../syntax_node/items/contract.snap | 4 +- .../test_files/syntax_node/items/enums.snap | 30 +-- .../test_files/syntax_node/items/extern.snap | 4 +- .../test_files/syntax_node/items/func.snap | 16 +- .../test_files/syntax_node/items/impl.snap | 4 +- .../syntax_node/items/impl_trait.snap | 8 +- .../test_files/syntax_node/items/mod.snap | 16 +- .../test_files/syntax_node/items/trait.snap | 20 +- .../test_files/syntax_node/items/type.snap | 6 +- .../test_files/syntax_node/items/use.snap | 54 ++--- .../syntax_node/structs/generics.snap | 12 +- crates/uitest/fixtures/parser/array.snap | 4 +- crates/uitest/fixtures/parser/block.snap | 10 +- crates/uitest/fixtures/parser/call.snap | 12 +- crates/uitest/fixtures/parser/const_.snap | 18 +- crates/uitest/fixtures/parser/enum_.snap | 22 +- crates/uitest/fixtures/parser/extern_.snap | 14 +- .../fixtures/parser/fn_missing_body.snap | 14 +- .../parser/fn_missing_parameters.snap | 22 +- .../uitest/fixtures/parser/fn_modifiers.snap | 44 ++-- crates/uitest/fixtures/parser/for_.snap | 34 +-- crates/uitest/fixtures/parser/func.fe | 7 +- crates/uitest/fixtures/parser/func.snap | 46 +++- crates/uitest/fixtures/parser/if_.snap | 68 +----- crates/uitest/fixtures/parser/impl_.snap | 20 +- crates/uitest/fixtures/parser/impl_trait.snap | 32 +-- crates/uitest/fixtures/parser/index.snap | 6 +- crates/uitest/fixtures/parser/match_.snap | 18 +- crates/uitest/fixtures/parser/method.snap | 20 +- crates/uitest/fixtures/parser/operators.snap | 20 +- crates/uitest/fixtures/parser/struct_.snap | 16 +- .../parser/struct_field_missing_comma.snap | 2 +- crates/uitest/fixtures/parser/trait_.snap | 4 +- .../uitest/fixtures/parser/trait_pub_fn.snap | 12 +- crates/uitest/fixtures/parser/while_.snap | 14 +- crates/uitest/fixtures/ty/def/kind_bound.fe | 4 +- crates/uitest/fixtures/ty/def/trait_def.fe | 4 +- .../trait_impl/impl_method_stricter_bound.fe | 6 +- .../impl_method_stricter_bound.snap | 2 +- 70 files changed, 973 insertions(+), 788 deletions(-) diff --git a/crates/hir/src/lower/parse.rs b/crates/hir/src/lower/parse.rs index 81deadeb6f..d2c8ff7b71 100644 --- a/crates/hir/src/lower/parse.rs +++ b/crates/hir/src/lower/parse.rs @@ -47,7 +47,7 @@ impl DiagnosticVoucher for ParserError { self.error.msg(), vec![SubDiagnostic::new( LabelStyle::Primary, - self.error.msg(), + self.error.label(), Some(span), )], vec![], diff --git a/crates/hir/src/visitor.rs b/crates/hir/src/visitor.rs index 158b0c6d89..60a32d887b 100644 --- a/crates/hir/src/visitor.rs +++ b/crates/hir/src/visitor.rs @@ -2171,8 +2171,8 @@ mod tests { fn visitor() { let mut db = TestDb::default(); let text = r#" - #[attr1] - #[attr2] + #attr1 + #attr2 fn foo() { 1 "foo" @@ -2197,8 +2197,8 @@ mod tests { ); assert_eq!(visitor.attributes.len(), 2); - assert_eq!("#[attr1]", db.text_at(top_mod, &visitor.attributes[0])); - assert_eq!("#[attr2]", db.text_at(top_mod, &visitor.attributes[1])); + assert_eq!("#attr1", db.text_at(top_mod, &visitor.attributes[0])); + assert_eq!("#attr2", db.text_at(top_mod, &visitor.attributes[1])); assert_eq!(visitor.lit_ints.len(), 2); assert_eq!("1", db.text_at(top_mod, &visitor.lit_ints[0])); diff --git a/crates/parser2/src/ast/expr.rs b/crates/parser2/src/ast/expr.rs index b3f6dd1dfa..e3a1a8ddef 100644 --- a/crates/parser2/src/ast/expr.rs +++ b/crates/parser2/src/ast/expr.rs @@ -913,7 +913,6 @@ mod tests { let if_expr: IfExpr = parse_expr("if { true } { return } else { continue }"); if let ExprKind::Block(stmts) = if_expr.cond().unwrap().kind() { - dbg!(&stmts); assert!(matches!( stmts.into_iter().next().unwrap().kind(), crate::ast::StmtKind::Expr(_) diff --git a/crates/parser2/src/ast/item.rs b/crates/parser2/src/ast/item.rs index a97315bbc6..15e15dbad3 100644 --- a/crates/parser2/src/ast/item.rs +++ b/crates/parser2/src/ast/item.rs @@ -549,7 +549,6 @@ mod tests { } "#; let s: Struct = parse_item(source); - dbg!(&s); assert_eq!(s.name().unwrap().text(), "Foo"); let mut count = 0; for field in s.fields().unwrap() { diff --git a/crates/parser2/src/lib.rs b/crates/parser2/src/lib.rs index 3176dfee05..1c09055784 100644 --- a/crates/parser2/src/lib.rs +++ b/crates/parser2/src/lib.rs @@ -26,25 +26,51 @@ pub fn parse_source_file(text: &str) -> (GreenNode, Vec) { /// An parse error which is accumulated in the [`parser::Parser`] while parsing. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ParseError { - Expected(SmallVec<[SyntaxKind; 2]>, Option, TextSize), - Unexpected(TextRange), - + Expected(SmallVec<[SyntaxKind; 2]>, ExpectedKind, TextSize), + Unexpected(String, TextRange), Msg(String, TextRange), } impl ParseError { - pub fn expected(tokens: &[SyntaxKind], msg: Option<&str>, pos: TextSize) -> Self { + pub fn expected(tokens: &[SyntaxKind], kind: Option, pos: TextSize) -> Self { ParseError::Expected( SmallVec::from_slice(tokens), - msg.map(|s| s.to_string()), + kind.unwrap_or(ExpectedKind::Unspecified), pos, ) } pub fn msg(&self) -> String { match self { - ParseError::Expected(_, Some(msg), _) => msg.clone(), - ParseError::Expected(tokens, None, _) => { + ParseError::Expected(_, exp, _) => match exp { + ExpectedKind::Body(kind) => format!("{} requires a body", kind.describe()), + ExpectedKind::Name(kind) => format!("expected name for {}", kind.describe()), + ExpectedKind::ClosingBracket { bracket, parent } => format!( + "missing closing {} for {}", + bracket.describe(), + parent.describe() + ), + ExpectedKind::Separator { separator, element } => { + format!( + "expected {} separator after {}", + separator.describe(), + element.describe() + ) + } + ExpectedKind::TypeSpecifier(kind) => { + format!("missing type bound for {}", kind.describe()) + } + ExpectedKind::Syntax(kind) => format!("expected {}", kind.describe()), + ExpectedKind::Unspecified => self.label(), + }, + ParseError::Unexpected(m, _) => m.clone(), + ParseError::Msg(m, _) => m.clone(), + } + } + + pub fn label(&self) -> String { + match self { + ParseError::Expected(tokens, _, _) => { if tokens.len() == 1 { return format!("expected {}", tokens[0].describe()); } @@ -59,15 +85,35 @@ impl ParseError { } s } - ParseError::Unexpected(_) => "unexpected syntax".into(), - ParseError::Msg(m, _) => m.clone(), + ParseError::Unexpected(_, _) => "unexpected".into(), + ParseError::Msg(msg, _) => msg.clone(), } } pub fn range(&self) -> TextRange { match self { ParseError::Expected(_, _, pos) => TextRange::empty(*pos), - ParseError::Unexpected(r) | ParseError::Msg(_, r) => *r, + ParseError::Unexpected(_, r) | ParseError::Msg(_, r) => *r, } } } + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ExpectedKind { + Body(SyntaxKind), + Name(SyntaxKind), + ClosingBracket { + bracket: SyntaxKind, + parent: SyntaxKind, + }, + TypeSpecifier(SyntaxKind), + Separator { + separator: SyntaxKind, + element: SyntaxKind, + }, + Syntax(SyntaxKind), + Unspecified, + // TODO: + // - newline after attribute in attrlistscope + // +} diff --git a/crates/parser2/src/parser/attr.rs b/crates/parser2/src/parser/attr.rs index 19286d5820..e767976cf9 100644 --- a/crates/parser2/src/parser/attr.rs +++ b/crates/parser2/src/parser/attr.rs @@ -5,7 +5,7 @@ use super::{ define_scope, parse_list, token_stream::TokenStream, Checkpoint, ErrProof, Parser, Recovery, }; -use crate::SyntaxKind; +use crate::{ExpectedKind, SyntaxKind}; pub(super) fn parse_attr_list( parser: &mut Parser, @@ -40,7 +40,13 @@ impl super::Parse for AttrListScope { _ => break, }; parser.set_newline_as_trivia(false); - if parser.find(SyntaxKind::Newline, None)? { + if parser.find( + SyntaxKind::Newline, + ExpectedKind::Separator { + separator: SyntaxKind::Newline, + element: SyntaxKind::Attr, + }, + )? { parser.bump(); } } @@ -61,10 +67,7 @@ impl super::Parse for AttrScope { parser.bump_expected(SyntaxKind::Pound); parser.set_scope_recovery_stack(&[SyntaxKind::LParen]); - if parser.find( - SyntaxKind::Ident, - Some("expected an attribute name after `#`"), - )? { + if parser.find(SyntaxKind::Ident, ExpectedKind::Name(SyntaxKind::Attr))? { parser.bump() } @@ -89,6 +92,7 @@ impl super::Parse for AttrArgListScope { parse_list( parser, false, + SyntaxKind::AttrArgList, (SyntaxKind::LParen, SyntaxKind::RParen), |parser| parser.parse(AttrArgScope::default()), ) @@ -104,16 +108,16 @@ impl super::Parse for AttrArgScope { type Error = Recovery; fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { - let msg = Some("expected attribute argument in the form `key: value`"); + let expected_err = ExpectedKind::Syntax(SyntaxKind::AttrArg); parser.set_scope_recovery_stack(&[SyntaxKind::Ident, SyntaxKind::Colon]); - if parser.find_and_pop(SyntaxKind::Ident, msg)? { + if parser.find_and_pop(SyntaxKind::Ident, expected_err)? { parser.bump(); } - if parser.find_and_pop(SyntaxKind::Colon, msg)? { + if parser.find_and_pop(SyntaxKind::Colon, expected_err)? { parser.bump(); } - if parser.find(SyntaxKind::Ident, msg)? { + if parser.find(SyntaxKind::Ident, expected_err)? { parser.bump(); } Ok(()) diff --git a/crates/parser2/src/parser/expr.rs b/crates/parser2/src/parser/expr.rs index 53862fe2ea..e44088834f 100644 --- a/crates/parser2/src/parser/expr.rs +++ b/crates/parser2/src/parser/expr.rs @@ -1,13 +1,14 @@ -use std::convert::Infallible; +use std::convert::{identity, Infallible}; use unwrap_infallible::UnwrapInfallible; use super::{ - define_scope, expr_atom, + define_scope, + expr_atom::{self, is_expr_atom_head}, param::{CallArgListScope, GenericArgListScope}, token_stream::TokenStream, Checkpoint, ErrProof, Parser, Recovery, }; -use crate::SyntaxKind; +use crate::{ExpectedKind, SyntaxKind}; /// Parses expression. pub fn parse_expr(parser: &mut Parser) -> Result<(), Recovery> { @@ -112,8 +113,10 @@ fn parse_expr_atom( Some(kind) if prefix_binding_power(kind).is_some() => { parser.parse_cp(UnExprScope::default(), None) } - Some(_) => expr_atom::parse_expr_atom(parser, allow_struct_init), - None => parser + Some(kind) if is_expr_atom_head(kind) => { + expr_atom::parse_expr_atom(parser, allow_struct_init) + } + _ => parser .error_and_recover("expected expression") .map(|_| parser.checkpoint()), } @@ -273,7 +276,10 @@ impl super::Parse for IndexExprScope { if parser.find( SyntaxKind::RBracket, - Some("missing closing `]` in index expression"), + ExpectedKind::ClosingBracket { + bracket: SyntaxKind::RBracket, + parent: SyntaxKind::IndexExpr, + }, )? { parser.bump(); } @@ -293,7 +299,10 @@ impl super::Parse for CallExprScope { parser.parse(GenericArgListScope::default())?; } - if parser.find_and_pop(SyntaxKind::LParen, None)? { + if parser.find_and_pop( + SyntaxKind::LParen, + ExpectedKind::Syntax(SyntaxKind::CallArgList), + )? { parser.parse(CallArgListScope::default())?; } Ok(()) @@ -309,7 +318,10 @@ impl super::Parse for MethodExprScope { parser.set_newline_as_trivia(false); parser.set_scope_recovery_stack(&[SyntaxKind::Ident, SyntaxKind::Lt, SyntaxKind::LParen]); - if parser.find_and_pop(SyntaxKind::Ident, None)? { + if parser.find_and_pop( + SyntaxKind::Ident, + ExpectedKind::Name(SyntaxKind::MethodCallExpr), + )? { parser.bump(); } @@ -318,7 +330,10 @@ impl super::Parse for MethodExprScope { parser.parse(GenericArgListScope::default())?; } - if parser.find_and_pop(SyntaxKind::LParen, None)? { + if parser.find_and_pop( + SyntaxKind::LParen, + ExpectedKind::Syntax(SyntaxKind::CallArgList), + )? { parser.parse(CallArgListScope::default())?; } Ok(()) @@ -472,14 +487,18 @@ fn is_call_expr(parser: &mut Parser) -> bool { let mut is_call = true; if parser.current_kind() == Some(SyntaxKind::Lt) { - // xxx `call` error recovery test: "without error" should only apply to base scope - is_call &= parser.parses_without_error(GenericArgListScope::default()) + is_call &= parser + .parse_ok(GenericArgListScope::default()) + .is_ok_and(identity) } if parser.current_kind() != Some(SyntaxKind::LParen) { false } else { - is_call && parser.parses_without_error(CallArgListScope::default()) + is_call + && parser + .parse_ok(CallArgListScope::default()) + .is_ok_and(identity) } }) } @@ -496,7 +515,9 @@ fn is_method_call(parser: &mut Parser) -> bool { } if parser.current_kind() == Some(SyntaxKind::Lt) - && !parser.parses_without_error(GenericArgListScope::default()) + && !parser + .parse_ok(GenericArgListScope::default()) + .is_ok_and(identity) { return false; } @@ -505,7 +526,9 @@ fn is_method_call(parser: &mut Parser) -> bool { false } else { parser.set_newline_as_trivia(is_trivia); - parser.parses_without_error(CallArgListScope::default()) + parser + .parse_ok(CallArgListScope::default()) + .is_ok_and(identity) } }); parser.set_newline_as_trivia(is_trivia); diff --git a/crates/parser2/src/parser/expr_atom.rs b/crates/parser2/src/parser/expr_atom.rs index 586f1934ad..e966e44ec6 100644 --- a/crates/parser2/src/parser/expr_atom.rs +++ b/crates/parser2/src/parser/expr_atom.rs @@ -4,7 +4,7 @@ use rowan::Checkpoint; use crate::{ parser::{lit, path}, - SyntaxKind, + ExpectedKind, SyntaxKind, TextRange, }; use super::{ @@ -17,6 +17,18 @@ use super::{ ErrProof, Parser, Recovery, }; +// Must be kept in sync with `parse_expr_atom` +pub(super) fn is_expr_atom_head(kind: SyntaxKind) -> bool { + use SyntaxKind::*; + match kind { + IfKw | MatchKw | LBrace | LParen | LBracket => true, + kind if lit::is_lit(kind) => true, + kind if path::is_path_segment(kind) => true, + _ => false, + } +} + +/// Panics if `!is_expr_atom_head(parser.current_kind())` pub(super) fn parse_expr_atom( parser: &mut Parser, allow_record_init: bool, @@ -34,9 +46,7 @@ pub(super) fn parse_expr_atom( Some(kind) if path::is_path_segment(kind) => { parser.parse_cp(PathExprScope::new(allow_record_init), None) } - _ => parser - .error_and_recover("expected expression") // xxx - .map(|()| parser.checkpoint()), + _ => unreachable!(), } } @@ -83,7 +93,13 @@ impl super::Parse for BlockExprScope { parser.bump_if(SyntaxKind::Newline); } - if parser.find(SyntaxKind::RBrace, Some("missing closing `}` for block"))? { + if parser.find( + SyntaxKind::RBrace, + crate::ExpectedKind::ClosingBracket { + bracket: SyntaxKind::RBrace, + parent: SyntaxKind::BlockExpr, + }, + )? { parser.bump(); } Ok(()) @@ -100,7 +116,7 @@ impl super::Parse for IfExprScope { parser.set_scope_recovery_stack(&[SyntaxKind::LBrace, SyntaxKind::ElseKw]); parse_expr_no_struct(parser)?; - if parser.find_and_pop(SyntaxKind::LBrace, Some("missing `if` body"))? { + if parser.find_and_pop(SyntaxKind::LBrace, ExpectedKind::Body(SyntaxKind::IfExpr))? { parser.parse(BlockExprScope::default())?; } @@ -122,8 +138,10 @@ impl super::Parse for MatchExprScope { parser.bump_expected(SyntaxKind::MatchKw); parse_expr_no_struct(parser)?; - if parser.find(SyntaxKind::LBrace, None)? { - dbg!(parser.current_kind()); + if parser.find( + SyntaxKind::LBrace, + ExpectedKind::Body(SyntaxKind::MatchExpr), + )? { parser.parse(MatchArmListScope::default())?; } Ok(()) @@ -166,7 +184,7 @@ impl super::Parse for MatchArmScope { parser.set_scope_recovery_stack(&[SyntaxKind::FatArrow]); parse_pat(parser)?; - if parser.find_and_pop(SyntaxKind::FatArrow, None)? { + if parser.find_and_pop(SyntaxKind::FatArrow, ExpectedKind::Unspecified)? { parser.bump(); } parse_expr(parser) @@ -188,8 +206,14 @@ impl super::Parse for PathExprScope { type Error = Recovery; fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { - // xxx "expected an expression"? - parser.or_recover(|p| p.parse(path::PathScope::default()))?; + parser.or_recover(|p| { + p.parse(path::PathScope::default()).map_err(|_| { + crate::ParseError::Msg( + "expected an expression".into(), + TextRange::empty(p.end_of_prev_token), + ) + }) + })?; if parser.current_kind() == Some(SyntaxKind::LBrace) && self.allow_record_init { self.set_kind(SyntaxKind::RecordInitExpr); @@ -207,6 +231,7 @@ impl super::Parse for RecordFieldListScope { parse_list( parser, true, + SyntaxKind::RecordFieldList, (SyntaxKind::LBrace, SyntaxKind::RBrace), |parser| parser.parse(RecordFieldScope::default()), ) @@ -299,7 +324,10 @@ impl super::Parse for ArrayScope { if parser.find( SyntaxKind::RBracket, - Some("missing closing `]` in array definition"), + ExpectedKind::ClosingBracket { + bracket: SyntaxKind::RBracket, + parent: SyntaxKind::ArrayExpr, + }, )? { parser.bump(); } diff --git a/crates/parser2/src/parser/func.rs b/crates/parser2/src/parser/func.rs index 6af9f122da..e12872d333 100644 --- a/crates/parser2/src/parser/func.rs +++ b/crates/parser2/src/parser/func.rs @@ -1,4 +1,4 @@ -use crate::SyntaxKind; +use crate::{ExpectedKind, SyntaxKind}; use super::{ define_scope, @@ -49,8 +49,6 @@ fn parse_normal_fn_def_impl( parser: &mut Parser, allow_self: bool, ) -> Result<(), Recovery> { - // xxx check where newlines are allowed - parser.set_scope_recovery_stack(&[ SyntaxKind::Ident, SyntaxKind::Lt, @@ -60,14 +58,17 @@ fn parse_normal_fn_def_impl( SyntaxKind::LBrace, ]); - if parser.find_and_pop(SyntaxKind::Ident, None)? { + if parser.find_and_pop(SyntaxKind::Ident, ExpectedKind::Name(SyntaxKind::Func))? { parser.bump(); } parser.expect_and_pop_recovery_stack()?; parse_generic_params_opt(parser, false)?; - if parser.find_and_pop(SyntaxKind::LParen, None)? { + if parser.find_and_pop( + SyntaxKind::LParen, + ExpectedKind::Syntax(SyntaxKind::FuncParamList), + )? { parser.parse(FuncParamListScope::new(allow_self))?; } @@ -79,7 +80,7 @@ fn parse_normal_fn_def_impl( parser.expect_and_pop_recovery_stack()?; parse_where_clause_opt(parser)?; - if parser.find_and_pop(SyntaxKind::LBrace, None)? { + if parser.find_and_pop(SyntaxKind::LBrace, ExpectedKind::Body(SyntaxKind::Func))? { parser.parse(BlockExprScope::default())?; } Ok(()) @@ -97,14 +98,17 @@ fn parse_trait_fn_def_impl( SyntaxKind::LBrace, ]); - if parser.find_and_pop(SyntaxKind::Ident, None)? { + if parser.find_and_pop(SyntaxKind::Ident, ExpectedKind::Name(SyntaxKind::Func))? { parser.bump(); } parser.expect_and_pop_recovery_stack()?; parse_generic_params_opt(parser, false)?; - if parser.find_and_pop(SyntaxKind::LParen, None)? { + if parser.find_and_pop( + SyntaxKind::LParen, + ExpectedKind::Syntax(SyntaxKind::FuncParamList), + )? { parser.parse(FuncParamListScope::new(true))?; } @@ -127,11 +131,14 @@ fn parse_extern_fn_def_impl( ) -> Result<(), Recovery> { parser.set_scope_recovery_stack(&[SyntaxKind::Ident, SyntaxKind::LParen, SyntaxKind::Arrow]); - if parser.find_and_pop(SyntaxKind::Ident, None)? { + if parser.find_and_pop(SyntaxKind::Ident, ExpectedKind::Name(SyntaxKind::Func))? { parser.bump(); } - if parser.find_and_pop(SyntaxKind::LParen, None)? { + if parser.find_and_pop( + SyntaxKind::LParen, + ExpectedKind::Syntax(SyntaxKind::FuncParamList), + )? { parser.parse(FuncParamListScope::new(true))?; } diff --git a/crates/parser2/src/parser/item.rs b/crates/parser2/src/parser/item.rs index d0c9a415be..8517751098 100644 --- a/crates/parser2/src/parser/item.rs +++ b/crates/parser2/src/parser/item.rs @@ -2,7 +2,7 @@ use std::{cell::Cell, convert::Infallible, rc::Rc}; use unwrap_infallible::UnwrapInfallible; -use crate::{parser::func::FuncScope, SyntaxKind}; +use crate::{parser::func::FuncScope, ExpectedKind, SyntaxKind}; use super::{ attr, define_scope, @@ -47,6 +47,7 @@ impl super::Parse for ItemListScope { if self.inside_mod { parser.bump_expected(LBrace); + parser.set_scope_recovery_stack(&[RBrace]); } loop { @@ -56,12 +57,34 @@ impl super::Parse for ItemListScope { } if parser.current_kind().is_none() { if self.inside_mod { - parser.error("`}` to close the module"); + parser.add_error(crate::ParseError::expected( + &[RBrace], + Some(ExpectedKind::ClosingBracket { + bracket: RBrace, + parent: Mod, + }), + parser.current_pos, + )); } break; } - parser.parse(ItemScope::default())?; + let ok = parser.parse_ok(ItemScope::default())?; + if parser.current_kind().is_none() || (self.inside_mod && parser.bump_if(RBrace)) { + break; + } + if ok { + parser.set_newline_as_trivia(false); + if parser.find( + Newline, + ExpectedKind::Separator { + separator: Newline, + element: Item, + }, + )? { + parser.bump(); + } + } } Ok(()) } @@ -91,7 +114,7 @@ impl super::Parse for ItemScope { }; if modifier.is_unsafe() && parser.current_kind() != Some(FnKw) { - parser.error("expected `fn` after `unsafe` keyword"); // xxx + parser.error("expected `fn` after `unsafe` keyword"); } else if modifier.is_pub() && matches!(parser.current_kind(), Some(ImplKw | ExternKw)) { let error_msg = format!( "`pub` can't be used for `{}`", @@ -100,6 +123,14 @@ impl super::Parse for ItemScope { parser.error(&error_msg); } + parser.expect( + &[ + ModKw, FnKw, StructKw, ContractKw, EnumKw, TraitKw, ImplKw, UseKw, ConstKw, + ExternKw, TypeKw, + ], + Some(ExpectedKind::Syntax(SyntaxKind::Item)), + )?; + match parser.current_kind() { Some(ModKw) => parser.parse_cp(ModScope::default(), checkpoint), Some(FnKw) => parser.parse_cp(FuncScope::default(), checkpoint), @@ -112,21 +143,10 @@ impl super::Parse for ItemScope { Some(ConstKw) => parser.parse_cp(ConstScope::default(), checkpoint), Some(ExternKw) => parser.parse_cp(ExternScope::default(), checkpoint), Some(TypeKw) => parser.parse_cp(TypeAliasScope::default(), checkpoint), - tok => parser - .error_and_recover(&format! {"expected item: but got {tok:?}"}) - .map(|_| checkpoint.unwrap_or_else(|| parser.checkpoint())), + _ => unreachable!(), }?; - parser.set_newline_as_trivia(false); - if parser.current_kind().is_some() && !parser.bump_if(SyntaxKind::Newline) { - // xxx - parser.bump_or_recover( - SyntaxKind::Newline, - "expected newline after item definition", - ) - } else { - Ok(()) - } + Ok(()) } } @@ -146,11 +166,13 @@ impl super::Parse for ItemModifierScope { Some(kind) if kind.is_modifier_head() => { let new_kind = modifier_kind.union(kind); if new_kind == modifier_kind { - parser.unexpected_token_error("duplicate modifier", None); + parser.unexpected_token_error(format!( + "duplicate {} modifier", + kind.describe(), + )); } else if kind == SyntaxKind::PubKw && modifier_kind.is_unsafe() { parser.unexpected_token_error( - "`pub` modifier must come before `unsafe`", - None, + "`pub` modifier must come before `unsafe`".into(), ); } else { parser.bump(); @@ -213,12 +235,16 @@ impl super::Parse for ModScope { fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::ModKw); - parser.set_scope_recovery_stack(&[SyntaxKind::Ident, SyntaxKind::LBrace]); + parser.set_scope_recovery_stack(&[ + SyntaxKind::Ident, + SyntaxKind::LBrace, + SyntaxKind::RBrace, + ]); - if parser.find_and_pop(SyntaxKind::Ident, None)? { + if parser.find_and_pop(SyntaxKind::Ident, ExpectedKind::Name(SyntaxKind::Mod))? { parser.bump(); } - if parser.find_and_pop(SyntaxKind::LBrace, Some("`mod` body"))? { + if parser.find_and_pop(SyntaxKind::LBrace, ExpectedKind::Body(SyntaxKind::Mod))? { parser.parse(ItemListScope::new(true))?; } Ok(()) @@ -234,10 +260,10 @@ impl super::Parse for ContractScope { parser.set_scope_recovery_stack(&[SyntaxKind::Ident, SyntaxKind::LBrace]); - if parser.find_and_pop(SyntaxKind::Ident, None)? { + if parser.find_and_pop(SyntaxKind::Ident, ExpectedKind::Name(SyntaxKind::Contract))? { parser.bump(); } - if parser.find_and_pop(SyntaxKind::LBrace, Some("contract field definition"))? { + if parser.find_and_pop(SyntaxKind::LBrace, ExpectedKind::Body(SyntaxKind::Contract))? { parser.parse(RecordFieldDefListScope::default())?; } Ok(()) @@ -258,7 +284,7 @@ impl super::Parse for EnumScope { SyntaxKind::LBrace, ]); - if parser.find_and_pop(SyntaxKind::Ident, None)? { + if parser.find_and_pop(SyntaxKind::Ident, ExpectedKind::Name(SyntaxKind::Enum))? { parser.bump(); } @@ -268,7 +294,7 @@ impl super::Parse for EnumScope { parser.pop_recovery_stack(); parse_where_clause_opt(parser)?; - if parser.find_and_pop(SyntaxKind::LBrace, Some("enum body definition"))? { + if parser.find_and_pop(SyntaxKind::LBrace, ExpectedKind::Body(SyntaxKind::Enum))? { parser.parse(VariantDefListScope::default())?; } Ok(()) @@ -283,6 +309,7 @@ impl super::Parse for VariantDefListScope { parse_list( parser, true, + SyntaxKind::VariantDefList, (SyntaxKind::LBrace, SyntaxKind::RBrace), |parser| parser.parse(VariantDefScope::default()), ) @@ -293,7 +320,6 @@ define_scope! { VariantDefScope, VariantDef, Inheritance } impl super::Parse for VariantDefScope { type Error = Recovery; fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { - // xxx check for keywords when bumping ident parser.bump_or_recover(SyntaxKind::Ident, "expected ident for the variant name")?; if parser.current_kind() == Some(SyntaxKind::LParen) { @@ -309,8 +335,6 @@ define_scope! { TraitScope, Trait, Inheritance } impl super::Parse for TraitScope { type Error = Recovery; - // xxx add TraitSignature syntax kind - fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::TraitKw); parser.set_scope_recovery_stack(&[ @@ -320,10 +344,7 @@ impl super::Parse for TraitScope { SyntaxKind::WhereKw, SyntaxKind::LBrace, ]); - if parser.find_and_pop( - SyntaxKind::Ident, - Some("expected identifier for the trait name"), - )? { + if parser.find_and_pop(SyntaxKind::Ident, ExpectedKind::Name(SyntaxKind::Trait))? { parser.bump(); } @@ -338,14 +359,14 @@ impl super::Parse for TraitScope { parser.expect_and_pop_recovery_stack()?; parse_where_clause_opt(parser)?; - if parser.find(SyntaxKind::LBrace, Some("missing trait body"))? { + if parser.find(SyntaxKind::LBrace, ExpectedKind::Body(SyntaxKind::Trait))? { parser.parse(TraitItemListScope::default())?; } Ok(()) } } -define_scope! {SuperTraitListScope, SuperTraitList, Inheritance(Plus)} // xxx remove Plus? +define_scope! {SuperTraitListScope, SuperTraitList, Inheritance(Plus)} impl super::Parse for SuperTraitListScope { type Error = Recovery; @@ -378,11 +399,10 @@ impl super::Parse for ImplScope { parse_generic_params_opt(parser, false)?; let is_impl_trait = parser.dry_run(|parser| { - // xxx reconsider, with new changes to parses_without_error - // We don't use `parses_without_error` here, because it's too strict; - // we only care whether the token after the trait/type is `for`. - let _ = parse_type(parser, None); - parser.bump_if(SyntaxKind::ForKw) + parser.parse(TraitRefScope::default()).is_ok() + && parser + .find(SyntaxKind::ForKw, ExpectedKind::Unspecified) + .is_ok_and(|x| x) }); if is_impl_trait { @@ -394,8 +414,9 @@ impl super::Parse for ImplScope { ]); parser.parse(TraitRefScope::default())?; - parser.pop_recovery_stack(); - parser.bump_expected(SyntaxKind::ForKw); + if parser.find_and_pop(SyntaxKind::ForKw, ExpectedKind::Unspecified)? { + parser.bump(); + } } else { parser.set_scope_recovery_stack(&[SyntaxKind::WhereKw, SyntaxKind::LBrace]); } @@ -405,7 +426,10 @@ impl super::Parse for ImplScope { parser.expect_and_pop_recovery_stack()?; parse_where_clause_opt(parser)?; - if parser.find_and_pop(SyntaxKind::LBrace, Some("impl body"))? { + if parser.find_and_pop( + SyntaxKind::LBrace, + ExpectedKind::Body(SyntaxKind::ImplTrait), + )? { if is_impl_trait { parser.parse(ImplTraitItemListScope::default())?; } else { @@ -454,17 +478,19 @@ impl super::Parse for ConstScope { parser.set_newline_as_trivia(false); parser.set_scope_recovery_stack(&[SyntaxKind::Ident, SyntaxKind::Colon, SyntaxKind::Eq]); - if parser.find_and_pop(SyntaxKind::Ident, None)? { + if parser.find_and_pop(SyntaxKind::Ident, ExpectedKind::Name(SyntaxKind::Const))? { parser.bump(); } - if parser.find_and_pop(SyntaxKind::Colon, None)? { + if parser.find_and_pop( + SyntaxKind::Colon, + ExpectedKind::TypeSpecifier(SyntaxKind::Const), + )? { parser.bump(); parse_type(parser, None)?; } - if parser.find_and_pop( - SyntaxKind::Eq, - Some("expected `=` for const value definition"), - )? { + + parser.set_newline_as_trivia(true); + if parser.find_and_pop(SyntaxKind::Eq, ExpectedKind::Unspecified)? { parser.bump(); parse_expr(parser)?; } @@ -480,7 +506,7 @@ impl super::Parse for ExternScope { parser.bump_expected(SyntaxKind::ExternKw); parser.set_scope_recovery_stack(&[SyntaxKind::LBrace]); - if parser.find(SyntaxKind::LBrace, Some("missing `extern` body"))? { + if parser.find(SyntaxKind::LBrace, ExpectedKind::Body(SyntaxKind::Extern))? { parser.parse(ExternItemListScope::default())?; } Ok(()) @@ -505,20 +531,14 @@ impl super::Parse for TypeAliasScope { parser.bump_expected(SyntaxKind::TypeKw); parser.set_scope_recovery_stack(&[SyntaxKind::Ident, SyntaxKind::Lt, SyntaxKind::Eq]); - if parser.find_and_pop( - SyntaxKind::Ident, - Some("expected identifier for type alias name"), - )? { + if parser.find_and_pop(SyntaxKind::Ident, ExpectedKind::Name(SyntaxKind::TypeAlias))? { parser.bump(); } parser.pop_recovery_stack(); parse_generic_params_opt(parser, true)?; - if parser.find_and_pop( - SyntaxKind::Eq, - Some("expected `=` for type alias definition"), - )? { + if parser.find_and_pop(SyntaxKind::Eq, ExpectedKind::Unspecified)? { parser.bump(); parse_type(parser, None)?; } @@ -558,7 +578,11 @@ fn parse_fn_item_block( checkpoint.get_or_insert(modifier_checkpoint); } else { while is_modifier(parser.current_kind()) { - parser.unexpected_token_error("modifier is not allowed in this block", None); + let kind = parser.current_kind().unwrap(); + parser.unexpected_token_error(format!( + "{} modifier is not allowed in this block", + kind.describe() + )); } } } @@ -568,10 +592,7 @@ fn parse_fn_item_block( parser.parse_cp(FuncScope::new(fn_def_scope), checkpoint)?; parser.set_newline_as_trivia(false); - parser.expect( - &[SyntaxKind::Newline, SyntaxKind::RBrace], - Some("expected newline after item definition"), - )?; + parser.expect(&[SyntaxKind::Newline, SyntaxKind::RBrace], None)?; } _ => { let proof = parser.error_msg_on_current_token("only `fn` is allowed in this block"); diff --git a/crates/parser2/src/parser/mod.rs b/crates/parser2/src/parser/mod.rs index 5c340d42e8..6ca9beff90 100644 --- a/crates/parser2/src/parser/mod.rs +++ b/crates/parser2/src/parser/mod.rs @@ -6,7 +6,7 @@ use rustc_hash::{FxHashMap, FxHashSet}; use smallvec::SmallVec; use self::token_stream::{BackTrackableTokenStream, LexicalToken, TokenStream}; -use crate::{syntax_node::SyntaxNode, GreenNode, ParseError, SyntaxKind, TextRange}; +use crate::{syntax_node::SyntaxNode, ExpectedKind, GreenNode, ParseError, SyntaxKind, TextRange}; pub mod token_stream; @@ -72,36 +72,6 @@ impl Parser { self.peek_non_trivia() } - // xxx doc - pub fn current_token_range(&mut self) -> Option { - let mut start = self.current_pos; - if !self.is_newline_trivia { - for tok in &self.next_trivias { - if tok.syntax_kind() == SyntaxKind::Newline { - return Some(TextRange::new(start, start + tok.text_size())); - } - start += tok.text_size(); - } - } - - while let Some(next) = self.stream.peek().map(|tok| tok.syntax_kind()) { - if self.is_trivia(next) { - let next = self.stream.next().unwrap(); - start += next.text_size(); - - self.next_trivias.push_back(next); - continue; - } else { - return Some(TextRange::new( - start, - start + self.stream.peek().unwrap().text_size(), - )); - } - } - - None - } - /// Returns the current non-trivia token kind of the parser. pub fn current_kind(&mut self) -> Option { self.current_token().map(|tok| tok.syntax_kind()) @@ -150,7 +120,7 @@ impl Parser { Ok(()) } else { let pos = self.current_pos; - let (index, unexpected) = self.recover(None); + let (index, unexpected) = self.recover(); let proof = if unexpected.is_some() { ErrProof(()) } else { @@ -163,11 +133,10 @@ impl Parser { r } - // xxx pub fn expect( &mut self, expected: &[SyntaxKind], - msg: Option<&str>, + kind: Option, ) -> Result<(), Recovery> { let current = self.current_kind(); @@ -179,11 +148,11 @@ impl Parser { Ok(()) } else { let pos = self.current_pos; - let (index, unexpected) = self.recover(None); + let (index, unexpected) = self.recover(); let proof = if unexpected.is_some() { ErrProof(()) } else { - self.add_error(ParseError::expected(expected, msg, pos)) + self.add_error(ParseError::expected(expected, kind, pos)) }; self.pop_recovery_stack(); self.allow_local_recovery(Err(Recovery(index, proof))) @@ -229,10 +198,9 @@ impl Parser { mut scope: T, checkpoint: Option, ) -> Result - // xxx checkpoint handling where T: Parse + 'static, - E: XxxRecoveryThing, + E: Recoverable, { let checkpoint = self.enter(scope.clone(), checkpoint); let start_checkpoint = self.checkpoint(); @@ -245,37 +213,22 @@ impl Parser { pub fn parse(&mut self, scope: T) -> Result<(), E> where T: Parse + 'static, - E: XxxRecoveryThing, + E: Recoverable, { - self.parse_cp(scope, None).map(|_| ()) + self.parse_ok(scope).map(|_| ()) } - // xxx do we ever want to use this? - pub fn parses_without_error(&mut self, mut scope: T) -> bool + pub fn parse_ok(&mut self, mut scope: T) -> Result where T: Parse + 'static, - E: XxxRecoveryThing, - { - debug_assert!(self.is_dry_run()); - let checkpoint = self.enter(scope.clone(), None); - let r = scope.parse(self); - let is_err = self.leave(checkpoint); - r.is_ok() && !is_err - } - - // xxx remove? - pub fn parse_or_recover(&mut self, mut scope: T) -> Result<(), Recovery> - where - T: Parse + 'static, + E: Recoverable, { let checkpoint = self.enter(scope.clone(), None); let res = scope.parse(self); self.leave(checkpoint); - if let Err(err) = res { - let proof = self.add_error(err); - self.try_recover().map_err(|r| r.add_err_proof(proof))?; - } - Ok(()) + let ok = res.is_ok(); + let res = self.allow_local_recovery(res); + res.map(|_| ok) } pub fn or_recover(&mut self, f: F) -> Result<(), Recovery> @@ -301,7 +254,7 @@ impl Parser { if !self.parents.is_empty() { self.bump_trivias(); } - // xxx don't push current scope onto parents stack + self.parents .push(ScopeEntry::new(Box::new(scope), self.is_newline_trivia)); // `is_newline_trivia` is always `true` when entering a scope. @@ -332,10 +285,6 @@ impl Parser { } pub fn add_error(&mut self, err: ParseError) -> ErrProof { - eprintln!( - "add_error: {err:?} {}", - std::backtrace::Backtrace::capture() - ); self.parents.last_mut().unwrap().is_err = true; self.errors.push(err); ErrProof(()) @@ -356,21 +305,6 @@ impl Parser { self.try_recover().map_err(|r| r.add_err_proof(proof)) } - // xxx check uses of error_and_recover - pub fn recover_and_error_if_no_skipped_tokens( - &mut self, - msg: &str, - ) -> Result<(), Recovery> { - let (index, unexpected) = self.recover(None); - if unexpected.is_none() { - self.add_error(ParseError::Msg( - msg.into(), - TextRange::empty(self.current_pos), - )); - } - self.allow_local_recovery(Err(Recovery(index, ErrProof(())))) - } - /// Runs the parser in the dry run mode. /// /// Any changes to the parser state will be reverted. @@ -432,16 +366,16 @@ impl Parser { pub fn find( &mut self, kind: SyntaxKind, - msg: Option<&str>, + err: ExpectedKind, ) -> Result> { self.scope_aux_recovery().push(kind); - self.find_and_pop(kind, msg) + self.find_and_pop(kind, err) } pub fn find_and_pop( &mut self, kind: SyntaxKind, - msg: Option<&str>, + err: ExpectedKind, ) -> Result> { debug_assert_eq!(self.scope_aux_recovery().last(), Some(&kind)); @@ -453,7 +387,7 @@ impl Parser { if self.current_kind() == Some(kind) { Ok(true) } else { - let proof = self.add_error(ParseError::expected(&[kind], msg, pos)); + let proof = self.add_error(ParseError::expected(&[kind], Some(err), pos)); r.map(|_| false).map_err(|rec| rec.add_err_proof(proof)) } }; @@ -462,26 +396,15 @@ impl Parser { } pub fn try_recover(&mut self) -> Result<(), Recovery<()>> { - let (index, _) = self.recover(None); + let (index, _) = self.recover(); self.allow_local_recovery(Err(Recovery(index, ()))) } - // xxx remove checkpoint arg? /// Consumes tokens until a recovery token is found, and reports an error on any /// unexpected tokens. - /// Returns the index of the scope that matched the recovery token. - fn recover( - &mut self, - checkpoint: Option, - ) -> (Option, Option) { - if !self.is_dry_run() { - eprintln!( - "recover! {:?} {:?} scopes: {:#?}", - self.current_kind(), - self.current_token().map(|t| t.text().to_string()), - self.parents - ); - } + /// Returns the index of the scope that matched the recovery token, + /// and the total string length of the unexpected tokens. + fn recover(&mut self) -> (Option, Option) { let mut unexpected = None; let mut open_brackets_in_error = FxHashMap::default(); let mut match_scope_index = None; @@ -502,12 +425,6 @@ impl Parser { .find(|(_i, scope)| scope.is_recovery_match(kind)) { match_scope_index = Some(scope_index); - if !self.is_dry_run() { - eprintln!( - "recovered at {scope_index} on {kind:?}, {:#?}", - self.parents[scope_index] - ); - } break; } @@ -515,16 +432,7 @@ impl Parser { if !self.parents.is_empty() { self.bump_trivias(); } - unexpected = Some(( - self.current_pos, - checkpoint.unwrap_or_else(|| self.checkpoint()), - )); - } - if !self.is_dry_run() { - eprintln!( - "skipping {kind:?} {:?}", - self.current_token().unwrap().text() - ); + unexpected = Some((self.current_pos, self.checkpoint())); } self.bump(); } @@ -535,22 +443,23 @@ impl Parser { .start_node_at(checkpoint, SyntaxKind::Error.into()); self.builder.finish_node(); - self.add_error(ParseError::Unexpected(TextRange::new( - start_pos, - self.current_pos, - ))); + self.add_error(ParseError::Unexpected( + format!( + "unexpected syntax while parsing {}", + self.parents.last().unwrap().scope.syntax_kind().describe() + ), + TextRange::new(start_pos, self.current_pos), + )); } } - eprintln!("{}", std::backtrace::Backtrace::capture()); ( match_scope_index.map(ScopeIndex), unexpected.map(|(start_pos, _)| start_pos), ) } - // xxx - fn allow_local_recovery(&self, r: Result<(), E>) -> Result<(), E> { + fn allow_local_recovery(&self, r: Result<(), E>) -> Result<(), E> { match r { Ok(()) => Ok(()), Err(e) if e.is_local_recovery(self) => Ok(()), @@ -689,16 +598,15 @@ impl Parser { self.add_error(ParseError::Msg(msg.into(), TextRange::new(start, end))) } - // xxx remove this or error_msg_on_current_token - /// Wrap the current token in a `SyntaxKind::Error`, and add `msg` to the error list. - fn unexpected_token_error(&mut self, msg: &str, checkpoint: Option) { - let checkpoint = self.enter(ErrorScope::default(), checkpoint); + /// Wrap the current token in a `SyntaxKind::Error`, and add a `ParseError::Unexpected`. + fn unexpected_token_error(&mut self, msg: String) { + let checkpoint = self.enter(ErrorScope::default(), None); let start_pos = self.current_pos; self.bump(); - self.add_error(ParseError::Msg( - msg.into(), + self.add_error(ParseError::Unexpected( + msg, TextRange::new(start_pos, self.current_pos), )); self.leave(checkpoint); @@ -755,14 +663,14 @@ impl From> for Recovery<()> { } } -pub trait XxxRecoveryThing { +pub trait Recoverable { fn is_local_recovery(&self, _parser: &Parser) -> bool { false } } -impl XxxRecoveryThing for ParseError {} -impl XxxRecoveryThing for Infallible {} -impl XxxRecoveryThing for Recovery { +impl Recoverable for ParseError {} +impl Recoverable for Infallible {} +impl Recoverable for Recovery { fn is_local_recovery(&self, parser: &Parser) -> bool { self.0 .as_ref() @@ -964,12 +872,12 @@ use define_scope; #[doc(hidden)] use define_scope_struct; -// xxx move /// Parse a comma-separated list of elements, with trailing commas allowed. /// Panics if `parser.current_kind() != Some(brackets.0)` fn parse_list( parser: &mut Parser, newline_delim: bool, + list_kind: SyntaxKind, brackets: (SyntaxKind, SyntaxKind), element: F, ) -> Result<(), Recovery> @@ -978,13 +886,18 @@ where { parser.bump_expected(brackets.0); + let expected_closing_bracket = Some(ExpectedKind::ClosingBracket { + bracket: brackets.1, + parent: list_kind, + }); + loop { if parser.bump_if(brackets.1) { return Ok(()); } + element(parser)?; - dbg!(parser.current_token().map(|t| t.text().to_string())); if parser.current_kind() != Some(SyntaxKind::Comma) && parser.current_kind() != Some(brackets.1) { @@ -993,13 +906,12 @@ where let newline = parser.current_kind() == Some(SyntaxKind::Newline) || { parser.with_recovery_tokens( |parser| { - // xxx clean let pos = parser.current_pos; - let (index, unexpected) = parser.recover(None); + let (index, unexpected) = parser.recover(); if unexpected.is_none() { parser.add_error(ParseError::expected( &[brackets.1, SyntaxKind::Comma], - None, + expected_closing_bracket, pos, )); } @@ -1012,24 +924,22 @@ where parser.set_newline_as_trivia(nt); if newline { - dbg!(newline_delim); parser.add_error(ParseError::expected( &[brackets.1, SyntaxKind::Comma], - None, + expected_closing_bracket, parser.current_pos, )); if !newline_delim { return Ok(()); } } else { - parser.expect(&[brackets.1, SyntaxKind::Comma], None)?; + parser.expect(&[brackets.1, SyntaxKind::Comma], expected_closing_bracket)?; if !parser.bump_if(SyntaxKind::Comma) { break; } } } else if !parser.bump_if(SyntaxKind::Comma) { - dbg!("2", parser.current_kind()); - parser.expect(&[brackets.1], None)?; + parser.expect(&[brackets.1], expected_closing_bracket)?; break; } } diff --git a/crates/parser2/src/parser/param.rs b/crates/parser2/src/parser/param.rs index 10af889769..7d79e78a45 100644 --- a/crates/parser2/src/parser/param.rs +++ b/crates/parser2/src/parser/param.rs @@ -1,6 +1,6 @@ use std::convert::Infallible; -use crate::{ParseError, SyntaxKind}; +use crate::{ExpectedKind, ParseError, SyntaxKind}; use super::{ define_scope, @@ -25,6 +25,7 @@ impl super::Parse for FuncParamListScope { parse_list( parser, false, + SyntaxKind::FuncParamList, (SyntaxKind::LParen, SyntaxKind::RParen), |parser| parser.parse(FnParamScope::new(self.allow_self)), ) @@ -72,7 +73,7 @@ impl super::Parse for FnParamScope { } if parser.find( SyntaxKind::Colon, - Some("missing type bound for fn parameter"), + ExpectedKind::TypeSpecifier(SyntaxKind::FnParam), )? { parser.bump(); parse_type(parser, None)?; @@ -93,20 +94,26 @@ impl super::Parse for GenericParamListScope { type Error = Recovery; fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { - parse_list(parser, false, (SyntaxKind::Lt, SyntaxKind::Gt), |parser| { - parser.expect( - &[SyntaxKind::Ident, SyntaxKind::ConstKw, SyntaxKind::Gt], - None, - )?; - match parser.current_kind() { - Some(SyntaxKind::ConstKw) => parser.parse(ConstGenericParamScope::default()), - Some(SyntaxKind::Ident) => { - parser.parse(TypeGenericParamScope::new(self.disallow_trait_bound)) + parse_list( + parser, + false, + SyntaxKind::GenericParamList, + (SyntaxKind::Lt, SyntaxKind::Gt), + |parser| { + parser.expect( + &[SyntaxKind::Ident, SyntaxKind::ConstKw, SyntaxKind::Gt], + None, + )?; + match parser.current_kind() { + Some(SyntaxKind::ConstKw) => parser.parse(ConstGenericParamScope::default()), + Some(SyntaxKind::Ident) => { + parser.parse(TypeGenericParamScope::new(self.disallow_trait_bound)) + } + Some(SyntaxKind::Gt) => Ok(()), + _ => unreachable!(), } - Some(SyntaxKind::Gt) => Ok(()), - _ => unreachable!(), - } - }) + }, + ) } } @@ -123,10 +130,16 @@ impl super::Parse for ConstGenericParamScope { parser.bump_expected(SyntaxKind::ConstKw); parser.set_scope_recovery_stack(&[SyntaxKind::Ident, SyntaxKind::Colon]); - if parser.find_and_pop(SyntaxKind::Ident, None)? { + if parser.find_and_pop( + SyntaxKind::Ident, + ExpectedKind::Name(SyntaxKind::ConstGenericParam), + )? { parser.bump(); } - if parser.find_and_pop(SyntaxKind::Colon, None)? { + if parser.find_and_pop( + SyntaxKind::Colon, + ExpectedKind::TypeSpecifier(SyntaxKind::ConstGenericParam), + )? { parser.bump(); parse_type(parser, None)?; } @@ -211,7 +224,13 @@ fn parse_kind_bound(parser: &mut Parser) -> Result<(), Recove if parser.bump_if(SyntaxKind::LParen) { parse_kind_bound(parser)?; - if parser.find(SyntaxKind::RParen, None)? { + if parser.find( + SyntaxKind::RParen, + ExpectedKind::ClosingBracket { + bracket: SyntaxKind::RParen, + parent: SyntaxKind::TypeBound, + }, + )? { parser.bump(); } } else if parser.current_kind() == Some(SyntaxKind::Star) { @@ -266,10 +285,9 @@ impl super::Parse for TraitRefScope { type Error = Recovery; fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { - // xxx add test that triggers this parser.or_recover(|parser| { parser.parse(PathScope::default()).map_err(|_| { - ParseError::expected(&[SyntaxKind::TraitRef], None, parser.current_pos) + ParseError::expected(&[SyntaxKind::TraitRef], None, parser.end_of_prev_token) }) })?; @@ -289,9 +307,13 @@ impl super::Parse for GenericArgListScope { type Error = Recovery; fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { - parse_list(parser, false, (SyntaxKind::Lt, SyntaxKind::Gt), |parser| { - parser.parse(GenericArgScope::default()) - }) + parse_list( + parser, + false, + SyntaxKind::GenericArgList, + (SyntaxKind::Lt, SyntaxKind::Gt), + |parser| parser.parse(GenericArgScope::default()), + ) } } @@ -335,6 +357,7 @@ impl super::Parse for CallArgListScope { parse_list( parser, false, + SyntaxKind::CallArgList, (SyntaxKind::LParen, SyntaxKind::RParen), |parser| parser.parse(CallArgScope::default()), ) @@ -379,27 +402,34 @@ impl super::Parse for WhereClauseScope { _ => break, } - if !parser.bump_if(SyntaxKind::Comma) { - if parser.current_kind().is_some() && is_type_start(parser.current_kind().unwrap()) - { - parser.set_newline_as_trivia(false); - let newline = parser.current_kind() == Some(SyntaxKind::Newline); - parser.set_newline_as_trivia(true); - - if newline { - parser.add_error(ParseError::expected( - &[SyntaxKind::Comma], - None, - parser.current_pos, - )); - } else if parser.find(SyntaxKind::Comma, None)? { - parser.bump(); - } else { - break; - } + if !parser.bump_if(SyntaxKind::Comma) + && parser.current_kind().is_some() + && is_type_start(parser.current_kind().unwrap()) + { + parser.set_newline_as_trivia(false); + let newline = parser.current_kind() == Some(SyntaxKind::Newline); + parser.set_newline_as_trivia(true); + + if newline { + parser.add_error(ParseError::expected( + &[SyntaxKind::Comma], + None, + parser.current_pos, + )); + } else if parser.find( + SyntaxKind::Comma, + ExpectedKind::Separator { + separator: SyntaxKind::Comma, + element: SyntaxKind::WherePredicate, + }, + )? { + parser.bump(); + } else { + break; } } } + if pred_count == 0 { parser.error("`where` clause requires one or more type constraints"); } @@ -419,8 +449,8 @@ impl super::Parse for WherePredicateScope { } else { parser.add_error(ParseError::expected( &[SyntaxKind::Colon], - Some("missing type bound in `where` clause"), - parser.current_pos, + Some(ExpectedKind::TypeSpecifier(SyntaxKind::WherePredicate)), + parser.end_of_prev_token, )); } Ok(()) diff --git a/crates/parser2/src/parser/pat.rs b/crates/parser2/src/parser/pat.rs index 3cb964f981..709a5419f2 100644 --- a/crates/parser2/src/parser/pat.rs +++ b/crates/parser2/src/parser/pat.rs @@ -106,6 +106,7 @@ impl super::Parse for TuplePatElemListScope { parse_list( parser, false, + SyntaxKind::TuplePatElemList, (SyntaxKind::LParen, SyntaxKind::RParen), parse_pat, ) @@ -118,13 +119,8 @@ impl super::Parse for PathPatScope { fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.or_recover(|p| { - p.parse(PathScope::default()).map_err(|e| { - ParseError::expected( - &[SyntaxKind::PathPat], - Some("expected a pattern"), - e.range().start(), - ) - }) + p.parse(PathScope::default()) + .map_err(|e| ParseError::expected(&[SyntaxKind::PathPat], None, e.range().start())) })?; parser.set_newline_as_trivia(false); @@ -148,6 +144,7 @@ impl super::Parse for RecordPatFieldListScope { parse_list( parser, true, + SyntaxKind::RecordPatFieldList, (SyntaxKind::LBrace, SyntaxKind::RBrace), |parser| parser.parse(RecordPatFieldScope::default()), ) diff --git a/crates/parser2/src/parser/path.rs b/crates/parser2/src/parser/path.rs index 8ed45ce55f..60751afe5f 100644 --- a/crates/parser2/src/parser/path.rs +++ b/crates/parser2/src/parser/path.rs @@ -38,7 +38,7 @@ impl super::Parse for PathSegmentScope { _ => Err(ParseError::expected( &[SyntaxKind::PathSegment], None, - parser.current_pos, + parser.end_of_prev_token, )), } } diff --git a/crates/parser2/src/parser/stmt.rs b/crates/parser2/src/parser/stmt.rs index affd4c8ba4..ff134db01f 100644 --- a/crates/parser2/src/parser/stmt.rs +++ b/crates/parser2/src/parser/stmt.rs @@ -1,6 +1,6 @@ use std::convert::Infallible; -use crate::SyntaxKind; +use crate::{ExpectedKind, SyntaxKind}; use super::{ define_scope, @@ -37,7 +37,7 @@ impl super::Parse for LetStmtScope { fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::LetKw); parser.set_newline_as_trivia(false); - parse_pat(parser)?; // xxx "expected pattern" error msg + parse_pat(parser)?; if parser.current_kind() == Some(SyntaxKind::Colon) { parser.bump_expected(SyntaxKind::Colon); @@ -58,15 +58,18 @@ impl super::Parse for ForStmtScope { fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { parser.bump_expected(SyntaxKind::ForKw); - parser.set_scope_recovery_stack(&[SyntaxKind::InKw, SyntaxKind::LBrace]); + parser.set_scope_recovery_stack(&[SyntaxKind::InKw, SyntaxKind::Ident, SyntaxKind::LBrace]); parse_pat(parser)?; - if parser.find_and_pop(SyntaxKind::InKw, None)? { + if parser.find_and_pop(SyntaxKind::InKw, ExpectedKind::Unspecified)? { parser.bump(); } parse_expr_no_struct(parser)?; - if parser.find_and_pop(SyntaxKind::LBrace, None)? { + // pop `Ident` recovery token, which is only included because it solves a contrived test case + parser.pop_recovery_stack(); + + if parser.find_and_pop(SyntaxKind::LBrace, ExpectedKind::Body(SyntaxKind::ForStmt))? { parser.parse(BlockExprScope::default())?; } Ok(()) @@ -83,7 +86,10 @@ impl super::Parse for WhileStmtScope { parser.set_scope_recovery_stack(&[SyntaxKind::LBrace]); parse_expr_no_struct(parser)?; - if parser.find_and_pop(SyntaxKind::LBrace, None)? { + if parser.find_and_pop( + SyntaxKind::LBrace, + ExpectedKind::Body(SyntaxKind::WhileStmt), + )? { parser.parse(BlockExprScope::default())?; } Ok(()) diff --git a/crates/parser2/src/parser/struct_.rs b/crates/parser2/src/parser/struct_.rs index c958c50769..962039eda7 100644 --- a/crates/parser2/src/parser/struct_.rs +++ b/crates/parser2/src/parser/struct_.rs @@ -1,4 +1,4 @@ -use crate::SyntaxKind; +use crate::{ExpectedKind, SyntaxKind}; use super::{ attr::parse_attr_list, @@ -29,7 +29,7 @@ impl super::Parse for StructScope { SyntaxKind::LBrace, ]); - if parser.find_and_pop(SyntaxKind::Ident, None)? { + if parser.find_and_pop(SyntaxKind::Ident, ExpectedKind::Name(SyntaxKind::Struct))? { parser.bump(); } @@ -39,7 +39,7 @@ impl super::Parse for StructScope { parser.expect_and_pop_recovery_stack()?; parse_where_clause_opt(parser)?; - if parser.find_and_pop(SyntaxKind::LBrace, Some("struct field definition"))? { + if parser.find_and_pop(SyntaxKind::LBrace, ExpectedKind::Body(SyntaxKind::Struct))? { parser.parse(RecordFieldDefListScope::default())?; } Ok(()) @@ -62,6 +62,7 @@ impl super::Parse for RecordFieldDefListScope { parse_list( parser, true, + SyntaxKind::RecordFieldDefList, (SyntaxKind::LBrace, SyntaxKind::RBrace), |parser| parser.parse(RecordFieldDefScope::default()), ) @@ -99,11 +100,17 @@ impl super::Parse for RecordFieldDefScope { parser.set_scope_recovery_stack(&[SyntaxKind::Colon]); - if parser.find(SyntaxKind::Ident, Some("expected a field name"))? { + if parser.find( + SyntaxKind::Ident, + ExpectedKind::Name(SyntaxKind::RecordField), + )? { parser.bump(); } - if parser.find(SyntaxKind::Colon, Some("missing field type"))? { + if parser.find( + SyntaxKind::Colon, + ExpectedKind::TypeSpecifier(SyntaxKind::RecordField), + )? { parser.bump(); parse_type(parser, None).map(|_| ())?; } diff --git a/crates/parser2/src/parser/type_.rs b/crates/parser2/src/parser/type_.rs index 1f05ffa8ad..e09eb0f881 100644 --- a/crates/parser2/src/parser/type_.rs +++ b/crates/parser2/src/parser/type_.rs @@ -1,4 +1,4 @@ -use crate::{ParseError, SyntaxKind}; +use crate::{ExpectedKind, ParseError, SyntaxKind}; use super::{ define_scope, @@ -89,6 +89,7 @@ impl super::Parse for TupleTypeScope { parse_list( parser, false, + SyntaxKind::TupleType, (SyntaxKind::LParen, SyntaxKind::RParen), |parser| { parse_type(parser, None)?; @@ -114,13 +115,19 @@ impl super::Parse for ArrayTypeScope { parse_type(parser, None)?; - if parser.find_and_pop(SyntaxKind::SemiColon, None)? { + if parser.find_and_pop(SyntaxKind::SemiColon, ExpectedKind::Unspecified)? { parser.bump(); } parse_expr(parser)?; - if parser.find_and_pop(SyntaxKind::RBracket, None)? { + if parser.find_and_pop( + SyntaxKind::RBracket, + ExpectedKind::ClosingBracket { + bracket: SyntaxKind::RBracket, + parent: SyntaxKind::ArrayType, + }, + )? { parser.bump(); } Ok(()) diff --git a/crates/parser2/src/parser/use_tree.rs b/crates/parser2/src/parser/use_tree.rs index 7302fca0fb..9e9c60b5c9 100644 --- a/crates/parser2/src/parser/use_tree.rs +++ b/crates/parser2/src/parser/use_tree.rs @@ -1,4 +1,4 @@ -use std::{cell::Cell, rc::Rc}; +use std::{cell::Cell, convert::identity, rc::Rc}; use crate::{parser::path::is_path_segment, ParseError, SyntaxKind, TextRange}; @@ -19,7 +19,7 @@ impl super::Parse for UseTreeScope { } let use_path_scope = UsePathScope::default(); - parser.parse_or_recover(use_path_scope.clone())?; + parser.or_recover(|p| p.parse(use_path_scope.clone()))?; let is_glob = use_path_scope.is_glob.get(); if parser.current_kind() == Some(SyntaxKind::AsKw) { @@ -27,7 +27,7 @@ impl super::Parse for UseTreeScope { parser.error_msg_on_current_token("can't use `as` with `*`"); } if parser.current_kind() == Some(SyntaxKind::AsKw) { - parser.parse_or_recover(UseTreeAliasScope::default())?; + parser.or_recover(|p| p.parse(UseTreeAliasScope::default()))?; } return Ok(()); } @@ -57,6 +57,7 @@ impl super::Parse for UseTreeListScope { parse_list( parser, true, + SyntaxKind::UseTreeList, (SyntaxKind::LBrace, SyntaxKind::RBrace), |parser| parser.parse(UseTreeScope::default()), ) @@ -78,7 +79,9 @@ impl super::Parse for UsePathScope { loop { let is_path_segment = parser.dry_run(|parser| { parser.bump_if(SyntaxKind::Colon2) - && parser.parses_without_error(UsePathSegmentScope::default()) + && parser + .parse_ok(UsePathSegmentScope::default()) + .is_ok_and(identity) }); if is_path_segment { if self.is_glob.get() { @@ -112,7 +115,7 @@ impl super::Parse for UsePathSegmentScope { _ => { return Err(ParseError::Msg( "expected identifier or `self`".into(), - TextRange::empty(parser.current_pos), + TextRange::empty(parser.end_of_prev_token), )); } } diff --git a/crates/parser2/src/syntax_kind.rs b/crates/parser2/src/syntax_kind.rs index cf97d6ab89..a1e9bb16ba 100644 --- a/crates/parser2/src/syntax_kind.rs +++ b/crates/parser2/src/syntax_kind.rs @@ -520,8 +520,6 @@ impl SyntaxKind { ) } - // xxx - /// Panics if `self` is not a token kind pub fn describe(self) -> &'static str { match self { SyntaxKind::Newline => "newline", @@ -559,9 +557,9 @@ impl SyntaxKind { SyntaxKind::Pipe2 => "`||`", SyntaxKind::Lt => "`<`", SyntaxKind::Gt => "`>`", - SyntaxKind::Eq => "``", - SyntaxKind::Eq2 => "``", - SyntaxKind::NotEq => "``", + SyntaxKind::Eq => "`=`", + SyntaxKind::Eq2 => "`==`", + SyntaxKind::NotEq => "`!=`", SyntaxKind::AsKw => "`as`", SyntaxKind::TrueKw => "`true`", SyntaxKind::FalseKw => "`false`", @@ -599,13 +597,198 @@ impl SyntaxKind { SyntaxKind::LtEq => "`<=`", SyntaxKind::GtEq => "`>=`", - SyntaxKind::PathType => "a type name", - SyntaxKind::TraitRef => "a trait name", - SyntaxKind::PathSegment => "a path segment", - SyntaxKind::PathPat => "a pattern", - _ => unimplemented!(), + SyntaxKind::PathType => "type", + SyntaxKind::TraitRef => "trait name", + SyntaxKind::PathSegment => "path segment", + SyntaxKind::PathPat => "pattern", + + SyntaxKind::ArrayExpr => "array definition", + SyntaxKind::RecordFieldDef => "field", + SyntaxKind::IndexExpr => "index expression", + SyntaxKind::BlockExpr => "block", + SyntaxKind::TypeBound => "type bound", + SyntaxKind::CallArgList => "function call arguments", + + SyntaxKind::InvalidToken => unimplemented!(), + SyntaxKind::WhiteSpace => "whitespace", + SyntaxKind::Comment => "comment", + SyntaxKind::DocComment => "doc comment", + + SyntaxKind::Lit => "literal", + SyntaxKind::BinExpr => "binary expression", + SyntaxKind::UnExpr => "unary expression", + SyntaxKind::CallExpr => "function call expression", + SyntaxKind::CallArg => "function call argument", + SyntaxKind::MethodCallExpr => "method call expression", + SyntaxKind::GenericArgList => "generic type argument list", + SyntaxKind::TypeGenericArg => "generic type argument", + SyntaxKind::ConstGenericArg => "generic const argument", + SyntaxKind::PathExpr => "path", + SyntaxKind::RecordInitExpr => "record initialization expression", + SyntaxKind::RecordFieldList => "record field list", + SyntaxKind::RecordField => "field", + SyntaxKind::FieldExpr => "field", + SyntaxKind::TupleExpr => "tuple expression", + SyntaxKind::ArrayRepExpr => "array expression", + SyntaxKind::LitExpr => "literal expression", + SyntaxKind::IfExpr => "`if` expression", + SyntaxKind::MatchExpr => "`match` expression", + SyntaxKind::ParenExpr => "parenthesized expression", + SyntaxKind::AssignExpr => "assignment expression", + SyntaxKind::AugAssignExpr => "augmented assignment expression", + SyntaxKind::LetStmt => "`let` statement", + SyntaxKind::ForStmt => "`for` statement", + SyntaxKind::WhileStmt => "`while` statement", + SyntaxKind::ContinueStmt => "`continue` statement", + SyntaxKind::BreakStmt => "`break` statement", + SyntaxKind::ReturnStmt => "`return` statement", + SyntaxKind::ExprStmt => "`expr` statement", + SyntaxKind::WildCardPat => "wildcard pattern", + SyntaxKind::RestPat => "`..` pattern", + SyntaxKind::LitPat => "literal pattern", + SyntaxKind::TuplePat => "tuple pattern", + SyntaxKind::TuplePatElemList => "tuple pattern element list", + SyntaxKind::PathTuplePat => "path tuple pattern", + SyntaxKind::RecordPat => "record pattern", + SyntaxKind::RecordPatFieldList => "record pattern field list", + SyntaxKind::RecordPatField => "record pattern field", + SyntaxKind::OrPat => "`or` pattern", + SyntaxKind::MatchArm => "`match` arm", + SyntaxKind::MatchArmList => "`match` arm list", + SyntaxKind::Item => "item", + SyntaxKind::Mod => "`mod`", + SyntaxKind::Func => "function definition", + SyntaxKind::Struct => "struct definition", + SyntaxKind::Contract => "contract definition", + SyntaxKind::Enum => "enum definition", + SyntaxKind::TypeAlias => "type alias", + SyntaxKind::Impl => "`impl` block", + SyntaxKind::ImplItemList => "`impl` item list", + SyntaxKind::Trait => "trait definition", + SyntaxKind::SuperTraitList => "supertrait list", + SyntaxKind::TraitItemList => "`trait` item list", + SyntaxKind::ImplTrait => "`impl` trait block", + SyntaxKind::ImplTraitItemList => "`impl` trait item list", + SyntaxKind::Const => "const definition", + SyntaxKind::Use => "`use` statement", + SyntaxKind::UseTree => "`use` tree", + SyntaxKind::UseTreeList => "`use` tree list", + SyntaxKind::UsePath => "`use` path", + SyntaxKind::UsePathSegment => "`use` path segment", + SyntaxKind::UseTreeRename => "`use as` rename", + SyntaxKind::Extern => "`extern` block", + SyntaxKind::ExternItemList => "`extern` body", + SyntaxKind::ItemList => "item list", + SyntaxKind::ItemModifier => "item modifier", + SyntaxKind::PtrType => "pointer type", + SyntaxKind::SelfType => "`Self` type", + SyntaxKind::TupleType => "tuple type definition", + SyntaxKind::ArrayType => "array type definition", + SyntaxKind::Path => "path", + SyntaxKind::Attr => "attribute", + SyntaxKind::AttrArgList => "attribute argument list", + SyntaxKind::AttrArg => "attribute argument", + SyntaxKind::DocCommentAttr => "doc comment", + SyntaxKind::AttrList => "attribute list", + SyntaxKind::Visibility => "visibility modifier", + SyntaxKind::RecordFieldDefList => "record field list", + SyntaxKind::VariantDef => "`enum` variant definition", + SyntaxKind::VariantDefList => "`enum` variant list", + SyntaxKind::TypeGenericParam => "generic type parameter", + SyntaxKind::ConstGenericParam => "constant generic parameter", + SyntaxKind::GenericParamList => "generic parameter list", + SyntaxKind::FuncSignature => "function signature", + SyntaxKind::FuncParamList => "function parameter list", + SyntaxKind::FnParam => "function parameter", + SyntaxKind::TypeBoundList => "type bound list", + SyntaxKind::KindBoundAbs => "kind bound", + SyntaxKind::KindBoundMono => "kind bound", + SyntaxKind::WhereClause => "`where` clause", + SyntaxKind::WherePredicate => "`where` predicate", + SyntaxKind::Root => todo!(), + SyntaxKind::Error => todo!(), } } + + pub fn is_token(self) -> bool { + matches!( + self, + SyntaxKind::Newline + | SyntaxKind::Ident + | SyntaxKind::Int + | SyntaxKind::String + | SyntaxKind::LParen + | SyntaxKind::RParen + | SyntaxKind::LBrace + | SyntaxKind::RBrace + | SyntaxKind::LBracket + | SyntaxKind::RBracket + | SyntaxKind::Colon + | SyntaxKind::Colon2 + | SyntaxKind::SemiColon + | SyntaxKind::Dot + | SyntaxKind::Dot2 + | SyntaxKind::Comma + | SyntaxKind::Arrow + | SyntaxKind::FatArrow + | SyntaxKind::Underscore + | SyntaxKind::Pound + | SyntaxKind::Plus + | SyntaxKind::Minus + | SyntaxKind::Star + | SyntaxKind::Star2 + | SyntaxKind::Slash + | SyntaxKind::Percent + | SyntaxKind::Tilde + | SyntaxKind::Not + | SyntaxKind::Hat + | SyntaxKind::Amp + | SyntaxKind::Amp2 + | SyntaxKind::Pipe + | SyntaxKind::Pipe2 + | SyntaxKind::Lt + | SyntaxKind::Gt + | SyntaxKind::Eq + | SyntaxKind::Eq2 + | SyntaxKind::NotEq + | SyntaxKind::AsKw + | SyntaxKind::TrueKw + | SyntaxKind::FalseKw + | SyntaxKind::BreakKw + | SyntaxKind::ContinueKw + | SyntaxKind::ContractKw + | SyntaxKind::FnKw + | SyntaxKind::ModKw + | SyntaxKind::ConstKw + | SyntaxKind::IfKw + | SyntaxKind::ElseKw + | SyntaxKind::MatchKw + | SyntaxKind::ForKw + | SyntaxKind::InKw + | SyntaxKind::WhereKw + | SyntaxKind::WhileKw + | SyntaxKind::PubKw + | SyntaxKind::ReturnKw + | SyntaxKind::SelfKw + | SyntaxKind::SelfTypeKw + | SyntaxKind::StructKw + | SyntaxKind::EnumKw + | SyntaxKind::TraitKw + | SyntaxKind::ImplKw + | SyntaxKind::TypeKw + | SyntaxKind::LetKw + | SyntaxKind::MutKw + | SyntaxKind::UseKw + | SyntaxKind::ExternKw + | SyntaxKind::UnsafeKw + | SyntaxKind::IngotKw + | SyntaxKind::SuperKw + | SyntaxKind::LShift + | SyntaxKind::RShift + | SyntaxKind::LtEq + | SyntaxKind::GtEq + ) + } } impl From for rowan::SyntaxKind { diff --git a/crates/parser2/test_files/error_recovery/items/const_.snap b/crates/parser2/test_files/error_recovery/items/const_.snap index a82e34328d..04dc26dcef 100644 --- a/crates/parser2/test_files/error_recovery/items/const_.snap +++ b/crates/parser2/test_files/error_recovery/items/const_.snap @@ -5,7 +5,7 @@ input_file: crates/parser2/test_files/error_recovery/items/const_.fe --- Root@0..44 ItemList@0..44 - Item@0..14 + Item@0..12 Const@0..12 ConstKw@0..5 "const" WhiteSpace@5..6 " " @@ -16,9 +16,9 @@ Root@0..44 LitExpr@10..12 Lit@10..12 Int@10..12 "10" - Newline@12..14 "\n\n" - Item@14..29 - Const@14..29 + Newline@12..14 "\n\n" + Item@14..26 + Const@14..26 ConstKw@14..19 "const" WhiteSpace@19..20 " " Ident@20..21 "X" @@ -28,9 +28,8 @@ Root@0..44 Path@23..26 PathSegment@23..26 Ident@23..26 "i32" - WhiteSpace@26..27 " " - Error@27..29 - Newline@27..29 "\n\n" + WhiteSpace@26..27 " " + Newline@27..29 "\n\n" Item@29..44 Const@29..44 ConstKw@29..34 "const" diff --git a/crates/parser2/test_files/error_recovery/items/enum_.snap b/crates/parser2/test_files/error_recovery/items/enum_.snap index 968cd001f0..3b0e168ce1 100644 --- a/crates/parser2/test_files/error_recovery/items/enum_.snap +++ b/crates/parser2/test_files/error_recovery/items/enum_.snap @@ -4,8 +4,8 @@ expression: node input_file: crates/parser2/test_files/error_recovery/items/enum_.fe --- Root@0..150 - ItemList@0..150 - Item@0..65 + ItemList@0..149 + Item@0..63 Enum@0..63 ItemModifier@0..3 PubKw@0..3 "pub" @@ -67,8 +67,8 @@ Root@0..150 Ident@60..61 "Z" Newline@61..62 "\n" RBrace@62..63 "}" - Newline@63..65 "\n\n" - Item@65..150 + Newline@63..65 "\n\n" + Item@65..149 Enum@65..149 ItemModifier@65..68 PubKw@65..68 "pub" @@ -160,5 +160,5 @@ Root@0..150 RParen@146..147 ")" Newline@147..148 "\n" RBrace@148..149 "}" - Newline@149..150 "\n" + Newline@149..150 "\n" diff --git a/crates/parser2/test_files/error_recovery/items/func.snap b/crates/parser2/test_files/error_recovery/items/func.snap index af1583e0ab..30d836c5ab 100644 --- a/crates/parser2/test_files/error_recovery/items/func.snap +++ b/crates/parser2/test_files/error_recovery/items/func.snap @@ -4,8 +4,8 @@ expression: node input_file: crates/parser2/test_files/error_recovery/items/func.fe --- Root@0..133 - ItemList@0..133 - Item@0..80 + ItemList@0..132 + Item@0..78 Func@0..78 FnKw@0..2 "fn" WhiteSpace@2..3 " " @@ -95,8 +95,8 @@ Root@0..133 LBrace@74..75 "{" Newline@75..77 "\n\n" RBrace@77..78 "}" - Newline@78..80 "\n\n" - Item@80..133 + Newline@78..80 "\n\n" + Item@80..132 Func@80..132 FnKw@80..82 "fn" WhiteSpace@82..83 " " @@ -152,5 +152,5 @@ Root@0..133 LBrace@128..129 "{" Newline@129..131 "\n\n" RBrace@131..132 "}" - Newline@132..133 "\n" + Newline@132..133 "\n" diff --git a/crates/parser2/test_files/error_recovery/items/impl_.snap b/crates/parser2/test_files/error_recovery/items/impl_.snap index fc151f4e6b..131376c4b1 100644 --- a/crates/parser2/test_files/error_recovery/items/impl_.snap +++ b/crates/parser2/test_files/error_recovery/items/impl_.snap @@ -5,7 +5,7 @@ input_file: crates/parser2/test_files/error_recovery/items/impl_.fe --- Root@0..56 ItemList@0..56 - Item@0..39 + Item@0..37 Impl@0..37 ImplKw@0..4 "impl" WhiteSpace@4..5 " " @@ -49,7 +49,7 @@ Root@0..56 LBrace@34..35 "{" WhiteSpace@35..36 " " RBrace@36..37 "}" - Newline@37..39 "\n\n" + Newline@37..39 "\n\n" Item@39..56 Impl@39..56 ImplKw@39..43 "impl" diff --git a/crates/parser2/test_files/error_recovery/items/impl_trait.snap b/crates/parser2/test_files/error_recovery/items/impl_trait.snap index ca96ad8587..5e30b5159b 100644 --- a/crates/parser2/test_files/error_recovery/items/impl_trait.snap +++ b/crates/parser2/test_files/error_recovery/items/impl_trait.snap @@ -5,7 +5,7 @@ input_file: crates/parser2/test_files/error_recovery/items/impl_trait.fe --- Root@0..90 ItemList@0..90 - Item@0..38 + Item@0..36 ImplTrait@0..36 ImplKw@0..4 "impl" WhiteSpace@4..5 " " @@ -66,8 +66,8 @@ Root@0..90 ImplTraitItemList@34..36 LBrace@34..35 "{" RBrace@35..36 "}" - Newline@36..38 "\n\n" - Item@38..73 + Newline@36..38 "\n\n" + Item@38..71 ImplTrait@38..71 ImplKw@38..42 "impl" WhiteSpace@42..43 " " @@ -124,24 +124,27 @@ Root@0..90 ImplTraitItemList@69..71 LBrace@69..70 "{" RBrace@70..71 "}" - Newline@71..73 "\n\n" + Newline@71..73 "\n\n" Item@73..90 - Impl@73..81 + ImplTrait@73..90 ImplKw@73..77 "impl" WhiteSpace@77..78 " " - PathType@78..79 + TraitRef@78..79 Path@78..79 PathSegment@78..79 Ident@78..79 "E" WhiteSpace@79..80 " " Error@80..81 InvalidToken@80..81 "@" - WhiteSpace@81..82 " " - Error@82..90 + WhiteSpace@81..82 " " ForKw@82..85 "for" WhiteSpace@85..86 " " - Ident@86..87 "F" + PathType@86..87 + Path@86..87 + PathSegment@86..87 + Ident@86..87 "F" WhiteSpace@87..88 " " - LBrace@88..89 "{" - RBrace@89..90 "}" + ImplTraitItemList@88..90 + LBrace@88..89 "{" + RBrace@89..90 "}" diff --git a/crates/parser2/test_files/error_recovery/items/struct_.snap b/crates/parser2/test_files/error_recovery/items/struct_.snap index cddf79090e..2557680498 100644 --- a/crates/parser2/test_files/error_recovery/items/struct_.snap +++ b/crates/parser2/test_files/error_recovery/items/struct_.snap @@ -5,7 +5,7 @@ input_file: crates/parser2/test_files/error_recovery/items/struct_.fe --- Root@0..160 ItemList@0..160 - Item@0..76 + Item@0..74 Struct@0..74 ItemModifier@0..3 PubKw@0..3 "pub" @@ -68,7 +68,7 @@ Root@0..160 Ident@69..72 "foo" Newline@72..73 "\n" RBrace@73..74 "}" - Newline@74..76 "\n\n" + Newline@74..76 "\n\n" Item@76..160 Struct@76..160 ItemModifier@76..79 diff --git a/crates/parser2/test_files/error_recovery/items/trait_.snap b/crates/parser2/test_files/error_recovery/items/trait_.snap index 4768468b2e..99e95864ef 100644 --- a/crates/parser2/test_files/error_recovery/items/trait_.snap +++ b/crates/parser2/test_files/error_recovery/items/trait_.snap @@ -5,7 +5,7 @@ input_file: crates/parser2/test_files/error_recovery/items/trait_.fe --- Root@0..133 ItemList@0..133 - Item@0..20 + Item@0..18 Trait@0..18 TraitKw@0..5 "trait" WhiteSpace@5..6 " " @@ -23,8 +23,8 @@ Root@0..133 TraitItemList@16..18 LBrace@16..17 "{" RBrace@17..18 "}" - Newline@18..20 "\n\n" - Item@20..37 + Newline@18..20 "\n\n" + Item@20..35 Trait@20..35 TraitKw@20..25 "trait" WhiteSpace@25..26 " " @@ -38,7 +38,7 @@ Root@0..133 TraitItemList@33..35 LBrace@33..34 "{" RBrace@34..35 "}" - Newline@35..37 "\n\n" + Newline@35..37 "\n\n" Item@37..51 Trait@37..51 TraitKw@37..42 "trait" @@ -52,7 +52,7 @@ Root@0..133 WhiteSpace@49..50 " " Gt@50..51 ">" Newline@51..53 "\n\n" - Item@53..87 + Item@53..85 Trait@53..85 TraitKw@53..58 "trait" WhiteSpace@58..59 " " @@ -88,7 +88,7 @@ Root@0..133 TraitItemList@83..85 LBrace@83..84 "{" RBrace@84..85 "}" - Newline@85..87 "\n\n" + Newline@85..87 "\n\n" Item@87..133 Trait@87..133 TraitKw@87..92 "trait" diff --git a/crates/parser2/test_files/error_recovery/items/type_.snap b/crates/parser2/test_files/error_recovery/items/type_.snap index d5292f1c34..968b01aa9d 100644 --- a/crates/parser2/test_files/error_recovery/items/type_.snap +++ b/crates/parser2/test_files/error_recovery/items/type_.snap @@ -4,8 +4,8 @@ expression: node input_file: crates/parser2/test_files/error_recovery/items/type_.fe --- Root@0..72 - ItemList@0..72 - Item@0..31 + ItemList@0..70 + Item@0..29 TypeAlias@0..29 TypeKw@0..4 "type" WhiteSpace@4..5 " " @@ -37,8 +37,8 @@ Root@0..72 PathSegment@27..28 Ident@27..28 "E" Gt@28..29 ">" - Newline@29..31 "\n\n" - Item@31..72 + Newline@29..31 "\n\n" + Item@31..70 TypeAlias@31..70 TypeKw@31..35 "type" WhiteSpace@35..36 " " @@ -86,5 +86,5 @@ Root@0..72 PathSegment@68..69 Ident@68..69 "U" Gt@69..70 ">" - Newline@70..72 "\n\n" + Newline@70..72 "\n\n" diff --git a/crates/parser2/test_files/error_recovery/items/use_.snap b/crates/parser2/test_files/error_recovery/items/use_.snap index 120cd71b40..5d052e46a7 100644 --- a/crates/parser2/test_files/error_recovery/items/use_.snap +++ b/crates/parser2/test_files/error_recovery/items/use_.snap @@ -5,7 +5,7 @@ input_file: crates/parser2/test_files/error_recovery/items/use_.fe --- Root@0..63 ItemList@0..63 - Item@0..19 + Item@0..18 Use@0..18 UseKw@0..3 "use" WhiteSpace@3..4 " " @@ -22,8 +22,8 @@ Root@0..63 Colon2@15..17 "::" UsePathSegment@17..18 Ident@17..18 "A" - Newline@18..19 "\n" - Item@19..43 + Newline@18..19 "\n" + Item@19..42 Use@19..42 UseKw@19..22 "use" WhiteSpace@22..23 " " @@ -51,7 +51,7 @@ Root@0..63 UsePathSegment@40..41 Ident@40..41 "B" RBrace@41..42 "}" - Newline@42..43 "\n" + Newline@42..43 "\n" Item@43..63 Use@43..63 UseKw@43..46 "use" diff --git a/crates/parser2/test_files/error_recovery/stmts/for_.snap b/crates/parser2/test_files/error_recovery/stmts/for_.snap index bd08005e3d..d74f0a69bf 100644 --- a/crates/parser2/test_files/error_recovery/stmts/for_.snap +++ b/crates/parser2/test_files/error_recovery/stmts/for_.snap @@ -16,8 +16,10 @@ Root@0..71 PathSegment@6..7 Ident@6..7 "i" WhiteSpace@7..8 " " - Error@8..11 - Ident@8..11 "arr" + PathExpr@8..11 + Path@8..11 + PathSegment@8..11 + Ident@8..11 "arr" WhiteSpace@11..12 " " BlockExpr@12..15 LBrace@12..13 "{" diff --git a/crates/parser2/test_files/syntax_node/exprs/block.snap b/crates/parser2/test_files/syntax_node/exprs/block.snap index b19de81ef4..4c6ab0b269 100644 --- a/crates/parser2/test_files/syntax_node/exprs/block.snap +++ b/crates/parser2/test_files/syntax_node/exprs/block.snap @@ -8,7 +8,7 @@ Root@0..75 LBrace@0..1 "{" Newline@1..2 "\n" WhiteSpace@2..6 " " - Item@6..21 + Item@6..20 Use@6..20 UseKw@6..9 "use" WhiteSpace@9..10 " " @@ -19,9 +19,9 @@ Root@0..75 Colon2@15..17 "::" UsePathSegment@17..20 Ident@17..20 "Foo" - Newline@20..21 "\n" + Newline@20..21 "\n" WhiteSpace@21..25 " " - Item@25..39 + Item@25..38 Struct@25..38 StructKw@25..31 "struct" WhiteSpace@31..32 " " @@ -30,9 +30,9 @@ Root@0..75 RecordFieldDefList@36..38 LBrace@36..37 "{" RBrace@37..38 "}" - Newline@38..39 "\n" + Newline@38..39 "\n" WhiteSpace@39..43 " " - Item@43..55 + Item@43..54 Func@43..54 FnKw@43..45 "fn" WhiteSpace@45..46 " " @@ -44,7 +44,7 @@ Root@0..75 BlockExpr@52..54 LBrace@52..53 "{" RBrace@53..54 "}" - Newline@54..55 "\n" + Newline@54..55 "\n" WhiteSpace@55..59 " " Newline@59..60 "\n" WhiteSpace@60..64 " " diff --git a/crates/parser2/test_files/syntax_node/items/const.snap b/crates/parser2/test_files/syntax_node/items/const.snap index 8808db0b79..6b23631b34 100644 --- a/crates/parser2/test_files/syntax_node/items/const.snap +++ b/crates/parser2/test_files/syntax_node/items/const.snap @@ -4,8 +4,8 @@ expression: node input_file: crates/parser2/test_files/syntax_node/items/const.fe --- Root@0..160 - ItemList@0..160 - Item@0..24 + ItemList@0..159 + Item@0..22 Const@0..22 ItemModifier@0..3 PubKw@0..3 "pub" @@ -25,8 +25,8 @@ Root@0..160 LitExpr@21..22 Lit@21..22 Int@21..22 "1" - Newline@22..24 "\n\n" - Item@24..160 + Newline@22..24 "\n\n" + Item@24..159 Const@24..159 ConstKw@24..29 "const" WhiteSpace@29..30 " " @@ -139,5 +139,5 @@ Root@0..160 RBrace@156..157 "}" Newline@157..158 "\n" RBrace@158..159 "}" - Newline@159..160 "\n" + Newline@159..160 "\n" diff --git a/crates/parser2/test_files/syntax_node/items/contract.snap b/crates/parser2/test_files/syntax_node/items/contract.snap index 2119b58bd2..b66008047c 100644 --- a/crates/parser2/test_files/syntax_node/items/contract.snap +++ b/crates/parser2/test_files/syntax_node/items/contract.snap @@ -5,7 +5,7 @@ input_file: crates/parser2/test_files/syntax_node/items/contract.fe --- Root@0..90 ItemList@0..90 - Item@0..19 + Item@0..17 Contract@0..17 ContractKw@0..8 "contract" WhiteSpace@8..9 " " @@ -14,7 +14,7 @@ Root@0..90 RecordFieldDefList@15..17 LBrace@15..16 "{" RBrace@16..17 "}" - Newline@17..19 "\n\n" + Newline@17..19 "\n\n" Item@19..90 Contract@19..90 ItemModifier@19..22 diff --git a/crates/parser2/test_files/syntax_node/items/enums.snap b/crates/parser2/test_files/syntax_node/items/enums.snap index 734018e9f4..dea2366607 100644 --- a/crates/parser2/test_files/syntax_node/items/enums.snap +++ b/crates/parser2/test_files/syntax_node/items/enums.snap @@ -4,8 +4,8 @@ expression: node input_file: crates/parser2/test_files/syntax_node/items/enums.fe --- Root@0..493 - ItemList@0..493 - Item@0..15 + ItemList@0..492 + Item@0..13 Enum@0..13 EnumKw@0..4 "enum" WhiteSpace@4..5 " " @@ -14,8 +14,8 @@ Root@0..493 VariantDefList@11..13 LBrace@11..12 "{" RBrace@12..13 "}" - Newline@13..15 "\n\n" - Item@15..59 + Newline@13..15 "\n\n" + Item@15..57 Enum@15..57 EnumKw@15..19 "enum" WhiteSpace@19..20 " " @@ -47,8 +47,8 @@ Root@0..493 RParen@54..55 ")" Newline@55..56 "\n" RBrace@56..57 "}" - Newline@57..59 "\n\n" - Item@59..142 + Newline@57..59 "\n\n" + Item@59..140 Enum@59..140 EnumKw@59..63 "enum" WhiteSpace@63..64 " " @@ -105,8 +105,8 @@ Root@0..493 RBrace@137..138 "}" Newline@138..139 "\n" RBrace@139..140 "}" - Newline@140..142 "\n\n" - Item@142..204 + Newline@140..142 "\n\n" + Item@142..202 Enum@142..202 EnumKw@142..146 "enum" WhiteSpace@146..147 " " @@ -156,8 +156,8 @@ Root@0..493 Comma@199..200 "," Newline@200..201 "\n" RBrace@201..202 "}" - Newline@202..204 "\n\n" - Item@204..308 + Newline@202..204 "\n\n" + Item@204..306 Enum@204..306 EnumKw@204..208 "enum" WhiteSpace@208..209 " " @@ -261,8 +261,8 @@ Root@0..493 Comma@303..304 "," Newline@304..305 "\n" RBrace@305..306 "}" - Newline@306..308 "\n\n" - Item@308..436 + Newline@306..308 "\n\n" + Item@308..434 Enum@308..434 EnumKw@308..312 "enum" WhiteSpace@312..313 " " @@ -416,8 +416,8 @@ Root@0..493 RParen@431..432 ")" Newline@432..433 "\n" RBrace@433..434 "}" - Newline@434..436 "\n\n" - Item@436..493 + Newline@434..436 "\n\n" + Item@436..492 Enum@436..492 EnumKw@436..440 "enum" WhiteSpace@440..441 " " @@ -479,5 +479,5 @@ Root@0..493 RParen@489..490 ")" WhiteSpace@490..491 " " RBrace@491..492 "}" - Newline@492..493 "\n" + Newline@492..493 "\n" diff --git a/crates/parser2/test_files/syntax_node/items/extern.snap b/crates/parser2/test_files/syntax_node/items/extern.snap index 05a72a60d2..5a89154c0f 100644 --- a/crates/parser2/test_files/syntax_node/items/extern.snap +++ b/crates/parser2/test_files/syntax_node/items/extern.snap @@ -5,7 +5,7 @@ input_file: crates/parser2/test_files/syntax_node/items/extern.fe --- Root@0..146 ItemList@0..146 - Item@0..13 + Item@0..11 Extern@0..11 ExternKw@0..6 "extern" WhiteSpace@6..7 " " @@ -13,7 +13,7 @@ Root@0..146 LBrace@7..8 "{" Newline@8..10 "\n\n" RBrace@10..11 "}" - Newline@11..13 "\n\n" + Newline@11..13 "\n\n" Item@13..146 Extern@13..146 ExternKw@13..19 "extern" diff --git a/crates/parser2/test_files/syntax_node/items/func.snap b/crates/parser2/test_files/syntax_node/items/func.snap index c1c5235f6e..52e9c4036b 100644 --- a/crates/parser2/test_files/syntax_node/items/func.snap +++ b/crates/parser2/test_files/syntax_node/items/func.snap @@ -5,7 +5,7 @@ input_file: crates/parser2/test_files/syntax_node/items/func.fe --- Root@0..351 ItemList@0..351 - Item@0..32 + Item@0..30 Func@0..30 ItemModifier@0..3 PubKw@0..3 "pub" @@ -36,8 +36,8 @@ Root@0..351 Int@27..28 "1" Newline@28..29 "\n" RBrace@29..30 "}" - Newline@30..32 "\n\n" - Item@32..82 + Newline@30..32 "\n\n" + Item@32..80 Func@32..80 FnKw@32..34 "fn" WhiteSpace@34..35 " " @@ -83,8 +83,8 @@ Root@0..351 Int@77..78 "1" Newline@78..79 "\n" RBrace@79..80 "}" - Newline@80..82 "\n\n" - Item@82..180 + Newline@80..82 "\n\n" + Item@82..178 Func@82..178 FnKw@82..84 "fn" WhiteSpace@84..85 " " @@ -158,8 +158,8 @@ Root@0..351 Int@175..176 "1" Newline@176..177 "\n" RBrace@177..178 "}" - Newline@178..180 "\n\n" - Item@180..298 + Newline@178..180 "\n\n" + Item@180..296 Func@180..296 FnKw@180..182 "fn" WhiteSpace@182..183 " " @@ -279,7 +279,7 @@ Root@0..351 Ident@293..294 "t" Newline@294..295 "\n" RBrace@295..296 "}" - Newline@296..298 "\n\n" + Newline@296..298 "\n\n" Item@298..351 Func@298..351 FnKw@298..300 "fn" diff --git a/crates/parser2/test_files/syntax_node/items/impl.snap b/crates/parser2/test_files/syntax_node/items/impl.snap index c984174c5e..da14d92754 100644 --- a/crates/parser2/test_files/syntax_node/items/impl.snap +++ b/crates/parser2/test_files/syntax_node/items/impl.snap @@ -5,7 +5,7 @@ input_file: crates/parser2/test_files/syntax_node/items/impl.fe --- Root@0..272 ItemList@0..272 - Item@0..139 + Item@0..137 Impl@0..137 ImplKw@0..4 "impl" GenericParamList@4..12 @@ -112,7 +112,7 @@ Root@0..272 RBrace@134..135 "}" Newline@135..136 "\n" RBrace@136..137 "}" - Newline@137..139 "\n\n" + Newline@137..139 "\n\n" Item@139..272 Impl@139..272 ImplKw@139..143 "impl" diff --git a/crates/parser2/test_files/syntax_node/items/impl_trait.snap b/crates/parser2/test_files/syntax_node/items/impl_trait.snap index aaa6cb9c8e..cba9fbebb5 100644 --- a/crates/parser2/test_files/syntax_node/items/impl_trait.snap +++ b/crates/parser2/test_files/syntax_node/items/impl_trait.snap @@ -5,7 +5,7 @@ input_file: crates/parser2/test_files/syntax_node/items/impl_trait.fe --- Root@0..334 ItemList@0..334 - Item@0..69 + Item@0..67 ImplTrait@0..67 ImplKw@0..4 "impl" GenericParamList@4..7 @@ -69,8 +69,8 @@ Root@0..334 RBrace@64..65 "}" Newline@65..66 "\n" RBrace@66..67 "}" - Newline@67..69 "\n\n" - Item@69..207 + Newline@67..69 "\n\n" + Item@69..205 ImplTrait@69..205 ImplKw@69..73 "impl" GenericParamList@73..79 @@ -223,7 +223,7 @@ Root@0..334 RBrace@202..203 "}" Newline@203..204 "\n" RBrace@204..205 "}" - Newline@205..207 "\n\n" + Newline@205..207 "\n\n" Item@207..334 ImplTrait@207..334 ImplKw@207..211 "impl" diff --git a/crates/parser2/test_files/syntax_node/items/mod.snap b/crates/parser2/test_files/syntax_node/items/mod.snap index d5cd3c1e7b..60b6e63e9e 100644 --- a/crates/parser2/test_files/syntax_node/items/mod.snap +++ b/crates/parser2/test_files/syntax_node/items/mod.snap @@ -5,7 +5,7 @@ input_file: crates/parser2/test_files/syntax_node/items/mod.fe --- Root@0..146 ItemList@0..146 - Item@0..109 + Item@0..107 Mod@0..107 ItemModifier@0..3 PubKw@0..3 "pub" @@ -18,7 +18,7 @@ Root@0..146 LBrace@12..13 "{" Newline@13..14 "\n" WhiteSpace@14..18 " " - Item@18..79 + Item@18..78 Func@18..78 FnKw@18..20 "fn" WhiteSpace@20..21 " " @@ -65,11 +65,11 @@ Root@0..146 Newline@72..73 "\n" WhiteSpace@73..77 " " RBrace@77..78 "}" - Newline@78..79 "\n" + Newline@78..79 "\n" WhiteSpace@79..83 " " Newline@83..84 "\n" WhiteSpace@84..88 " " - Item@88..106 + Item@88..105 Struct@88..105 ItemModifier@88..91 PubKw@88..91 "pub" @@ -81,9 +81,9 @@ Root@0..146 RecordFieldDefList@103..105 LBrace@103..104 "{" RBrace@104..105 "}" - Newline@105..106 "\n" + Newline@105..106 "\n" RBrace@106..107 "}" - Newline@107..109 "\n\n" + Newline@107..109 "\n\n" Item@109..146 Mod@109..146 ItemModifier@109..112 @@ -97,7 +97,7 @@ Root@0..146 LBrace@121..122 "{" Newline@122..123 "\n" WhiteSpace@123..127 " " - Item@127..145 + Item@127..144 Struct@127..144 ItemModifier@127..130 PubKw@127..130 "pub" @@ -109,6 +109,6 @@ Root@0..146 RecordFieldDefList@142..144 LBrace@142..143 "{" RBrace@143..144 "}" - Newline@144..145 "\n" + Newline@144..145 "\n" RBrace@145..146 "}" diff --git a/crates/parser2/test_files/syntax_node/items/trait.snap b/crates/parser2/test_files/syntax_node/items/trait.snap index 60cb70e803..4d29724f54 100644 --- a/crates/parser2/test_files/syntax_node/items/trait.snap +++ b/crates/parser2/test_files/syntax_node/items/trait.snap @@ -5,7 +5,7 @@ input_file: crates/parser2/test_files/syntax_node/items/trait.fe --- Root@0..652 ItemList@0..652 - Item@0..17 + Item@0..15 Trait@0..15 TraitKw@0..5 "trait" WhiteSpace@5..6 " " @@ -14,8 +14,8 @@ Root@0..652 TraitItemList@13..15 LBrace@13..14 "{" RBrace@14..15 "}" - Newline@15..17 "\n\n" - Item@17..184 + Newline@15..17 "\n\n" + Item@17..182 Trait@17..182 ItemModifier@17..20 PubKw@17..20 "pub" @@ -175,8 +175,8 @@ Root@0..652 RBrace@179..180 "}" Newline@180..181 "\n" RBrace@181..182 "}" - Newline@182..184 "\n\n" - Item@184..274 + Newline@182..184 "\n\n" + Item@184..271 Trait@184..271 ItemModifier@184..187 PubKw@184..187 "pub" @@ -248,8 +248,8 @@ Root@0..652 Ident@266..269 "Sub" Newline@269..270 "\n" RBrace@270..271 "}" - Newline@271..274 "\n\n\n" - Item@274..357 + Newline@271..274 "\n\n\n" + Item@274..355 Trait@274..355 ItemModifier@274..277 PubKw@274..277 "pub" @@ -308,8 +308,8 @@ Root@0..652 RParen@352..353 ")" Newline@353..354 "\n" RBrace@354..355 "}" - Newline@355..357 "\n\n" - Item@357..595 + Newline@355..357 "\n\n" + Item@357..592 Impl@357..592 ImplKw@357..361 "impl" GenericParamList@361..364 @@ -483,7 +483,7 @@ Root@0..652 RBrace@589..590 "}" Newline@590..591 "\n" RBrace@591..592 "}" - Newline@592..595 "\n\n\n" + Newline@592..595 "\n\n\n" Item@595..652 Trait@595..652 ItemModifier@595..598 diff --git a/crates/parser2/test_files/syntax_node/items/type.snap b/crates/parser2/test_files/syntax_node/items/type.snap index 6148c44b09..d3a347df82 100644 --- a/crates/parser2/test_files/syntax_node/items/type.snap +++ b/crates/parser2/test_files/syntax_node/items/type.snap @@ -5,7 +5,7 @@ input_file: crates/parser2/test_files/syntax_node/items/type.fe --- Root@0..54 ItemList@0..54 - Item@0..21 + Item@0..18 TypeAlias@0..18 ItemModifier@0..3 PubKw@0..3 "pub" @@ -20,8 +20,8 @@ Root@0..54 Path@15..18 PathSegment@15..18 Ident@15..18 "i32" - WhiteSpace@18..19 " " - Newline@19..21 "\n\n" + WhiteSpace@18..19 " " + Newline@19..21 "\n\n" Item@21..54 TypeAlias@21..54 TypeKw@21..25 "type" diff --git a/crates/parser2/test_files/syntax_node/items/use.snap b/crates/parser2/test_files/syntax_node/items/use.snap index c7ceedab25..d425d218c7 100644 --- a/crates/parser2/test_files/syntax_node/items/use.snap +++ b/crates/parser2/test_files/syntax_node/items/use.snap @@ -4,8 +4,8 @@ expression: node input_file: crates/parser2/test_files/syntax_node/items/use.fe --- Root@0..308 - ItemList@0..308 - Item@0..13 + ItemList@0..307 + Item@0..12 Use@0..12 UseKw@0..3 "use" WhiteSpace@3..4 " " @@ -16,8 +16,8 @@ Root@0..308 Colon2@7..9 "::" UsePathSegment@9..12 Ident@9..12 "Bar" - Newline@12..13 "\n" - Item@13..30 + Newline@12..13 "\n" + Item@13..29 Use@13..29 ItemModifier@13..16 PubKw@13..16 "pub" @@ -31,8 +31,8 @@ Root@0..308 Colon2@24..26 "::" UsePathSegment@26..29 Ident@26..29 "Bar" - Newline@29..30 "\n" - Item@30..41 + Newline@29..30 "\n" + Item@30..40 Use@30..40 UseKw@30..33 "use" WhiteSpace@33..34 " " @@ -43,8 +43,8 @@ Root@0..308 Colon2@37..39 "::" UsePathSegment@39..40 Star@39..40 "*" - Newline@40..41 "\n" - Item@41..62 + Newline@40..41 "\n" + Item@41..61 Use@41..61 UseKw@41..44 "use" WhiteSpace@44..45 " " @@ -60,8 +60,8 @@ Root@0..308 AsKw@54..56 "as" WhiteSpace@56..57 " " Ident@57..61 "Bar1" - Newline@61..62 "\n" - Item@62..83 + Newline@61..62 "\n" + Item@62..81 Use@62..81 UseKw@62..65 "use" WhiteSpace@65..66 " " @@ -77,8 +77,8 @@ Root@0..308 AsKw@77..79 "as" WhiteSpace@79..80 " " Underscore@80..81 "_" - Newline@81..83 "\n\n" - Item@83..103 + Newline@81..83 "\n\n" + Item@83..102 Use@83..102 UseKw@83..86 "use" WhiteSpace@86..87 " " @@ -100,8 +100,8 @@ Root@0..308 UsePathSegment@98..101 Ident@98..101 "Bar" RBrace@101..102 "}" - Newline@102..103 "\n" - Item@103..124 + Newline@102..103 "\n" + Item@103..123 Use@103..123 UseKw@103..106 "use" WhiteSpace@106..107 " " @@ -123,8 +123,8 @@ Root@0..308 UsePathSegment@119..122 Ident@119..122 "Bar" RBrace@122..123 "}" - Newline@123..124 "\n" - Item@124..153 + Newline@123..124 "\n" + Item@124..152 Use@124..152 UseKw@124..127 "use" WhiteSpace@127..128 " " @@ -151,8 +151,8 @@ Root@0..308 WhiteSpace@146..147 " " Ident@147..151 "Bar1" RBrace@151..152 "}" - Newline@152..153 "\n" - Item@153..204 + Newline@152..153 "\n" + Item@153..202 Use@153..202 UseKw@153..156 "use" WhiteSpace@156..157 " " @@ -204,8 +204,8 @@ Root@0..308 UsePathSegment@200..201 Star@200..201 "*" RBrace@201..202 "}" - Newline@202..204 "\n\n" - Item@204..273 + Newline@202..204 "\n\n" + Item@204..272 Use@204..272 UseKw@204..207 "use" WhiteSpace@207..208 " " @@ -262,8 +262,8 @@ Root@0..308 UsePathSegment@270..271 Ident@270..271 "T" RBrace@271..272 "}" - Newline@272..273 "\n" - Item@273..280 + Newline@272..273 "\n" + Item@273..278 Use@273..278 UseKw@273..276 "use" WhiteSpace@276..277 " " @@ -271,8 +271,8 @@ Root@0..308 UsePath@277..278 UsePathSegment@277..278 Star@277..278 "*" - Newline@278..280 "\n\n" - Item@280..293 + Newline@278..280 "\n\n" + Item@280..292 Use@280..292 UseKw@280..283 "use" WhiteSpace@283..284 " " @@ -283,8 +283,8 @@ Root@0..308 Colon2@289..291 "::" UsePathSegment@291..292 Star@291..292 "*" - Newline@292..293 "\n" - Item@293..308 + Newline@292..293 "\n" + Item@293..307 Use@293..307 UseKw@293..296 "use" WhiteSpace@296..297 " " @@ -295,5 +295,5 @@ Root@0..308 Colon2@302..304 "::" UsePathSegment@304..307 Ident@304..307 "Foo" - Newline@307..308 "\n" + Newline@307..308 "\n" diff --git a/crates/parser2/test_files/syntax_node/structs/generics.snap b/crates/parser2/test_files/syntax_node/structs/generics.snap index b714a4ad32..6debda1ee7 100644 --- a/crates/parser2/test_files/syntax_node/structs/generics.snap +++ b/crates/parser2/test_files/syntax_node/structs/generics.snap @@ -5,7 +5,7 @@ input_file: crates/parser2/test_files/syntax_node/structs/generics.fe --- Root@0..563 ItemList@0..563 - Item@0..78 + Item@0..76 Struct@0..76 ItemModifier@0..3 PubKw@0..3 "pub" @@ -64,8 +64,8 @@ Root@0..563 Comma@73..74 "," Newline@74..75 "\n" RBrace@75..76 "}" - Newline@76..78 "\n\n" - Item@78..192 + Newline@76..78 "\n\n" + Item@78..190 Struct@78..190 ItemModifier@78..81 PubKw@78..81 "pub" @@ -153,8 +153,8 @@ Root@0..563 Comma@187..188 "," Newline@188..189 "\n" RBrace@189..190 "}" - Newline@190..192 "\n\n" - Item@192..416 + Newline@190..192 "\n\n" + Item@192..414 Struct@192..414 ItemModifier@192..195 PubKw@192..195 "pub" @@ -342,7 +342,7 @@ Root@0..563 Comma@411..412 "," Newline@412..413 "\n" RBrace@413..414 "}" - Newline@414..416 "\n\n" + Newline@414..416 "\n\n" Item@416..563 Struct@416..563 ItemModifier@416..419 diff --git a/crates/uitest/fixtures/parser/array.snap b/crates/uitest/fixtures/parser/array.snap index d7e1b55303..c0635ba26d 100644 --- a/crates/uitest/fixtures/parser/array.snap +++ b/crates/uitest/fixtures/parser/array.snap @@ -3,10 +3,10 @@ source: crates/uitest/tests/parser.rs expression: diags input_file: crates/uitest/fixtures/parser/array.fe --- -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing array definition ┌─ array.fe:2:7 │ 2 │ [1, 2 a, 3] - │ ^ unexpected syntax + │ ^ unexpected diff --git a/crates/uitest/fixtures/parser/block.snap b/crates/uitest/fixtures/parser/block.snap index f9c92cf9dd..e18fd86102 100644 --- a/crates/uitest/fixtures/parser/block.snap +++ b/crates/uitest/fixtures/parser/block.snap @@ -3,16 +3,10 @@ source: crates/uitest/tests/parser.rs expression: diags input_file: crates/uitest/fixtures/parser/block.fe --- -error[1-0001]: expected newline after statement - ┌─ block.fe:3:15 - │ -3 │ let x: i32 u32 = 10 - │ ^ expected newline after statement - -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing block ┌─ block.fe:3:16 │ 3 │ let x: i32 u32 = 10 - │ ^^^^^^^^ unexpected syntax + │ ^^^^^^^^ unexpected diff --git a/crates/uitest/fixtures/parser/call.snap b/crates/uitest/fixtures/parser/call.snap index 349b3acb40..78ba7e21a8 100644 --- a/crates/uitest/fixtures/parser/call.snap +++ b/crates/uitest/fixtures/parser/call.snap @@ -3,22 +3,22 @@ source: crates/uitest/tests/parser.rs expression: diags input_file: crates/uitest/fixtures/parser/call.fe --- -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing function call arguments ┌─ call.fe:2:10 │ 2 │ foo(x, y a, z ;) - │ ^ unexpected syntax + │ ^ unexpected -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing function call arguments ┌─ call.fe:2:15 │ 2 │ foo(x, y a, z ;) - │ ^ unexpected syntax + │ ^ unexpected -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing generic type argument list ┌─ call.fe:4:12 │ 4 │ foo(x, y) - │ ^ unexpected syntax + │ ^ unexpected diff --git a/crates/uitest/fixtures/parser/const_.snap b/crates/uitest/fixtures/parser/const_.snap index b20e4b9d4f..a8a17904e1 100644 --- a/crates/uitest/fixtures/parser/const_.snap +++ b/crates/uitest/fixtures/parser/const_.snap @@ -3,28 +3,28 @@ source: crates/uitest/tests/parser.rs expression: diags input_file: crates/uitest/fixtures/parser/const_.fe --- -error[1-0001]: expected type annotation for `const` +error[1-0001]: missing type bound for const definition ┌─ const_.fe:1:8 │ 1 │ const X = 10 - │ ^ expected type annotation for `const` + │ ^ expected `:` -error[1-0001]: expected `=` for const value definition +error[1-0001]: expected `=` ┌─ const_.fe:3:13 │ 3 │ const X: i32 - │ ^ expected `=` for const value definition + │ ^ expected `=` -error[1-0001]: expected path segment - ┌─ const_.fe:5:10 +error[1-0001]: expected type + ┌─ const_.fe:5:9 │ 5 │ const X: ]@ = 1 - │ ^ expected path segment + │ ^ expected type -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing type ┌─ const_.fe:5:10 │ 5 │ const X: ]@ = 1 - │ ^^ unexpected syntax + │ ^^ unexpected diff --git a/crates/uitest/fixtures/parser/enum_.snap b/crates/uitest/fixtures/parser/enum_.snap index a0515384a5..a17f1482cf 100644 --- a/crates/uitest/fixtures/parser/enum_.snap +++ b/crates/uitest/fixtures/parser/enum_.snap @@ -3,34 +3,34 @@ source: crates/uitest/tests/parser.rs expression: diags input_file: crates/uitest/fixtures/parser/enum_.fe --- -error[1-0001]: expected `)` +error[1-0001]: missing closing `)` for tuple type definition ┌─ enum_.fe:2:13 │ 2 │ X(u32, T - │ ^ expected `)` + │ ^ expected `)` or `,` -error[1-0001]: expected comma after enum variant definition +error[1-0001]: missing closing `}` for `enum` variant list ┌─ enum_.fe:2:13 │ 2 │ X(u32, T - │ ^ expected comma after enum variant definition + │ ^ expected `}` or `,` -error[1-0001]: expected comma after enum variant definition +error[1-0001]: missing closing `}` for `enum` variant list ┌─ enum_.fe:3:6 │ 3 │ A - │ ^ expected comma after enum variant definition + │ ^ expected `}` or `,` -error[1-0001]: expected comma after enum variant definition - ┌─ enum_.fe:4:14 +error[1-0001]: unexpected syntax while parsing `enum` variant list + ┌─ enum_.fe:4:15 │ 4 │ Y(T, u32) A - │ ^ expected comma after enum variant definition + │ ^ unexpected -error[1-0001]: expected comma after enum variant definition +error[1-0001]: missing closing `}` for `enum` variant list ┌─ enum_.fe:4:16 │ 4 │ Y(T, u32) A - │ ^ expected comma after enum variant definition + │ ^ expected `}` or `,` diff --git a/crates/uitest/fixtures/parser/extern_.snap b/crates/uitest/fixtures/parser/extern_.snap index ea4ed0fec5..bdd33cecdb 100644 --- a/crates/uitest/fixtures/parser/extern_.snap +++ b/crates/uitest/fixtures/parser/extern_.snap @@ -9,10 +9,16 @@ error[1-0001]: only `fn` is allowed in this block 4 │ struct Foo { │ ^^^^^^ only `fn` is allowed in this block -error[1-0001]: unexpected syntax - ┌─ extern_.fe:4:5 +error[1-0001]: expected name for field + ┌─ extern_.fe:6:8 │ -4 │ struct Foo { - │ ^^^^^^^^^^^^ unexpected syntax +6 │ pub unsafe fn foo() + │ ^ expected identifier + +error[1-0001]: unexpected syntax while parsing function definition + ┌─ extern_.fe:7:1 + │ +7 │ } + │ ^ unexpected diff --git a/crates/uitest/fixtures/parser/fn_missing_body.snap b/crates/uitest/fixtures/parser/fn_missing_body.snap index 835c7fdcda..40eea7d4fb 100644 --- a/crates/uitest/fixtures/parser/fn_missing_body.snap +++ b/crates/uitest/fixtures/parser/fn_missing_body.snap @@ -3,22 +3,16 @@ source: crates/uitest/tests/parser.rs expression: diags input_file: crates/uitest/fixtures/parser/fn_missing_body.fe --- -error[1-0001]: function body is required +error[1-0001]: expected `{` or `where` ┌─ fn_missing_body.fe:1:28 │ 1 │ fn foo(x: u8, y: u64) -> u8 - │ ^ function body is required + │ ^ expected `{` or `where` -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing function definition ┌─ fn_missing_body.fe:3:13 │ 3 │ fn bar() asdf - │ ^^^^ unexpected syntax - -error[1-0001]: function body is required - ┌─ fn_missing_body.fe:3:17 - │ -3 │ fn bar() asdf - │ ^ function body is required + │ ^^^^ unexpected diff --git a/crates/uitest/fixtures/parser/fn_missing_parameters.snap b/crates/uitest/fixtures/parser/fn_missing_parameters.snap index 581a2f8ff8..5240af8580 100644 --- a/crates/uitest/fixtures/parser/fn_missing_parameters.snap +++ b/crates/uitest/fixtures/parser/fn_missing_parameters.snap @@ -3,34 +3,28 @@ source: crates/uitest/tests/parser.rs expression: diags input_file: crates/uitest/fixtures/parser/fn_missing_parameters.fe --- -error[1-0001]: expected `(` for the function arguments +error[1-0001]: expected function parameter list ┌─ fn_missing_parameters.fe:1:7 │ 1 │ fn foo -> u8 {} - │ ^ expected `(` for the function arguments + │ ^ expected `(` -error[1-0001]: expected `(` for the function arguments +error[1-0001]: expected function parameter list ┌─ fn_missing_parameters.fe:3:7 │ 3 │ fn bar { - │ ^ expected `(` for the function arguments + │ ^ expected `(` -error[1-0001]: expected `(` for the function arguments +error[1-0001]: expected function parameter list ┌─ fn_missing_parameters.fe:6:7 │ 6 │ fn baz -> u8 {} - │ ^ expected `(` for the function arguments + │ ^ expected `(` -error[1-0001]: expected `(` for the function arguments +error[1-0001]: expected function parameter list ┌─ fn_missing_parameters.fe:8:8 │ 8 │ fn f where T: U {} - │ ^ expected `(` for the function arguments - -error[1-0001]: expected newline after type bounds - ┌─ fn_missing_parameters.fe:8:19 - │ -8 │ fn f where T: U {} - │ ^ expected newline after type bounds + │ ^ expected `(` diff --git a/crates/uitest/fixtures/parser/fn_modifiers.snap b/crates/uitest/fixtures/parser/fn_modifiers.snap index 90584fadc6..8e560a1bfb 100644 --- a/crates/uitest/fixtures/parser/fn_modifiers.snap +++ b/crates/uitest/fixtures/parser/fn_modifiers.snap @@ -3,76 +3,76 @@ source: crates/uitest/tests/parser.rs expression: diags input_file: crates/uitest/fixtures/parser/fn_modifiers.fe --- -error[1-0001]: duplicate modifier +error[1-0001]: duplicate `pub` modifier ┌─ fn_modifiers.fe:1:5 │ 1 │ pub pub struct Foo {} - │ ^^^ duplicate modifier + │ ^^^ unexpected -error[1-0001]: duplicate modifier +error[1-0001]: duplicate `pub` modifier ┌─ fn_modifiers.fe:3:9 │ 3 │ pub pub unsafe unsafe fn f() {} - │ ^^^ duplicate modifier + │ ^^^ unexpected -error[1-0001]: duplicate modifier +error[1-0001]: duplicate `unsafe` modifier ┌─ fn_modifiers.fe:3:20 │ 3 │ pub pub unsafe unsafe fn f() {} - │ ^^^^^^ duplicate modifier + │ ^^^^^^ unexpected error[1-0001]: `pub` modifier must come before `unsafe` ┌─ fn_modifiers.fe:4:12 │ 4 │ unsafe pub fn g() {} - │ ^^^ `pub` modifier must come before `unsafe` + │ ^^^ unexpected -error[1-0001]: duplicate modifier +error[1-0001]: duplicate `unsafe` modifier ┌─ fn_modifiers.fe:5:12 │ 5 │ unsafe unsafe pub unsafe pub pub unsafe fn h() {} - │ ^^^^^^ duplicate modifier + │ ^^^^^^ unexpected error[1-0001]: `pub` modifier must come before `unsafe` ┌─ fn_modifiers.fe:5:19 │ 5 │ unsafe unsafe pub unsafe pub pub unsafe fn h() {} - │ ^^^ `pub` modifier must come before `unsafe` + │ ^^^ unexpected -error[1-0001]: duplicate modifier +error[1-0001]: duplicate `unsafe` modifier ┌─ fn_modifiers.fe:5:23 │ 5 │ unsafe unsafe pub unsafe pub pub unsafe fn h() {} - │ ^^^^^^ duplicate modifier + │ ^^^^^^ unexpected -error[1-0001]: duplicate modifier +error[1-0001]: duplicate `pub` modifier ┌─ fn_modifiers.fe:5:30 │ 5 │ unsafe unsafe pub unsafe pub pub unsafe fn h() {} - │ ^^^ duplicate modifier + │ ^^^ unexpected -error[1-0001]: duplicate modifier +error[1-0001]: duplicate `pub` modifier ┌─ fn_modifiers.fe:5:34 │ 5 │ unsafe unsafe pub unsafe pub pub unsafe fn h() {} - │ ^^^ duplicate modifier + │ ^^^ unexpected -error[1-0001]: duplicate modifier +error[1-0001]: duplicate `unsafe` modifier ┌─ fn_modifiers.fe:5:38 │ 5 │ unsafe unsafe pub unsafe pub pub unsafe fn h() {} - │ ^^^^^^ duplicate modifier + │ ^^^^^^ unexpected -error[1-0001]: modifier is not allowed in this block +error[1-0001]: `pub` modifier is not allowed in this block ┌─ fn_modifiers.fe:13:5 │ 13 │ pub unsafe fn f(self) {} - │ ^^^ modifier is not allowed in this block + │ ^^^ unexpected -error[1-0001]: modifier is not allowed in this block +error[1-0001]: `unsafe` modifier is not allowed in this block ┌─ fn_modifiers.fe:13:9 │ 13 │ pub unsafe fn f(self) {} - │ ^^^^^^ modifier is not allowed in this block + │ ^^^^^^ unexpected diff --git a/crates/uitest/fixtures/parser/for_.snap b/crates/uitest/fixtures/parser/for_.snap index 7ab22c5374..38a718c03d 100644 --- a/crates/uitest/fixtures/parser/for_.snap +++ b/crates/uitest/fixtures/parser/for_.snap @@ -3,46 +3,46 @@ source: crates/uitest/tests/parser.rs expression: diags input_file: crates/uitest/fixtures/parser/for_.fe --- -error[1-0001]: expected `in` keyword +error[1-0001]: expected `in` ┌─ for_.fe:2:6 │ 2 │ for i arr { } - │ ^ expected `in` keyword + │ ^ expected `in` -error[1-0001]: expected path segment - ┌─ for_.fe:4:5 +error[1-0001]: expected pattern + ┌─ for_.fe:4:4 │ 4 │ for in arr { } - │ ^ expected path segment + │ ^ expected pattern -error[1-0001]: expected path segment - ┌─ for_.fe:6:5 +error[1-0001]: expected pattern + ┌─ for_.fe:6:4 │ 6 │ for @ in arr {} - │ ^ expected path segment + │ ^ expected pattern -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing pattern ┌─ for_.fe:6:5 │ 6 │ for @ in arr {} - │ ^ unexpected syntax + │ ^ unexpected -error[1-0001]: expected path segment - ┌─ for_.fe:8:5 +error[1-0001]: expected pattern + ┌─ for_.fe:8:4 │ 8 │ for @ in arr x y {} - │ ^ expected path segment + │ ^ expected pattern -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing pattern ┌─ for_.fe:8:5 │ 8 │ for @ in arr x y {} - │ ^ unexpected syntax + │ ^ unexpected -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing `for` statement ┌─ for_.fe:8:14 │ 8 │ for @ in arr x y {} - │ ^^^ unexpected syntax + │ ^^^ unexpected diff --git a/crates/uitest/fixtures/parser/func.fe b/crates/uitest/fixtures/parser/func.fe index 481ba1e975..b2848720db 100644 --- a/crates/uitest/fixtures/parser/func.fe +++ b/crates/uitest/fixtures/parser/func.fe @@ -1,10 +1,13 @@ -fn foo>(x: i32, _ mut y: u32, z: u32) -> T, u where T: Trait2 +fn foo>(x: i32, _ mut y: u32, z: u32) -> T, u where T: Trait2 { } fn foo<<(x: i32) - where T: Trait2 + where T: Trait2 { } + +fn bar() + where T: 75 {} \ No newline at end of file diff --git a/crates/uitest/fixtures/parser/func.snap b/crates/uitest/fixtures/parser/func.snap index 1d09f337b4..0d7cdc30b7 100644 --- a/crates/uitest/fixtures/parser/func.snap +++ b/crates/uitest/fixtures/parser/func.snap @@ -3,28 +3,52 @@ source: crates/uitest/tests/parser.rs expression: diags input_file: crates/uitest/fixtures/parser/func.fe --- -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing function definition ┌─ func.fe:1:17 │ -1 │ fn foo>(x: i32, _ mut y: u32, z: u32) -> T, u where T: Trait2 - │ ^ unexpected syntax +1 │ fn foo>(x: i32, _ mut y: u32, z: u32) -> T, u where T: Trait2 + │ ^ unexpected -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing function parameter ┌─ func.fe:1:29 │ -1 │ fn foo>(x: i32, _ mut y: u32, z: u32) -> T, u where T: Trait2 - │ ^^^ unexpected syntax +1 │ fn foo>(x: i32, _ mut y: u32, z: u32) -> T, u where T: Trait2 + │ ^^^ unexpected -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing function definition ┌─ func.fe:1:54 │ -1 │ fn foo>(x: i32, _ mut y: u32, z: u32) -> T, u where T: Trait2 - │ ^^^ unexpected syntax +1 │ fn foo>(x: i32, _ mut y: u32, z: u32) -> T, u where T: Trait2 + │ ^^^ unexpected -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing generic parameter list ┌─ func.fe:6:8 │ 6 │ fn foo<<(x: i32) - │ ^^ unexpected syntax + │ ^^ unexpected + +error[1-0001]: expected trait name + ┌─ func.fe:12:10 + │ +12 │ fn bar() + │ ^ expected trait name + +error[1-0001]: unexpected syntax while parsing trait name + ┌─ func.fe:12:11 + │ +12 │ fn bar() + │ ^ unexpected + +error[1-0001]: expected trait name + ┌─ func.fe:13:13 + │ +13 │ where T: 75 {} + │ ^ expected trait name + +error[1-0001]: unexpected syntax while parsing trait name + ┌─ func.fe:13:14 + │ +13 │ where T: 75 {} + │ ^^ unexpected diff --git a/crates/uitest/fixtures/parser/if_.snap b/crates/uitest/fixtures/parser/if_.snap index 2d56b32f3b..0faed6fa90 100644 --- a/crates/uitest/fixtures/parser/if_.snap +++ b/crates/uitest/fixtures/parser/if_.snap @@ -3,59 +3,23 @@ source: crates/uitest/tests/parser.rs expression: diags input_file: crates/uitest/fixtures/parser/if_.fe --- -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing `if` expression ┌─ if_.fe:3:6 │ 3 │ if x y { - │ ^ unexpected syntax + │ ^ unexpected -error[1-0001]: expected `{` or `if` after `else` - ┌─ if_.fe:8:7 - │ -8 │ } else x {} - │ ^ expected `{` or `if` after `else` - -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing `if` expression ┌─ if_.fe:8:8 │ 8 │ } else x {} - │ ^ unexpected syntax - -error[1-0001]: expected newline after statement - ┌─ if_.fe:8:9 - │ -8 │ } else x {} - │ ^ expected newline after statement - -error[1-0001]: unexpected syntax - ┌─ if_.fe:8:10 - │ -8 │ } else x {} - │ ^^ unexpected syntax - -error[1-0001]: expected `{` or `if` after `else` - ┌─ if_.fe:10:14 - │ -10 │ if x { } else x if x { } else { } - │ ^ expected `{` or `if` after `else` + │ ^ unexpected -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing `if` expression ┌─ if_.fe:10:15 │ 10 │ if x { } else x if x { } else { } - │ ^ unexpected syntax - -error[1-0001]: expected newline after statement - ┌─ if_.fe:10:16 - │ -10 │ if x { } else x if x { } else { } - │ ^ expected newline after statement - -error[1-0001]: unexpected syntax - ┌─ if_.fe:10:17 - │ -10 │ if x { } else x if x { } else { } - │ ^^^^^^^^^^^^^^^^^ unexpected syntax + │ ^ unexpected error[1-0001]: expected expression ┌─ if_.fe:14:1 @@ -63,24 +27,4 @@ error[1-0001]: expected expression 14 │ else { │ ^ expected expression -error[1-0001]: unexpected syntax - ┌─ if_.fe:14:1 - │ -14 │ ╭ else { -15 │ │ 1 -16 │ │ } - │ ╰─^ unexpected syntax - -error[1-0001]: expected newline after statement - ┌─ if_.fe:18:2 - │ -18 │ } - │ ^ expected newline after statement - -error[1-0001]: expected `}` - ┌─ if_.fe:18:2 - │ -18 │ } - │ ^ expected `}` - diff --git a/crates/uitest/fixtures/parser/impl_.snap b/crates/uitest/fixtures/parser/impl_.snap index 98820d8cf7..47c112976d 100644 --- a/crates/uitest/fixtures/parser/impl_.snap +++ b/crates/uitest/fixtures/parser/impl_.snap @@ -3,22 +3,10 @@ source: crates/uitest/tests/parser.rs expression: diags input_file: crates/uitest/fixtures/parser/impl_.fe --- -error[1-0001]: expected path segment - ┌─ impl_.fe:2:5 +error[1-0001]: expected type + ┌─ impl_.fe:1:12 │ -2 │ where T: Integer - │ ^ expected path segment - -error[1-0001]: expected closing `>` - ┌─ impl_.fe:2:5 - │ -2 │ where T: Integer - │ ^ expected closing `>` - -error[1-0001]: expected path segment - ┌─ impl_.fe:5:13 - │ -5 │ impl Foo - │ ^ expected path segment +1 │ impl Foo for Y` +error[1-0001]: missing closing `>` for generic type argument list ┌─ impl_trait.fe:1:23 │ 1 │ impl X for Y` + │ ^ expected `>` or `,` -error[1-0001]: expected newline after type bounds - ┌─ impl_trait.fe:1:34 - │ -1 │ impl X for Y` +error[1-0001]: missing closing `>` for generic type argument list ┌─ impl_trait.fe:3:12 │ 3 │ impl X` + │ ^ expected `>` or `,` -error[1-0001]: expected closing `>` +error[1-0001]: missing closing `>` for generic type argument list ┌─ impl_trait.fe:3:20 │ 3 │ impl X` - -error[1-0001]: expected newline after type bounds - ┌─ impl_trait.fe:3:31 - │ -3 │ impl X` or `,` -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing `impl` trait block ┌─ impl_trait.fe:5:8 │ 5 │ impl X @ for Y {} - │ ^ unexpected syntax + │ ^ unexpected diff --git a/crates/uitest/fixtures/parser/index.snap b/crates/uitest/fixtures/parser/index.snap index ac5fc06466..edbface333 100644 --- a/crates/uitest/fixtures/parser/index.snap +++ b/crates/uitest/fixtures/parser/index.snap @@ -3,13 +3,13 @@ source: crates/uitest/tests/parser.rs expression: diags input_file: crates/uitest/fixtures/parser/index.fe --- -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing index expression ┌─ index.fe:2:5 │ 2 │ x[1 a] - │ ^ unexpected syntax + │ ^ unexpected -error[1-0001]: expected `]` +error[1-0001]: missing closing `]` for index expression ┌─ index.fe:3:8 │ 3 │ x[2 + 3 diff --git a/crates/uitest/fixtures/parser/match_.snap b/crates/uitest/fixtures/parser/match_.snap index 6e8f2ce149..85a9fbc3e4 100644 --- a/crates/uitest/fixtures/parser/match_.snap +++ b/crates/uitest/fixtures/parser/match_.snap @@ -3,11 +3,11 @@ source: crates/uitest/tests/parser.rs expression: diags input_file: crates/uitest/fixtures/parser/match_.fe --- -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing `match` expression ┌─ match_.fe:2:10 │ 2 │ match X => { - │ ^^ unexpected syntax + │ ^^ unexpected error[1-0001]: expected `=>` ┌─ match_.fe:4:7 @@ -16,21 +16,15 @@ error[1-0001]: expected `=>` │ ^ expected `=>` error[1-0001]: expected pattern - ┌─ match_.fe:8:16 + ┌─ match_.fe:8:13 │ 8 │ Foo(i, j, => true x - │ ^ expected pattern + │ ^ expected pattern -error[1-0001]: expected `)` - ┌─ match_.fe:8:16 - │ -8 │ Foo(i, j, => true x - │ ^ expected `)` - -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing `match` arm list ┌─ match_.fe:8:24 │ 8 │ Foo(i, j, => true x - │ ^ unexpected syntax + │ ^ unexpected diff --git a/crates/uitest/fixtures/parser/method.snap b/crates/uitest/fixtures/parser/method.snap index b1097ffbb7..dea18a27a7 100644 --- a/crates/uitest/fixtures/parser/method.snap +++ b/crates/uitest/fixtures/parser/method.snap @@ -3,28 +3,16 @@ source: crates/uitest/tests/parser.rs expression: diags input_file: crates/uitest/fixtures/parser/method.fe --- -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing generic type argument list ┌─ method.fe:2:23 │ 2 │ foo::bar.baz(1, 2) - │ ^ unexpected syntax + │ ^ unexpected -error[1-0001]: expected path segment - ┌─ method.fe:2:25 - │ -2 │ foo::bar.baz(1, 2) - │ ^ expected path segment - -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing function call arguments ┌─ method.fe:4:17 │ 4 │ foo::bar.x(1, 2 E,) - │ ^ unexpected syntax - -error[1-0001]: expected expression - ┌─ method.fe:4:19 - │ -4 │ foo::bar.x(1, 2 E,) - │ ^ expected expression + │ ^ unexpected diff --git a/crates/uitest/fixtures/parser/operators.snap b/crates/uitest/fixtures/parser/operators.snap index 6a1ab56ff8..d15e9a7f48 100644 --- a/crates/uitest/fixtures/parser/operators.snap +++ b/crates/uitest/fixtures/parser/operators.snap @@ -9,11 +9,11 @@ error[1-0001]: expected expression 3 │ x + = 1 │ ^ expected expression -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing binary expression ┌─ operators.fe:3:9 │ 3 │ x + = 1 - │ ^^^ unexpected syntax + │ ^^^ unexpected error[1-0001]: expected expression ┌─ operators.fe:5:8 @@ -21,11 +21,11 @@ error[1-0001]: expected expression 5 │ x - = 1 │ ^ expected expression -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing binary expression ┌─ operators.fe:5:12 │ 5 │ x - = 1 - │ ^^^ unexpected syntax + │ ^^^ unexpected error[1-0001]: expected expression ┌─ operators.fe:6:8 @@ -33,11 +33,11 @@ error[1-0001]: expected expression 6 │ x * = 1 │ ^ expected expression -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing binary expression ┌─ operators.fe:6:9 │ 6 │ x * = 1 - │ ^^^ unexpected syntax + │ ^^^ unexpected error[1-0001]: expected expression ┌─ operators.fe:8:8 @@ -45,11 +45,11 @@ error[1-0001]: expected expression 8 │ x < < 1 │ ^ expected expression -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing binary expression ┌─ operators.fe:8:9 │ 8 │ x < < 1 - │ ^^^ unexpected syntax + │ ^^^ unexpected error[1-0001]: expected expression ┌─ operators.fe:10:8 @@ -57,10 +57,10 @@ error[1-0001]: expected expression 10 │ x < = 1 │ ^ expected expression -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing binary expression ┌─ operators.fe:10:9 │ 10 │ x < = 1 - │ ^^^ unexpected syntax + │ ^^^ unexpected diff --git a/crates/uitest/fixtures/parser/struct_.snap b/crates/uitest/fixtures/parser/struct_.snap index 2fc4443c29..ac499b6e46 100644 --- a/crates/uitest/fixtures/parser/struct_.snap +++ b/crates/uitest/fixtures/parser/struct_.snap @@ -3,23 +3,23 @@ source: crates/uitest/tests/parser.rs expression: diags input_file: crates/uitest/fixtures/parser/struct_.fe --- -error[1-0001]: expected identifier +error[1-0001]: expected name for struct definition ┌─ struct_.fe:1:11 │ 1 │ pub struct` or `,` +error[1-0001]: missing closing `>` for generic parameter list ┌─ struct_.fe:1:16 │ 1 │ pub struct` or `,` -error[1-0001]: expected `:` for type bounds +error[1-0001]: missing type bound for `where` predicate ┌─ struct_.fe:2:8 │ 2 │ where T - │ ^ expected `:` for type bounds + │ ^ expected `:` error[1-0001]: expected `,` ┌─ struct_.fe:2:8 @@ -27,13 +27,13 @@ error[1-0001]: expected `,` 2 │ where T │ ^ expected `,` -error[1-0001]: expected `name: type` for the field definition +error[1-0001]: missing type bound for field ┌─ struct_.fe:6:8 │ 6 │ foo - │ ^ expected `name: type` for the field definition + │ ^ expected `:` -error[1-0001]: expected `}` or `,` +error[1-0001]: missing closing `}` for record field list ┌─ struct_.fe:6:8 │ 6 │ foo @@ -45,7 +45,7 @@ error[1-0001]: function definition in struct is not allowed 11 │ pub fn foo() -> i32 { │ ^^ function definition in struct is not allowed -error[1-0001]: expected `}` or `,` +error[1-0001]: missing closing `}` for record field list ┌─ struct_.fe:13:6 │ 13 │ } diff --git a/crates/uitest/fixtures/parser/struct_field_missing_comma.snap b/crates/uitest/fixtures/parser/struct_field_missing_comma.snap index 12ccdb42ac..904c376215 100644 --- a/crates/uitest/fixtures/parser/struct_field_missing_comma.snap +++ b/crates/uitest/fixtures/parser/struct_field_missing_comma.snap @@ -3,7 +3,7 @@ source: crates/uitest/tests/parser.rs expression: diags input_file: crates/uitest/fixtures/parser/struct_field_missing_comma.fe --- -error[1-0001]: expected `}` or `,` +error[1-0001]: missing closing `}` for record field list ┌─ struct_field_missing_comma.fe:2:10 │ 2 │ x: u8 diff --git a/crates/uitest/fixtures/parser/trait_.snap b/crates/uitest/fixtures/parser/trait_.snap index 919f4a05da..305c3fdb5a 100644 --- a/crates/uitest/fixtures/parser/trait_.snap +++ b/crates/uitest/fixtures/parser/trait_.snap @@ -15,10 +15,10 @@ error[1-0001]: expected `{`, `where` or `:` 5 │ trait Bar │ ^ expected `{`, `where` or `:` -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing generic parameter list ┌─ trait_.fe:9:11 │ 9 │ trait Bar< - │ ^ unexpected syntax + │ ^ unexpected diff --git a/crates/uitest/fixtures/parser/trait_pub_fn.snap b/crates/uitest/fixtures/parser/trait_pub_fn.snap index 16075bfc96..7cf14e7b3b 100644 --- a/crates/uitest/fixtures/parser/trait_pub_fn.snap +++ b/crates/uitest/fixtures/parser/trait_pub_fn.snap @@ -3,22 +3,22 @@ source: crates/uitest/tests/parser.rs expression: diags input_file: crates/uitest/fixtures/parser/trait_pub_fn.fe --- -error[1-0001]: modifier is not allowed in this block +error[1-0001]: `pub` modifier is not allowed in this block ┌─ trait_pub_fn.fe:2:5 │ 2 │ pub fn foo(mut self) - │ ^^^ modifier is not allowed in this block + │ ^^^ unexpected -error[1-0001]: modifier is not allowed in this block +error[1-0001]: `pub` modifier is not allowed in this block ┌─ trait_pub_fn.fe:3:5 │ 3 │ pub unsafe fn bar(self) - │ ^^^ modifier is not allowed in this block + │ ^^^ unexpected -error[1-0001]: modifier is not allowed in this block +error[1-0001]: `unsafe` modifier is not allowed in this block ┌─ trait_pub_fn.fe:3:9 │ 3 │ pub unsafe fn bar(self) - │ ^^^^^^ modifier is not allowed in this block + │ ^^^^^^ unexpected diff --git a/crates/uitest/fixtures/parser/while_.snap b/crates/uitest/fixtures/parser/while_.snap index 3da7cf9756..a8a480c2ec 100644 --- a/crates/uitest/fixtures/parser/while_.snap +++ b/crates/uitest/fixtures/parser/while_.snap @@ -9,23 +9,17 @@ error[1-0001]: expected expression 2 │ while @ {} │ ^ expected expression -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing `while` statement ┌─ while_.fe:2:7 │ 2 │ while @ {} - │ ^ unexpected syntax + │ ^ unexpected -error[1-0001]: expected item: but got Some(WhileKw) - ┌─ while_.fe:8:1 - │ -8 │ while true {} - │ ^ expected item: but got Some(WhileKw) - -error[1-0001]: unexpected syntax +error[1-0001]: unexpected syntax while parsing item ┌─ while_.fe:8:1 │ 8 │ ╭ while true {} 9 │ │ } - │ ╰─^ unexpected syntax + │ ╰─^ unexpected diff --git a/crates/uitest/fixtures/ty/def/kind_bound.fe b/crates/uitest/fixtures/ty/def/kind_bound.fe index 40a88a27fe..fef8948dc7 100644 --- a/crates/uitest/fixtures/ty/def/kind_bound.fe +++ b/crates/uitest/fixtures/ty/def/kind_bound.fe @@ -4,7 +4,7 @@ pub struct Wrapper1 value: T } -// (* -> *) -> * -> * +// (* -> *) -> * -> * pub struct Wrapper2 where T: * -> * { @@ -14,7 +14,7 @@ where T: * -> * // ((* -> *) -> *) -> (* -> *) -> * pub struct Wrapper3 -where T: (* -> *) -> * -> * +where T: (* -> *) -> * -> *, U: * -> * { value: T diff --git a/crates/uitest/fixtures/ty/def/trait_def.fe b/crates/uitest/fixtures/ty/def/trait_def.fe index 8150bbd239..d86cd7d930 100644 --- a/crates/uitest/fixtures/ty/def/trait_def.fe +++ b/crates/uitest/fixtures/ty/def/trait_def.fe @@ -1,6 +1,6 @@ trait Clone {} -pub trait Trait -where T: * -> * +pub trait Trait +where T: * -> *, T: (* -> *) -> * { diff --git a/crates/uitest/fixtures/ty/trait_impl/impl_method_stricter_bound.fe b/crates/uitest/fixtures/ty/trait_impl/impl_method_stricter_bound.fe index 5389447499..35dbbddd58 100644 --- a/crates/uitest/fixtures/ty/trait_impl/impl_method_stricter_bound.fe +++ b/crates/uitest/fixtures/ty/trait_impl/impl_method_stricter_bound.fe @@ -15,9 +15,9 @@ pub trait Foo2 { } impl Foo2 for i32 { - fn foo(self, t: T, u: U) - where - T: Bar + Baz + fn foo(self, t: T, u: U) + where + T: Bar + Baz, U: Bar {} } \ No newline at end of file diff --git a/crates/uitest/fixtures/ty/trait_impl/impl_method_stricter_bound.snap b/crates/uitest/fixtures/ty/trait_impl/impl_method_stricter_bound.snap index 3ec4a0a25b..a56e79283d 100644 --- a/crates/uitest/fixtures/ty/trait_impl/impl_method_stricter_bound.snap +++ b/crates/uitest/fixtures/ty/trait_impl/impl_method_stricter_bound.snap @@ -12,7 +12,7 @@ error[6-0009]: impl method has stricter bound than the declared method in the tr error[6-0009]: impl method has stricter bound than the declared method in the trait ┌─ impl_method_stricter_bound.fe:18:8 │ -18 │ fn foo(self, t: T, u: U) +18 │ fn foo(self, t: T, u: U) │ ^^^ method has stricter bounds than the declared method in the trait: `T: Baz`, `U: Bar` From b130adb29e175a149cdf24a426de49ceef34ff0d Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Wed, 27 Mar 2024 15:44:11 -0700 Subject: [PATCH 3/6] Remove `RecoveryMethod` in favor of an optional list of match tokens --- crates/parser2/src/parser/attr.rs | 32 ++--------- crates/parser2/src/parser/expr.rs | 24 ++++----- crates/parser2/src/parser/expr_atom.rs | 26 ++++----- crates/parser2/src/parser/func.rs | 3 +- crates/parser2/src/parser/item.rs | 40 +++++++------- crates/parser2/src/parser/lit.rs | 6 +-- crates/parser2/src/parser/mod.rs | 73 +++++--------------------- crates/parser2/src/parser/param.rs | 58 ++++++-------------- crates/parser2/src/parser/pat.rs | 18 +++---- crates/parser2/src/parser/path.rs | 8 +-- crates/parser2/src/parser/stmt.rs | 14 ++--- crates/parser2/src/parser/struct_.rs | 18 ++----- crates/parser2/src/parser/type_.rs | 21 ++------ crates/parser2/src/parser/use_tree.rs | 26 ++------- 14 files changed, 109 insertions(+), 258 deletions(-) diff --git a/crates/parser2/src/parser/attr.rs b/crates/parser2/src/parser/attr.rs index e767976cf9..68f45d4b4e 100644 --- a/crates/parser2/src/parser/attr.rs +++ b/crates/parser2/src/parser/attr.rs @@ -17,13 +17,7 @@ pub(super) fn parse_attr_list( } } -define_scope! { - pub(crate) AttrListScope, - AttrList, - Override( - Newline - ) -} +define_scope! { pub(crate) AttrListScope, AttrList, (Newline) } impl super::Parse for AttrListScope { type Error = Recovery; @@ -54,11 +48,7 @@ impl super::Parse for AttrListScope { } } -define_scope! { - AttrScope, - Attr, - Inheritance -} +define_scope! { AttrScope, Attr } impl super::Parse for AttrScope { type Error = Recovery; @@ -80,11 +70,7 @@ impl super::Parse for AttrScope { } } -define_scope! { - AttrArgListScope, - AttrArgList, - Override(Comma, RParen) -} +define_scope! { AttrArgListScope, AttrArgList, (Comma, RParen) } impl super::Parse for AttrArgListScope { type Error = Recovery; @@ -99,11 +85,7 @@ impl super::Parse for AttrArgListScope { } } -define_scope! { - AttrArgScope, - AttrArg, - Inheritance -} +define_scope! { AttrArgScope, AttrArg } impl super::Parse for AttrArgScope { type Error = Recovery; @@ -124,11 +106,7 @@ impl super::Parse for AttrArgScope { } } -define_scope! { - DocCommentAttrScope, - DocCommentAttr, - Inheritance -} +define_scope! { DocCommentAttrScope, DocCommentAttr } impl super::Parse for DocCommentAttrScope { type Error = Infallible; diff --git a/crates/parser2/src/parser/expr.rs b/crates/parser2/src/parser/expr.rs index e44088834f..054e5bbcd2 100644 --- a/crates/parser2/src/parser/expr.rs +++ b/crates/parser2/src/parser/expr.rs @@ -216,7 +216,7 @@ fn infix_binding_power(parser: &mut Parser) -> Option<(u8, u8 Some(bp) } -define_scope! { UnExprScope, UnExpr, Inheritance } +define_scope! { UnExprScope, UnExpr } impl super::Parse for UnExprScope { type Error = Recovery; @@ -229,7 +229,7 @@ impl super::Parse for UnExprScope { } } -define_scope! { BinExprScope, BinExpr, Inheritance } +define_scope! { BinExprScope, BinExpr } impl super::Parse for BinExprScope { type Error = Recovery; @@ -241,7 +241,7 @@ impl super::Parse for BinExprScope { } } -define_scope! { AugAssignExprScope, AugAssignExpr, Inheritance } +define_scope! { AugAssignExprScope, AugAssignExpr } impl super::Parse for AugAssignExprScope { type Error = Recovery; @@ -253,7 +253,7 @@ impl super::Parse for AugAssignExprScope { } } -define_scope! { AssignExprScope, AssignExpr, Inheritance } +define_scope! { AssignExprScope, AssignExpr } impl super::Parse for AssignExprScope { type Error = Recovery; @@ -265,7 +265,7 @@ impl super::Parse for AssignExprScope { } } -define_scope! { IndexExprScope, IndexExpr, Override(RBracket, Newline) } +define_scope! { IndexExprScope, IndexExpr, (RBracket, Newline) } impl super::Parse for IndexExprScope { type Error = Recovery; @@ -287,7 +287,7 @@ impl super::Parse for IndexExprScope { } } -define_scope! { CallExprScope, CallExpr, Inheritance } +define_scope! { CallExprScope, CallExpr } impl super::Parse for CallExprScope { type Error = Recovery; @@ -309,7 +309,7 @@ impl super::Parse for CallExprScope { } } -define_scope! { MethodExprScope, MethodCallExpr, Inheritance } +define_scope! { MethodExprScope, MethodCallExpr } impl super::Parse for MethodExprScope { type Error = Recovery; @@ -340,7 +340,7 @@ impl super::Parse for MethodExprScope { } } -define_scope! { FieldExprScope, FieldExpr, Inheritance } +define_scope! { FieldExprScope, FieldExpr } impl super::Parse for FieldExprScope { type Error = Recovery; @@ -353,7 +353,7 @@ impl super::Parse for FieldExprScope { } } -define_scope! { pub(super) LShiftScope, LShift, Inheritance } +define_scope! { pub(super) LShiftScope, LShift } impl super::Parse for LShiftScope { type Error = Infallible; @@ -364,7 +364,7 @@ impl super::Parse for LShiftScope { } } -define_scope! { pub(super) RShiftScope, RShift, Inheritance } +define_scope! { pub(super) RShiftScope, RShift } impl super::Parse for RShiftScope { type Error = Infallible; @@ -375,7 +375,7 @@ impl super::Parse for RShiftScope { } } -define_scope! { pub(super) LtEqScope, LtEq, Inheritance } +define_scope! { pub(super) LtEqScope, LtEq } impl super::Parse for LtEqScope { type Error = Infallible; @@ -386,7 +386,7 @@ impl super::Parse for LtEqScope { } } -define_scope! { pub(super) GtEqScope, GtEq, Inheritance } +define_scope! { pub(super) GtEqScope, GtEq } impl super::Parse for GtEqScope { type Error = Infallible; diff --git a/crates/parser2/src/parser/expr_atom.rs b/crates/parser2/src/parser/expr_atom.rs index e966e44ec6..6126656061 100644 --- a/crates/parser2/src/parser/expr_atom.rs +++ b/crates/parser2/src/parser/expr_atom.rs @@ -53,7 +53,7 @@ pub(super) fn parse_expr_atom( define_scope! { pub(crate) BlockExprScope, BlockExpr, - Override( + ( RBrace, Newline, LetKw, @@ -106,7 +106,7 @@ impl super::Parse for BlockExprScope { } } -define_scope! { IfExprScope, IfExpr, Inheritance } +define_scope! { IfExprScope, IfExpr } impl super::Parse for IfExprScope { type Error = Recovery; @@ -130,7 +130,7 @@ impl super::Parse for IfExprScope { } } -define_scope! { MatchExprScope, MatchExpr, Inheritance } +define_scope! { MatchExprScope, MatchExpr } impl super::Parse for MatchExprScope { type Error = Recovery; @@ -148,7 +148,7 @@ impl super::Parse for MatchExprScope { } } -define_scope! { MatchArmListScope, MatchArmList, Override(SyntaxKind::Newline, SyntaxKind::RBrace) } +define_scope! { MatchArmListScope, MatchArmList, (SyntaxKind::Newline, SyntaxKind::RBrace) } impl super::Parse for MatchArmListScope { type Error = Recovery; @@ -174,7 +174,7 @@ impl super::Parse for MatchArmListScope { } } -define_scope! { MatchArmScope, MatchArm, Inheritance } +define_scope! { MatchArmScope, MatchArm } impl super::Parse for MatchArmScope { type Error = Recovery; @@ -191,7 +191,7 @@ impl super::Parse for MatchArmScope { } } -define_scope! { pub(crate) LitExprScope, LitExpr, Inheritance } +define_scope! { pub(crate) LitExprScope, LitExpr } impl super::Parse for LitExprScope { type Error = Infallible; @@ -201,7 +201,7 @@ impl super::Parse for LitExprScope { } } -define_scope! { PathExprScope{ allow_record_init: bool }, PathExpr, Inheritance } +define_scope! { PathExprScope{ allow_record_init: bool }, PathExpr } impl super::Parse for PathExprScope { type Error = Recovery; @@ -223,7 +223,7 @@ impl super::Parse for PathExprScope { } } -define_scope! { RecordFieldListScope, RecordFieldList, Override(RBrace, Comma) } +define_scope! { RecordFieldListScope, RecordFieldList, (RBrace, Comma) } impl super::Parse for RecordFieldListScope { type Error = Recovery; @@ -238,7 +238,7 @@ impl super::Parse for RecordFieldListScope { } } -define_scope! { RecordFieldScope, RecordField, Inheritance } +define_scope! { RecordFieldScope, RecordField } impl super::Parse for RecordFieldScope { type Error = Recovery; @@ -253,7 +253,7 @@ impl super::Parse for RecordFieldScope { } } -define_scope! { ParenScope, ParenExpr, Override(RParen, Comma) } +define_scope! { ParenScope, ParenExpr, (RParen, Comma) } impl super::Parse for ParenScope { type Error = Recovery; @@ -283,11 +283,7 @@ impl super::Parse for ParenScope { } } -define_scope! { - ArrayScope, - ArrayExpr, - Override(RBracket, Comma, SemiColon) -} +define_scope! { ArrayScope, ArrayExpr, (RBracket, Comma, SemiColon) } impl super::Parse for ArrayScope { type Error = Recovery; diff --git a/crates/parser2/src/parser/func.rs b/crates/parser2/src/parser/func.rs index e12872d333..928abd7ec1 100644 --- a/crates/parser2/src/parser/func.rs +++ b/crates/parser2/src/parser/func.rs @@ -13,8 +13,7 @@ define_scope! { pub(crate) FuncScope { fn_def_scope: FuncDefScope }, - Func, - Inheritance + Func } #[derive(Clone, Copy, Debug)] diff --git a/crates/parser2/src/parser/item.rs b/crates/parser2/src/parser/item.rs index 8517751098..49e7aca5b6 100644 --- a/crates/parser2/src/parser/item.rs +++ b/crates/parser2/src/parser/item.rs @@ -21,7 +21,7 @@ define_scope! { #[doc(hidden)] pub ItemListScope {inside_mod: bool}, ItemList, - Override( + ( ModKw, FnKw, StructKw, @@ -93,8 +93,7 @@ impl super::Parse for ItemListScope { define_scope! { #[doc(hidden)] pub(super) ItemScope, - Item, - Inheritance + Item } impl super::Parse for ItemScope { type Error = Recovery; @@ -152,8 +151,7 @@ impl super::Parse for ItemScope { define_scope! { ItemModifierScope {kind: Rc>}, - ItemModifier, - Inheritance + ItemModifier } impl super::Parse for ItemModifierScope { type Error = Infallible; @@ -228,7 +226,7 @@ impl ModifierKind { } } -define_scope! { ModScope, Mod, Inheritance } +define_scope! { ModScope, Mod } impl super::Parse for ModScope { type Error = Recovery; @@ -251,7 +249,7 @@ impl super::Parse for ModScope { } } -define_scope! { ContractScope, Contract, Inheritance } +define_scope! { ContractScope, Contract } impl super::Parse for ContractScope { type Error = Recovery; @@ -270,7 +268,7 @@ impl super::Parse for ContractScope { } } -define_scope! { EnumScope, Enum, Inheritance } +define_scope! { EnumScope, Enum } impl super::Parse for EnumScope { type Error = Recovery; @@ -301,7 +299,7 @@ impl super::Parse for EnumScope { } } -define_scope! { VariantDefListScope, VariantDefList, Override(Comma, RBrace) } +define_scope! { VariantDefListScope, VariantDefList, (Comma, RBrace) } impl super::Parse for VariantDefListScope { type Error = Recovery; @@ -316,7 +314,7 @@ impl super::Parse for VariantDefListScope { } } -define_scope! { VariantDefScope, VariantDef, Inheritance } +define_scope! { VariantDefScope, VariantDef } impl super::Parse for VariantDefScope { type Error = Recovery; fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { @@ -331,7 +329,7 @@ impl super::Parse for VariantDefScope { } } -define_scope! { TraitScope, Trait, Inheritance } +define_scope! { TraitScope, Trait } impl super::Parse for TraitScope { type Error = Recovery; @@ -366,7 +364,7 @@ impl super::Parse for TraitScope { } } -define_scope! {SuperTraitListScope, SuperTraitList, Inheritance(Plus)} +define_scope! {SuperTraitListScope, SuperTraitList, (Plus)} impl super::Parse for SuperTraitListScope { type Error = Recovery; @@ -380,7 +378,7 @@ impl super::Parse for SuperTraitListScope { } } -define_scope! { TraitItemListScope, TraitItemList, Override(RBrace, Newline, FnKw) } +define_scope! { TraitItemListScope, TraitItemList, (RBrace, Newline, FnKw) } impl super::Parse for TraitItemListScope { type Error = Recovery; @@ -389,7 +387,7 @@ impl super::Parse for TraitItemListScope { } } -define_scope! { ImplScope, Impl, Override(ForKw, LBrace) } +define_scope! { ImplScope, Impl, (ForKw, LBrace) } impl super::Parse for ImplScope { type Error = Recovery; @@ -440,7 +438,7 @@ impl super::Parse for ImplScope { } } -define_scope! { ImplTraitItemListScope, ImplTraitItemList, Override(RBrace, FnKw) } +define_scope! { ImplTraitItemListScope, ImplTraitItemList, (RBrace, FnKw) } impl super::Parse for ImplTraitItemListScope { type Error = Recovery; @@ -449,7 +447,7 @@ impl super::Parse for ImplTraitItemListScope { } } -define_scope! { ImplItemListScope, ImplItemList, Override(RBrace, FnKw) } +define_scope! { ImplItemListScope, ImplItemList, (RBrace, FnKw) } impl super::Parse for ImplItemListScope { type Error = Recovery; @@ -458,7 +456,7 @@ impl super::Parse for ImplItemListScope { } } -define_scope! { UseScope, Use, Inheritance } +define_scope! { UseScope, Use } impl super::Parse for UseScope { type Error = Recovery; @@ -468,7 +466,7 @@ impl super::Parse for UseScope { } } -define_scope! { ConstScope, Const, Inheritance } +define_scope! { ConstScope, Const } impl super::Parse for ConstScope { type Error = Recovery; @@ -498,7 +496,7 @@ impl super::Parse for ConstScope { } } -define_scope! { ExternScope, Extern, Inheritance } +define_scope! { ExternScope, Extern } impl super::Parse for ExternScope { type Error = Recovery; @@ -513,7 +511,7 @@ impl super::Parse for ExternScope { } } -define_scope! { ExternItemListScope, ExternItemList, Override(PubKw, UnsafeKw, FnKw) } +define_scope! { ExternItemListScope, ExternItemList, (PubKw, UnsafeKw, FnKw) } impl super::Parse for ExternItemListScope { type Error = Recovery; @@ -522,7 +520,7 @@ impl super::Parse for ExternItemListScope { } } -define_scope! { TypeAliasScope, TypeAlias, Inheritance } +define_scope! { TypeAliasScope, TypeAlias } impl super::Parse for TypeAliasScope { type Error = Recovery; diff --git a/crates/parser2/src/parser/lit.rs b/crates/parser2/src/parser/lit.rs index f0b5717c35..a2748796c0 100644 --- a/crates/parser2/src/parser/lit.rs +++ b/crates/parser2/src/parser/lit.rs @@ -4,11 +4,7 @@ use crate::SyntaxKind; use super::{define_scope, token_stream::TokenStream, Parser}; -define_scope! { - pub(crate) LitScope, - Lit, - Inheritance -} +define_scope! { pub(crate) LitScope, Lit } impl super::Parse for LitScope { type Error = Infallible; diff --git a/crates/parser2/src/parser/mod.rs b/crates/parser2/src/parser/mod.rs index 6ca9beff90..01e78e366e 100644 --- a/crates/parser2/src/parser/mod.rs +++ b/crates/parser2/src/parser/mod.rs @@ -2,7 +2,7 @@ use std::{collections::VecDeque, convert::Infallible}; pub(crate) use item::ItemListScope; -use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_hash::FxHashMap; use smallvec::SmallVec; use self::token_stream::{BackTrackableTokenStream, LexicalToken, TokenStream}; @@ -624,7 +624,7 @@ impl Parser { pub trait ParsingScope { /// Returns the recovery method of the current scope. - fn recovery_method(&self) -> &RecoveryMethod; + fn recovery_tokens(&self) -> &[SyntaxKind]; fn syntax_kind(&self) -> SyntaxKind; } @@ -689,34 +689,6 @@ struct DryRunState { next_trivias: VecDeque, } -/// Represents the recovery method of the current scope. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum RecoveryMethod { - /// Uses the recovery method of the parent scope and its own recovery set. - Inheritance(FxHashSet), - - /// The scope has its own recovery set and don't use parent scope's recovery - /// set. - Override(FxHashSet), -} - -impl RecoveryMethod { - fn inheritance(tokens: &[SyntaxKind]) -> Self { - Self::Inheritance(tokens.iter().copied().collect()) - } - - fn override_(tokens: &[SyntaxKind]) -> Self { - Self::Override(tokens.iter().copied().collect()) - } - - fn recovery_set(&self) -> &FxHashSet { - match self { - RecoveryMethod::Inheritance(set) => set, - RecoveryMethod::Override(set) => set, - } - } -} - struct ScopeEntry { scope: Box, is_newline_trivia: bool, @@ -734,8 +706,7 @@ impl ScopeEntry { } fn is_recovery_match(&self, kind: SyntaxKind) -> bool { - self.scope.recovery_method().recovery_set().contains(&kind) - || self.aux_recovery_tokens.contains(&kind) + self.scope.recovery_tokens().contains(&kind) || self.aux_recovery_tokens.contains(&kind) } } @@ -763,37 +734,19 @@ where } } -define_scope! { - ErrorScope, - Error, - Inheritance -} - -define_scope! { - pub RootScope, - Root, - Override() -} +define_scope! { ErrorScope, Error } +define_scope! { pub RootScope, Root } macro_rules! define_scope { ( $(#[$attrs: meta])* $visibility: vis $scope_name: ident $({ $($field: ident: $ty: ty),* })?, - $kind: path, - Inheritance $(($($recoveries: path), *))? + $kind: path ) => { crate::parser::define_scope_struct! {$visibility $scope_name {$($($field: $ty), *)?}, $kind} impl crate::parser::ParsingScope for $scope_name { - fn recovery_method(&self) -> &crate::parser::RecoveryMethod { - lazy_static::lazy_static! { - pub(super) static ref RECOVERY_METHOD: crate::parser::RecoveryMethod = { - #[allow(unused)] - use crate::SyntaxKind::*; - crate::parser::RecoveryMethod::inheritance(&[$($($recoveries), *)?]) - }; - } - - &RECOVERY_METHOD + fn recovery_tokens(&self) -> &[crate::SyntaxKind] { + &[] } fn syntax_kind(&self) -> crate::SyntaxKind { @@ -806,21 +759,21 @@ macro_rules! define_scope { $(#[$attrs: meta])* $visibility: vis $scope_name: ident $({ $($field: ident: $ty: ty),* })?, $kind: path, - Override($($recoveries: path), *) + ($($recoveries: path), *) ) => { crate::parser::define_scope_struct! {$visibility $scope_name {$($($field: $ty), *)?}, $kind} impl crate::parser::ParsingScope for $scope_name { - fn recovery_method(&self) -> &crate::parser::RecoveryMethod { + fn recovery_tokens(&self) -> &[crate::SyntaxKind] { lazy_static::lazy_static! { - pub(super) static ref RECOVERY_METHOD: crate::parser::RecoveryMethod = { + pub(super) static ref RECOVERY_TOKENS: smallvec::SmallVec<[SyntaxKind; 4]> = { #[allow(unused)] use crate::SyntaxKind::*; - crate::parser::RecoveryMethod::override_(&[$($recoveries), *]) + smallvec::SmallVec::from_slice(&[$($recoveries), *]) }; } - &RECOVERY_METHOD + &RECOVERY_TOKENS } fn syntax_kind(&self) -> crate::SyntaxKind { diff --git a/crates/parser2/src/parser/param.rs b/crates/parser2/src/parser/param.rs index 7d79e78a45..60c19663bb 100644 --- a/crates/parser2/src/parser/param.rs +++ b/crates/parser2/src/parser/param.rs @@ -16,7 +16,7 @@ use super::{ define_scope! { pub(crate) FuncParamListScope{ allow_self: bool}, FuncParamList, - Override(RParen, Comma) + (RParen, Comma) } impl super::Parse for FuncParamListScope { type Error = Recovery; @@ -32,11 +32,7 @@ impl super::Parse for FuncParamListScope { } } -define_scope! { - FnParamScope{allow_self: bool}, - FnParam, - Inheritance -} +define_scope! { FnParamScope{allow_self: bool}, FnParam } impl super::Parse for FnParamScope { type Error = Recovery; @@ -88,7 +84,7 @@ impl super::Parse for FnParamScope { define_scope! { pub(crate) GenericParamListScope {disallow_trait_bound: bool}, GenericParamList, - Override(Comma, Gt) + (Comma, Gt) } impl super::Parse for GenericParamListScope { type Error = Recovery; @@ -117,11 +113,7 @@ impl super::Parse for GenericParamListScope { } } -define_scope! { - ConstGenericParamScope, - ConstGenericParam, - Inheritance -} +define_scope! { ConstGenericParamScope, ConstGenericParam } impl super::Parse for ConstGenericParamScope { type Error = Recovery; @@ -154,8 +146,7 @@ impl super::Parse for ConstGenericParamScope { define_scope! { TypeGenericParamScope {disallow_trait_bound: bool}, - TypeGenericParam, - Inheritance + TypeGenericParam } impl super::Parse for TypeGenericParamScope { type Error = Recovery; @@ -174,7 +165,7 @@ impl super::Parse for TypeGenericParamScope { define_scope! { TypeBoundListScope{disallow_trait_bound: bool}, TypeBoundList, - Inheritance(Plus) + (Plus) } impl super::Parse for TypeBoundListScope { type Error = Recovery; @@ -193,8 +184,7 @@ impl super::Parse for TypeBoundListScope { define_scope! { TypeBoundScope{disallow_trait_bound: bool}, - TypeBound, - Inheritance + TypeBound } impl super::Parse for TypeBoundScope { type Error = Recovery; @@ -248,11 +238,7 @@ fn parse_kind_bound(parser: &mut Parser) -> Result<(), Recove Ok(()) } -define_scope! { - KindBoundMonoScope, - KindBoundMono, - Inheritance -} +define_scope! { KindBoundMonoScope, KindBoundMono } impl super::Parse for KindBoundMonoScope { type Error = Infallible; @@ -262,11 +248,7 @@ impl super::Parse for KindBoundMonoScope { } } -define_scope! { - KindBoundAbsScope, - KindBoundAbs, - Inheritance -} +define_scope! { KindBoundAbsScope, KindBoundAbs } impl super::Parse for KindBoundAbsScope { type Error = Recovery; @@ -276,11 +258,7 @@ impl super::Parse for KindBoundAbsScope { } } -define_scope! { - pub(super) TraitRefScope, - TraitRef, - Inheritance -} +define_scope! { pub(super) TraitRefScope, TraitRef } impl super::Parse for TraitRefScope { type Error = Recovery; @@ -301,7 +279,7 @@ impl super::Parse for TraitRefScope { define_scope! { pub(crate) GenericArgListScope, GenericArgList, - Override(Gt, Comma) + (Gt, Comma) } impl super::Parse for GenericArgListScope { type Error = Recovery; @@ -317,11 +295,7 @@ impl super::Parse for GenericArgListScope { } } -define_scope! { - GenericArgScope, - TypeGenericArg, - Override() -} +define_scope! { GenericArgScope, TypeGenericArg } impl super::Parse for GenericArgScope { type Error = Recovery; @@ -349,7 +323,7 @@ impl super::Parse for GenericArgScope { } } -define_scope! { pub(crate) CallArgListScope, CallArgList, Override(RParen, Comma) } +define_scope! { pub(crate) CallArgListScope, CallArgList, (RParen, Comma) } impl super::Parse for CallArgListScope { type Error = Recovery; @@ -364,7 +338,7 @@ impl super::Parse for CallArgListScope { } } -define_scope! { CallArgScope, CallArg, Override(Comma, RParen) } +define_scope! { CallArgScope, CallArg, (Comma, RParen) } impl super::Parse for CallArgScope { type Error = Recovery; @@ -383,7 +357,7 @@ impl super::Parse for CallArgScope { } } -define_scope! { pub(crate) WhereClauseScope, WhereClause, Inheritance(Newline) } +define_scope! { pub(crate) WhereClauseScope, WhereClause, (Newline) } impl super::Parse for WhereClauseScope { type Error = Recovery; @@ -437,7 +411,7 @@ impl super::Parse for WhereClauseScope { } } -define_scope! { pub(crate) WherePredicateScope, WherePredicate, Inheritance } +define_scope! { pub(crate) WherePredicateScope, WherePredicate } impl super::Parse for WherePredicateScope { type Error = Recovery; diff --git a/crates/parser2/src/parser/pat.rs b/crates/parser2/src/parser/pat.rs index 709a5419f2..fa392a05aa 100644 --- a/crates/parser2/src/parser/pat.rs +++ b/crates/parser2/src/parser/pat.rs @@ -57,7 +57,7 @@ pub fn parse_pat(parser: &mut Parser) -> Result<(), Recovery< Ok(()) } -define_scope! { WildCardPatScope, WildCardPat, Inheritance(SyntaxKind::Pipe) } +define_scope! { WildCardPatScope, WildCardPat, (Pipe) } impl super::Parse for WildCardPatScope { type Error = Infallible; @@ -68,7 +68,7 @@ impl super::Parse for WildCardPatScope { } } -define_scope! { RestPatScope, RestPat, Inheritance } +define_scope! { RestPatScope, RestPat } impl super::Parse for RestPatScope { type Error = Infallible; @@ -79,7 +79,7 @@ impl super::Parse for RestPatScope { } } -define_scope! { LitPatScope, LitPat, Inheritance(SyntaxKind::Pipe) } +define_scope! { LitPatScope, LitPat, (Pipe) } impl super::Parse for LitPatScope { type Error = Infallible; @@ -89,7 +89,7 @@ impl super::Parse for LitPatScope { } } -define_scope! { TuplePatScope, TuplePat, Inheritance } +define_scope! { TuplePatScope, TuplePat } impl super::Parse for TuplePatScope { type Error = Recovery; @@ -98,7 +98,7 @@ impl super::Parse for TuplePatScope { } } -define_scope! { TuplePatElemListScope, TuplePatElemList, Override(RParen, Comma) } +define_scope! { TuplePatElemListScope, TuplePatElemList, (RParen, Comma) } impl super::Parse for TuplePatElemListScope { type Error = Recovery; @@ -113,7 +113,7 @@ impl super::Parse for TuplePatElemListScope { } } -define_scope! { PathPatScope, PathPat, Inheritance(Pipe) } +define_scope! { PathPatScope, PathPat, (Pipe) } impl super::Parse for PathPatScope { type Error = Recovery; @@ -136,7 +136,7 @@ impl super::Parse for PathPatScope { } } -define_scope! { RecordPatFieldListScope, RecordPatFieldList, Override(Comma, RBrace) } +define_scope! { RecordPatFieldListScope, RecordPatFieldList, (Comma, RBrace) } impl super::Parse for RecordPatFieldListScope { type Error = Recovery; @@ -151,7 +151,7 @@ impl super::Parse for RecordPatFieldListScope { } } -define_scope! { RecordPatFieldScope, RecordPatField, Inheritance } +define_scope! { RecordPatFieldScope, RecordPatField } impl super::Parse for RecordPatFieldScope { type Error = Recovery; @@ -168,7 +168,7 @@ impl super::Parse for RecordPatFieldScope { } } -define_scope! { OrPatScope, OrPat, Inheritance(SyntaxKind::Pipe) } +define_scope! { OrPatScope, OrPat, (Pipe) } impl super::Parse for OrPatScope { type Error = Recovery; diff --git a/crates/parser2/src/parser/path.rs b/crates/parser2/src/parser/path.rs index 60751afe5f..22dd77e0ea 100644 --- a/crates/parser2/src/parser/path.rs +++ b/crates/parser2/src/parser/path.rs @@ -6,7 +6,7 @@ define_scope! { #[doc(hidden)] pub PathScope, Path, - Inheritance(Colon2) + (Colon2) } impl super::Parse for PathScope { type Error = ParseError; @@ -21,11 +21,7 @@ impl super::Parse for PathScope { } } -define_scope! { - PathSegmentScope, - PathSegment, - Inheritance -} +define_scope! { PathSegmentScope, PathSegment } impl super::Parse for PathSegmentScope { type Error = ParseError; diff --git a/crates/parser2/src/parser/stmt.rs b/crates/parser2/src/parser/stmt.rs index ff134db01f..f00ac4c435 100644 --- a/crates/parser2/src/parser/stmt.rs +++ b/crates/parser2/src/parser/stmt.rs @@ -30,7 +30,7 @@ pub fn parse_stmt(parser: &mut Parser) -> Result<(), Recovery } } -define_scope! { LetStmtScope, LetStmt, Inheritance } +define_scope! { LetStmtScope, LetStmt } impl super::Parse for LetStmtScope { type Error = Recovery; @@ -51,7 +51,7 @@ impl super::Parse for LetStmtScope { } } -define_scope! { ForStmtScope, ForStmt, Inheritance } +define_scope! { ForStmtScope, ForStmt } impl super::Parse for ForStmtScope { type Error = Recovery; @@ -76,7 +76,7 @@ impl super::Parse for ForStmtScope { } } -define_scope! { WhileStmtScope, WhileStmt, Inheritance } +define_scope! { WhileStmtScope, WhileStmt } impl super::Parse for WhileStmtScope { type Error = Recovery; @@ -96,7 +96,7 @@ impl super::Parse for WhileStmtScope { } } -define_scope! { ContinueStmtScope, ContinueStmt, Inheritance } +define_scope! { ContinueStmtScope, ContinueStmt } impl super::Parse for ContinueStmtScope { type Error = Infallible; @@ -106,7 +106,7 @@ impl super::Parse for ContinueStmtScope { } } -define_scope! { BreakStmtScope, BreakStmt, Inheritance } +define_scope! { BreakStmtScope, BreakStmt } impl super::Parse for BreakStmtScope { type Error = Infallible; @@ -116,7 +116,7 @@ impl super::Parse for BreakStmtScope { } } -define_scope! { ReturnStmtScope, ReturnStmt, Inheritance } +define_scope! { ReturnStmtScope, ReturnStmt } impl super::Parse for ReturnStmtScope { type Error = Recovery; @@ -134,7 +134,7 @@ impl super::Parse for ReturnStmtScope { } } -define_scope! { ExprStmtScope, ExprStmt, Inheritance } +define_scope! { ExprStmtScope, ExprStmt } impl super::Parse for ExprStmtScope { type Error = Recovery; diff --git a/crates/parser2/src/parser/struct_.rs b/crates/parser2/src/parser/struct_.rs index 962039eda7..d89264cab7 100644 --- a/crates/parser2/src/parser/struct_.rs +++ b/crates/parser2/src/parser/struct_.rs @@ -11,11 +11,7 @@ use super::{ ErrProof, Parser, Recovery, }; -define_scope! { - pub(crate) StructScope, - Struct, - Inheritance -} +define_scope! { pub(crate) StructScope, Struct } impl super::Parse for StructScope { type Error = Recovery; @@ -49,11 +45,7 @@ impl super::Parse for StructScope { define_scope! { pub(crate) RecordFieldDefListScope, RecordFieldDefList, - Override( - RBrace, - Comma, - Newline - ) + (RBrace, Comma, Newline) } impl super::Parse for RecordFieldDefListScope { type Error = Recovery; @@ -69,11 +61,7 @@ impl super::Parse for RecordFieldDefListScope { } } -define_scope! { - RecordFieldDefScope, - RecordFieldDef, - Inheritance -} +define_scope! { RecordFieldDefScope, RecordFieldDef } impl super::Parse for RecordFieldDefScope { type Error = Recovery; diff --git a/crates/parser2/src/parser/type_.rs b/crates/parser2/src/parser/type_.rs index e09eb0f881..b4900093c2 100644 --- a/crates/parser2/src/parser/type_.rs +++ b/crates/parser2/src/parser/type_.rs @@ -33,7 +33,7 @@ pub(crate) fn is_type_start(kind: SyntaxKind) -> bool { } } -define_scope!(PtrTypeScope, PtrType, Inheritance); +define_scope!(PtrTypeScope, PtrType); impl super::Parse for PtrTypeScope { type Error = Recovery; fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { @@ -43,7 +43,7 @@ impl super::Parse for PtrTypeScope { } } -define_scope!(pub(crate) PathTypeScope , PathType, Inheritance); +define_scope!(pub(crate) PathTypeScope , PathType); impl super::Parse for PathTypeScope { type Error = Recovery; fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { @@ -62,7 +62,7 @@ impl super::Parse for PathTypeScope { } } -define_scope!(pub(super) SelfTypeScope, SelfType, Inheritance); +define_scope!(pub(super) SelfTypeScope, SelfType); impl super::Parse for SelfTypeScope { type Error = Recovery; @@ -75,14 +75,7 @@ impl super::Parse for SelfTypeScope { Ok(()) } } -define_scope! { - pub(crate) TupleTypeScope, - TupleType, - Override( - RParen, - Comma - ) -} +define_scope! { pub(crate) TupleTypeScope, TupleType, (RParen, Comma) } impl super::Parse for TupleTypeScope { type Error = Recovery; fn parse(&mut self, parser: &mut Parser) -> Result<(), Self::Error> { @@ -99,11 +92,7 @@ impl super::Parse for TupleTypeScope { } } -define_scope! { - ArrayTypeScope, - ArrayType, - Inheritance -} +define_scope! { ArrayTypeScope, ArrayType } impl super::Parse for ArrayTypeScope { type Error = Recovery; diff --git a/crates/parser2/src/parser/use_tree.rs b/crates/parser2/src/parser/use_tree.rs index 9e9c60b5c9..51eaad579d 100644 --- a/crates/parser2/src/parser/use_tree.rs +++ b/crates/parser2/src/parser/use_tree.rs @@ -4,11 +4,7 @@ use crate::{parser::path::is_path_segment, ParseError, SyntaxKind, TextRange}; use super::{define_scope, parse_list, token_stream::TokenStream, ErrProof, Parser, Recovery}; -define_scope! { - pub(crate) UseTreeScope, - UseTree, - Inheritance -} +define_scope! { pub(crate) UseTreeScope, UseTree } impl super::Parse for UseTreeScope { type Error = Recovery; @@ -45,11 +41,7 @@ impl super::Parse for UseTreeScope { } } -define_scope! { - UseTreeListScope, - UseTreeList, - Override(Comma, RBrace) -} +define_scope! { UseTreeListScope, UseTreeList, (Comma, RBrace) } impl super::Parse for UseTreeListScope { type Error = Recovery; @@ -67,7 +59,7 @@ impl super::Parse for UseTreeListScope { define_scope! { UsePathScope{ is_glob: Rc>}, UsePath, - Inheritance(Colon2) + (Colon2) } impl super::Parse for UsePathScope { type Error = ParseError; @@ -99,11 +91,7 @@ impl super::Parse for UsePathScope { } } -define_scope! { - UsePathSegmentScope, - UsePathSegment, - Inheritance -} +define_scope! { UsePathSegmentScope, UsePathSegment } impl super::Parse for UsePathSegmentScope { type Error = ParseError; @@ -123,11 +111,7 @@ impl super::Parse for UsePathSegmentScope { } } -define_scope! { - UseTreeAliasScope, - UseTreeRename, - Inheritance -} +define_scope! { UseTreeAliasScope, UseTreeRename } impl super::Parse for UseTreeAliasScope { type Error = ParseError; From d3917cc2ade6746e2a1afc8e42ade4aee027d9a0 Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Wed, 27 Mar 2024 22:06:40 -0700 Subject: [PATCH 4/6] Fix build warning (unused field in def_analysis::DefKind::Impl) --- crates/hir-analysis/src/ty/def_analysis.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/hir-analysis/src/ty/def_analysis.rs b/crates/hir-analysis/src/ty/def_analysis.rs index 4a074b42a9..ab9d90802f 100644 --- a/crates/hir-analysis/src/ty/def_analysis.rs +++ b/crates/hir-analysis/src/ty/def_analysis.rs @@ -220,7 +220,7 @@ impl<'db> DefAnalyzer<'db> { fn for_impl(db: &'db dyn HirAnalysisDb, impl_: HirImpl, ty: TyId) -> Self { let assumptions = collect_impl_block_constraints(db, impl_); - let def = DefKind::Impl(impl_, ty); + let def = DefKind::Impl(impl_); Self { db, def, @@ -384,7 +384,7 @@ impl<'db> DefAnalyzer<'db> { self.visit_impl_trait(&mut ctxt, impl_trait); } - DefKind::Impl(hir_impl, _) => { + DefKind::Impl(hir_impl) => { let mut ctxt = VisitorCtxt::with_impl(self.db.as_hir_db(), hir_impl); self.visit_impl(&mut ctxt, hir_impl) } @@ -889,7 +889,7 @@ enum DefKind { Adt(AdtDef), Trait(TraitDef), ImplTrait(Implementor), - Impl(HirImpl, TyId), + Impl(HirImpl), Func(FuncDef), } @@ -899,7 +899,7 @@ impl DefKind { Self::Adt(def) => def.params(db), Self::Trait(def) => def.params(db), Self::ImplTrait(def) => def.params(db), - Self::Impl(hir_impl, _) => { + Self::Impl(hir_impl) => { collect_generic_params(db, GenericParamOwnerId::new(db, hir_impl.into())).params(db) } Self::Func(def) => def.params(db), @@ -927,7 +927,7 @@ impl DefKind { Self::Adt(def) => def.adt_ref(db).scope(db), Self::Trait(def) => def.trait_(db).scope(), Self::ImplTrait(def) => def.hir_impl_trait(db).scope(), - Self::Impl(hir_impl, _) => hir_impl.scope(), + Self::Impl(hir_impl) => hir_impl.scope(), Self::Func(def) => def.hir_func(db).scope(), } } From e8ff9422fe353d5f7de73e6f3440fe005fef1a16 Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Fri, 5 Apr 2024 14:48:27 -0700 Subject: [PATCH 5/6] Remove dead code --- crates/parser2/src/parser/mod.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/crates/parser2/src/parser/mod.rs b/crates/parser2/src/parser/mod.rs index 01e78e366e..66623d512a 100644 --- a/crates/parser2/src/parser/mod.rs +++ b/crates/parser2/src/parser/mod.rs @@ -2,7 +2,6 @@ use std::{collections::VecDeque, convert::Infallible}; pub(crate) use item::ItemListScope; -use rustc_hash::FxHashMap; use smallvec::SmallVec; use self::token_stream::{BackTrackableTokenStream, LexicalToken, TokenStream}; @@ -406,17 +405,8 @@ impl Parser { /// and the total string length of the unexpected tokens. fn recover(&mut self) -> (Option, Option) { let mut unexpected = None; - let mut open_brackets_in_error = FxHashMap::default(); let mut match_scope_index = None; while let Some(kind) = self.current_kind() { - if kind.is_open_bracket_kind() { - *open_brackets_in_error.entry(kind).or_insert(0) += 1; - } else if let Some(open_bracket) = kind.corresponding_open_bracket_kind() { - if open_brackets_in_error.get(&open_bracket).unwrap_or(&0) != &0 { - *open_brackets_in_error.get_mut(&open_bracket).unwrap() -= 1; - } - } - if let Some((scope_index, _)) = self .parents .iter() From 273ce09db7c1f7db21aeef541d48e78972ace665 Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Fri, 5 Apr 2024 15:57:08 -0700 Subject: [PATCH 6/6] Fix review nits --- crates/parser2/src/ast/item.rs | 1 - crates/parser2/src/parser/expr_atom.rs | 5 +++-- crates/parser2/src/parser/mod.rs | 13 ------------- crates/parser2/src/parser/param.rs | 8 ++++++-- crates/parser2/src/parser/stmt.rs | 18 ++++++++++++------ 5 files changed, 21 insertions(+), 24 deletions(-) diff --git a/crates/parser2/src/ast/item.rs b/crates/parser2/src/ast/item.rs index 15e15dbad3..bb8880ab85 100644 --- a/crates/parser2/src/ast/item.rs +++ b/crates/parser2/src/ast/item.rs @@ -728,7 +728,6 @@ mod tests { let u: Use = parse_item(source); let use_tree = u.use_tree().unwrap(); let mut count = 0; - dbg!(use_tree.path().unwrap()); for segment in use_tree.path().unwrap() { match count { 0 => { diff --git a/crates/parser2/src/parser/expr_atom.rs b/crates/parser2/src/parser/expr_atom.rs index 6126656061..08578e05b4 100644 --- a/crates/parser2/src/parser/expr_atom.rs +++ b/crates/parser2/src/parser/expr_atom.rs @@ -1,6 +1,7 @@ use std::convert::Infallible; use rowan::Checkpoint; +use unwrap_infallible::UnwrapInfallible; use crate::{ parser::{lit, path}, @@ -40,9 +41,9 @@ pub(super) fn parse_expr_atom( Some(LBrace) => parser.parse_cp(BlockExprScope::default(), None), Some(LParen) => parser.parse_cp(ParenScope::default(), None), Some(LBracket) => parser.parse_cp(ArrayScope::default(), None), - Some(kind) if lit::is_lit(kind) => parser + Some(kind) if lit::is_lit(kind) => Ok(parser .parse_cp(LitExprScope::default(), None) - .map_err(|e| e.into()), + .unwrap_infallible()), Some(kind) if path::is_path_segment(kind) => { parser.parse_cp(PathExprScope::new(allow_record_init), None) } diff --git a/crates/parser2/src/parser/mod.rs b/crates/parser2/src/parser/mod.rs index 66623d512a..25bee8bde2 100644 --- a/crates/parser2/src/parser/mod.rs +++ b/crates/parser2/src/parser/mod.rs @@ -34,7 +34,6 @@ pub struct Parser { stream: BackTrackableTokenStream, builder: rowan::GreenNodeBuilder<'static>, - /// The second element holds `is_newline_trivia` of the parent. parents: Vec, errors: Vec, @@ -641,18 +640,6 @@ impl Recovery<()> { #[derive(Debug)] pub struct ErrProof(()); -impl From for Recovery { - fn from(_value: Infallible) -> Self { - unreachable!() - } -} - -impl From> for Recovery<()> { - fn from(r: Recovery) -> Self { - Recovery(r.0, ()) - } -} - pub trait Recoverable { fn is_local_recovery(&self, _parser: &Parser) -> bool { false diff --git a/crates/parser2/src/parser/param.rs b/crates/parser2/src/parser/param.rs index 60c19663bb..934a043db6 100644 --- a/crates/parser2/src/parser/param.rs +++ b/crates/parser2/src/parser/param.rs @@ -1,5 +1,7 @@ use std::convert::Infallible; +use unwrap_infallible::UnwrapInfallible; + use crate::{ExpectedKind, ParseError, SyntaxKind}; use super::{ @@ -224,7 +226,9 @@ fn parse_kind_bound(parser: &mut Parser) -> Result<(), Recove parser.bump(); } } else if parser.current_kind() == Some(SyntaxKind::Star) { - parser.parse(KindBoundMonoScope::default())?; + parser + .parse(KindBoundMonoScope::default()) + .unwrap_infallible(); } else { // guaranteed by `expected`, unless other recovery // other tokens are added to the current scope @@ -309,7 +313,7 @@ impl super::Parse for GenericArgScope { Some(kind) if kind.is_literal_leaf() => { self.set_kind(SyntaxKind::ConstGenericArg); - parser.parse(LitExprScope::default())?; + parser.parse(LitExprScope::default()).unwrap_infallible(); } _ => { diff --git a/crates/parser2/src/parser/stmt.rs b/crates/parser2/src/parser/stmt.rs index f00ac4c435..3873c94b19 100644 --- a/crates/parser2/src/parser/stmt.rs +++ b/crates/parser2/src/parser/stmt.rs @@ -1,5 +1,7 @@ use std::convert::Infallible; +use unwrap_infallible::UnwrapInfallible; + use crate::{ExpectedKind, SyntaxKind}; use super::{ @@ -19,12 +21,16 @@ pub fn parse_stmt(parser: &mut Parser) -> Result<(), Recovery Some(LetKw) => parser.parse(LetStmtScope::default()), Some(ForKw) => parser.parse(ForStmtScope::default()), Some(WhileKw) => parser.parse(WhileStmtScope::default()), - Some(ContinueKw) => parser - .parse(ContinueStmtScope::default()) - .map_err(|e| e.into()), - Some(BreakKw) => parser - .parse(BreakStmtScope::default()) - .map_err(|e| e.into()), + Some(ContinueKw) => { + parser + .parse(ContinueStmtScope::default()) + .unwrap_infallible(); + Ok(()) + } + Some(BreakKw) => { + parser.parse(BreakStmtScope::default()).unwrap_infallible(); + Ok(()) + } Some(ReturnKw) => parser.parse(ReturnStmtScope::default()), _ => parser.parse(ExprStmtScope::default()), }