10496: internal: move some macro tests r=matklad a=matklad

bors r+
🤖

Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2021-10-09 15:19:39 +00:00 committed by GitHub
commit b2b703b2d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 309 additions and 285 deletions

4
Cargo.lock generated
View File

@ -345,9 +345,9 @@ dependencies = [
[[package]]
name = "expect-test"
version = "1.1.0"
version = "1.2.0-pre.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2300477aab3a378f2ca00a4fbd4dc713654ab7ed790e4017493cb33656280633"
checksum = "3a2f1664bc69648747878bfe3430ad9b58bc8d9b50b3b1df9f3c081345e33197"
dependencies = [
"dissimilar",
"once_cell",

View File

@ -16,7 +16,7 @@ tt = { path = "../tt", version = "0.0.0" }
[dev-dependencies]
mbe = { path = "../mbe" }
syntax = { path = "../syntax" }
expect-test = "1.1"
expect-test = "1.2.0-pre.1"
oorandom = "11"
# We depend on both individually instead of using `features = ["derive"]` to microoptimize the
# build graph: if the feature was enabled, syn would be built early on in the graph if `smolstr`

View File

@ -35,4 +35,4 @@ limit = { path = "../limit", version = "0.0.0" }
[dev-dependencies]
test_utils = { path = "../test_utils" }
expect-test = "1.1"
expect-test = "1.2.0-pre.1"

View File

@ -28,7 +28,7 @@ use crate::{
db::DefDatabase, nameres::ModuleSource, resolver::HasResolver, test_db::TestDB, AsMacroCall,
};
fn check(ra_fixture: &str, expect: Expect) {
fn check(ra_fixture: &str, mut expect: Expect) {
let db = TestDB::with_files(ra_fixture);
let krate = db.crate_graph().iter().next().unwrap();
let def_map = db.crate_def_map(krate);
@ -65,16 +65,29 @@ fn check(ra_fixture: &str, expect: Expect) {
format_to!(expn_text, "/* error: {} */", err);
}
if let Some((parse, _token_map)) = exp.value {
assert!(
parse.errors().is_empty(),
"parse errors in expansion: \n{:#?}",
parse.errors()
);
let pp = pretty_print_macro_expansion(parse.syntax_node());
let indent = IndentLevel::from_node(call.syntax());
let pp = reindent(indent, pp);
format_to!(expn_text, "{}", pp);
if call.to_string().contains("// +tree") {
let tree = format!("{:#?}", parse.syntax_node())
.split_inclusive("\n")
.map(|line| format!("// {}", line))
.collect::<String>();
format_to!(expn_text, "\n{}", tree)
}
}
let range = call.syntax().text_range();
let range: Range<usize> = range.into();
expanded_text.replace_range(range, &expn_text)
}
expect.indent(false);
expect.assert_eq(&expanded_text);
}
@ -97,20 +110,37 @@ fn reindent(indent: IndentLevel, pp: String) -> String {
fn pretty_print_macro_expansion(expn: SyntaxNode) -> String {
let mut res = String::new();
let mut prev_kind = SyntaxKind::EOF;
let mut indent_level = 0;
for token in iter::successors(expn.first_token(), |t| t.next_token()) {
let curr_kind = token.kind();
let space = match (prev_kind, curr_kind) {
_ if prev_kind.is_trivia() || curr_kind.is_trivia() => "",
(T!['{'], T!['}']) => "",
(T![=], _) | (_, T![=]) => " ",
(_, T!['{']) => " ",
(T![;] | T!['}'], _) => "\n",
(T![;] | T!['{'] | T!['}'], _) => "\n",
(_, T!['}']) => "\n",
(IDENT | LIFETIME_IDENT, IDENT | LIFETIME_IDENT) => " ",
(IDENT, _) if curr_kind.is_keyword() => " ",
(_, IDENT) if prev_kind.is_keyword() => " ",
(T![>], IDENT) => " ",
(T![>], _) if curr_kind.is_keyword() => " ",
(T![->], _) | (_, T![->]) => " ",
(T![&&], _) | (_, T![&&]) => " ",
_ => "",
};
match prev_kind {
T!['{'] => indent_level += 1,
T!['}'] => indent_level -= 1,
_ => (),
}
res.push_str(space);
if space == "\n" {
let level = if curr_kind == T!['}'] { indent_level - 1 } else { indent_level };
res.push_str(&" ".repeat(level));
}
prev_kind = curr_kind;
format_to!(res, "{}", token)
}

View File

@ -9,6 +9,45 @@ use expect_test::expect;
use crate::macro_expansion_tests::check;
#[test]
fn mbe_smoke_test() {
check(
r#"
macro_rules! impl_froms {
($e:ident: $($v:ident),*) => {
$(
impl From<$v> for $e {
fn from(it: $v) -> $e { $e::$v(it) }
}
)*
}
}
impl_froms!(TokenTree: Leaf, Subtree);
"#,
expect![[r#"
macro_rules! impl_froms {
($e:ident: $($v:ident),*) => {
$(
impl From<$v> for $e {
fn from(it: $v) -> $e { $e::$v(it) }
}
)*
}
}
impl From<Leaf> for TokenTree {
fn from(it:Leaf) -> TokenTree {
TokenTree::Leaf(it)
}
}
impl From<Subtree> for TokenTree {
fn from(it:Subtree) -> TokenTree {
TokenTree::Subtree(it)
}
}
"#]],
);
}
#[test]
fn expansion_does_not_parse_as_expression() {
check(
@ -52,9 +91,9 @@ fn match_by_first_token_literally() {
check(
r#"
macro_rules! m {
($ i:ident) => ( mod $ i {} );
(= $ i:ident) => ( fn $ i() {} );
(+ $ i:ident) => ( struct $ i; )
($i:ident) => ( mod $i {} );
(= $i:ident) => ( fn $i() {} );
(+ $i:ident) => ( struct $i; )
}
m! { foo }
m! { = bar }
@ -62,9 +101,9 @@ m! { + Baz }
"#,
expect![[r#"
macro_rules! m {
($ i:ident) => ( mod $ i {} );
(= $ i:ident) => ( fn $ i() {} );
(+ $ i:ident) => ( struct $ i; )
($i:ident) => ( mod $i {} );
(= $i:ident) => ( fn $i() {} );
(+ $i:ident) => ( struct $i; )
}
mod foo {}
fn bar() {}
@ -78,9 +117,9 @@ fn match_by_last_token_literally() {
check(
r#"
macro_rules! m {
($ i:ident) => ( mod $ i {} );
($ i:ident =) => ( fn $ i() {} );
($ i:ident +) => ( struct $ i; )
($i:ident) => ( mod $i {} );
($i:ident =) => ( fn $i() {} );
($i:ident +) => ( struct $i; )
}
m! { foo }
m! { bar = }
@ -88,9 +127,9 @@ m! { Baz + }
"#,
expect![[r#"
macro_rules! m {
($ i:ident) => ( mod $ i {} );
($ i:ident =) => ( fn $ i() {} );
($ i:ident +) => ( struct $ i; )
($i:ident) => ( mod $i {} );
($i:ident =) => ( fn $i() {} );
($i:ident +) => ( struct $i; )
}
mod foo {}
fn bar() {}
@ -104,9 +143,9 @@ fn match_by_ident() {
check(
r#"
macro_rules! m {
($ i:ident) => ( mod $ i {} );
(spam $ i:ident) => ( fn $ i() {} );
(eggs $ i:ident) => ( struct $ i; )
($i:ident) => ( mod $i {} );
(spam $i:ident) => ( fn $i() {} );
(eggs $i:ident) => ( struct $i; )
}
m! { foo }
m! { spam bar }
@ -114,9 +153,9 @@ m! { eggs Baz }
"#,
expect![[r#"
macro_rules! m {
($ i:ident) => ( mod $ i {} );
(spam $ i:ident) => ( fn $ i() {} );
(eggs $ i:ident) => ( struct $ i; )
($i:ident) => ( mod $i {} );
(spam $i:ident) => ( fn $i() {} );
(eggs $i:ident) => ( struct $i; )
}
mod foo {}
fn bar() {}
@ -130,9 +169,9 @@ fn match_by_separator_token() {
check(
r#"
macro_rules! m {
($ ($ i:ident),*) => ($ ( mod $ i {} )*);
($ ($ i:ident)#*) => ($ ( fn $ i() {} )*);
($ i:ident ,# $ j:ident) => ( struct $ i; struct $ j; )
($($i:ident),*) => ($(mod $i {} )*);
($($i:ident)#*) => ($(fn $i() {} )*);
($i:ident ,# $ j:ident) => ( struct $i; struct $ j; )
}
m! { foo, bar }
@ -143,9 +182,9 @@ m! { Foo,# Bar }
"#,
expect![[r##"
macro_rules! m {
($ ($ i:ident),*) => ($ ( mod $ i {} )*);
($ ($ i:ident)#*) => ($ ( fn $ i() {} )*);
($ i:ident ,# $ j:ident) => ( struct $ i; struct $ j; )
($($i:ident),*) => ($(mod $i {} )*);
($($i:ident)#*) => ($(fn $i() {} )*);
($i:ident ,# $ j:ident) => ( struct $i; struct $ j; )
}
mod foo {}
@ -159,3 +198,188 @@ struct Bar;
"##]],
);
}
#[test]
fn test_match_group_pattern_with_multiple_defs() {
check(
r#"
macro_rules! m {
($($i:ident),*) => ( impl Bar { $(fn $i() {})* } );
}
m! { foo, bar }
"#,
expect![[r#"
macro_rules! m {
($($i:ident),*) => ( impl Bar { $(fn $i() {})* } );
}
impl Bar {
fn foo() {}
fn bar() {}
}
"#]],
);
}
#[test]
fn test_match_group_pattern_with_multiple_statement() {
check(
r#"
macro_rules! m {
($($i:ident),*) => ( fn baz() { $($i ();)* } );
}
m! { foo, bar }
"#,
expect![[r#"
macro_rules! m {
($($i:ident),*) => ( fn baz() { $($i ();)* } );
}
fn baz() {
foo();
bar();
}
"#]],
)
}
#[test]
fn test_match_group_pattern_with_multiple_statement_without_semi() {
check(
r#"
macro_rules! m {
($($i:ident),*) => ( fn baz() { $($i() );* } );
}
m! { foo, bar }
"#,
expect![[r#"
macro_rules! m {
($($i:ident),*) => ( fn baz() { $($i() );* } );
}
fn baz() {
foo();
bar()
}
"#]],
)
}
#[test]
fn test_match_group_empty_fixed_token() {
check(
r#"
macro_rules! m {
($($i:ident)* #abc) => ( fn baz() { $($i ();)* } );
}
m!{#abc}
"#,
expect![[r##"
macro_rules! m {
($($i:ident)* #abc) => ( fn baz() { $($i ();)* } );
}
fn baz() {}
"##]],
)
}
#[test]
fn test_match_group_in_subtree() {
check(
r#"
macro_rules! m {
(fn $name:ident { $($i:ident)* } ) => ( fn $name() { $($i ();)* } );
}
m! { fn baz { a b } }
"#,
expect![[r#"
macro_rules! m {
(fn $name:ident { $($i:ident)* } ) => ( fn $name() { $($i ();)* } );
}
fn baz() {
a();
b();
}
"#]],
)
}
#[test]
fn test_expr_order() {
check(
r#"
macro_rules! m {
($ i:expr) => { fn bar() { $ i * 3; } }
}
// +tree
m! { 1 + 2 }
"#,
expect![[r#"
macro_rules! m {
($ i:expr) => { fn bar() { $ i * 3; } }
}
fn bar() {
1+2*3;
}
// MACRO_ITEMS@0..15
// FN@0..15
// FN_KW@0..2 "fn"
// NAME@2..5
// IDENT@2..5 "bar"
// PARAM_LIST@5..7
// L_PAREN@5..6 "("
// R_PAREN@6..7 ")"
// BLOCK_EXPR@7..15
// STMT_LIST@7..15
// L_CURLY@7..8 "{"
// EXPR_STMT@8..14
// BIN_EXPR@8..13
// BIN_EXPR@8..11
// LITERAL@8..9
// INT_NUMBER@8..9 "1"
// PLUS@9..10 "+"
// LITERAL@10..11
// INT_NUMBER@10..11 "2"
// STAR@11..12 "*"
// LITERAL@12..13
// INT_NUMBER@12..13 "3"
// SEMICOLON@13..14 ";"
// R_CURLY@14..15 "}"
"#]],
)
}
#[test]
fn test_match_group_with_multichar_sep() {
check(
r#"
macro_rules! m {
(fn $name:ident { $($i:literal)* }) => ( fn $name() -> bool { $($i)&&* } );
}
m! (fn baz { true false } );
"#,
expect![[r#"
macro_rules! m {
(fn $name:ident { $($i:literal)* }) => ( fn $name() -> bool { $($i)&&* } );
}
fn baz() -> bool {
true && false
}
"#]],
);
check(
r#"
macro_rules! m {
(fn $name:ident { $($i:literal)&&* }) => ( fn $name() -> bool { $($i)&&* } );
}
m! (fn baz { true && false } );
"#,
expect![[r#"
macro_rules! m {
(fn $name:ident { $($i:literal)&&* }) => ( fn $name() -> bool { $($i)&&* } );
}
fn baz() -> bool {
true && false
}
"#]],
);
}

View File

@ -8,18 +8,18 @@ use crate::macro_expansion_tests::check;
fn unary_minus_is_a_literal() {
check(
r#"
macro_rules! m { ($x:literal) => (literal!()); ($x:tt) => (not_a_literal!()); }
macro_rules! m { ($x:literal) => (literal!();); ($x:tt) => (not_a_literal!();); }
m!(92);
m!(-92);
m!(-9.2);
m!(--92);
"#,
expect![[r#"
macro_rules! m { ($x:literal) => (literal!()); ($x:tt) => (not_a_literal!()); }
literal!()
literal!()
literal!()
/* error: leftover tokens */not_a_literal!()
macro_rules! m { ($x:literal) => (literal!();); ($x:tt) => (not_a_literal!();); }
literal!();
literal!();
literal!();
/* error: leftover tokens */not_a_literal!();
"#]],
)
}

View File

@ -16,7 +16,7 @@ macro_rules! m {
($($i:ident)*) => ($_);
($($true:ident)*) => ($true);
($($false:ident)*) => ($false);
($) => ($);
($) => (m!($););
}
m!($);
"#,
@ -29,9 +29,9 @@ macro_rules! m {
($($i:ident)*) => ($_);
($($true:ident)*) => ($true);
($($false:ident)*) => ($false);
($) => ($);
($) => (m!($););
}
$
m!($);
"#]],
)
}

View File

@ -25,4 +25,4 @@ mbe = { path = "../mbe", version = "0.0.0" }
limit = { path = "../limit", version = "0.0.0" }
[dev-dependencies]
expect-test = "1.1"
expect-test = "1.2.0-pre.1"

View File

@ -33,7 +33,7 @@ limit = { path = "../limit", version = "0.0.0" }
[dev-dependencies]
test_utils = { path = "../test_utils" }
expect-test = "1.1"
expect-test = "1.2.0-pre.1"
tracing = "0.1"
tracing-subscriber = { version = "0.2", default-features = false, features = [
"env-filter",

View File

@ -38,4 +38,4 @@ hir = { path = "../hir", version = "0.0.0" }
[dev-dependencies]
test_utils = { path = "../test_utils" }
expect-test = "1.1"
expect-test = "1.2.0-pre.1"

View File

@ -25,4 +25,4 @@ hir = { path = "../hir", version = "0.0.0" }
[dev-dependencies]
test_utils = { path = "../test_utils" }
sourcegen = { path = "../sourcegen" }
expect-test = "1.1"
expect-test = "1.2.0-pre.1"

View File

@ -28,7 +28,7 @@ profile = { path = "../profile", version = "0.0.0" }
hir = { path = "../hir", version = "0.0.0" }
[dev-dependencies]
expect-test = "1.1"
expect-test = "1.2.0-pre.1"
xshell = "0.1"
test_utils = { path = "../test_utils" }

View File

@ -31,4 +31,4 @@ limit = { path = "../limit", version = "0.0.0" }
[dev-dependencies]
test_utils = { path = "../test_utils" }
expect-test = "1.1"
expect-test = "1.2.0-pre.1"

View File

@ -23,7 +23,7 @@ hir = { path = "../hir", version = "0.0.0" }
ide_db = { path = "../ide_db", version = "0.0.0" }
[dev-dependencies]
expect-test = "1.1"
expect-test = "1.2.0-pre.1"
test_utils = { path = "../test_utils" }
sourcegen = { path = "../sourcegen" }

View File

@ -21,4 +21,4 @@ hir = { path = "../hir", version = "0.0.0" }
[dev-dependencies]
test_utils = { path = "../test_utils" }
expect-test = "1.1"
expect-test = "1.2.0-pre.1"

View File

@ -12,7 +12,7 @@ doctest = false
cov-mark = "2.0.0-pre.1"
rustc-hash = "1.1.0"
smallvec = "1.2.0"
expect-test = "1.1"
expect-test = "1.2.0-pre.1"
tracing = "0.1"
syntax = { path = "../syntax", version = "0.0.0" }

View File

@ -71,235 +71,6 @@ macro_rules! foobar {
assert_eq!(get_text(tt::TokenId(13), T!['{']), "{");
}
#[test]
fn test_convert_tt() {
parse_macro(r#"
macro_rules! impl_froms {
($e:ident: $($v:ident),*) => {
$(
impl From<$v> for $e {
fn from(it: $v) -> $e {
$e::$v(it)
}
}
)*
}
}
"#)
.assert_expand_tt(
"impl_froms!(TokenTree: Leaf, Subtree);",
"impl From <Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree ::Leaf (it)}} \
impl From <Subtree > for TokenTree {fn from (it : Subtree) -> TokenTree {TokenTree ::Subtree (it)}}"
);
}
#[test]
fn test_convert_tt2() {
parse_macro(
r#"
macro_rules! impl_froms {
($e:ident: $($v:ident),*) => {
$(
impl From<$v> for $e {
fn from(it: $v) -> $e {
$e::$v(it)
}
}
)*
}
}
"#,
)
.assert_expand(
"impl_froms!(TokenTree: Leaf, Subtree);",
r#"
SUBTREE $
IDENT impl 20
IDENT From 21
PUNCH < [joint] 22
IDENT Leaf 53
PUNCH > [alone] 25
IDENT for 26
IDENT TokenTree 51
SUBTREE {} 29
IDENT fn 30
IDENT from 31
SUBTREE () 32
IDENT it 33
PUNCH : [alone] 34
IDENT Leaf 53
PUNCH - [joint] 37
PUNCH > [alone] 38
IDENT TokenTree 51
SUBTREE {} 41
IDENT TokenTree 51
PUNCH : [joint] 44
PUNCH : [joint] 45
IDENT Leaf 53
SUBTREE () 48
IDENT it 49
IDENT impl 20
IDENT From 21
PUNCH < [joint] 22
IDENT Subtree 55
PUNCH > [alone] 25
IDENT for 26
IDENT TokenTree 51
SUBTREE {} 29
IDENT fn 30
IDENT from 31
SUBTREE () 32
IDENT it 33
PUNCH : [alone] 34
IDENT Subtree 55
PUNCH - [joint] 37
PUNCH > [alone] 38
IDENT TokenTree 51
SUBTREE {} 41
IDENT TokenTree 51
PUNCH : [joint] 44
PUNCH : [joint] 45
IDENT Subtree 55
SUBTREE () 48
IDENT it 49
"#,
);
}
#[test]
fn test_expr_order() {
let expanded = parse_macro(
r#"
macro_rules! foo {
($ i:expr) => {
fn bar() { $ i * 2; }
}
}
"#,
)
.expand_items("foo! { 1 + 1}");
let dump = format!("{:#?}", expanded);
assert_eq_text!(
r#"MACRO_ITEMS@0..15
FN@0..15
FN_KW@0..2 "fn"
NAME@2..5
IDENT@2..5 "bar"
PARAM_LIST@5..7
L_PAREN@5..6 "("
R_PAREN@6..7 ")"
BLOCK_EXPR@7..15
STMT_LIST@7..15
L_CURLY@7..8 "{"
EXPR_STMT@8..14
BIN_EXPR@8..13
BIN_EXPR@8..11
LITERAL@8..9
INT_NUMBER@8..9 "1"
PLUS@9..10 "+"
LITERAL@10..11
INT_NUMBER@10..11 "1"
STAR@11..12 "*"
LITERAL@12..13
INT_NUMBER@12..13 "2"
SEMICOLON@13..14 ";"
R_CURLY@14..15 "}""#,
dump.trim()
);
}
#[test]
fn test_match_group_pattern_with_multiple_defs() {
parse_macro(
r#"
macro_rules! foo {
($ ($ i:ident),*) => ( struct Bar { $ (
fn $ i {}
)*} );
}
"#,
)
.assert_expand_items("foo! { foo, bar }", "struct Bar {fn foo {} fn bar {}}");
}
#[test]
fn test_match_group_pattern_with_multiple_statement() {
parse_macro(
r#"
macro_rules! foo {
($ ($ i:ident),*) => ( fn baz { $ (
$ i ();
)*} );
}
"#,
)
.assert_expand_items("foo! { foo, bar }", "fn baz {foo () ; bar () ;}");
}
#[test]
fn test_match_group_pattern_with_multiple_statement_without_semi() {
parse_macro(
r#"
macro_rules! foo {
($ ($ i:ident),*) => ( fn baz { $ (
$i()
);*} );
}
"#,
)
.assert_expand_items("foo! { foo, bar }", "fn baz {foo () ;bar ()}");
}
#[test]
fn test_match_group_empty_fixed_token() {
parse_macro(
r#"
macro_rules! foo {
($ ($ i:ident)* #abc) => ( fn baz { $ (
$ i ();
)*} );
}
"#,
)
.assert_expand_items("foo! {#abc}", "fn baz {}");
}
#[test]
fn test_match_group_in_subtree() {
parse_macro(
r#"
macro_rules! foo {
(fn $name:ident {$($i:ident)*} ) => ( fn $name() { $ (
$ i ();
)*} );
}"#,
)
.assert_expand_items("foo! {fn baz {a b} }", "fn baz () {a () ; b () ;}");
}
#[test]
fn test_match_group_with_multichar_sep() {
parse_macro(
r#"
macro_rules! foo {
(fn $name:ident {$($i:literal)*} ) => ( fn $name() -> bool { $($i)&&*} );
}"#,
)
.assert_expand_items("foo! (fn baz {true true} );", "fn baz () -> bool {true &&true}");
}
#[test]
fn test_match_group_with_multichar_sep2() {
parse_macro(
r#"
macro_rules! foo {
(fn $name:ident {$($i:literal)&&*} ) => ( fn $name() -> bool { $($i)&&*} );
}"#,
)
.assert_expand_items("foo! (fn baz {true && true} );", "fn baz () -> bool {true &&true}");
}
#[test]
fn test_match_group_zero_match() {
parse_macro(

View File

@ -25,7 +25,7 @@ paths = { path = "../paths", version = "0.0.0" }
proc_macro_api = { path = "../proc_macro_api", version = "0.0.0" }
[dev-dependencies]
expect-test = "1.1.0"
expect-test = "1.2.0-pre.1"
# used as proc macro test targets
proc_macro_test = { path = "../proc_macro_test" }

View File

@ -16,7 +16,7 @@ semver = "1"
serde = { version = "1.0.106", features = ["derive"] }
serde_json = "1.0.48"
anyhow = "1.0.26"
expect-test = "1"
expect-test = "1.2.0-pre.1"
la-arena = { version = "0.2.0", path = "../../lib/arena" }
cfg = { path = "../cfg", version = "0.0.0" }

View File

@ -67,7 +67,7 @@ winapi = "0.3.8"
jemallocator = { version = "0.4.1", package = "tikv-jemallocator", optional = true }
[dev-dependencies]
expect-test = "1.1"
expect-test = "1.2.0-pre.1"
xshell = "0.1"
test_utils = { path = "../test_utils" }

View File

@ -26,7 +26,7 @@ profile = { path = "../profile", version = "0.0.0" }
[dev-dependencies]
rayon = "1"
expect-test = "1.1"
expect-test = "1.2.0-pre.1"
proc-macro2 = "1.0.8"
quote = "1.0.2"
ungrammar = "=1.14.8"

View File

@ -89,6 +89,9 @@ impl<T> Parse<T> {
pub fn syntax_node(&self) -> SyntaxNode {
SyntaxNode::new_root(self.green.clone())
}
pub fn errors(&self) -> &[SyntaxError] {
&*self.errors
}
}
impl<T: AstNode> Parse<T> {
@ -100,10 +103,6 @@ impl<T: AstNode> Parse<T> {
T::cast(self.syntax_node()).unwrap()
}
pub fn errors(&self) -> &[SyntaxError] {
&*self.errors
}
pub fn ok(self) -> Result<T, Arc<Vec<SyntaxError>>> {
if self.errors.is_empty() {
Ok(self.tree())