aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock111
-rw-r--r--crates/ra_cli/Cargo.toml2
-rw-r--r--crates/ra_cli/src/help.rs72
-rw-r--r--crates/ra_cli/src/main.rs143
-rw-r--r--crates/ra_hir/src/ids.rs2
-rw-r--r--crates/ra_hir/src/nameres.rs158
-rw-r--r--crates/ra_hir/src/nameres/collector.rs178
-rw-r--r--crates/ra_hir/src/nameres/per_ns.rs59
-rw-r--r--crates/ra_hir/src/nameres/raw.rs4
-rw-r--r--crates/ra_hir/src/nameres/tests.rs46
-rw-r--r--crates/ra_hir/src/nameres/tests/macros.rs119
-rw-r--r--crates/ra_hir/src/resolve.rs14
-rw-r--r--crates/ra_hir/src/ty/tests.rs70
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs12
-rw-r--r--crates/ra_mbe/Cargo.toml4
-rw-r--r--crates/ra_mbe/src/lib.rs4
-rw-r--r--crates/ra_mbe/src/mbe_expander.rs118
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs36
-rw-r--r--crates/ra_mbe/src/tests.rs18
-rw-r--r--crates/ra_parser/src/grammar.rs42
-rw-r--r--crates/ra_parser/src/grammar/attributes.rs4
-rw-r--r--crates/ra_parser/src/grammar/expressions.rs271
-rw-r--r--crates/ra_parser/src/grammar/expressions/atom.rs61
-rw-r--r--crates/ra_parser/src/grammar/items.rs22
-rw-r--r--crates/ra_parser/src/grammar/items/consts.rs2
-rw-r--r--crates/ra_parser/src/grammar/items/nominal.rs12
-rw-r--r--crates/ra_parser/src/grammar/items/traits.rs8
-rw-r--r--crates/ra_parser/src/grammar/items/use_item.rs30
-rw-r--r--crates/ra_parser/src/grammar/params.rs13
-rw-r--r--crates/ra_parser/src/grammar/paths.rs11
-rw-r--r--crates/ra_parser/src/grammar/patterns.rs49
-rw-r--r--crates/ra_parser/src/grammar/type_args.rs29
-rw-r--r--crates/ra_parser/src/grammar/type_params.rs18
-rw-r--r--crates/ra_parser/src/grammar/types.rs24
-rw-r--r--crates/ra_parser/src/parser.rs324
-rw-r--r--crates/ra_syntax/src/tests.rs16
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0054_qual_path_in_type_arg.rs5
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0054_qual_path_in_type_arg.txt126
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0055_dot_dot_dot.rs5
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0055_dot_dot_dot.txt50
-rw-r--r--crates/ra_tools/Cargo.toml2
-rw-r--r--crates/ra_tools/src/help.rs45
-rw-r--r--crates/ra_tools/src/main.rs117
-rw-r--r--docs/user/README.md4
44 files changed, 1401 insertions, 1059 deletions
diff --git a/Cargo.lock b/Cargo.lock
index ceb26961e..4e08a0bd1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -122,7 +122,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
122[[package]] 122[[package]]
123name = "chalk-engine" 123name = "chalk-engine"
124version = "0.9.0" 124version = "0.9.0"
125source = "git+https://github.com/rust-lang/chalk.git#5c6cea8bc02c8bc282223aa12528648b5cd0b6e4" 125source = "git+https://github.com/rust-lang/chalk.git#6a532fc2eb82275a5bda2785c7f5382d555f53f4"
126dependencies = [ 126dependencies = [
127 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git)", 127 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git)",
128 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 128 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -132,7 +132,7 @@ dependencies = [
132[[package]] 132[[package]]
133name = "chalk-ir" 133name = "chalk-ir"
134version = "0.1.0" 134version = "0.1.0"
135source = "git+https://github.com/rust-lang/chalk.git#5c6cea8bc02c8bc282223aa12528648b5cd0b6e4" 135source = "git+https://github.com/rust-lang/chalk.git#6a532fc2eb82275a5bda2785c7f5382d555f53f4"
136dependencies = [ 136dependencies = [
137 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)", 137 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)",
138 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git)", 138 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git)",
@@ -142,7 +142,7 @@ dependencies = [
142[[package]] 142[[package]]
143name = "chalk-macros" 143name = "chalk-macros"
144version = "0.1.1" 144version = "0.1.1"
145source = "git+https://github.com/rust-lang/chalk.git#5c6cea8bc02c8bc282223aa12528648b5cd0b6e4" 145source = "git+https://github.com/rust-lang/chalk.git#6a532fc2eb82275a5bda2785c7f5382d555f53f4"
146dependencies = [ 146dependencies = [
147 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 147 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
148] 148]
@@ -150,7 +150,7 @@ dependencies = [
150[[package]] 150[[package]]
151name = "chalk-rust-ir" 151name = "chalk-rust-ir"
152version = "0.1.0" 152version = "0.1.0"
153source = "git+https://github.com/rust-lang/chalk.git#5c6cea8bc02c8bc282223aa12528648b5cd0b6e4" 153source = "git+https://github.com/rust-lang/chalk.git#6a532fc2eb82275a5bda2785c7f5382d555f53f4"
154dependencies = [ 154dependencies = [
155 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)", 155 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)",
156 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)", 156 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)",
@@ -160,7 +160,7 @@ dependencies = [
160[[package]] 160[[package]]
161name = "chalk-solve" 161name = "chalk-solve"
162version = "0.1.0" 162version = "0.1.0"
163source = "git+https://github.com/rust-lang/chalk.git#5c6cea8bc02c8bc282223aa12528648b5cd0b6e4" 163source = "git+https://github.com/rust-lang/chalk.git#6a532fc2eb82275a5bda2785c7f5382d555f53f4"
164dependencies = [ 164dependencies = [
165 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)", 165 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)",
166 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)", 166 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)",
@@ -168,7 +168,6 @@ dependencies = [
168 "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)", 168 "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)",
169 "derive-new 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", 169 "derive-new 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
170 "ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", 170 "ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
171 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
172 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 171 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
173 "petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", 172 "petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
174 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 173 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -186,16 +185,6 @@ dependencies = [
186] 185]
187 186
188[[package]] 187[[package]]
189name = "clap"
190version = "2.33.0"
191source = "registry+https://github.com/rust-lang/crates.io-index"
192dependencies = [
193 "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
194 "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
195 "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
196]
197
198[[package]]
199name = "clicolors-control" 188name = "clicolors-control"
200version = "1.0.1" 189version = "1.0.1"
201source = "registry+https://github.com/rust-lang/crates.io-index" 190source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -333,26 +322,6 @@ version = "0.3.6"
333source = "registry+https://github.com/rust-lang/crates.io-index" 322source = "registry+https://github.com/rust-lang/crates.io-index"
334 323
335[[package]] 324[[package]]
336name = "failure"
337version = "0.1.5"
338source = "registry+https://github.com/rust-lang/crates.io-index"
339dependencies = [
340 "backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)",
341 "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
342]
343
344[[package]]
345name = "failure_derive"
346version = "0.1.5"
347source = "registry+https://github.com/rust-lang/crates.io-index"
348dependencies = [
349 "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
350 "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
351 "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
352 "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
353]
354
355[[package]]
356name = "filetime" 325name = "filetime"
357version = "0.2.7" 326version = "0.2.7"
358source = "registry+https://github.com/rust-lang/crates.io-index" 327source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -859,6 +828,11 @@ dependencies = [
859] 828]
860 829
861[[package]] 830[[package]]
831name = "pico-args"
832version = "0.2.0"
833source = "registry+https://github.com/rust-lang/crates.io-index"
834
835[[package]]
862name = "ppv-lite86" 836name = "ppv-lite86"
863version = "0.2.5" 837version = "0.2.5"
864source = "registry+https://github.com/rust-lang/crates.io-index" 838source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -875,14 +849,6 @@ dependencies = [
875 849
876[[package]] 850[[package]]
877name = "proc-macro2" 851name = "proc-macro2"
878version = "0.4.30"
879source = "registry+https://github.com/rust-lang/crates.io-index"
880dependencies = [
881 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
882]
883
884[[package]]
885name = "proc-macro2"
886version = "1.0.2" 852version = "1.0.2"
887source = "registry+https://github.com/rust-lang/crates.io-index" 853source = "registry+https://github.com/rust-lang/crates.io-index"
888dependencies = [ 854dependencies = [
@@ -913,14 +879,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
913 879
914[[package]] 880[[package]]
915name = "quote" 881name = "quote"
916version = "0.6.13"
917source = "registry+https://github.com/rust-lang/crates.io-index"
918dependencies = [
919 "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
920]
921
922[[package]]
923name = "quote"
924version = "1.0.2" 882version = "1.0.2"
925source = "registry+https://github.com/rust-lang/crates.io-index" 883source = "registry+https://github.com/rust-lang/crates.io-index"
926dependencies = [ 884dependencies = [
@@ -967,9 +925,9 @@ dependencies = [
967name = "ra_cli" 925name = "ra_cli"
968version = "0.1.0" 926version = "0.1.0"
969dependencies = [ 927dependencies = [
970 "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
971 "flexi_logger 0.14.3 (registry+https://github.com/rust-lang/crates.io-index)", 928 "flexi_logger 0.14.3 (registry+https://github.com/rust-lang/crates.io-index)",
972 "indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 929 "indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
930 "pico-args 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
973 "ra_batch 0.1.0", 931 "ra_batch 0.1.0",
974 "ra_db 0.1.0", 932 "ra_db 0.1.0",
975 "ra_hir 0.1.0", 933 "ra_hir 0.1.0",
@@ -1088,6 +1046,7 @@ dependencies = [
1088 "ra_tt 0.1.0", 1046 "ra_tt 0.1.0",
1089 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1047 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1090 "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", 1048 "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
1049 "test_utils 0.1.0",
1091] 1050]
1092 1051
1093[[package]] 1052[[package]]
@@ -1148,8 +1107,8 @@ dependencies = [
1148name = "ra_tools" 1107name = "ra_tools"
1149version = "0.1.0" 1108version = "0.1.0"
1150dependencies = [ 1109dependencies = [
1151 "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
1152 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 1110 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
1111 "pico-args 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1153 "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1112 "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1154 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1113 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1155 "ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 1114 "ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1587,16 +1546,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1587 1546
1588[[package]] 1547[[package]]
1589name = "syn" 1548name = "syn"
1590version = "0.15.44"
1591source = "registry+https://github.com/rust-lang/crates.io-index"
1592dependencies = [
1593 "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
1594 "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
1595 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
1596]
1597
1598[[package]]
1599name = "syn"
1600version = "1.0.5" 1549version = "1.0.5"
1601source = "registry+https://github.com/rust-lang/crates.io-index" 1550source = "registry+https://github.com/rust-lang/crates.io-index"
1602dependencies = [ 1551dependencies = [
@@ -1606,17 +1555,6 @@ dependencies = [
1606] 1555]
1607 1556
1608[[package]] 1557[[package]]
1609name = "synstructure"
1610version = "0.10.2"
1611source = "registry+https://github.com/rust-lang/crates.io-index"
1612dependencies = [
1613 "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
1614 "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
1615 "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
1616 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
1617]
1618
1619[[package]]
1620name = "tempfile" 1558name = "tempfile"
1621version = "3.1.0" 1559version = "3.1.0"
1622source = "registry+https://github.com/rust-lang/crates.io-index" 1560source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1652,14 +1590,6 @@ version = "0.1.9"
1652source = "registry+https://github.com/rust-lang/crates.io-index" 1590source = "registry+https://github.com/rust-lang/crates.io-index"
1653 1591
1654[[package]] 1592[[package]]
1655name = "textwrap"
1656version = "0.11.0"
1657source = "registry+https://github.com/rust-lang/crates.io-index"
1658dependencies = [
1659 "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
1660]
1661
1662[[package]]
1663name = "thread_local" 1593name = "thread_local"
1664version = "0.3.6" 1594version = "0.3.6"
1665source = "registry+https://github.com/rust-lang/crates.io-index" 1595source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1721,11 +1651,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1721 1651
1722[[package]] 1652[[package]]
1723name = "unicode-xid" 1653name = "unicode-xid"
1724version = "0.1.0"
1725source = "registry+https://github.com/rust-lang/crates.io-index"
1726
1727[[package]]
1728name = "unicode-xid"
1729version = "0.2.0" 1654version = "0.2.0"
1730source = "registry+https://github.com/rust-lang/crates.io-index" 1655source = "registry+https://github.com/rust-lang/crates.io-index"
1731 1656
@@ -1858,7 +1783,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1858"checksum chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)" = "<none>" 1783"checksum chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)" = "<none>"
1859"checksum chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git)" = "<none>" 1784"checksum chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git)" = "<none>"
1860"checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" 1785"checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68"
1861"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
1862"checksum clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e" 1786"checksum clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e"
1863"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 1787"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
1864"checksum console 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b147390a412132d75d10dd3b7b175a69cf5fd95032f7503c7091b8831ba10242" 1788"checksum console 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b147390a412132d75d10dd3b7b175a69cf5fd95032f7503c7091b8831ba10242"
@@ -1875,8 +1799,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1875"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" 1799"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b"
1876"checksum ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dc01d68e08ca384955a3aeba9217102ca1aa85b6e168639bf27739f1d749d87" 1800"checksum ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dc01d68e08ca384955a3aeba9217102ca1aa85b6e168639bf27739f1d749d87"
1877"checksum encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 1801"checksum encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
1878"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
1879"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
1880"checksum filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd7380b54ced79dda72ecc35cc4fbbd1da6bba54afaa37e96fd1c2a308cd469" 1802"checksum filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd7380b54ced79dda72ecc35cc4fbbd1da6bba54afaa37e96fd1c2a308cd469"
1881"checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" 1803"checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33"
1882"checksum flexi_logger 0.14.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66473c1b6a0d2a72f6ed983d33021a4c744a1d179e6f4265867b7d0a9dd679c5" 1804"checksum flexi_logger 0.14.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66473c1b6a0d2a72f6ed983d33021a4c744a1d179e6f4265867b7d0a9dd679c5"
@@ -1938,13 +1860,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1938"checksum paste-impl 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4214c9e912ef61bf42b81ba9a47e8aad1b2ffaf739ab162bf96d1e011f54e6c5" 1860"checksum paste-impl 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4214c9e912ef61bf42b81ba9a47e8aad1b2ffaf739ab162bf96d1e011f54e6c5"
1939"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 1861"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
1940"checksum petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3659d1ee90221741f65dd128d9998311b0e40c5d3c23a62445938214abce4f" 1862"checksum petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3659d1ee90221741f65dd128d9998311b0e40c5d3c23a62445938214abce4f"
1863"checksum pico-args 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2fce25154205cf4360b456fd7d48994afe20663b77e3bd3d0a353a2fccf7f22c"
1941"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" 1864"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b"
1942"checksum proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e688f31d92ffd7c1ddc57a1b4e6d773c0f2a14ee437a4b0a4f5a69c80eb221c8" 1865"checksum proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e688f31d92ffd7c1ddc57a1b4e6d773c0f2a14ee437a4b0a4f5a69c80eb221c8"
1943"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
1944"checksum proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "175a40b9cf564ce9bf050654633dbf339978706b8ead1a907bb970b63185dd95" 1866"checksum proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "175a40b9cf564ce9bf050654633dbf339978706b8ead1a907bb970b63185dd95"
1945"checksum proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf147e022eacf0c8a054ab864914a7602618adba841d800a9a9868a5237a529f" 1867"checksum proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf147e022eacf0c8a054ab864914a7602618adba841d800a9a9868a5237a529f"
1946"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" 1868"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
1947"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
1948"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" 1869"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
1949"checksum ra_vfs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdf6a0926414eb0c00866eb9274894182302f879cd06b5459c1d8ee7f1234aed" 1870"checksum ra_vfs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdf6a0926414eb0c00866eb9274894182302f879cd06b5459c1d8ee7f1234aed"
1950"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" 1871"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
@@ -1993,13 +1914,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1993"checksum smol_str 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "590700be3630457c56f8c73c0ea39881476ad7076cd84057d44f4f38f79914fb" 1914"checksum smol_str 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "590700be3630457c56f8c73c0ea39881476ad7076cd84057d44f4f38f79914fb"
1994"checksum stacker 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fb79482f57cf598af52094ec4cc3b3c42499d3ce5bd426f2ac41515b7e57404b" 1915"checksum stacker 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fb79482f57cf598af52094ec4cc3b3c42499d3ce5bd426f2ac41515b7e57404b"
1995"checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f" 1916"checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f"
1996"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
1997"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" 1917"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
1998"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f"
1999"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" 1918"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
2000"checksum termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625" 1919"checksum termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625"
2001"checksum text_unit 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e08bbcb7a3adbda0eb23431206b653bdad3d8dea311e72d36bf2215e27a42579" 1920"checksum text_unit 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e08bbcb7a3adbda0eb23431206b653bdad3d8dea311e72d36bf2215e27a42579"
2002"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
2003"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" 1921"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
2004"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865" 1922"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865"
2005"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" 1923"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
@@ -2008,7 +1926,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
2008"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" 1926"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426"
2009"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9" 1927"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9"
2010"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" 1928"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20"
2011"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
2012"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" 1929"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
2013"checksum url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75b414f6c464c879d7f9babf951f23bc3743fb7313c081b2e6ca719067ea9d61" 1930"checksum url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75b414f6c464c879d7f9babf951f23bc3743fb7313c081b2e6ca719067ea9d61"
2014"checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" 1931"checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a"
diff --git a/crates/ra_cli/Cargo.toml b/crates/ra_cli/Cargo.toml
index 205dd223b..d42ac3ad4 100644
--- a/crates/ra_cli/Cargo.toml
+++ b/crates/ra_cli/Cargo.toml
@@ -6,7 +6,7 @@ authors = ["rust-analyzer developers"]
6publish = false 6publish = false
7 7
8[dependencies] 8[dependencies]
9clap = { version = "2.32.0", default-features = false } 9pico-args = "0.2.0"
10flexi_logger = "0.14.0" 10flexi_logger = "0.14.0"
11indicatif = "0.11.0" 11indicatif = "0.11.0"
12 12
diff --git a/crates/ra_cli/src/help.rs b/crates/ra_cli/src/help.rs
new file mode 100644
index 000000000..5171578f0
--- /dev/null
+++ b/crates/ra_cli/src/help.rs
@@ -0,0 +1,72 @@
1pub const GLOBAL_HELP: &str = "ra-cli
2
3USAGE:
4 ra_cli <SUBCOMMAND>
5
6FLAGS:
7 -h, --help Prints help information
8
9SUBCOMMANDS:
10 analysis-bench
11 analysis-stats
12 highlight
13 parse
14 symbols";
15
16pub const ANALYSIS_BENCH_HELP: &str = "ra_cli-analysis-bench
17
18USAGE:
19 ra_cli analysis-bench [FLAGS] [OPTIONS] [PATH]
20
21FLAGS:
22 -h, --help Prints help information
23 -v, --verbose
24
25OPTIONS:
26 --complete <PATH:LINE:COLUMN> Compute completions at this location
27 --highlight <PATH> Hightlight this file
28
29ARGS:
30 <PATH> Project to analyse";
31
32pub const ANALYSIS_STATS_HELP: &str = "ra-cli-analysis-stats
33
34USAGE:
35 ra_cli analysis-stats [FLAGS] [OPTIONS] [PATH]
36
37FLAGS:
38 -h, --help Prints help information
39 --memory-usage
40 -v, --verbose
41
42OPTIONS:
43 -o <ONLY>
44
45ARGS:
46 <PATH>";
47
48pub const HIGHLIGHT_HELP: &str = "ra-cli-highlight
49
50USAGE:
51 ra_cli highlight [FLAGS]
52
53FLAGS:
54 -h, --help Prints help information
55 -r, --rainbow";
56
57pub const SYMBOLS_HELP: &str = "ra-cli-symbols
58
59USAGE:
60 ra_cli highlight [FLAGS]
61
62FLAGS:
63 -h, --help Prints help inforamtion";
64
65pub const PARSE_HELP: &str = "ra-cli-parse
66
67USAGE:
68 ra_cli parse [FLAGS]
69
70FLAGS:
71 -h, --help Prints help inforamtion
72 --no-dump";
diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs
index de8191ca3..e6334cf56 100644
--- a/crates/ra_cli/src/main.rs
+++ b/crates/ra_cli/src/main.rs
@@ -1,10 +1,11 @@
1mod analysis_stats; 1mod analysis_stats;
2mod analysis_bench; 2mod analysis_bench;
3mod help;
3 4
4use std::{error::Error, io::Read}; 5use std::{error::Error, fmt::Write, io::Read};
5 6
6use clap::{App, Arg, SubCommand};
7use flexi_logger::Logger; 7use flexi_logger::Logger;
8use pico_args::Arguments;
8use ra_ide_api::{file_structure, Analysis}; 9use ra_ide_api::{file_structure, Analysis};
9use ra_prof::profile; 10use ra_prof::profile;
10use ra_syntax::{AstNode, SourceFile}; 11use ra_syntax::{AstNode, SourceFile};
@@ -13,77 +14,89 @@ type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>;
13 14
14fn main() -> Result<()> { 15fn main() -> Result<()> {
15 Logger::with_env().start()?; 16 Logger::with_env().start()?;
16 let matches = App::new("ra-cli") 17
17 .setting(clap::AppSettings::SubcommandRequiredElseHelp) 18 let subcommand = match std::env::args_os().nth(1) {
18 .subcommand(SubCommand::with_name("parse").arg(Arg::with_name("no-dump").long("--no-dump"))) 19 None => {
19 .subcommand(SubCommand::with_name("symbols")) 20 eprintln!("{}", help::GLOBAL_HELP);
20 .subcommand( 21 return Ok(());
21 SubCommand::with_name("highlight") 22 }
22 .arg(Arg::with_name("rainbow").short("r").long("rainbow")), 23 Some(s) => s,
23 ) 24 };
24 .subcommand( 25 let mut matches = Arguments::from_vec(std::env::args_os().skip(2).collect());
25 SubCommand::with_name("analysis-stats") 26
26 .arg(Arg::with_name("verbose").short("v").long("verbose")) 27 match &*subcommand.to_string_lossy() {
27 .arg(Arg::with_name("memory-usage").long("memory-usage")) 28 "parse" => {
28 .arg(Arg::with_name("only").short("o").takes_value(true)) 29 if matches.contains(["-h", "--help"]) {
29 .arg(Arg::with_name("path")), 30 eprintln!("{}", help::PARSE_HELP);
30 ) 31 return Ok(());
31 .subcommand( 32 }
32 SubCommand::with_name("analysis-bench") 33 let no_dump = matches.contains("--no-dump");
33 .arg(Arg::with_name("verbose").short("v").long("verbose")) 34 matches.finish().or_else(handle_extra_flags)?;
34 .arg( 35
35 Arg::with_name("highlight")
36 .long("highlight")
37 .takes_value(true)
38 .conflicts_with("complete")
39 .value_name("PATH")
40 .help("highlight this file"),
41 )
42 .arg(
43 Arg::with_name("complete")
44 .long("complete")
45 .takes_value(true)
46 .conflicts_with("highlight")
47 .value_name("PATH:LINE:COLUMN")
48 .help("compute completions at this location"),
49 )
50 .arg(Arg::with_name("path").value_name("PATH").help("project to analyze")),
51 )
52 .get_matches();
53 match matches.subcommand() {
54 ("parse", Some(matches)) => {
55 let _p = profile("parsing"); 36 let _p = profile("parsing");
56 let file = file()?; 37 let file = file()?;
57 if !matches.is_present("no-dump") { 38 if !no_dump {
58 println!("{:#?}", file.syntax()); 39 println!("{:#?}", file.syntax());
59 } 40 }
60 std::mem::forget(file); 41 std::mem::forget(file);
61 } 42 }
62 ("symbols", _) => { 43 "symbols" => {
44 if matches.contains(["-h", "--help"]) {
45 eprintln!("{}", help::SYMBOLS_HELP);
46 return Ok(());
47 }
48 matches.finish().or_else(handle_extra_flags)?;
63 let file = file()?; 49 let file = file()?;
64 for s in file_structure(&file) { 50 for s in file_structure(&file) {
65 println!("{:?}", s); 51 println!("{:?}", s);
66 } 52 }
67 } 53 }
68 ("highlight", Some(matches)) => { 54 "highlight" => {
55 if matches.contains(["-h", "--help"]) {
56 eprintln!("{}", help::HIGHLIGHT_HELP);
57 return Ok(());
58 }
59 let rainbow_opt = matches.contains(["-r", "--rainbow"]);
60 matches.finish().or_else(handle_extra_flags)?;
69 let (analysis, file_id) = Analysis::from_single_file(read_stdin()?); 61 let (analysis, file_id) = Analysis::from_single_file(read_stdin()?);
70 let html = analysis.highlight_as_html(file_id, matches.is_present("rainbow")).unwrap(); 62 let html = analysis.highlight_as_html(file_id, rainbow_opt).unwrap();
71 println!("{}", html); 63 println!("{}", html);
72 } 64 }
73 ("analysis-stats", Some(matches)) => { 65 "analysis-stats" => {
74 let verbose = matches.is_present("verbose"); 66 if matches.contains(["-h", "--help"]) {
75 let memory_usage = matches.is_present("memory-usage"); 67 eprintln!("{}", help::ANALYSIS_STATS_HELP);
76 let path = matches.value_of("path").unwrap_or(""); 68 return Ok(());
77 let only = matches.value_of("only"); 69 }
78 analysis_stats::run(verbose, memory_usage, path.as_ref(), only)?; 70 let verbose = matches.contains(["-v", "--verbose"]);
71 let memory_usage = matches.contains("--memory-usage");
72 let path: String = matches.value_from_str("--path")?.unwrap_or_default();
73 let only = matches.value_from_str(["-o", "--only"])?.map(|v: String| v.to_owned());
74 matches.finish().or_else(handle_extra_flags)?;
75 analysis_stats::run(
76 verbose,
77 memory_usage,
78 path.as_ref(),
79 only.as_ref().map(String::as_ref),
80 )?;
79 } 81 }
80 ("analysis-bench", Some(matches)) => { 82 "analysis-bench" => {
81 let verbose = matches.is_present("verbose"); 83 if matches.contains(["-h", "--help"]) {
82 let path = matches.value_of("path").unwrap_or(""); 84 eprintln!("{}", help::ANALYSIS_BENCH_HELP);
83 let op = if let Some(path) = matches.value_of("highlight") { 85 return Ok(());
86 }
87 let verbose = matches.contains(["-v", "--verbose"]);
88 let path: String = matches.value_from_str("--path")?.unwrap_or_default();
89 let highlight_path = matches.value_from_str("--highlight")?;
90 let complete_path = matches.value_from_str("--complete")?;
91 if highlight_path.is_some() && complete_path.is_some() {
92 panic!("either --highlight or --complete must be set, not both")
93 }
94 let op = if let Some(path) = highlight_path {
95 let path: String = path;
84 analysis_bench::Op::Highlight { path: path.into() } 96 analysis_bench::Op::Highlight { path: path.into() }
85 } else if let Some(path_line_col) = matches.value_of("complete") { 97 } else if let Some(path_line_col) = complete_path {
86 let (path_line, column) = rsplit_at_char(path_line_col, ':')?; 98 let path_line_col: String = path_line_col;
99 let (path_line, column) = rsplit_at_char(path_line_col.as_str(), ':')?;
87 let (path, line) = rsplit_at_char(path_line, ':')?; 100 let (path, line) = rsplit_at_char(path_line, ':')?;
88 analysis_bench::Op::Complete { 101 analysis_bench::Op::Complete {
89 path: path.into(), 102 path: path.into(),
@@ -93,13 +106,27 @@ fn main() -> Result<()> {
93 } else { 106 } else {
94 panic!("either --highlight or --complete must be set") 107 panic!("either --highlight or --complete must be set")
95 }; 108 };
109 matches.finish().or_else(handle_extra_flags)?;
96 analysis_bench::run(verbose, path.as_ref(), op)?; 110 analysis_bench::run(verbose, path.as_ref(), op)?;
97 } 111 }
98 _ => unreachable!(), 112 _ => eprintln!("{}", help::GLOBAL_HELP),
99 } 113 }
100 Ok(()) 114 Ok(())
101} 115}
102 116
117fn handle_extra_flags(e: pico_args::Error) -> Result<()> {
118 if let pico_args::Error::UnusedArgsLeft(flags) = e {
119 let mut invalid_flags = String::new();
120 for flag in flags {
121 write!(&mut invalid_flags, "{}, ", flag)?;
122 }
123 let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2);
124 Err(format!("Invalid flags: {}", invalid_flags).into())
125 } else {
126 Err(e.to_string().into())
127 }
128}
129
103fn file() -> Result<SourceFile> { 130fn file() -> Result<SourceFile> {
104 let text = read_stdin()?; 131 let text = read_stdin()?;
105 Ok(SourceFile::parse(&text).tree()) 132 Ok(SourceFile::parse(&text).tree())
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index e0d0d4209..9ea4e695d 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -90,7 +90,7 @@ impl HirFileId {
90 }) 90 })
91 .ok()?; 91 .ok()?;
92 match macro_file.macro_file_kind { 92 match macro_file.macro_file_kind {
93 MacroFileKind::Items => Some(Parse::to_syntax(mbe::token_tree_to_ast_item_list(&tt))), 93 MacroFileKind::Items => mbe::token_tree_to_items(&tt).ok().map(Parse::to_syntax),
94 MacroFileKind::Expr => mbe::token_tree_to_expr(&tt).ok().map(Parse::to_syntax), 94 MacroFileKind::Expr => mbe::token_tree_to_expr(&tt).ok().map(Parse::to_syntax),
95 } 95 }
96 } 96 }
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 74546e5e2..7488d75a5 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -67,7 +67,6 @@ use test_utils::tested_by;
67use crate::{ 67use crate::{
68 db::{AstDatabase, DefDatabase}, 68 db::{AstDatabase, DefDatabase},
69 diagnostics::DiagnosticSink, 69 diagnostics::DiagnosticSink,
70 either::Either,
71 ids::MacroDefId, 70 ids::MacroDefId,
72 nameres::diagnostics::DefDiagnostic, 71 nameres::diagnostics::DefDiagnostic,
73 AstId, BuiltinType, Crate, HirFileId, MacroDef, Module, ModuleDef, Name, Path, PathKind, Trait, 72 AstId, BuiltinType, Crate, HirFileId, MacroDef, Module, ModuleDef, Name, Path, PathKind, Trait,
@@ -105,8 +104,6 @@ pub struct CrateDefMap {
105 /// However, do we want to put it as a global variable? 104 /// However, do we want to put it as a global variable?
106 poison_macros: FxHashSet<MacroDefId>, 105 poison_macros: FxHashSet<MacroDefId>,
107 106
108 exported_macros: FxHashMap<Name, MacroDefId>,
109
110 diagnostics: Vec<DefDiagnostic>, 107 diagnostics: Vec<DefDiagnostic>,
111} 108}
112 109
@@ -138,12 +135,6 @@ pub(crate) struct ModuleData {
138#[derive(Debug, Default, PartialEq, Eq, Clone)] 135#[derive(Debug, Default, PartialEq, Eq, Clone)]
139pub struct ModuleScope { 136pub struct ModuleScope {
140 items: FxHashMap<Name, Resolution>, 137 items: FxHashMap<Name, Resolution>,
141 /// Macros in current module scoped
142 ///
143 /// This scope works exactly the same way that item scoping does.
144 /// Macro invocation with quantified path will search in it.
145 /// See details below.
146 macros: FxHashMap<Name, MacroDef>,
147 /// Macros visable in current module in legacy textual scope 138 /// Macros visable in current module in legacy textual scope
148 /// 139 ///
149 /// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first. 140 /// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first.
@@ -152,6 +143,10 @@ pub struct ModuleScope {
152 /// and only normal scoped `macros` will be searched in. 143 /// and only normal scoped `macros` will be searched in.
153 /// 144 ///
154 /// Note that this automatically inherit macros defined textually before the definition of module itself. 145 /// Note that this automatically inherit macros defined textually before the definition of module itself.
146 ///
147 /// Module scoped macros will be inserted into `items` instead of here.
148 // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
149 // be all resolved to the last one defined if shadowing happens.
155 legacy_macros: FxHashMap<Name, MacroDef>, 150 legacy_macros: FxHashMap<Name, MacroDef>,
156} 151}
157 152
@@ -164,35 +159,43 @@ static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| {
164 .collect() 159 .collect()
165}); 160});
166 161
162/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
163/// Other methods will only resolve values, types and module scoped macros only.
167impl ModuleScope { 164impl ModuleScope {
168 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, &'a Resolution)> + 'a { 165 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, &'a Resolution)> + 'a {
169 //FIXME: shadowing 166 //FIXME: shadowing
170 self.items.iter().chain(BUILTIN_SCOPE.iter()) 167 self.items.iter().chain(BUILTIN_SCOPE.iter())
171 } 168 }
169
170 /// Iterate over all module scoped macros
171 pub fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDef)> + 'a {
172 self.items
173 .iter()
174 .filter_map(|(name, res)| res.def.get_macros().map(|macro_| (name, macro_)))
175 }
176
177 /// Iterate over all legacy textual scoped macros visable at the end of the module
178 pub fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDef)> + 'a {
179 self.legacy_macros.iter().map(|(name, def)| (name, *def))
180 }
181
182 /// Get a name from current module scope, legacy macros are not included
172 pub fn get(&self, name: &Name) -> Option<&Resolution> { 183 pub fn get(&self, name: &Name) -> Option<&Resolution> {
173 self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name)) 184 self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name))
174 } 185 }
186
175 pub fn traits<'a>(&'a self) -> impl Iterator<Item = Trait> + 'a { 187 pub fn traits<'a>(&'a self) -> impl Iterator<Item = Trait> + 'a {
176 self.items.values().filter_map(|r| match r.def.take_types() { 188 self.items.values().filter_map(|r| match r.def.take_types() {
177 Some(ModuleDef::Trait(t)) => Some(t), 189 Some(ModuleDef::Trait(t)) => Some(t),
178 _ => None, 190 _ => None,
179 }) 191 })
180 } 192 }
181 /// It resolves in module scope. Textual scoped macros are ignored here. 193
182 fn get_item_or_macro(&self, name: &Name) -> Option<ItemOrMacro> {
183 match (self.get(name), self.macros.get(name)) {
184 (Some(item), _) if !item.def.is_none() => Some(Either::A(item.def)),
185 (_, Some(macro_)) => Some(Either::B(*macro_)),
186 _ => None,
187 }
188 }
189 fn get_legacy_macro(&self, name: &Name) -> Option<MacroDef> { 194 fn get_legacy_macro(&self, name: &Name) -> Option<MacroDef> {
190 self.legacy_macros.get(name).copied() 195 self.legacy_macros.get(name).copied()
191 } 196 }
192} 197}
193 198
194type ItemOrMacro = Either<PerNs<ModuleDef>, MacroDef>;
195
196#[derive(Debug, Clone, PartialEq, Eq, Default)] 199#[derive(Debug, Clone, PartialEq, Eq, Default)]
197pub struct Resolution { 200pub struct Resolution {
198 /// None for unresolved 201 /// None for unresolved
@@ -201,20 +204,26 @@ pub struct Resolution {
201 pub import: Option<ImportId>, 204 pub import: Option<ImportId>,
202} 205}
203 206
207impl Resolution {
208 pub(crate) fn from_macro(macro_: MacroDef) -> Self {
209 Resolution { def: PerNs::macros(macro_), import: None }
210 }
211}
212
204#[derive(Debug, Clone)] 213#[derive(Debug, Clone)]
205struct ResolvePathResult { 214struct ResolvePathResult {
206 resolved_def: ItemOrMacro, 215 resolved_def: PerNs<ModuleDef>,
207 segment_index: Option<usize>, 216 segment_index: Option<usize>,
208 reached_fixedpoint: ReachedFixedPoint, 217 reached_fixedpoint: ReachedFixedPoint,
209} 218}
210 219
211impl ResolvePathResult { 220impl ResolvePathResult {
212 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { 221 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
213 ResolvePathResult::with(Either::A(PerNs::none()), reached_fixedpoint, None) 222 ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None)
214 } 223 }
215 224
216 fn with( 225 fn with(
217 resolved_def: ItemOrMacro, 226 resolved_def: PerNs<ModuleDef>,
218 reached_fixedpoint: ReachedFixedPoint, 227 reached_fixedpoint: ReachedFixedPoint,
219 segment_index: Option<usize>, 228 segment_index: Option<usize>,
220 ) -> ResolvePathResult { 229 ) -> ResolvePathResult {
@@ -234,21 +243,6 @@ enum ReachedFixedPoint {
234 No, 243 No,
235} 244}
236 245
237/// helper function for select item or macro to use
238fn or(left: ItemOrMacro, right: ItemOrMacro) -> ItemOrMacro {
239 match (left, right) {
240 (Either::A(s), Either::A(o)) => Either::A(s.or(o)),
241 (Either::B(s), _) => Either::B(s),
242 (Either::A(s), Either::B(o)) => {
243 if !s.is_none() {
244 Either::A(s)
245 } else {
246 Either::B(o)
247 }
248 }
249 }
250}
251
252impl CrateDefMap { 246impl CrateDefMap {
253 pub(crate) fn crate_def_map_query( 247 pub(crate) fn crate_def_map_query(
254 // Note that this doesn't have `+ AstDatabase`! 248 // Note that this doesn't have `+ AstDatabase`!
@@ -269,7 +263,6 @@ impl CrateDefMap {
269 root, 263 root,
270 modules, 264 modules,
271 poison_macros: FxHashSet::default(), 265 poison_macros: FxHashSet::default(),
272 exported_macros: FxHashMap::default(),
273 diagnostics: Vec::new(), 266 diagnostics: Vec::new(),
274 } 267 }
275 }; 268 };
@@ -328,16 +321,6 @@ impl CrateDefMap {
328 path: &Path, 321 path: &Path,
329 ) -> (PerNs<ModuleDef>, Option<usize>) { 322 ) -> (PerNs<ModuleDef>, Option<usize>) {
330 let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path); 323 let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path);
331 (res.resolved_def.a().unwrap_or_else(PerNs::none), res.segment_index)
332 }
333
334 pub(crate) fn resolve_path_with_macro(
335 &self,
336 db: &impl DefDatabase,
337 original_module: CrateModuleId,
338 path: &Path,
339 ) -> (ItemOrMacro, Option<usize>) {
340 let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path);
341 (res.resolved_def, res.segment_index) 324 (res.resolved_def, res.segment_index)
342 } 325 }
343 326
@@ -351,13 +334,13 @@ impl CrateDefMap {
351 path: &Path, 334 path: &Path,
352 ) -> ResolvePathResult { 335 ) -> ResolvePathResult {
353 let mut segments = path.segments.iter().enumerate(); 336 let mut segments = path.segments.iter().enumerate();
354 let mut curr_per_ns: ItemOrMacro = match path.kind { 337 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind {
355 PathKind::Crate => { 338 PathKind::Crate => {
356 Either::A(PerNs::types(Module { krate: self.krate, module_id: self.root }.into())) 339 PerNs::types(Module { krate: self.krate, module_id: self.root }.into())
340 }
341 PathKind::Self_ => {
342 PerNs::types(Module { krate: self.krate, module_id: original_module }.into())
357 } 343 }
358 PathKind::Self_ => Either::A(PerNs::types(
359 Module { krate: self.krate, module_id: original_module }.into(),
360 )),
361 // plain import or absolute path in 2015: crate-relative with 344 // plain import or absolute path in 2015: crate-relative with
362 // fallback to extern prelude (with the simplification in 345 // fallback to extern prelude (with the simplification in
363 // rust-lang/rust#57745) 346 // rust-lang/rust#57745)
@@ -379,11 +362,11 @@ impl CrateDefMap {
379 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 362 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
380 }; 363 };
381 log::debug!("resolving {:?} in module", segment); 364 log::debug!("resolving {:?} in module", segment);
382 self.resolve_name_in_module_with_macro(db, original_module, &segment.name) 365 self.resolve_name_in_module(db, original_module, &segment.name)
383 } 366 }
384 PathKind::Super => { 367 PathKind::Super => {
385 if let Some(p) = self.modules[original_module].parent { 368 if let Some(p) = self.modules[original_module].parent {
386 Either::A(PerNs::types(Module { krate: self.krate, module_id: p }.into())) 369 PerNs::types(Module { krate: self.krate, module_id: p }.into())
387 } else { 370 } else {
388 log::debug!("super path in root module"); 371 log::debug!("super path in root module");
389 return ResolvePathResult::empty(ReachedFixedPoint::Yes); 372 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
@@ -397,7 +380,7 @@ impl CrateDefMap {
397 }; 380 };
398 if let Some(def) = self.extern_prelude.get(&segment.name) { 381 if let Some(def) = self.extern_prelude.get(&segment.name) {
399 log::debug!("absolute path {:?} resolved to crate {:?}", path, def); 382 log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
400 Either::A(PerNs::types(*def)) 383 PerNs::types(*def)
401 } else { 384 } else {
402 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude 385 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
403 } 386 }
@@ -405,7 +388,7 @@ impl CrateDefMap {
405 }; 388 };
406 389
407 for (i, segment) in segments { 390 for (i, segment) in segments {
408 let curr = match curr_per_ns.as_ref().a().and_then(|m| m.as_ref().take_types()) { 391 let curr = match curr_per_ns.as_ref().take_types() {
409 Some(r) => r, 392 Some(r) => r,
410 None => { 393 None => {
411 // we still have path segments left, but the path so far 394 // we still have path segments left, but the path so far
@@ -425,8 +408,7 @@ impl CrateDefMap {
425 Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ }; 408 Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ };
426 log::debug!("resolving {:?} in other crate", path); 409 log::debug!("resolving {:?} in other crate", path);
427 let defp_map = db.crate_def_map(module.krate); 410 let defp_map = db.crate_def_map(module.krate);
428 let (def, s) = 411 let (def, s) = defp_map.resolve_path(db, module.module_id, &path);
429 defp_map.resolve_path_with_macro(db, module.module_id, &path);
430 return ResolvePathResult::with( 412 return ResolvePathResult::with(
431 def, 413 def,
432 ReachedFixedPoint::Yes, 414 ReachedFixedPoint::Yes,
@@ -434,8 +416,9 @@ impl CrateDefMap {
434 ); 416 );
435 } 417 }
436 418
437 match self[module.module_id].scope.get_item_or_macro(&segment.name) { 419 // Since it is a quantified path here, it should not contains legacy macros
438 Some(res) => res, 420 match self[module.module_id].scope.get(&segment.name) {
421 Some(res) => res.def,
439 _ => { 422 _ => {
440 log::debug!("path segment {:?} not found", segment.name); 423 log::debug!("path segment {:?} not found", segment.name);
441 return ResolvePathResult::empty(ReachedFixedPoint::No); 424 return ResolvePathResult::empty(ReachedFixedPoint::No);
@@ -446,10 +429,10 @@ impl CrateDefMap {
446 // enum variant 429 // enum variant
447 tested_by!(can_import_enum_variant); 430 tested_by!(can_import_enum_variant);
448 match e.variant(db, &segment.name) { 431 match e.variant(db, &segment.name) {
449 Some(variant) => Either::A(PerNs::both(variant.into(), variant.into())), 432 Some(variant) => PerNs::both(variant.into(), variant.into()),
450 None => { 433 None => {
451 return ResolvePathResult::with( 434 return ResolvePathResult::with(
452 Either::A(PerNs::types((*e).into())), 435 PerNs::types((*e).into()),
453 ReachedFixedPoint::Yes, 436 ReachedFixedPoint::Yes,
454 Some(i), 437 Some(i),
455 ); 438 );
@@ -466,7 +449,7 @@ impl CrateDefMap {
466 ); 449 );
467 450
468 return ResolvePathResult::with( 451 return ResolvePathResult::with(
469 Either::A(PerNs::types(*s)), 452 PerNs::types(*s),
470 ReachedFixedPoint::Yes, 453 ReachedFixedPoint::Yes,
471 Some(i), 454 Some(i),
472 ); 455 );
@@ -476,14 +459,12 @@ impl CrateDefMap {
476 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None) 459 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
477 } 460 }
478 461
479 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> ItemOrMacro { 462 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> {
480 let from_crate_root = self[self.root] 463 let from_crate_root =
481 .scope 464 self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def);
482 .get_item_or_macro(name)
483 .unwrap_or_else(|| Either::A(PerNs::none()));
484 let from_extern_prelude = self.resolve_name_in_extern_prelude(name); 465 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
485 466
486 or(from_crate_root, Either::A(from_extern_prelude)) 467 from_crate_root.or(from_extern_prelude)
487 } 468 }
488 469
489 pub(crate) fn resolve_name_in_module( 470 pub(crate) fn resolve_name_in_module(
@@ -492,47 +473,38 @@ impl CrateDefMap {
492 module: CrateModuleId, 473 module: CrateModuleId,
493 name: &Name, 474 name: &Name,
494 ) -> PerNs<ModuleDef> { 475 ) -> PerNs<ModuleDef> {
495 self.resolve_name_in_module_with_macro(db, module, name).a().unwrap_or_else(PerNs::none)
496 }
497
498 fn resolve_name_in_module_with_macro(
499 &self,
500 db: &impl DefDatabase,
501 module: CrateModuleId,
502 name: &Name,
503 ) -> ItemOrMacro {
504 // Resolve in: 476 // Resolve in:
505 // - legacy scope 477 // - legacy scope of macro
506 // - current module / scope 478 // - current module / scope
507 // - extern prelude 479 // - extern prelude
508 // - std prelude 480 // - std prelude
509 let from_legacy_macro = self[module] 481 let from_legacy_macro =
510 .scope 482 self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros);
511 .get_legacy_macro(name) 483 let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def);
512 .map_or_else(|| Either::A(PerNs::none()), Either::B);
513 let from_scope =
514 self[module].scope.get_item_or_macro(name).unwrap_or_else(|| Either::A(PerNs::none()));
515 let from_extern_prelude = 484 let from_extern_prelude =
516 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); 485 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
517 let from_prelude = self.resolve_in_prelude(db, name); 486 let from_prelude = self.resolve_in_prelude(db, name);
518 487
519 or(from_legacy_macro, or(from_scope, or(Either::A(from_extern_prelude), from_prelude))) 488 from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude)
520 } 489 }
521 490
522 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { 491 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> {
523 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)) 492 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it))
524 } 493 }
525 494
526 fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> ItemOrMacro { 495 fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs<ModuleDef> {
527 if let Some(prelude) = self.prelude { 496 if let Some(prelude) = self.prelude {
528 let resolution = if prelude.krate == self.krate { 497 let keep;
529 self[prelude.module_id].scope.get_item_or_macro(name) 498 let def_map = if prelude.krate == self.krate {
499 self
530 } else { 500 } else {
531 db.crate_def_map(prelude.krate)[prelude.module_id].scope.get_item_or_macro(name) 501 // Extend lifetime
502 keep = db.crate_def_map(prelude.krate);
503 &keep
532 }; 504 };
533 resolution.unwrap_or_else(|| Either::A(PerNs::none())) 505 def_map[prelude.module_id].scope.get(name).map_or_else(PerNs::none, |res| res.def)
534 } else { 506 } else {
535 Either::A(PerNs::none()) 507 PerNs::none()
536 } 508 }
537 } 509 }
538} 510}
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index 09cda7656..03fbbd33f 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -5,14 +5,13 @@ use test_utils::tested_by;
5 5
6use crate::{ 6use crate::{
7 db::DefDatabase, 7 db::DefDatabase,
8 either::Either,
9 ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, 8 ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind},
10 name::MACRO_RULES, 9 name::MACRO_RULES,
11 nameres::{ 10 nameres::{
12 diagnostics::DefDiagnostic, 11 diagnostics::DefDiagnostic,
13 mod_resolution::{resolve_submodule, ParentModule}, 12 mod_resolution::{resolve_submodule, ParentModule},
14 raw, CrateDefMap, CrateModuleId, ItemOrMacro, ModuleData, ModuleDef, PerNs, 13 raw, Crate, CrateDefMap, CrateModuleId, ModuleData, ModuleDef, PerNs, ReachedFixedPoint,
15 ReachedFixedPoint, Resolution, ResolveMode, 14 Resolution, ResolveMode,
16 }, 15 },
17 AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static, 16 AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static,
18 Struct, Trait, TypeAlias, Union, 17 Struct, Trait, TypeAlias, Union,
@@ -123,30 +122,51 @@ where
123 let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); 122 let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
124 // show unresolved imports in completion, etc 123 // show unresolved imports in completion, etc
125 for (module_id, import, import_data) in unresolved_imports { 124 for (module_id, import, import_data) in unresolved_imports {
126 self.record_resolved_import(module_id, Either::A(PerNs::none()), import, &import_data) 125 self.record_resolved_import(module_id, PerNs::none(), import, &import_data)
127 } 126 }
128 } 127 }
129 128
129 /// Define a macro with `macro_rules`.
130 ///
131 /// It will define the macro in legacy textual scope, and if it has `#[macro_export]`,
132 /// then it is also defined in the root module scope.
133 /// You can `use` or invoke it by `crate::macro_name` anywhere, before or after the definition.
134 ///
135 /// It is surprising that the macro will never be in the current module scope.
136 /// These code fails with "unresolved import/macro",
137 /// ```rust,compile_fail
138 /// mod m { macro_rules! foo { () => {} } }
139 /// use m::foo as bar;
140 /// ```
141 ///
142 /// ```rust,compile_fail
143 /// macro_rules! foo { () => {} }
144 /// self::foo!();
145 /// crate::foo!();
146 /// ```
147 ///
148 /// Well, this code compiles, bacause the plain path `foo` in `use` is searched
149 /// in the legacy textual scope only.
150 /// ```rust
151 /// macro_rules! foo { () => {} }
152 /// use foo as bar;
153 /// ```
130 fn define_macro( 154 fn define_macro(
131 &mut self, 155 &mut self,
132 module_id: CrateModuleId, 156 module_id: CrateModuleId,
133 name: Name, 157 name: Name,
134 macro_id: MacroDefId, 158 macro_: MacroDef,
135 export: bool, 159 export: bool,
136 ) { 160 ) {
137 let def = Either::B(MacroDef { id: macro_id }); 161 // Textual scoping
162 self.define_legacy_macro(module_id, name.clone(), macro_);
138 163
164 // Module scoping
139 // In Rust, `#[macro_export]` macros are unconditionally visible at the 165 // In Rust, `#[macro_export]` macros are unconditionally visible at the
140 // crate root, even if the parent modules is **not** visible. 166 // crate root, even if the parent modules is **not** visible.
141 if export { 167 if export {
142 self.update(self.def_map.root, None, &[(name.clone(), def.clone())]); 168 self.update(self.def_map.root, None, &[(name.clone(), Resolution::from_macro(macro_))]);
143
144 // Exported macros are collected in crate level ready for
145 // glob import with `#[macro_use]`.
146 self.def_map.exported_macros.insert(name.clone(), macro_id);
147 } 169 }
148 self.update(module_id, None, &[(name.clone(), def)]);
149 self.define_legacy_macro(module_id, name.clone(), macro_id);
150 } 170 }
151 171
152 /// Define a legacy textual scoped macro in module 172 /// Define a legacy textual scoped macro in module
@@ -156,14 +176,12 @@ where
156 /// the definition of current module. 176 /// the definition of current module.
157 /// And also, `macro_use` on a module will import all legacy macros visable inside to 177 /// And also, `macro_use` on a module will import all legacy macros visable inside to
158 /// current legacy scope, with possible shadowing. 178 /// current legacy scope, with possible shadowing.
159 fn define_legacy_macro(&mut self, module_id: CrateModuleId, name: Name, macro_id: MacroDefId) { 179 fn define_legacy_macro(&mut self, module_id: CrateModuleId, name: Name, macro_: MacroDef) {
160 // Always shadowing 180 // Always shadowing
161 self.def_map.modules[module_id].scope.legacy_macros.insert(name, MacroDef { id: macro_id }); 181 self.def_map.modules[module_id].scope.legacy_macros.insert(name, macro_);
162 } 182 }
163 183
164 /// Import macros from `#[macro_use] extern crate`. 184 /// Import macros from `#[macro_use] extern crate`.
165 ///
166 /// They are non-scoped, and will only be inserted into mutable `global_macro_scope`.
167 fn import_macros_from_extern_crate( 185 fn import_macros_from_extern_crate(
168 &mut self, 186 &mut self,
169 current_module_id: CrateModuleId, 187 current_module_id: CrateModuleId,
@@ -184,14 +202,20 @@ where
184 202
185 if let Some(ModuleDef::Module(m)) = res.take_types() { 203 if let Some(ModuleDef::Module(m)) = res.take_types() {
186 tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); 204 tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use);
187 self.import_all_macros_exported(current_module_id, m); 205 self.import_all_macros_exported(current_module_id, m.krate);
188 } 206 }
189 } 207 }
190 208
191 fn import_all_macros_exported(&mut self, current_module_id: CrateModuleId, module: Module) { 209 /// Import all exported macros from another crate
192 let item_map = self.db.crate_def_map(module.krate); 210 ///
193 for (name, &macro_id) in &item_map.exported_macros { 211 /// Exported macros are just all macros in the root module scope.
194 self.define_legacy_macro(current_module_id, name.clone(), macro_id); 212 /// Note that it contains not only all `#[macro_export]` macros, but also all aliases
213 /// created by `use` in the root module, ignoring the visibility of `use`.
214 fn import_all_macros_exported(&mut self, current_module_id: CrateModuleId, krate: Crate) {
215 let def_map = self.db.crate_def_map(krate);
216 for (name, def) in def_map[def_map.root].scope.macros() {
217 // `macro_use` only bring things into legacy scope.
218 self.define_legacy_macro(current_module_id, name.clone(), def);
195 } 219 }
196 } 220 }
197 221
@@ -219,7 +243,7 @@ where
219 &self, 243 &self,
220 module_id: CrateModuleId, 244 module_id: CrateModuleId,
221 import: &raw::ImportData, 245 import: &raw::ImportData,
222 ) -> (ItemOrMacro, ReachedFixedPoint) { 246 ) -> (PerNs<ModuleDef>, ReachedFixedPoint) {
223 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); 247 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
224 if import.is_extern_crate { 248 if import.is_extern_crate {
225 let res = self.def_map.resolve_name_in_extern_prelude( 249 let res = self.def_map.resolve_name_in_extern_prelude(
@@ -228,7 +252,7 @@ where
228 .as_ident() 252 .as_ident()
229 .expect("extern crate should have been desugared to one-element path"), 253 .expect("extern crate should have been desugared to one-element path"),
230 ); 254 );
231 (Either::A(res), ReachedFixedPoint::Yes) 255 (res, ReachedFixedPoint::Yes)
232 } else { 256 } else {
233 let res = self.def_map.resolve_path_fp_with_macro( 257 let res = self.def_map.resolve_path_fp_with_macro(
234 self.db, 258 self.db,
@@ -244,13 +268,13 @@ where
244 fn record_resolved_import( 268 fn record_resolved_import(
245 &mut self, 269 &mut self,
246 module_id: CrateModuleId, 270 module_id: CrateModuleId,
247 def: ItemOrMacro, 271 def: PerNs<ModuleDef>,
248 import_id: raw::ImportId, 272 import_id: raw::ImportId,
249 import: &raw::ImportData, 273 import: &raw::ImportData,
250 ) { 274 ) {
251 if import.is_glob { 275 if import.is_glob {
252 log::debug!("glob import: {:?}", import); 276 log::debug!("glob import: {:?}", import);
253 match def.a().and_then(|item| item.take_types()) { 277 match def.take_types() {
254 Some(ModuleDef::Module(m)) => { 278 Some(ModuleDef::Module(m)) => {
255 if import.is_prelude { 279 if import.is_prelude {
256 tested_by!(std_prelude); 280 tested_by!(std_prelude);
@@ -260,30 +284,29 @@ where
260 // glob import from other crate => we can just import everything once 284 // glob import from other crate => we can just import everything once
261 let item_map = self.db.crate_def_map(m.krate); 285 let item_map = self.db.crate_def_map(m.krate);
262 let scope = &item_map[m.module_id].scope; 286 let scope = &item_map[m.module_id].scope;
287
288 // Module scoped macros is included
263 let items = scope 289 let items = scope
264 .items 290 .items
265 .iter() 291 .iter()
266 .map(|(name, res)| (name.clone(), Either::A(res.clone()))); 292 .map(|(name, res)| (name.clone(), res.clone()))
267 let macros = 293 .collect::<Vec<_>>();
268 scope.macros.iter().map(|(name, res)| (name.clone(), Either::B(*res)));
269 294
270 let all = items.chain(macros).collect::<Vec<_>>(); 295 self.update(module_id, Some(import_id), &items);
271 self.update(module_id, Some(import_id), &all);
272 } else { 296 } else {
273 // glob import from same crate => we do an initial 297 // glob import from same crate => we do an initial
274 // import, and then need to propagate any further 298 // import, and then need to propagate any further
275 // additions 299 // additions
276 let scope = &self.def_map[m.module_id].scope; 300 let scope = &self.def_map[m.module_id].scope;
301
302 // Module scoped macros is included
277 let items = scope 303 let items = scope
278 .items 304 .items
279 .iter() 305 .iter()
280 .map(|(name, res)| (name.clone(), Either::A(res.clone()))); 306 .map(|(name, res)| (name.clone(), res.clone()))
281 let macros = 307 .collect::<Vec<_>>();
282 scope.macros.iter().map(|(name, res)| (name.clone(), Either::B(*res)));
283 308
284 let all = items.chain(macros).collect::<Vec<_>>(); 309 self.update(module_id, Some(import_id), &items);
285
286 self.update(module_id, Some(import_id), &all);
287 // record the glob import in case we add further items 310 // record the glob import in case we add further items
288 self.glob_imports 311 self.glob_imports
289 .entry(m.module_id) 312 .entry(m.module_id)
@@ -303,7 +326,7 @@ where
303 import: Some(import_id), 326 import: Some(import_id),
304 }; 327 };
305 let name = variant.name(self.db)?; 328 let name = variant.name(self.db)?;
306 Some((name, Either::A(res))) 329 Some((name, res))
307 }) 330 })
308 .collect::<Vec<_>>(); 331 .collect::<Vec<_>>();
309 self.update(module_id, Some(import_id), &resolutions); 332 self.update(module_id, Some(import_id), &resolutions);
@@ -323,18 +346,12 @@ where
323 346
324 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 347 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
325 if import.is_extern_crate && module_id == self.def_map.root { 348 if import.is_extern_crate && module_id == self.def_map.root {
326 if let Some(def) = def.a().and_then(|item| item.take_types()) { 349 if let Some(def) = def.take_types() {
327 self.def_map.extern_prelude.insert(name.clone(), def); 350 self.def_map.extern_prelude.insert(name.clone(), def);
328 } 351 }
329 } 352 }
330 353
331 let resolution = match def { 354 let resolution = Resolution { def, import: Some(import_id) };
332 Either::A(item) => {
333 Either::A(Resolution { def: item, import: Some(import_id) })
334 }
335 Either::B(macro_) => Either::B(macro_),
336 };
337
338 self.update(module_id, Some(import_id), &[(name, resolution)]); 355 self.update(module_id, Some(import_id), &[(name, resolution)]);
339 } 356 }
340 None => tested_by!(bogus_paths), 357 None => tested_by!(bogus_paths),
@@ -346,7 +363,7 @@ where
346 &mut self, 363 &mut self,
347 module_id: CrateModuleId, 364 module_id: CrateModuleId,
348 import: Option<raw::ImportId>, 365 import: Option<raw::ImportId>,
349 resolutions: &[(Name, Either<Resolution, MacroDef>)], 366 resolutions: &[(Name, Resolution)],
350 ) { 367 ) {
351 self.update_recursive(module_id, import, resolutions, 0) 368 self.update_recursive(module_id, import, resolutions, 0)
352 } 369 }
@@ -355,7 +372,7 @@ where
355 &mut self, 372 &mut self,
356 module_id: CrateModuleId, 373 module_id: CrateModuleId,
357 import: Option<raw::ImportId>, 374 import: Option<raw::ImportId>,
358 resolutions: &[(Name, Either<Resolution, MacroDef>)], 375 resolutions: &[(Name, Resolution)],
359 depth: usize, 376 depth: usize,
360 ) { 377 ) {
361 if depth > 100 { 378 if depth > 100 {
@@ -365,35 +382,30 @@ where
365 let module_items = &mut self.def_map.modules[module_id].scope; 382 let module_items = &mut self.def_map.modules[module_id].scope;
366 let mut changed = false; 383 let mut changed = false;
367 for (name, res) in resolutions { 384 for (name, res) in resolutions {
368 match res { 385 let existing = module_items.items.entry(name.clone()).or_default();
369 // item
370 Either::A(res) => {
371 let existing = module_items.items.entry(name.clone()).or_default();
372
373 if existing.def.types.is_none() && res.def.types.is_some() {
374 existing.def.types = res.def.types;
375 existing.import = import.or(res.import);
376 changed = true;
377 }
378 if existing.def.values.is_none() && res.def.values.is_some() {
379 existing.def.values = res.def.values;
380 existing.import = import.or(res.import);
381 changed = true;
382 }
383 386
384 if existing.def.is_none() 387 if existing.def.types.is_none() && res.def.types.is_some() {
385 && res.def.is_none() 388 existing.def.types = res.def.types;
386 && existing.import.is_none() 389 existing.import = import.or(res.import);
387 && res.import.is_some() 390 changed = true;
388 { 391 }
389 existing.import = res.import; 392 if existing.def.values.is_none() && res.def.values.is_some() {
390 } 393 existing.def.values = res.def.values;
391 } 394 existing.import = import.or(res.import);
392 // macro 395 changed = true;
393 Either::B(res) => { 396 }
394 // Always shadowing 397 if existing.def.macros.is_none() && res.def.macros.is_some() {
395 module_items.macros.insert(name.clone(), *res); 398 existing.def.macros = res.def.macros;
396 } 399 existing.import = import.or(res.import);
400 changed = true;
401 }
402
403 if existing.def.is_none()
404 && res.def.is_none()
405 && existing.import.is_none()
406 && res.import.is_some()
407 {
408 existing.import = res.import;
397 } 409 }
398 } 410 }
399 411
@@ -425,7 +437,7 @@ where
425 path, 437 path,
426 ); 438 );
427 439
428 if let Some(def) = resolved_res.resolved_def.b() { 440 if let Some(def) = resolved_res.resolved_def.get_macros() {
429 let call_id = MacroCallLoc { def: def.id, ast_id: *ast_id }.id(self.db); 441 let call_id = MacroCallLoc { def: def.id, ast_id: *ast_id }.id(self.db);
430 resolved.push((*module_id, call_id, def.id)); 442 resolved.push((*module_id, call_id, def.id));
431 res = ReachedFixedPoint::No; 443 res = ReachedFixedPoint::No;
@@ -528,7 +540,7 @@ where
528 if let Some(prelude_module) = self.def_collector.def_map.prelude { 540 if let Some(prelude_module) = self.def_collector.def_map.prelude {
529 if prelude_module.krate != self.def_collector.def_map.krate { 541 if prelude_module.krate != self.def_collector.def_map.krate {
530 tested_by!(prelude_is_macro_use); 542 tested_by!(prelude_is_macro_use);
531 self.def_collector.import_all_macros_exported(self.module_id, prelude_module); 543 self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate);
532 } 544 }
533 } 545 }
534 546
@@ -636,7 +648,7 @@ where
636 ), 648 ),
637 import: None, 649 import: None,
638 }; 650 };
639 self.def_collector.update(self.module_id, None, &[(name, Either::A(resolution))]); 651 self.def_collector.update(self.module_id, None, &[(name, resolution)]);
640 res 652 res
641 } 653 }
642 654
@@ -667,7 +679,7 @@ where
667 raw::DefKind::TypeAlias(ast_id) => PerNs::types(def!(TypeAlias, ast_id)), 679 raw::DefKind::TypeAlias(ast_id) => PerNs::types(def!(TypeAlias, ast_id)),
668 }; 680 };
669 let resolution = Resolution { def, import: None }; 681 let resolution = Resolution { def, import: None };
670 self.def_collector.update(self.module_id, None, &[(name, Either::A(resolution))]) 682 self.def_collector.update(self.module_id, None, &[(name, resolution)])
671 } 683 }
672 684
673 fn collect_macro(&mut self, mac: &raw::MacroData) { 685 fn collect_macro(&mut self, mac: &raw::MacroData) {
@@ -675,7 +687,8 @@ where
675 if is_macro_rules(&mac.path) { 687 if is_macro_rules(&mac.path) {
676 if let Some(name) = &mac.name { 688 if let Some(name) = &mac.name {
677 let macro_id = MacroDefId(mac.ast_id.with_file_id(self.file_id)); 689 let macro_id = MacroDefId(mac.ast_id.with_file_id(self.file_id));
678 self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export) 690 let macro_ = MacroDef { id: macro_id };
691 self.def_collector.define_macro(self.module_id, name.clone(), macro_, mac.export);
679 } 692 }
680 return; 693 return;
681 } 694 }
@@ -706,7 +719,7 @@ where
706 fn import_all_legacy_macros(&mut self, module_id: CrateModuleId) { 719 fn import_all_legacy_macros(&mut self, module_id: CrateModuleId) {
707 let macros = self.def_collector.def_map[module_id].scope.legacy_macros.clone(); 720 let macros = self.def_collector.def_map[module_id].scope.legacy_macros.clone();
708 for (name, macro_) in macros { 721 for (name, macro_) in macros {
709 self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_.id); 722 self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_);
710 } 723 }
711 } 724 }
712} 725}
@@ -758,7 +771,6 @@ mod tests {
758 root, 771 root,
759 modules, 772 modules,
760 poison_macros: FxHashSet::default(), 773 poison_macros: FxHashSet::default(),
761 exported_macros: FxHashMap::default(),
762 diagnostics: Vec::new(), 774 diagnostics: Vec::new(),
763 } 775 }
764 }; 776 };
diff --git a/crates/ra_hir/src/nameres/per_ns.rs b/crates/ra_hir/src/nameres/per_ns.rs
index c40a3ff9d..d07cc08f4 100644
--- a/crates/ra_hir/src/nameres/per_ns.rs
+++ b/crates/ra_hir/src/nameres/per_ns.rs
@@ -1,78 +1,87 @@
1use crate::MacroDef;
2
1#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 3#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
2pub enum Namespace { 4pub enum Namespace {
3 Types, 5 Types,
4 Values, 6 Values,
7 // Note that only type inference uses this enum, and it doesn't care about macros.
8 // Macro,
5} 9}
6 10
7#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 11#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
8pub struct PerNs<T> { 12pub struct PerNs<T> {
9 pub types: Option<T>, 13 pub types: Option<T>,
10 pub values: Option<T>, 14 pub values: Option<T>,
15 /// Since macros has different type, many methods simply ignore it.
16 /// We can only use special method like `get_macros` to access it.
17 pub macros: Option<MacroDef>,
11} 18}
12 19
13impl<T> Default for PerNs<T> { 20impl<T> Default for PerNs<T> {
14 fn default() -> Self { 21 fn default() -> Self {
15 PerNs { types: None, values: None } 22 PerNs { types: None, values: None, macros: None }
16 } 23 }
17} 24}
18 25
19impl<T> PerNs<T> { 26impl<T> PerNs<T> {
20 pub fn none() -> PerNs<T> { 27 pub fn none() -> PerNs<T> {
21 PerNs { types: None, values: None } 28 PerNs { types: None, values: None, macros: None }
22 } 29 }
23 30
24 pub fn values(t: T) -> PerNs<T> { 31 pub fn values(t: T) -> PerNs<T> {
25 PerNs { types: None, values: Some(t) } 32 PerNs { types: None, values: Some(t), macros: None }
26 } 33 }
27 34
28 pub fn types(t: T) -> PerNs<T> { 35 pub fn types(t: T) -> PerNs<T> {
29 PerNs { types: Some(t), values: None } 36 PerNs { types: Some(t), values: None, macros: None }
30 } 37 }
31 38
32 pub fn both(types: T, values: T) -> PerNs<T> { 39 pub fn both(types: T, values: T) -> PerNs<T> {
33 PerNs { types: Some(types), values: Some(values) } 40 PerNs { types: Some(types), values: Some(values), macros: None }
34 } 41 }
35 42
36 pub fn is_none(&self) -> bool { 43 pub fn macros(macro_: MacroDef) -> PerNs<T> {
37 self.types.is_none() && self.values.is_none() 44 PerNs { types: None, values: None, macros: Some(macro_) }
38 } 45 }
39 46
40 pub fn is_both(&self) -> bool { 47 pub fn is_none(&self) -> bool {
41 self.types.is_some() && self.values.is_some() 48 self.types.is_none() && self.values.is_none() && self.macros.is_none()
42 } 49 }
43 50
44 pub fn take(self, namespace: Namespace) -> Option<T> { 51 pub fn is_all(&self) -> bool {
45 match namespace { 52 self.types.is_some() && self.values.is_some() && self.macros.is_some()
46 Namespace::Types => self.types,
47 Namespace::Values => self.values,
48 }
49 } 53 }
50 54
51 pub fn take_types(self) -> Option<T> { 55 pub fn take_types(self) -> Option<T> {
52 self.take(Namespace::Types) 56 self.types
53 } 57 }
54 58
55 pub fn take_values(self) -> Option<T> { 59 pub fn take_values(self) -> Option<T> {
56 self.take(Namespace::Values) 60 self.values
57 } 61 }
58 62
59 pub fn get(&self, namespace: Namespace) -> Option<&T> { 63 pub fn get_macros(&self) -> Option<MacroDef> {
60 self.as_ref().take(namespace) 64 self.macros
61 } 65 }
62 66
63 pub fn as_ref(&self) -> PerNs<&T> { 67 pub fn only_macros(&self) -> PerNs<T> {
64 PerNs { types: self.types.as_ref(), values: self.values.as_ref() } 68 PerNs { types: None, values: None, macros: self.macros }
65 } 69 }
66 70
67 pub fn or(self, other: PerNs<T>) -> PerNs<T> { 71 pub fn as_ref(&self) -> PerNs<&T> {
68 PerNs { types: self.types.or(other.types), values: self.values.or(other.values) } 72 PerNs { types: self.types.as_ref(), values: self.values.as_ref(), macros: self.macros }
69 } 73 }
70 74
71 pub fn and_then<U>(self, f: impl Fn(T) -> Option<U>) -> PerNs<U> { 75 pub fn or(self, other: PerNs<T>) -> PerNs<T> {
72 PerNs { types: self.types.and_then(&f), values: self.values.and_then(&f) } 76 PerNs {
77 types: self.types.or(other.types),
78 values: self.values.or(other.values),
79 macros: self.macros.or(other.macros),
80 }
73 } 81 }
74 82
83 /// Map types and values. Leave macros unchanged.
75 pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> { 84 pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> {
76 PerNs { types: self.types.map(&f), values: self.values.map(&f) } 85 PerNs { types: self.types.map(&f), values: self.values.map(&f), macros: self.macros }
77 } 86 }
78} 87}
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs
index c646d3d00..04b97cb90 100644
--- a/crates/ra_hir/src/nameres/raw.rs
+++ b/crates/ra_hir/src/nameres/raw.rs
@@ -76,8 +76,10 @@ impl RawItems {
76 source_map: ImportSourceMap::default(), 76 source_map: ImportSourceMap::default(),
77 }; 77 };
78 if let Some(node) = db.parse_or_expand(file_id) { 78 if let Some(node) = db.parse_or_expand(file_id) {
79 if let Some(source_file) = ast::SourceFile::cast(node) { 79 if let Some(source_file) = ast::SourceFile::cast(node.clone()) {
80 collector.process_module(None, source_file); 80 collector.process_module(None, source_file);
81 } else if let Some(item_list) = ast::MacroItems::cast(node) {
82 collector.process_module(None, item_list);
81 } 83 }
82 } 84 }
83 (Arc::new(collector.raw_items), Arc::new(collector.source_map)) 85 (Arc::new(collector.raw_items), Arc::new(collector.source_map))
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index 4ff897ca5..bc4b47b70 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -12,8 +12,7 @@ use test_utils::covers;
12 12
13use crate::{ 13use crate::{
14 mock::{CrateGraphFixture, MockDatabase}, 14 mock::{CrateGraphFixture, MockDatabase},
15 nameres::Resolution, 15 Crate,
16 Crate, Either,
17}; 16};
18 17
19use super::*; 18use super::*;
@@ -37,35 +36,38 @@ fn render_crate_def_map(map: &CrateDefMap) -> String {
37 *buf += path; 36 *buf += path;
38 *buf += "\n"; 37 *buf += "\n";
39 38
40 let items = map.modules[module].scope.items.iter().map(|(name, it)| (name, Either::A(it))); 39 let mut entries = map.modules[module]
41 let macros = map.modules[module].scope.macros.iter().map(|(name, m)| (name, Either::B(m))); 40 .scope
42 let mut entries = items.chain(macros).collect::<Vec<_>>(); 41 .items
43 42 .iter()
43 .map(|(name, res)| (name, res.def))
44 .collect::<Vec<_>>();
44 entries.sort_by_key(|(name, _)| *name); 45 entries.sort_by_key(|(name, _)| *name);
46
45 for (name, res) in entries { 47 for (name, res) in entries {
46 match res { 48 *buf += &format!("{}:", name);
47 Either::A(it) => { 49
48 *buf += &format!("{}: {}\n", name, dump_resolution(it)); 50 if res.types.is_some() {
49 } 51 *buf += " t";
50 Either::B(_) => { 52 }
51 *buf += &format!("{}: m\n", name); 53 if res.values.is_some() {
52 } 54 *buf += " v";
55 }
56 if res.macros.is_some() {
57 *buf += " m";
58 }
59 if res.is_none() {
60 *buf += " _";
53 } 61 }
62
63 *buf += "\n";
54 } 64 }
65
55 for (name, child) in map.modules[module].children.iter() { 66 for (name, child) in map.modules[module].children.iter() {
56 let path = path.to_string() + &format!("::{}", name); 67 let path = path.to_string() + &format!("::{}", name);
57 go(buf, map, &path, *child); 68 go(buf, map, &path, *child);
58 } 69 }
59 } 70 }
60
61 fn dump_resolution(resolution: &Resolution) -> &'static str {
62 match (resolution.def.types.is_some(), resolution.def.values.is_some()) {
63 (true, true) => "t v",
64 (true, false) => "t",
65 (false, true) => "v",
66 (false, false) => "_",
67 }
68 }
69} 71}
70 72
71fn def_map(fixtute: &str) -> String { 73fn def_map(fixtute: &str) -> String {
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs
index ebc4d6890..20ee63c67 100644
--- a/crates/ra_hir/src/nameres/tests/macros.rs
+++ b/crates/ra_hir/src/nameres/tests/macros.rs
@@ -21,7 +21,6 @@ fn macro_rules_are_globally_visible() {
21 â‹®crate 21 â‹®crate
22 â‹®Foo: t v 22 â‹®Foo: t v
23 â‹®nested: t 23 â‹®nested: t
24 â‹®structs: m
25 â‹® 24 â‹®
26 â‹®crate::nested 25 â‹®crate::nested
27 â‹®Bar: t v 26 â‹®Bar: t v
@@ -47,7 +46,6 @@ fn macro_rules_can_define_modules() {
47 ); 46 );
48 assert_snapshot!(map, @r###" 47 assert_snapshot!(map, @r###"
49 â‹®crate 48 â‹®crate
50 â‹®m: m
51 â‹®n1: t 49 â‹®n1: t
52 â‹® 50 â‹®
53 â‹®crate::n1 51 â‹®crate::n1
@@ -133,7 +131,6 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() {
133 â‹®crate 131 â‹®crate
134 â‹®Foo: t v 132 â‹®Foo: t v
135 â‹®bar: m 133 â‹®bar: m
136 â‹®baz: m
137 â‹®foo: m 134 â‹®foo: m
138 "###); 135 "###);
139} 136}
@@ -271,7 +268,6 @@ fn prelude_cycle() {
271 â‹®prelude: t 268 â‹®prelude: t
272 â‹® 269 â‹®
273 â‹®crate::prelude 270 â‹®crate::prelude
274 â‹®declare_mod: m
275 "###); 271 "###);
276} 272}
277 273
@@ -345,7 +341,6 @@ fn plain_macros_are_legacy_textual_scoped() {
345 â‹®Ok: t v 341 â‹®Ok: t v
346 â‹®OkAfter: t v 342 â‹®OkAfter: t v
347 â‹®OkShadowStop: t v 343 â‹®OkShadowStop: t v
348 â‹®foo: m
349 â‹®m1: t 344 â‹®m1: t
350 â‹®m2: t 345 â‹®m2: t
351 â‹®m3: t 346 â‹®m3: t
@@ -354,28 +349,132 @@ fn plain_macros_are_legacy_textual_scoped() {
354 â‹®ok_double_macro_use_shadow: v 349 â‹®ok_double_macro_use_shadow: v
355 â‹® 350 â‹®
356 â‹®crate::m7 351 â‹®crate::m7
357 â‹®baz: m
358 â‹® 352 â‹®
359 â‹®crate::m1 353 â‹®crate::m1
360 â‹®bar: m
361 â‹® 354 â‹®
362 â‹®crate::m5 355 â‹®crate::m5
363 â‹®m6: t 356 â‹®m6: t
364 â‹® 357 â‹®
365 â‹®crate::m5::m6 358 â‹®crate::m5::m6
366 â‹®foo: m
367 â‹® 359 â‹®
368 â‹®crate::m2 360 â‹®crate::m2
369 â‹® 361 â‹®
370 â‹®crate::m3 362 â‹®crate::m3
371 â‹®OkAfterInside: t v 363 â‹®OkAfterInside: t v
372 â‹®OkMacroUse: t v 364 â‹®OkMacroUse: t v
373 â‹®foo: m
374 â‹®m4: t 365 â‹®m4: t
375 â‹®ok_shadow: v 366 â‹®ok_shadow: v
376 â‹® 367 â‹®
377 â‹®crate::m3::m4 368 â‹®crate::m3::m4
378 â‹®bar: m
379 â‹®ok_shadow_deep: v 369 â‹®ok_shadow_deep: v
380 "###); 370 "###);
381} 371}
372
373#[test]
374fn type_value_macro_live_in_different_scopes() {
375 let map = def_map(
376 "
377 //- /main.rs
378 #[macro_export]
379 macro_rules! foo {
380 ($x:ident) => { type $x = (); }
381 }
382
383 foo!(foo);
384 use foo as bar;
385
386 use self::foo as baz;
387 fn baz() {}
388 ",
389 );
390 assert_snapshot!(map, @r###"
391 â‹®crate
392 â‹®bar: t m
393 â‹®baz: t v m
394 â‹®foo: t m
395 "###);
396}
397
398#[test]
399fn macro_use_can_be_aliased() {
400 let map = def_map_with_crate_graph(
401 "
402 //- /main.rs
403 #[macro_use]
404 extern crate foo;
405
406 foo!(Direct);
407 bar!(Alias);
408
409 //- /lib.rs
410 use crate::foo as bar;
411
412 mod m {
413 #[macro_export]
414 macro_rules! foo {
415 ($x:ident) => { struct $x; }
416 }
417 }
418 ",
419 crate_graph! {
420 "main": ("/main.rs", ["foo"]),
421 "foo": ("/lib.rs", []),
422 },
423 );
424 assert_snapshot!(map, @r###"
425 â‹®crate
426 â‹®Alias: t v
427 â‹®Direct: t v
428 â‹®foo: t
429 "###);
430}
431
432#[test]
433fn path_quantified_macros() {
434 let map = def_map(
435 "
436 //- /main.rs
437 macro_rules! foo {
438 ($x:ident) => { struct $x; }
439 }
440
441 crate::foo!(NotResolved);
442
443 crate::bar!(OkCrate);
444 bar!(OkPlain);
445 alias1!(NotHere);
446 m::alias1!(OkAliasPlain);
447 m::alias2!(OkAliasSuper);
448 m::alias3!(OkAliasCrate);
449 not_found!(NotFound);
450
451 mod m {
452 #[macro_export]
453 macro_rules! bar {
454 ($x:ident) => { struct $x; }
455 }
456
457 pub use bar as alias1;
458 pub use super::bar as alias2;
459 pub use crate::bar as alias3;
460 pub use self::bar as not_found;
461 }
462 ",
463 );
464 assert_snapshot!(map, @r###"
465 â‹®crate
466 â‹®OkAliasCrate: t v
467 â‹®OkAliasPlain: t v
468 â‹®OkAliasSuper: t v
469 â‹®OkCrate: t v
470 â‹®OkPlain: t v
471 â‹®bar: m
472 â‹®m: t
473 â‹®
474 â‹®crate::m
475 â‹®alias1: m
476 â‹®alias2: m
477 â‹®alias3: m
478 â‹®not_found: _
479 "###);
480}
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index ef75308f6..d9bdd0e22 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -6,7 +6,6 @@ use rustc_hash::{FxHashMap, FxHashSet};
6use crate::{ 6use crate::{
7 code_model::Crate, 7 code_model::Crate,
8 db::HirDatabase, 8 db::HirDatabase,
9 either::Either,
10 expr::{ 9 expr::{
11 scope::{ExprScopes, ScopeId}, 10 scope::{ExprScopes, ScopeId},
12 PatId, 11 PatId,
@@ -126,7 +125,7 @@ impl Resolver {
126 let mut resolution = PerNs::none(); 125 let mut resolution = PerNs::none();
127 for scope in self.scopes.iter().rev() { 126 for scope in self.scopes.iter().rev() {
128 resolution = resolution.or(scope.resolve_name(db, name)); 127 resolution = resolution.or(scope.resolve_name(db, name));
129 if resolution.is_both() { 128 if resolution.is_all() {
130 return resolution; 129 return resolution;
131 } 130 }
132 } 131 }
@@ -139,10 +138,7 @@ impl Resolver {
139 path: &Path, 138 path: &Path,
140 ) -> Option<MacroDef> { 139 ) -> Option<MacroDef> {
141 let (item_map, module) = self.module()?; 140 let (item_map, module) = self.module()?;
142 match item_map.resolve_path_with_macro(db, module, path) { 141 item_map.resolve_path(db, module, path).0.get_macros()
143 (Either::B(macro_def), None) => Some(macro_def),
144 _ => None,
145 }
146 } 142 }
147 143
148 /// Returns the resolved path segments 144 /// Returns the resolved path segments
@@ -191,6 +187,9 @@ impl Resolver {
191 if current.values.is_none() { 187 if current.values.is_none() {
192 current.values = res.values; 188 current.values = res.values;
193 } 189 }
190 if current.macros.is_none() {
191 current.macros = res.macros;
192 }
194 }); 193 });
195 } 194 }
196 names 195 names
@@ -313,6 +312,9 @@ impl Scope {
313 m.crate_def_map[m.module_id].scope.entries().for_each(|(name, res)| { 312 m.crate_def_map[m.module_id].scope.entries().for_each(|(name, res)| {
314 f(name.clone(), res.def.map(Resolution::Def)); 313 f(name.clone(), res.def.map(Resolution::Def));
315 }); 314 });
315 m.crate_def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| {
316 f(name.clone(), PerNs::macros(macro_));
317 });
316 m.crate_def_map.extern_prelude().iter().for_each(|(name, def)| { 318 m.crate_def_map.extern_prelude().iter().for_each(|(name, def)| {
317 f(name.clone(), PerNs::types(Resolution::Def(*def))); 319 f(name.clone(), PerNs::types(Resolution::Def(*def)));
318 }); 320 });
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 25716fe8c..c60e72abf 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -2838,6 +2838,64 @@ fn main() {
2838 ); 2838 );
2839} 2839}
2840 2840
2841#[test]
2842fn infer_path_quantified_macros_expanded() {
2843 assert_snapshot!(
2844 infer(r#"
2845#[macro_export]
2846macro_rules! foo {
2847 () => { 42i32 }
2848}
2849
2850mod m {
2851 pub use super::foo as bar;
2852}
2853
2854fn main() {
2855 let x = crate::foo!();
2856 let y = m::bar!();
2857}
2858"#),
2859 @r###"
2860 ![0; 5) '42i32': i32
2861 ![0; 5) '42i32': i32
2862 [111; 164) '{ ...!(); }': ()
2863 [121; 122) 'x': i32
2864 [148; 149) 'y': i32
2865 "###
2866 );
2867}
2868
2869#[test]
2870fn infer_type_value_macro_having_same_name() {
2871 assert_snapshot!(
2872 infer(r#"
2873#[macro_export]
2874macro_rules! foo {
2875 () => {
2876 mod foo {
2877 pub use super::foo;
2878 }
2879 };
2880 ($x:tt) => {
2881 $x
2882 };
2883}
2884
2885foo!();
2886
2887fn foo() {
2888 let foo = foo::foo!(42i32);
2889}
2890"#),
2891 @r###"
2892 ![0; 5) '42i32': i32
2893 [171; 206) '{ ...32); }': ()
2894 [181; 184) 'foo': i32
2895 "###
2896 );
2897}
2898
2841#[ignore] 2899#[ignore]
2842#[test] 2900#[test]
2843fn method_resolution_trait_before_autoref() { 2901fn method_resolution_trait_before_autoref() {
@@ -3007,7 +3065,7 @@ impl<T, U> Into<U> for T where U: From<T> {}
3007fn test() { S2.into()<|>; } 3065fn test() { S2.into()<|>; }
3008"#, 3066"#,
3009 ); 3067 );
3010 assert_eq!(t, "S1"); 3068 assert_eq!(t, "{unknown}");
3011} 3069}
3012 3070
3013#[test] 3071#[test]
@@ -3024,7 +3082,7 @@ impl<T, U: From<T>> Into<U> for T {}
3024fn test() { S2.into()<|>; } 3082fn test() { S2.into()<|>; }
3025"#, 3083"#,
3026 ); 3084 );
3027 assert_eq!(t, "S1"); 3085 assert_eq!(t, "{unknown}");
3028} 3086}
3029 3087
3030#[test] 3088#[test]
@@ -3066,7 +3124,7 @@ impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {}
3066fn test() { (S {}).method()<|>; } 3124fn test() { (S {}).method()<|>; }
3067"#, 3125"#,
3068 ); 3126 );
3069 assert_eq!(t, "{unknown}"); 3127 assert_eq!(t, "()");
3070} 3128}
3071 3129
3072#[test] 3130#[test]
@@ -3546,11 +3604,11 @@ fn test(x: Trait, y: &Trait) -> u64 {
3546 [129; 132) 'bar': fn bar() -> {unknown} 3604 [129; 132) 'bar': fn bar() -> {unknown}
3547 [129; 134) 'bar()': {unknown} 3605 [129; 134) 'bar()': {unknown}
3548 [140; 141) 'x': {unknown} 3606 [140; 141) 'x': {unknown}
3549 [140; 147) 'x.foo()': {unknown} 3607 [140; 147) 'x.foo()': u64
3550 [153; 154) 'y': &{unknown} 3608 [153; 154) 'y': &{unknown}
3551 [153; 160) 'y.foo()': {unknown} 3609 [153; 160) 'y.foo()': u64
3552 [166; 167) 'z': {unknown} 3610 [166; 167) 'z': {unknown}
3553 [166; 173) 'z.foo()': {unknown} 3611 [166; 173) 'z.foo()': u64
3554 "### 3612 "###
3555 ); 3613 );
3556} 3614}
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 8a127efa1..0367c6560 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -356,14 +356,6 @@ fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> {
356 } 356 }
357} 357}
358 358
359fn is_non_enumerable_trait(db: &impl HirDatabase, trait_: Trait) -> bool {
360 let name = trait_.name(db).unwrap_or_else(crate::Name::missing).to_string();
361 match &*name {
362 "Sized" => true,
363 _ => false,
364 }
365}
366
367fn convert_where_clauses( 359fn convert_where_clauses(
368 db: &impl HirDatabase, 360 db: &impl HirDatabase,
369 def: GenericDef, 361 def: GenericDef,
@@ -486,7 +478,7 @@ pub(crate) fn trait_datum_query(
486 associated_ty_ids: Vec::new(), 478 associated_ty_ids: Vec::new(),
487 where_clauses: Vec::new(), 479 where_clauses: Vec::new(),
488 flags: chalk_rust_ir::TraitFlags { 480 flags: chalk_rust_ir::TraitFlags {
489 non_enumerable: false, 481 non_enumerable: true,
490 auto: false, 482 auto: false,
491 marker: false, 483 marker: false,
492 upstream: true, 484 upstream: true,
@@ -503,7 +495,7 @@ pub(crate) fn trait_datum_query(
503 let flags = chalk_rust_ir::TraitFlags { 495 let flags = chalk_rust_ir::TraitFlags {
504 auto: trait_.is_auto(db), 496 auto: trait_.is_auto(db),
505 upstream: trait_.module(db).krate(db) != Some(krate), 497 upstream: trait_.module(db).krate(db) != Some(krate),
506 non_enumerable: is_non_enumerable_trait(db, trait_), 498 non_enumerable: true,
507 // FIXME set these flags correctly 499 // FIXME set these flags correctly
508 marker: false, 500 marker: false,
509 fundamental: false, 501 fundamental: false,
diff --git a/crates/ra_mbe/Cargo.toml b/crates/ra_mbe/Cargo.toml
index 68f559295..b058dde91 100644
--- a/crates/ra_mbe/Cargo.toml
+++ b/crates/ra_mbe/Cargo.toml
@@ -12,3 +12,7 @@ itertools = "0.8.0"
12rustc-hash = "1.0.0" 12rustc-hash = "1.0.0"
13smallvec = "0.6.9" 13smallvec = "0.6.9"
14log = "0.4.5" 14log = "0.4.5"
15
16[dev-dependencies]
17test_utils = { path = "../test_utils" }
18
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs
index 52c3d03b5..f07f000ff 100644
--- a/crates/ra_mbe/src/lib.rs
+++ b/crates/ra_mbe/src/lib.rs
@@ -41,8 +41,8 @@ pub enum ExpandError {
41} 41}
42 42
43pub use crate::syntax_bridge::{ 43pub use crate::syntax_bridge::{
44 ast_to_token_tree, syntax_node_to_token_tree, token_tree_to_ast_item_list, token_tree_to_expr, 44 ast_to_token_tree, syntax_node_to_token_tree, token_tree_to_expr, token_tree_to_items,
45 token_tree_to_macro_items, token_tree_to_macro_stmts, token_tree_to_pat, token_tree_to_ty, 45 token_tree_to_macro_stmts, token_tree_to_pat, token_tree_to_ty,
46}; 46};
47 47
48/// This struct contains AST for a single `macro_rules` definition. What might 48/// This struct contains AST for a single `macro_rules` definition. What might
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs
index 01641fdee..78df96880 100644
--- a/crates/ra_mbe/src/mbe_expander.rs
+++ b/crates/ra_mbe/src/mbe_expander.rs
@@ -81,21 +81,26 @@ struct Bindings {
81 81
82#[derive(Debug)] 82#[derive(Debug)]
83enum Binding { 83enum Binding {
84 Simple(tt::TokenTree), 84 Fragment(Fragment),
85 Nested(Vec<Binding>), 85 Nested(Vec<Binding>),
86 Empty, 86 Empty,
87} 87}
88 88
89#[derive(Debug, Clone)]
90enum Fragment {
91 /// token fragments are just copy-pasted into the output
92 Tokens(tt::TokenTree),
93 /// Ast fragments are inserted with fake delimiters, so as to make things
94 /// like `$i * 2` where `$i = 1 + 1` work as expectd.
95 Ast(tt::TokenTree),
96}
97
89impl Bindings { 98impl Bindings {
90 fn push_optional(&mut self, name: &SmolStr) { 99 fn push_optional(&mut self, name: &SmolStr) {
91 // FIXME: Do we have a better way to represent an empty token ? 100 // FIXME: Do we have a better way to represent an empty token ?
92 // Insert an empty subtree for empty token 101 // Insert an empty subtree for empty token
93 self.inner.insert( 102 let tt = tt::Subtree { delimiter: tt::Delimiter::None, token_trees: vec![] }.into();
94 name.clone(), 103 self.inner.insert(name.clone(), Binding::Fragment(Fragment::Tokens(tt)));
95 Binding::Simple(
96 tt::Subtree { delimiter: tt::Delimiter::None, token_trees: vec![] }.into(),
97 ),
98 );
99 } 104 }
100 105
101 fn push_empty(&mut self, name: &SmolStr) { 106 fn push_empty(&mut self, name: &SmolStr) {
@@ -106,13 +111,13 @@ impl Bindings {
106 self.inner.contains_key(name) 111 self.inner.contains_key(name)
107 } 112 }
108 113
109 fn get(&self, name: &SmolStr, nesting: &[usize]) -> Result<&tt::TokenTree, ExpandError> { 114 fn get(&self, name: &SmolStr, nesting: &[usize]) -> Result<&Fragment, ExpandError> {
110 let mut b = self.inner.get(name).ok_or_else(|| { 115 let mut b = self.inner.get(name).ok_or_else(|| {
111 ExpandError::BindingError(format!("could not find binding `{}`", name)) 116 ExpandError::BindingError(format!("could not find binding `{}`", name))
112 })?; 117 })?;
113 for &idx in nesting.iter() { 118 for &idx in nesting.iter() {
114 b = match b { 119 b = match b {
115 Binding::Simple(_) => break, 120 Binding::Fragment(_) => break,
116 Binding::Nested(bs) => bs.get(idx).ok_or_else(|| { 121 Binding::Nested(bs) => bs.get(idx).ok_or_else(|| {
117 ExpandError::BindingError(format!("could not find nested binding `{}`", name)) 122 ExpandError::BindingError(format!("could not find nested binding `{}`", name))
118 })?, 123 })?,
@@ -125,7 +130,7 @@ impl Bindings {
125 }; 130 };
126 } 131 }
127 match b { 132 match b {
128 Binding::Simple(it) => Ok(it), 133 Binding::Fragment(it) => Ok(it),
129 Binding::Nested(_) => Err(ExpandError::BindingError(format!( 134 Binding::Nested(_) => Err(ExpandError::BindingError(format!(
130 "expected simple binding, found nested binding `{}`", 135 "expected simple binding, found nested binding `{}`",
131 name 136 name
@@ -195,8 +200,8 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
195 crate::Leaf::Var(crate::Var { text, kind }) => { 200 crate::Leaf::Var(crate::Var { text, kind }) => {
196 let kind = kind.as_ref().ok_or(ExpandError::UnexpectedToken)?; 201 let kind = kind.as_ref().ok_or(ExpandError::UnexpectedToken)?;
197 match match_meta_var(kind.as_str(), input)? { 202 match match_meta_var(kind.as_str(), input)? {
198 Some(tt) => { 203 Some(fragment) => {
199 res.inner.insert(text.clone(), Binding::Simple(tt)); 204 res.inner.insert(text.clone(), Binding::Fragment(fragment));
200 } 205 }
201 None => res.push_optional(text), 206 None => res.push_optional(text),
202 } 207 }
@@ -292,7 +297,7 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
292 Ok(res) 297 Ok(res)
293} 298}
294 299
295fn match_meta_var(kind: &str, input: &mut TtCursor) -> Result<Option<tt::TokenTree>, ExpandError> { 300fn match_meta_var(kind: &str, input: &mut TtCursor) -> Result<Option<Fragment>, ExpandError> {
296 let fragment = match kind { 301 let fragment = match kind {
297 "path" => Path, 302 "path" => Path,
298 "expr" => Expr, 303 "expr" => Expr,
@@ -303,7 +308,7 @@ fn match_meta_var(kind: &str, input: &mut TtCursor) -> Result<Option<tt::TokenTr
303 "meta" => MetaItem, 308 "meta" => MetaItem,
304 "item" => Item, 309 "item" => Item,
305 _ => { 310 _ => {
306 let binding = match kind { 311 let tt = match kind {
307 "ident" => { 312 "ident" => {
308 let ident = input.eat_ident().ok_or(ExpandError::UnexpectedToken)?.clone(); 313 let ident = input.eat_ident().ok_or(ExpandError::UnexpectedToken)?.clone();
309 tt::Leaf::from(ident).into() 314 tt::Leaf::from(ident).into()
@@ -321,11 +326,12 @@ fn match_meta_var(kind: &str, input: &mut TtCursor) -> Result<Option<tt::TokenTr
321 }, 326 },
322 _ => return Err(ExpandError::UnexpectedToken), 327 _ => return Err(ExpandError::UnexpectedToken),
323 }; 328 };
324 return Ok(Some(binding)); 329 return Ok(Some(Fragment::Tokens(tt)));
325 } 330 }
326 }; 331 };
327 let binding = input.eat_fragment(fragment).ok_or(ExpandError::UnexpectedToken)?; 332 let tt = input.eat_fragment(fragment).ok_or(ExpandError::UnexpectedToken)?;
328 Ok(Some(binding)) 333 let fragment = if kind == "expr" { Fragment::Ast(tt) } else { Fragment::Tokens(tt) };
334 Ok(Some(fragment))
329} 335}
330 336
331#[derive(Debug)] 337#[derive(Debug)]
@@ -339,45 +345,20 @@ fn expand_subtree(
339 template: &crate::Subtree, 345 template: &crate::Subtree,
340 ctx: &mut ExpandCtx, 346 ctx: &mut ExpandCtx,
341) -> Result<tt::Subtree, ExpandError> { 347) -> Result<tt::Subtree, ExpandError> {
342 let token_trees = template 348 let mut buf: Vec<tt::TokenTree> = Vec::new();
343 .token_trees 349 for tt in template.token_trees.iter() {
344 .iter() 350 let tt = expand_tt(tt, ctx)?;
345 .map(|it| expand_tt(it, ctx)) 351 push_fragment(&mut buf, tt);
346 .filter(|it| {
347 // Filter empty subtree
348 if let Ok(tt::TokenTree::Subtree(subtree)) = it {
349 subtree.delimiter != tt::Delimiter::None || !subtree.token_trees.is_empty()
350 } else {
351 true
352 }
353 })
354 .collect::<Result<Vec<_>, ExpandError>>()?;
355
356 Ok(tt::Subtree { token_trees, delimiter: template.delimiter })
357}
358
359/// Reduce single token subtree to single token
360/// In `tt` matcher case, all tt tokens will be braced by a Delimiter::None
361/// which makes all sort of problems.
362fn reduce_single_token(mut subtree: tt::Subtree) -> tt::TokenTree {
363 if subtree.delimiter != tt::Delimiter::None || subtree.token_trees.len() != 1 {
364 return subtree.into();
365 } 352 }
366 353
367 match subtree.token_trees.pop().unwrap() { 354 Ok(tt::Subtree { delimiter: template.delimiter, token_trees: buf })
368 tt::TokenTree::Subtree(subtree) => reduce_single_token(subtree),
369 tt::TokenTree::Leaf(token) => token.into(),
370 }
371} 355}
372 356
373fn expand_tt( 357fn expand_tt(template: &crate::TokenTree, ctx: &mut ExpandCtx) -> Result<Fragment, ExpandError> {
374 template: &crate::TokenTree,
375 ctx: &mut ExpandCtx,
376) -> Result<tt::TokenTree, ExpandError> {
377 let res: tt::TokenTree = match template { 358 let res: tt::TokenTree = match template {
378 crate::TokenTree::Subtree(subtree) => expand_subtree(subtree, ctx)?.into(), 359 crate::TokenTree::Subtree(subtree) => expand_subtree(subtree, ctx)?.into(),
379 crate::TokenTree::Repeat(repeat) => { 360 crate::TokenTree::Repeat(repeat) => {
380 let mut token_trees: Vec<tt::TokenTree> = Vec::new(); 361 let mut buf: Vec<tt::TokenTree> = Vec::new();
381 ctx.nesting.push(0); 362 ctx.nesting.push(0);
382 // Dirty hack to make macro-expansion terminate. 363 // Dirty hack to make macro-expansion terminate.
383 // This should be replaced by a propper macro-by-example implementation 364 // This should be replaced by a propper macro-by-example implementation
@@ -418,23 +399,23 @@ fn expand_tt(
418 399
419 let idx = ctx.nesting.pop().unwrap(); 400 let idx = ctx.nesting.pop().unwrap();
420 ctx.nesting.push(idx + 1); 401 ctx.nesting.push(idx + 1);
421 token_trees.push(reduce_single_token(t)); 402 push_subtree(&mut buf, t);
422 403
423 if let Some(ref sep) = repeat.separator { 404 if let Some(ref sep) = repeat.separator {
424 match sep { 405 match sep {
425 crate::Separator::Ident(ident) => { 406 crate::Separator::Ident(ident) => {
426 has_seps = 1; 407 has_seps = 1;
427 token_trees.push(tt::Leaf::from(ident.clone()).into()); 408 buf.push(tt::Leaf::from(ident.clone()).into());
428 } 409 }
429 crate::Separator::Literal(lit) => { 410 crate::Separator::Literal(lit) => {
430 has_seps = 1; 411 has_seps = 1;
431 token_trees.push(tt::Leaf::from(lit.clone()).into()); 412 buf.push(tt::Leaf::from(lit.clone()).into());
432 } 413 }
433 414
434 crate::Separator::Puncts(puncts) => { 415 crate::Separator::Puncts(puncts) => {
435 has_seps = puncts.len(); 416 has_seps = puncts.len();
436 for punct in puncts { 417 for punct in puncts {
437 token_trees.push(tt::Leaf::from(*punct).into()); 418 buf.push(tt::Leaf::from(*punct).into());
438 } 419 }
439 } 420 }
440 } 421 }
@@ -450,16 +431,16 @@ fn expand_tt(
450 431
451 ctx.nesting.pop().unwrap(); 432 ctx.nesting.pop().unwrap();
452 for _ in 0..has_seps { 433 for _ in 0..has_seps {
453 token_trees.pop(); 434 buf.pop();
454 } 435 }
455 436
456 if crate::RepeatKind::OneOrMore == repeat.kind && counter == 0 { 437 if crate::RepeatKind::OneOrMore == repeat.kind && counter == 0 {
457 return Err(ExpandError::UnexpectedToken); 438 return Err(ExpandError::UnexpectedToken);
458 } 439 }
459 440
460 // Check if it is a singel token subtree without any delimiter 441 // Check if it is a single token subtree without any delimiter
461 // e.g {Delimiter:None> ['>'] /Delimiter:None>} 442 // e.g {Delimiter:None> ['>'] /Delimiter:None>}
462 reduce_single_token(tt::Subtree { token_trees, delimiter: tt::Delimiter::None }) 443 tt::Subtree { delimiter: tt::Delimiter::None, token_trees: buf }.into()
463 } 444 }
464 crate::TokenTree::Leaf(leaf) => match leaf { 445 crate::TokenTree::Leaf(leaf) => match leaf {
465 crate::Leaf::Ident(ident) => { 446 crate::Leaf::Ident(ident) => {
@@ -500,20 +481,15 @@ fn expand_tt(
500 } 481 }
501 .into() 482 .into()
502 } else { 483 } else {
503 let tkn = ctx.bindings.get(&v.text, &ctx.nesting)?.clone(); 484 let fragment = ctx.bindings.get(&v.text, &ctx.nesting)?.clone();
504 ctx.var_expanded = true; 485 ctx.var_expanded = true;
505 486 return Ok(fragment);
506 if let tt::TokenTree::Subtree(subtree) = tkn {
507 reduce_single_token(subtree)
508 } else {
509 tkn
510 }
511 } 487 }
512 } 488 }
513 crate::Leaf::Literal(l) => tt::Leaf::from(tt::Literal { text: l.text.clone() }).into(), 489 crate::Leaf::Literal(l) => tt::Leaf::from(tt::Literal { text: l.text.clone() }).into(),
514 }, 490 },
515 }; 491 };
516 Ok(res) 492 Ok(Fragment::Tokens(res))
517} 493}
518 494
519#[cfg(test)] 495#[cfg(test)]
@@ -586,3 +562,17 @@ mod tests {
586 expand_rule(&rules.rules[0], &invocation_tt) 562 expand_rule(&rules.rules[0], &invocation_tt)
587 } 563 }
588} 564}
565
566fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) {
567 match fragment {
568 Fragment::Tokens(tt::TokenTree::Subtree(tt)) => push_subtree(buf, tt),
569 Fragment::Tokens(tt) | Fragment::Ast(tt) => buf.push(tt),
570 }
571}
572
573fn push_subtree(buf: &mut Vec<tt::TokenTree>, tt: tt::Subtree) {
574 match tt.delimiter {
575 tt::Delimiter::None => buf.extend(tt.token_trees),
576 _ => buf.push(tt.into()),
577 }
578}
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs
index a380b1cfd..2d035307b 100644
--- a/crates/ra_mbe/src/syntax_bridge.rs
+++ b/crates/ra_mbe/src/syntax_bridge.rs
@@ -46,31 +46,19 @@ pub fn syntax_node_to_token_tree(node: &SyntaxNode) -> Option<(tt::Subtree, Toke
46// * TraitItems(SmallVec<[ast::TraitItem; 1]>) 46// * TraitItems(SmallVec<[ast::TraitItem; 1]>)
47// * ImplItems(SmallVec<[ast::ImplItem; 1]>) 47// * ImplItems(SmallVec<[ast::ImplItem; 1]>)
48// * ForeignItems(SmallVec<[ast::ForeignItem; 1]> 48// * ForeignItems(SmallVec<[ast::ForeignItem; 1]>
49//
50//
51
52fn token_tree_to_syntax_node<F>(tt: &tt::Subtree, f: F) -> Result<Parse<SyntaxNode>, ExpandError>
53where
54 F: Fn(&mut dyn ra_parser::TokenSource, &mut dyn ra_parser::TreeSink),
55{
56 let tokens = [tt.clone().into()];
57 let buffer = TokenBuffer::new(&tokens);
58 let mut token_source = SubtreeTokenSource::new(&buffer);
59 let mut tree_sink = TtTreeSink::new(buffer.begin());
60 f(&mut token_source, &mut tree_sink);
61 if tree_sink.roots.len() != 1 {
62 return Err(ExpandError::ConversionError);
63 }
64 //FIXME: would be cool to report errors
65 let parse = tree_sink.inner.finish();
66 Ok(parse)
67}
68 49
69fn fragment_to_syntax_node( 50fn fragment_to_syntax_node(
70 tt: &tt::Subtree, 51 tt: &tt::Subtree,
71 fragment_kind: FragmentKind, 52 fragment_kind: FragmentKind,
72) -> Result<Parse<SyntaxNode>, ExpandError> { 53) -> Result<Parse<SyntaxNode>, ExpandError> {
73 let tokens = [tt.clone().into()]; 54 let tmp;
55 let tokens = match tt {
56 tt::Subtree { delimiter: tt::Delimiter::None, token_trees } => token_trees.as_slice(),
57 _ => {
58 tmp = [tt.clone().into()];
59 &tmp[..]
60 }
61 };
74 let buffer = TokenBuffer::new(&tokens); 62 let buffer = TokenBuffer::new(&tokens);
75 let mut token_source = SubtreeTokenSource::new(&buffer); 63 let mut token_source = SubtreeTokenSource::new(&buffer);
76 let mut tree_sink = TtTreeSink::new(buffer.begin()); 64 let mut tree_sink = TtTreeSink::new(buffer.begin());
@@ -108,17 +96,11 @@ pub fn token_tree_to_macro_stmts(tt: &tt::Subtree) -> Result<Parse<ast::MacroStm
108} 96}
109 97
110/// Parses the token tree (result of macro expansion) as a sequence of items 98/// Parses the token tree (result of macro expansion) as a sequence of items
111pub fn token_tree_to_macro_items(tt: &tt::Subtree) -> Result<Parse<ast::MacroItems>, ExpandError> { 99pub fn token_tree_to_items(tt: &tt::Subtree) -> Result<Parse<ast::MacroItems>, ExpandError> {
112 let parse = fragment_to_syntax_node(tt, Items)?; 100 let parse = fragment_to_syntax_node(tt, Items)?;
113 parse.cast().ok_or_else(|| crate::ExpandError::ConversionError) 101 parse.cast().ok_or_else(|| crate::ExpandError::ConversionError)
114} 102}
115 103
116/// Parses the token tree (result of macro expansion) as a sequence of items
117pub fn token_tree_to_ast_item_list(tt: &tt::Subtree) -> Parse<ast::SourceFile> {
118 let parse = token_tree_to_syntax_node(tt, ra_parser::parse).unwrap();
119 parse.cast().unwrap()
120}
121
122impl TokenMap { 104impl TokenMap {
123 pub fn relative_range_of(&self, tt: tt::TokenId) -> Option<TextRange> { 105 pub fn relative_range_of(&self, tt: tt::TokenId) -> Option<TextRange> {
124 let idx = tt.0 as usize; 106 let idx = tt.0 as usize;
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs
index 034ea639b..312fa4626 100644
--- a/crates/ra_mbe/src/tests.rs
+++ b/crates/ra_mbe/src/tests.rs
@@ -1,4 +1,5 @@
1use ra_syntax::{ast, AstNode, NodeOrToken}; 1use ra_syntax::{ast, AstNode, NodeOrToken};
2use test_utils::assert_eq_text;
2 3
3use super::*; 4use super::*;
4 5
@@ -69,7 +70,7 @@ pub(crate) fn expand(rules: &MacroRules, invocation: &str) -> tt::Subtree {
69 70
70pub(crate) fn expand_to_items(rules: &MacroRules, invocation: &str) -> ast::MacroItems { 71pub(crate) fn expand_to_items(rules: &MacroRules, invocation: &str) -> ast::MacroItems {
71 let expanded = expand(rules, invocation); 72 let expanded = expand(rules, invocation);
72 token_tree_to_macro_items(&expanded).unwrap().tree() 73 token_tree_to_items(&expanded).unwrap().tree()
73} 74}
74 75
75#[allow(unused)] 76#[allow(unused)]
@@ -152,11 +153,10 @@ pub(crate) fn assert_expansion(
152 153
153 // wrap the given text to a macro call 154 // wrap the given text to a macro call
154 let expected = text_to_tokentree(&expected); 155 let expected = text_to_tokentree(&expected);
155
156 let (expanded_tree, expected_tree) = match kind { 156 let (expanded_tree, expected_tree) = match kind {
157 MacroKind::Items => { 157 MacroKind::Items => {
158 let expanded_tree = token_tree_to_macro_items(&expanded).unwrap().tree(); 158 let expanded_tree = token_tree_to_items(&expanded).unwrap().tree();
159 let expected_tree = token_tree_to_macro_items(&expected).unwrap().tree(); 159 let expected_tree = token_tree_to_items(&expected).unwrap().tree();
160 160
161 ( 161 (
162 debug_dump_ignore_spaces(expanded_tree.syntax()).trim().to_string(), 162 debug_dump_ignore_spaces(expanded_tree.syntax()).trim().to_string(),
@@ -178,7 +178,7 @@ pub(crate) fn assert_expansion(
178 let expected_tree = expected_tree.replace("C_C__C", "$crate"); 178 let expected_tree = expected_tree.replace("C_C__C", "$crate");
179 assert_eq!( 179 assert_eq!(
180 expanded_tree, expected_tree, 180 expanded_tree, expected_tree,
181 "left => {}\nright => {}", 181 "\nleft:\n{}\nright:\n{}",
182 expanded_tree, expected_tree, 182 expanded_tree, expected_tree,
183 ); 183 );
184 184
@@ -410,7 +410,7 @@ fn test_expand_to_item_list() {
410 ", 410 ",
411 ); 411 );
412 let expansion = expand(&rules, "structs!(Foo, Bar);"); 412 let expansion = expand(&rules, "structs!(Foo, Bar);");
413 let tree = token_tree_to_macro_items(&expansion).unwrap().tree(); 413 let tree = token_tree_to_items(&expansion).unwrap().tree();
414 assert_eq!( 414 assert_eq!(
415 format!("{:#?}", tree.syntax()).trim(), 415 format!("{:#?}", tree.syntax()).trim(),
416 r#" 416 r#"
@@ -667,9 +667,9 @@ fn test_expr_order() {
667 } 667 }
668"#, 668"#,
669 ); 669 );
670 670 let dump = format!("{:#?}", expand_to_items(&rules, "foo! { 1 + 1 }").syntax());
671 assert_eq!( 671 assert_eq_text!(
672 format!("{:#?}", expand_to_items(&rules, "foo! { 1 + 1 }").syntax()).trim(), 672 dump.trim(),
673 r#"MACRO_ITEMS@[0; 15) 673 r#"MACRO_ITEMS@[0; 15)
674 FN_DEF@[0; 15) 674 FN_DEF@[0; 15)
675 FN_KW@[0; 2) "fn" 675 FN_KW@[0; 2) "fn"
diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs
index a2ad580bc..0158f9b8a 100644
--- a/crates/ra_parser/src/grammar.rs
+++ b/crates/ra_parser/src/grammar.rs
@@ -93,12 +93,12 @@ pub(crate) mod fragments {
93 // https://doc.rust-lang.org/reference/paths.html#simple-paths 93 // https://doc.rust-lang.org/reference/paths.html#simple-paths
94 // The start of an meta must be a simple path 94 // The start of an meta must be a simple path
95 match p.current() { 95 match p.current() {
96 IDENT | T![::] | T![super] | T![self] | T![crate] => p.bump(), 96 IDENT | T![::] | T![super] | T![self] | T![crate] => p.bump_any(),
97 T![=] => { 97 T![=] => {
98 p.bump(); 98 p.bump_any();
99 match p.current() { 99 match p.current() {
100 c if c.is_literal() => p.bump(), 100 c if c.is_literal() => p.bump_any(),
101 T![true] | T![false] => p.bump(), 101 T![true] | T![false] => p.bump_any(),
102 _ => {} 102 _ => {}
103 } 103 }
104 break; 104 break;
@@ -126,7 +126,7 @@ pub(crate) mod fragments {
126 126
127 while !p.at(EOF) { 127 while !p.at(EOF) {
128 if p.at(T![;]) { 128 if p.at(T![;]) {
129 p.bump(); 129 p.bump(T![;]);
130 continue; 130 continue;
131 } 131 }
132 132
@@ -179,7 +179,7 @@ fn opt_visibility(p: &mut Parser) -> bool {
179 match p.current() { 179 match p.current() {
180 T![pub] => { 180 T![pub] => {
181 let m = p.start(); 181 let m = p.start();
182 p.bump(); 182 p.bump(T![pub]);
183 if p.at(T!['(']) { 183 if p.at(T!['(']) {
184 match p.nth(1) { 184 match p.nth(1) {
185 // test crate_visibility 185 // test crate_visibility
@@ -188,13 +188,13 @@ fn opt_visibility(p: &mut Parser) -> bool {
188 // pub(self) struct S; 188 // pub(self) struct S;
189 // pub(self) struct S; 189 // pub(self) struct S;
190 T![crate] | T![self] | T![super] => { 190 T![crate] | T![self] | T![super] => {
191 p.bump(); 191 p.bump_any();
192 p.bump(); 192 p.bump_any();
193 p.expect(T![')']); 193 p.expect(T![')']);
194 } 194 }
195 T![in] => { 195 T![in] => {
196 p.bump(); 196 p.bump_any();
197 p.bump(); 197 p.bump_any();
198 paths::use_path(p); 198 paths::use_path(p);
199 p.expect(T![')']); 199 p.expect(T![')']);
200 } 200 }
@@ -210,9 +210,9 @@ fn opt_visibility(p: &mut Parser) -> bool {
210 // 210 //
211 // test crate_keyword_path 211 // test crate_keyword_path
212 // fn foo() { crate::foo(); } 212 // fn foo() { crate::foo(); }
213 T![crate] if p.nth(1) != T![::] => { 213 T![crate] if !p.nth_at(1, T![::]) => {
214 let m = p.start(); 214 let m = p.start();
215 p.bump(); 215 p.bump_any();
216 m.complete(p, VISIBILITY); 216 m.complete(p, VISIBILITY);
217 } 217 }
218 _ => return false, 218 _ => return false,
@@ -223,7 +223,7 @@ fn opt_visibility(p: &mut Parser) -> bool {
223fn opt_alias(p: &mut Parser) { 223fn opt_alias(p: &mut Parser) {
224 if p.at(T![as]) { 224 if p.at(T![as]) {
225 let m = p.start(); 225 let m = p.start();
226 p.bump(); 226 p.bump_any();
227 if !p.eat(T![_]) { 227 if !p.eat(T![_]) {
228 name(p); 228 name(p);
229 } 229 }
@@ -234,9 +234,9 @@ fn opt_alias(p: &mut Parser) {
234fn abi(p: &mut Parser) { 234fn abi(p: &mut Parser) {
235 assert!(p.at(T![extern])); 235 assert!(p.at(T![extern]));
236 let abi = p.start(); 236 let abi = p.start();
237 p.bump(); 237 p.bump_any();
238 match p.current() { 238 match p.current() {
239 STRING | RAW_STRING => p.bump(), 239 STRING | RAW_STRING => p.bump_any(),
240 _ => (), 240 _ => (),
241 } 241 }
242 abi.complete(p, ABI); 242 abi.complete(p, ABI);
@@ -245,7 +245,7 @@ fn abi(p: &mut Parser) {
245fn opt_fn_ret_type(p: &mut Parser) -> bool { 245fn opt_fn_ret_type(p: &mut Parser) -> bool {
246 if p.at(T![->]) { 246 if p.at(T![->]) {
247 let m = p.start(); 247 let m = p.start();
248 p.bump(); 248 p.bump(T![->]);
249 types::type_(p); 249 types::type_(p);
250 m.complete(p, RET_TYPE); 250 m.complete(p, RET_TYPE);
251 true 251 true
@@ -257,7 +257,7 @@ fn opt_fn_ret_type(p: &mut Parser) -> bool {
257fn name_r(p: &mut Parser, recovery: TokenSet) { 257fn name_r(p: &mut Parser, recovery: TokenSet) {
258 if p.at(IDENT) { 258 if p.at(IDENT) {
259 let m = p.start(); 259 let m = p.start();
260 p.bump(); 260 p.bump_any();
261 m.complete(p, NAME); 261 m.complete(p, NAME);
262 } else { 262 } else {
263 p.err_recover("expected a name", recovery); 263 p.err_recover("expected a name", recovery);
@@ -271,11 +271,11 @@ fn name(p: &mut Parser) {
271fn name_ref(p: &mut Parser) { 271fn name_ref(p: &mut Parser) {
272 if p.at(IDENT) { 272 if p.at(IDENT) {
273 let m = p.start(); 273 let m = p.start();
274 p.bump(); 274 p.bump_any();
275 m.complete(p, NAME_REF); 275 m.complete(p, NAME_REF);
276 } else if p.at(T![self]) { 276 } else if p.at(T![self]) {
277 let m = p.start(); 277 let m = p.start();
278 p.bump(); 278 p.bump_any();
279 m.complete(p, T![self]); 279 m.complete(p, T![self]);
280 } else { 280 } else {
281 p.err_and_bump("expected identifier"); 281 p.err_and_bump("expected identifier");
@@ -285,7 +285,7 @@ fn name_ref(p: &mut Parser) {
285fn name_ref_or_index(p: &mut Parser) { 285fn name_ref_or_index(p: &mut Parser) {
286 if p.at(IDENT) || p.at(INT_NUMBER) { 286 if p.at(IDENT) || p.at(INT_NUMBER) {
287 let m = p.start(); 287 let m = p.start();
288 p.bump(); 288 p.bump_any();
289 m.complete(p, NAME_REF); 289 m.complete(p, NAME_REF);
290 } else { 290 } else {
291 p.err_and_bump("expected identifier"); 291 p.err_and_bump("expected identifier");
@@ -296,7 +296,7 @@ fn error_block(p: &mut Parser, message: &str) {
296 assert!(p.at(T!['{'])); 296 assert!(p.at(T!['{']));
297 let m = p.start(); 297 let m = p.start();
298 p.error(message); 298 p.error(message);
299 p.bump(); 299 p.bump_any();
300 expressions::expr_block_contents(p); 300 expressions::expr_block_contents(p);
301 p.eat(T!['}']); 301 p.eat(T!['}']);
302 m.complete(p, ERROR); 302 m.complete(p, ERROR);
diff --git a/crates/ra_parser/src/grammar/attributes.rs b/crates/ra_parser/src/grammar/attributes.rs
index e97170203..81a363a57 100644
--- a/crates/ra_parser/src/grammar/attributes.rs
+++ b/crates/ra_parser/src/grammar/attributes.rs
@@ -15,11 +15,11 @@ pub(super) fn outer_attributes(p: &mut Parser) {
15fn attribute(p: &mut Parser, inner: bool) { 15fn attribute(p: &mut Parser, inner: bool) {
16 let attr = p.start(); 16 let attr = p.start();
17 assert!(p.at(T![#])); 17 assert!(p.at(T![#]));
18 p.bump(); 18 p.bump_any();
19 19
20 if inner { 20 if inner {
21 assert!(p.at(T![!])); 21 assert!(p.at(T![!]));
22 p.bump(); 22 p.bump_any();
23 } 23 }
24 24
25 if p.at(T!['[']) { 25 if p.at(T!['[']) {
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs
index 855418f1c..1dd9a586c 100644
--- a/crates/ra_parser/src/grammar/expressions.rs
+++ b/crates/ra_parser/src/grammar/expressions.rs
@@ -14,20 +14,17 @@ const EXPR_FIRST: TokenSet = LHS_FIRST;
14 14
15pub(super) fn expr(p: &mut Parser) -> BlockLike { 15pub(super) fn expr(p: &mut Parser) -> BlockLike {
16 let r = Restrictions { forbid_structs: false, prefer_stmt: false }; 16 let r = Restrictions { forbid_structs: false, prefer_stmt: false };
17 let mut dollar_lvl = 0; 17 expr_bp(p, r, 1).1
18 expr_bp(p, r, 1, &mut dollar_lvl).1
19} 18}
20 19
21pub(super) fn expr_stmt(p: &mut Parser) -> (Option<CompletedMarker>, BlockLike) { 20pub(super) fn expr_stmt(p: &mut Parser) -> (Option<CompletedMarker>, BlockLike) {
22 let r = Restrictions { forbid_structs: false, prefer_stmt: true }; 21 let r = Restrictions { forbid_structs: false, prefer_stmt: true };
23 let mut dollar_lvl = 0; 22 expr_bp(p, r, 1)
24 expr_bp(p, r, 1, &mut dollar_lvl)
25} 23}
26 24
27fn expr_no_struct(p: &mut Parser) { 25fn expr_no_struct(p: &mut Parser) {
28 let r = Restrictions { forbid_structs: true, prefer_stmt: false }; 26 let r = Restrictions { forbid_structs: true, prefer_stmt: false };
29 let mut dollar_lvl = 0; 27 expr_bp(p, r, 1);
30 expr_bp(p, r, 1, &mut dollar_lvl);
31} 28}
32 29
33// test block 30// test block
@@ -46,7 +43,7 @@ pub(crate) fn block(p: &mut Parser) {
46pub(crate) fn naked_block(p: &mut Parser) { 43pub(crate) fn naked_block(p: &mut Parser) {
47 assert!(p.at(T!['{'])); 44 assert!(p.at(T!['{']));
48 let m = p.start(); 45 let m = p.start();
49 p.bump(); 46 p.bump_any();
50 expr_block_contents(p); 47 expr_block_contents(p);
51 p.expect(T!['}']); 48 p.expect(T!['}']);
52 m.complete(p, BLOCK); 49 m.complete(p, BLOCK);
@@ -153,7 +150,7 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) {
153 // } 150 // }
154 fn let_stmt(p: &mut Parser, m: Marker, with_semi: StmtWithSemi) { 151 fn let_stmt(p: &mut Parser, m: Marker, with_semi: StmtWithSemi) {
155 assert!(p.at(T![let])); 152 assert!(p.at(T![let]));
156 p.bump(); 153 p.bump_any();
157 patterns::pattern(p); 154 patterns::pattern(p);
158 if p.at(T![:]) { 155 if p.at(T![:]) {
159 types::ascription(p); 156 types::ascription(p);
@@ -198,7 +195,7 @@ pub(crate) fn expr_block_contents(p: &mut Parser) {
198 // } 195 // }
199 196
200 if p.at(T![;]) { 197 if p.at(T![;]) {
201 p.bump(); 198 p.bump_any();
202 continue; 199 continue;
203 } 200 }
204 201
@@ -212,72 +209,53 @@ struct Restrictions {
212 prefer_stmt: bool, 209 prefer_stmt: bool,
213} 210}
214 211
215enum Op { 212/// Binding powers of operators for a Pratt parser.
216 Simple, 213///
217 Composite(SyntaxKind, u8), 214/// See https://www.oilshell.org/blog/2016/11/03.html
218} 215#[rustfmt::skip]
219 216fn current_op(p: &Parser) -> (u8, SyntaxKind) {
220fn current_op(p: &Parser) -> (u8, Op) { 217 const NOT_AN_OP: (u8, SyntaxKind) = (0, T![@]);
221 if let Some(t) = p.current3() { 218 match p.current() {
222 match t { 219 T![|] if p.at(T![||]) => (3, T![||]),
223 (T![<], T![<], T![=]) => return (1, Op::Composite(T![<<=], 3)), 220 T![|] if p.at(T![|=]) => (1, T![|=]),
224 (T![>], T![>], T![=]) => return (1, Op::Composite(T![>>=], 3)), 221 T![|] => (6, T![|]),
225 _ => (), 222 T![>] if p.at(T![>>=]) => (1, T![>>=]),
226 } 223 T![>] if p.at(T![>>]) => (9, T![>>]),
227 } 224 T![>] if p.at(T![>=]) => (5, T![>=]),
228 225 T![>] => (5, T![>]),
229 if let Some(t) = p.current2() { 226 T![=] if p.at(T![=>]) => NOT_AN_OP,
230 match t { 227 T![=] if p.at(T![==]) => (5, T![==]),
231 (T![+], T![=]) => return (1, Op::Composite(T![+=], 2)), 228 T![=] => (1, T![=]),
232 (T![-], T![=]) => return (1, Op::Composite(T![-=], 2)), 229 T![<] if p.at(T![<=]) => (5, T![<=]),
233 (T![*], T![=]) => return (1, Op::Composite(T![*=], 2)), 230 T![<] if p.at(T![<<=]) => (1, T![<<=]),
234 (T![%], T![=]) => return (1, Op::Composite(T![%=], 2)), 231 T![<] if p.at(T![<<]) => (9, T![<<]),
235 (T![/], T![=]) => return (1, Op::Composite(T![/=], 2)), 232 T![<] => (5, T![<]),
236 (T![|], T![=]) => return (1, Op::Composite(T![|=], 2)), 233 T![+] if p.at(T![+=]) => (1, T![+=]),
237 (T![&], T![=]) => return (1, Op::Composite(T![&=], 2)), 234 T![+] => (10, T![+]),
238 (T![^], T![=]) => return (1, Op::Composite(T![^=], 2)), 235 T![^] if p.at(T![^=]) => (1, T![^=]),
239 (T![|], T![|]) => return (3, Op::Composite(T![||], 2)), 236 T![^] => (7, T![^]),
240 (T![&], T![&]) => return (4, Op::Composite(T![&&], 2)), 237 T![%] if p.at(T![%=]) => (1, T![%=]),
241 (T![<], T![=]) => return (5, Op::Composite(T![<=], 2)), 238 T![%] => (11, T![%]),
242 (T![>], T![=]) => return (5, Op::Composite(T![>=], 2)), 239 T![&] if p.at(T![&=]) => (1, T![&=]),
243 (T![<], T![<]) => return (9, Op::Composite(T![<<], 2)), 240 T![&] if p.at(T![&&]) => (4, T![&&]),
244 (T![>], T![>]) => return (9, Op::Composite(T![>>], 2)), 241 T![&] => (8, T![&]),
245 _ => (), 242 T![/] if p.at(T![/=]) => (1, T![/=]),
246 } 243 T![/] => (11, T![/]),
244 T![*] if p.at(T![*=]) => (1, T![*=]),
245 T![*] => (11, T![*]),
246 T![.] if p.at(T![..=]) => (2, T![..=]),
247 T![.] if p.at(T![..]) => (2, T![..]),
248 T![!] if p.at(T![!=]) => (5, T![!=]),
249 T![-] if p.at(T![-=]) => (1, T![-=]),
250 T![-] => (10, T![-]),
251
252 _ => NOT_AN_OP
247 } 253 }
248
249 let bp = match p.current() {
250 T![=] => 1,
251 T![..] | T![..=] => 2,
252 T![==] | T![!=] | T![<] | T![>] => 5,
253 T![|] => 6,
254 T![^] => 7,
255 T![&] => 8,
256 T![-] | T![+] => 10,
257 T![*] | T![/] | T![%] => 11,
258 _ => 0,
259 };
260 (bp, Op::Simple)
261} 254}
262 255
263// Parses expression with binding power of at least bp. 256// Parses expression with binding power of at least bp.
264fn expr_bp( 257fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> (Option<CompletedMarker>, BlockLike) {
265 p: &mut Parser, 258 let mut lhs = match lhs(p, r) {
266 r: Restrictions,
267 mut bp: u8,
268 dollar_lvl: &mut usize,
269) -> (Option<CompletedMarker>, BlockLike) {
270 // `newly_dollar_open` is a flag indicated that dollar is just closed after lhs, e.g.
271 // `$1$ + a`
272 // We use this flag to skip handling it.
273 let mut newly_dollar_open = if p.at_l_dollar() {
274 *dollar_lvl += p.eat_l_dollars();
275 true
276 } else {
277 false
278 };
279
280 let mut lhs = match lhs(p, r, dollar_lvl) {
281 Some((lhs, blocklike)) => { 259 Some((lhs, blocklike)) => {
282 // test stmt_bin_expr_ambiguity 260 // test stmt_bin_expr_ambiguity
283 // fn foo() { 261 // fn foo() {
@@ -293,42 +271,23 @@ fn expr_bp(
293 }; 271 };
294 272
295 loop { 273 loop {
296 if *dollar_lvl > 0 && p.at_r_dollar() {
297 *dollar_lvl -= p.eat_r_dollars(*dollar_lvl);
298 if !newly_dollar_open {
299 // We "pump" bp for make it highest priority
300 bp = 255;
301 }
302 newly_dollar_open = false;
303 }
304
305 let is_range = p.at(T![..]) || p.at(T![..=]); 274 let is_range = p.at(T![..]) || p.at(T![..=]);
306 let (op_bp, op) = current_op(p); 275 let (op_bp, op) = current_op(p);
307 if op_bp < bp { 276 if op_bp < bp {
308 break; 277 break;
309 } 278 }
310 let m = lhs.precede(p); 279 let m = lhs.precede(p);
311 match op { 280 p.bump(op);
312 Op::Simple => p.bump(),
313 Op::Composite(kind, n) => {
314 p.bump_compound(kind, n);
315 }
316 }
317 281
318 expr_bp(p, r, op_bp + 1, dollar_lvl); 282 expr_bp(p, r, op_bp + 1);
319 lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR }); 283 lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR });
320 } 284 }
321 (Some(lhs), BlockLike::NotBlock) 285 (Some(lhs), BlockLike::NotBlock)
322} 286}
323 287
324const LHS_FIRST: TokenSet = 288const LHS_FIRST: TokenSet = atom::ATOM_EXPR_FIRST.union(token_set![AMP, STAR, EXCL, DOT, MINUS]);
325 atom::ATOM_EXPR_FIRST.union(token_set![AMP, STAR, EXCL, DOTDOT, DOTDOTEQ, MINUS]);
326 289
327fn lhs( 290fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> {
328 p: &mut Parser,
329 r: Restrictions,
330 dollar_lvl: &mut usize,
331) -> Option<(CompletedMarker, BlockLike)> {
332 let m; 291 let m;
333 let kind = match p.current() { 292 let kind = match p.current() {
334 // test ref_expr 293 // test ref_expr
@@ -338,7 +297,7 @@ fn lhs(
338 // } 297 // }
339 T![&] => { 298 T![&] => {
340 m = p.start(); 299 m = p.start();
341 p.bump(); 300 p.bump_any();
342 p.eat(T![mut]); 301 p.eat(T![mut]);
343 REF_EXPR 302 REF_EXPR
344 } 303 }
@@ -350,20 +309,23 @@ fn lhs(
350 // } 309 // }
351 T![*] | T![!] | T![-] => { 310 T![*] | T![!] | T![-] => {
352 m = p.start(); 311 m = p.start();
353 p.bump(); 312 p.bump_any();
354 PREFIX_EXPR 313 PREFIX_EXPR
355 } 314 }
356 // test full_range_expr
357 // fn foo() { xs[..]; }
358 T![..] | T![..=] => {
359 m = p.start();
360 p.bump();
361 if p.at_ts(EXPR_FIRST) {
362 expr_bp(p, r, 2, dollar_lvl);
363 }
364 return Some((m.complete(p, RANGE_EXPR), BlockLike::NotBlock));
365 }
366 _ => { 315 _ => {
316 // test full_range_expr
317 // fn foo() { xs[..]; }
318 for &op in [T![..=], T![..]].iter() {
319 if p.at(op) {
320 m = p.start();
321 p.bump(op);
322 if p.at_ts(EXPR_FIRST) {
323 expr_bp(p, r, 2);
324 }
325 return Some((m.complete(p, RANGE_EXPR), BlockLike::NotBlock));
326 }
327 }
328
367 // test expression_after_block 329 // test expression_after_block
368 // fn foo() { 330 // fn foo() {
369 // let mut p = F{x: 5}; 331 // let mut p = F{x: 5};
@@ -374,7 +336,7 @@ fn lhs(
374 return Some(postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block()))); 336 return Some(postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block())));
375 } 337 }
376 }; 338 };
377 expr_bp(p, r, 255, dollar_lvl); 339 expr_bp(p, r, 255);
378 Some((m.complete(p, kind), BlockLike::NotBlock)) 340 Some((m.complete(p, kind), BlockLike::NotBlock))
379} 341}
380 342
@@ -399,29 +361,13 @@ fn postfix_expr(
399 // } 361 // }
400 T!['('] if allow_calls => call_expr(p, lhs), 362 T!['('] if allow_calls => call_expr(p, lhs),
401 T!['['] if allow_calls => index_expr(p, lhs), 363 T!['['] if allow_calls => index_expr(p, lhs),
402 T![.] if p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth(2) == T![::]) => { 364 T![.] => match postfix_dot_expr(p, lhs) {
403 method_call_expr(p, lhs) 365 Ok(it) => it,
404 } 366 Err(it) => {
405 T![.] if p.nth(1) == AWAIT_KW => { 367 lhs = it;
406 // test await_expr 368 break;
407 // fn foo() { 369 }
408 // x.await; 370 },
409 // x.0.await;
410 // x.0().await?.hello();
411 // }
412 let m = lhs.precede(p);
413 p.bump();
414 p.bump();
415 m.complete(p, AWAIT_EXPR)
416 }
417 T![.] => field_expr(p, lhs),
418 // test postfix_range
419 // fn foo() { let x = 1..; }
420 T![..] | T![..=] if !EXPR_FIRST.contains(p.nth(1)) => {
421 let m = lhs.precede(p);
422 p.bump();
423 m.complete(p, RANGE_EXPR)
424 }
425 T![?] => try_expr(p, lhs), 371 T![?] => try_expr(p, lhs),
426 T![as] => cast_expr(p, lhs), 372 T![as] => cast_expr(p, lhs),
427 _ => break, 373 _ => break,
@@ -429,7 +375,46 @@ fn postfix_expr(
429 allow_calls = true; 375 allow_calls = true;
430 block_like = BlockLike::NotBlock; 376 block_like = BlockLike::NotBlock;
431 } 377 }
432 (lhs, block_like) 378 return (lhs, block_like);
379
380 fn postfix_dot_expr(
381 p: &mut Parser,
382 lhs: CompletedMarker,
383 ) -> Result<CompletedMarker, CompletedMarker> {
384 assert!(p.at(T![.]));
385 if p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::])) {
386 return Ok(method_call_expr(p, lhs));
387 }
388
389 // test await_expr
390 // fn foo() {
391 // x.await;
392 // x.0.await;
393 // x.0().await?.hello();
394 // }
395 if p.nth(1) == T![await] {
396 let m = lhs.precede(p);
397 p.bump(T![.]);
398 p.bump(T![await]);
399 return Ok(m.complete(p, AWAIT_EXPR));
400 }
401
402 // test postfix_range
403 // fn foo() { let x = 1..; }
404 for &(op, la) in [(T![..=], 3), (T![..], 2)].iter() {
405 if p.at(op) {
406 return if EXPR_FIRST.contains(p.nth(la)) {
407 Err(lhs)
408 } else {
409 let m = lhs.precede(p);
410 p.bump(op);
411 Ok(m.complete(p, RANGE_EXPR))
412 };
413 }
414 }
415
416 Ok(field_expr(p, lhs))
417 }
433} 418}
434 419
435// test call_expr 420// test call_expr
@@ -453,7 +438,7 @@ fn call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
453fn index_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { 438fn index_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
454 assert!(p.at(T!['['])); 439 assert!(p.at(T!['[']));
455 let m = lhs.precede(p); 440 let m = lhs.precede(p);
456 p.bump(); 441 p.bump_any();
457 expr(p); 442 expr(p);
458 p.expect(T![']']); 443 p.expect(T![']']);
459 m.complete(p, INDEX_EXPR) 444 m.complete(p, INDEX_EXPR)
@@ -465,9 +450,9 @@ fn index_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
465// y.bar::<T>(1, 2,); 450// y.bar::<T>(1, 2,);
466// } 451// }
467fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { 452fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
468 assert!(p.at(T![.]) && p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth(2) == T![::])); 453 assert!(p.at(T![.]) && p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::])));
469 let m = lhs.precede(p); 454 let m = lhs.precede(p);
470 p.bump(); 455 p.bump_any();
471 name_ref(p); 456 name_ref(p);
472 type_args::opt_type_arg_list(p, true); 457 type_args::opt_type_arg_list(p, true);
473 if p.at(T!['(']) { 458 if p.at(T!['(']) {
@@ -493,12 +478,12 @@ fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
493fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { 478fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
494 assert!(p.at(T![.])); 479 assert!(p.at(T![.]));
495 let m = lhs.precede(p); 480 let m = lhs.precede(p);
496 p.bump(); 481 p.bump_any();
497 if p.at(IDENT) || p.at(INT_NUMBER) { 482 if p.at(IDENT) || p.at(INT_NUMBER) {
498 name_ref_or_index(p) 483 name_ref_or_index(p)
499 } else if p.at(FLOAT_NUMBER) { 484 } else if p.at(FLOAT_NUMBER) {
500 // FIXME: How to recover and instead parse INT + T![.]? 485 // FIXME: How to recover and instead parse INT + T![.]?
501 p.bump(); 486 p.bump_any();
502 } else { 487 } else {
503 p.error("expected field name or number") 488 p.error("expected field name or number")
504 } 489 }
@@ -512,7 +497,7 @@ fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
512fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { 497fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
513 assert!(p.at(T![?])); 498 assert!(p.at(T![?]));
514 let m = lhs.precede(p); 499 let m = lhs.precede(p);
515 p.bump(); 500 p.bump_any();
516 m.complete(p, TRY_EXPR) 501 m.complete(p, TRY_EXPR)
517} 502}
518 503
@@ -526,7 +511,7 @@ fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
526fn cast_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { 511fn cast_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
527 assert!(p.at(T![as])); 512 assert!(p.at(T![as]));
528 let m = lhs.precede(p); 513 let m = lhs.precede(p);
529 p.bump(); 514 p.bump_any();
530 // Use type_no_bounds(), because cast expressions are not 515 // Use type_no_bounds(), because cast expressions are not
531 // allowed to have bounds. 516 // allowed to have bounds.
532 types::type_no_bounds(p); 517 types::type_no_bounds(p);
@@ -536,7 +521,7 @@ fn cast_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
536fn arg_list(p: &mut Parser) { 521fn arg_list(p: &mut Parser) {
537 assert!(p.at(T!['('])); 522 assert!(p.at(T!['(']));
538 let m = p.start(); 523 let m = p.start();
539 p.bump(); 524 p.bump_any();
540 while !p.at(T![')']) && !p.at(EOF) { 525 while !p.at(T![')']) && !p.at(EOF) {
541 if !p.at_ts(EXPR_FIRST) { 526 if !p.at_ts(EXPR_FIRST) {
542 p.error("expected expression"); 527 p.error("expected expression");
@@ -567,7 +552,7 @@ fn path_expr(p: &mut Parser, r: Restrictions) -> (CompletedMarker, BlockLike) {
567 record_field_list(p); 552 record_field_list(p);
568 (m.complete(p, RECORD_LIT), BlockLike::NotBlock) 553 (m.complete(p, RECORD_LIT), BlockLike::NotBlock)
569 } 554 }
570 T![!] => { 555 T![!] if !p.at(T![!=]) => {
571 let block_like = items::macro_call_after_excl(p); 556 let block_like = items::macro_call_after_excl(p);
572 (m.complete(p, MACRO_CALL), block_like) 557 (m.complete(p, MACRO_CALL), block_like)
573 } 558 }
@@ -585,7 +570,7 @@ fn path_expr(p: &mut Parser, r: Restrictions) -> (CompletedMarker, BlockLike) {
585pub(crate) fn record_field_list(p: &mut Parser) { 570pub(crate) fn record_field_list(p: &mut Parser) {
586 assert!(p.at(T!['{'])); 571 assert!(p.at(T!['{']));
587 let m = p.start(); 572 let m = p.start();
588 p.bump(); 573 p.bump_any();
589 while !p.at(EOF) && !p.at(T!['}']) { 574 while !p.at(EOF) && !p.at(T!['}']) {
590 match p.current() { 575 match p.current() {
591 // test record_literal_field_with_attr 576 // test record_literal_field_with_attr
@@ -601,8 +586,8 @@ pub(crate) fn record_field_list(p: &mut Parser) {
601 } 586 }
602 m.complete(p, RECORD_FIELD); 587 m.complete(p, RECORD_FIELD);
603 } 588 }
604 T![..] => { 589 T![.] if p.at(T![..]) => {
605 p.bump(); 590 p.bump(T![..]);
606 expr(p); 591 expr(p);
607 } 592 }
608 T!['{'] => error_block(p, "expected a field"), 593 T!['{'] => error_block(p, "expected a field"),
diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs
index ec7f2441d..6e295fbf9 100644
--- a/crates/ra_parser/src/grammar/expressions/atom.rs
+++ b/crates/ra_parser/src/grammar/expressions/atom.rs
@@ -31,7 +31,7 @@ pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> {
31 return None; 31 return None;
32 } 32 }
33 let m = p.start(); 33 let m = p.start();
34 p.bump(); 34 p.bump_any();
35 Some(m.complete(p, LITERAL)) 35 Some(m.complete(p, LITERAL))
36} 36}
37 37
@@ -69,6 +69,7 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
69 let done = match p.current() { 69 let done = match p.current() {
70 T!['('] => tuple_expr(p), 70 T!['('] => tuple_expr(p),
71 T!['['] => array_expr(p), 71 T!['['] => array_expr(p),
72 L_DOLLAR => meta_var_expr(p),
72 T![|] => lambda_expr(p), 73 T![|] => lambda_expr(p),
73 T![move] if la == T![|] => lambda_expr(p), 74 T![move] if la == T![|] => lambda_expr(p),
74 T![async] if la == T![|] || (la == T![move] && p.nth(2) == T![|]) => lambda_expr(p), 75 T![async] if la == T![|] || (la == T![move] && p.nth(2) == T![|]) => lambda_expr(p),
@@ -100,14 +101,14 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
100 } 101 }
101 T![async] if la == T!['{'] || (la == T![move] && p.nth(2) == T!['{']) => { 102 T![async] if la == T!['{'] || (la == T![move] && p.nth(2) == T!['{']) => {
102 let m = p.start(); 103 let m = p.start();
103 p.bump(); 104 p.bump_any();
104 p.eat(T![move]); 105 p.eat(T![move]);
105 block_expr(p, Some(m)) 106 block_expr(p, Some(m))
106 } 107 }
107 T![match] => match_expr(p), 108 T![match] => match_expr(p),
108 T![unsafe] if la == T!['{'] => { 109 T![unsafe] if la == T!['{'] => {
109 let m = p.start(); 110 let m = p.start();
110 p.bump(); 111 p.bump_any();
111 block_expr(p, Some(m)) 112 block_expr(p, Some(m))
112 } 113 }
113 T!['{'] => { 114 T!['{'] => {
@@ -179,7 +180,7 @@ fn tuple_expr(p: &mut Parser) -> CompletedMarker {
179fn array_expr(p: &mut Parser) -> CompletedMarker { 180fn array_expr(p: &mut Parser) -> CompletedMarker {
180 assert!(p.at(T!['['])); 181 assert!(p.at(T!['[']));
181 let m = p.start(); 182 let m = p.start();
182 p.bump(); 183 p.bump_any();
183 if p.eat(T![']']) { 184 if p.eat(T![']']) {
184 return m.complete(p, ARRAY_EXPR); 185 return m.complete(p, ARRAY_EXPR);
185 } 186 }
@@ -261,11 +262,11 @@ fn lambda_expr(p: &mut Parser) -> CompletedMarker {
261fn if_expr(p: &mut Parser) -> CompletedMarker { 262fn if_expr(p: &mut Parser) -> CompletedMarker {
262 assert!(p.at(T![if])); 263 assert!(p.at(T![if]));
263 let m = p.start(); 264 let m = p.start();
264 p.bump(); 265 p.bump_any();
265 cond(p); 266 cond(p);
266 block(p); 267 block(p);
267 if p.at(T![else]) { 268 if p.at(T![else]) {
268 p.bump(); 269 p.bump_any();
269 if p.at(T![if]) { 270 if p.at(T![if]) {
270 if_expr(p); 271 if_expr(p);
271 } else { 272 } else {
@@ -284,8 +285,8 @@ fn if_expr(p: &mut Parser) -> CompletedMarker {
284fn label(p: &mut Parser) { 285fn label(p: &mut Parser) {
285 assert!(p.at(LIFETIME) && p.nth(1) == T![:]); 286 assert!(p.at(LIFETIME) && p.nth(1) == T![:]);
286 let m = p.start(); 287 let m = p.start();
287 p.bump(); 288 p.bump_any();
288 p.bump(); 289 p.bump_any();
289 m.complete(p, LABEL); 290 m.complete(p, LABEL);
290} 291}
291 292
@@ -296,7 +297,7 @@ fn label(p: &mut Parser) {
296fn loop_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { 297fn loop_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
297 assert!(p.at(T![loop])); 298 assert!(p.at(T![loop]));
298 let m = m.unwrap_or_else(|| p.start()); 299 let m = m.unwrap_or_else(|| p.start());
299 p.bump(); 300 p.bump_any();
300 block(p); 301 block(p);
301 m.complete(p, LOOP_EXPR) 302 m.complete(p, LOOP_EXPR)
302} 303}
@@ -309,7 +310,7 @@ fn loop_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
309fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { 310fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
310 assert!(p.at(T![while])); 311 assert!(p.at(T![while]));
311 let m = m.unwrap_or_else(|| p.start()); 312 let m = m.unwrap_or_else(|| p.start());
312 p.bump(); 313 p.bump_any();
313 cond(p); 314 cond(p);
314 block(p); 315 block(p);
315 m.complete(p, WHILE_EXPR) 316 m.complete(p, WHILE_EXPR)
@@ -322,7 +323,7 @@ fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
322fn for_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { 323fn for_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
323 assert!(p.at(T![for])); 324 assert!(p.at(T![for]));
324 let m = m.unwrap_or_else(|| p.start()); 325 let m = m.unwrap_or_else(|| p.start());
325 p.bump(); 326 p.bump_any();
326 patterns::pattern(p); 327 patterns::pattern(p);
327 p.expect(T![in]); 328 p.expect(T![in]);
328 expr_no_struct(p); 329 expr_no_struct(p);
@@ -356,7 +357,7 @@ fn cond(p: &mut Parser) {
356fn match_expr(p: &mut Parser) -> CompletedMarker { 357fn match_expr(p: &mut Parser) -> CompletedMarker {
357 assert!(p.at(T![match])); 358 assert!(p.at(T![match]));
358 let m = p.start(); 359 let m = p.start();
359 p.bump(); 360 p.bump_any();
360 expr_no_struct(p); 361 expr_no_struct(p);
361 if p.at(T!['{']) { 362 if p.at(T!['{']) {
362 match_arm_list(p); 363 match_arm_list(p);
@@ -452,7 +453,7 @@ fn match_arm(p: &mut Parser) -> BlockLike {
452fn match_guard(p: &mut Parser) -> CompletedMarker { 453fn match_guard(p: &mut Parser) -> CompletedMarker {
453 assert!(p.at(T![if])); 454 assert!(p.at(T![if]));
454 let m = p.start(); 455 let m = p.start();
455 p.bump(); 456 p.bump_any();
456 expr(p); 457 expr(p);
457 m.complete(p, MATCH_GUARD) 458 m.complete(p, MATCH_GUARD)
458} 459}
@@ -478,7 +479,7 @@ pub(super) fn block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
478fn return_expr(p: &mut Parser) -> CompletedMarker { 479fn return_expr(p: &mut Parser) -> CompletedMarker {
479 assert!(p.at(T![return])); 480 assert!(p.at(T![return]));
480 let m = p.start(); 481 let m = p.start();
481 p.bump(); 482 p.bump_any();
482 if p.at_ts(EXPR_FIRST) { 483 if p.at_ts(EXPR_FIRST) {
483 expr(p); 484 expr(p);
484 } 485 }
@@ -495,7 +496,7 @@ fn return_expr(p: &mut Parser) -> CompletedMarker {
495fn continue_expr(p: &mut Parser) -> CompletedMarker { 496fn continue_expr(p: &mut Parser) -> CompletedMarker {
496 assert!(p.at(T![continue])); 497 assert!(p.at(T![continue]));
497 let m = p.start(); 498 let m = p.start();
498 p.bump(); 499 p.bump_any();
499 p.eat(LIFETIME); 500 p.eat(LIFETIME);
500 m.complete(p, CONTINUE_EXPR) 501 m.complete(p, CONTINUE_EXPR)
501} 502}
@@ -512,7 +513,7 @@ fn continue_expr(p: &mut Parser) -> CompletedMarker {
512fn break_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker { 513fn break_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker {
513 assert!(p.at(T![break])); 514 assert!(p.at(T![break]));
514 let m = p.start(); 515 let m = p.start();
515 p.bump(); 516 p.bump_any();
516 p.eat(LIFETIME); 517 p.eat(LIFETIME);
517 // test break_ambiguity 518 // test break_ambiguity
518 // fn foo(){ 519 // fn foo(){
@@ -534,7 +535,7 @@ fn break_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker {
534fn try_block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { 535fn try_block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
535 assert!(p.at(T![try])); 536 assert!(p.at(T![try]));
536 let m = m.unwrap_or_else(|| p.start()); 537 let m = m.unwrap_or_else(|| p.start());
537 p.bump(); 538 p.bump_any();
538 block(p); 539 block(p);
539 m.complete(p, TRY_EXPR) 540 m.complete(p, TRY_EXPR)
540} 541}
@@ -548,9 +549,33 @@ fn try_block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
548fn box_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { 549fn box_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
549 assert!(p.at(T![box])); 550 assert!(p.at(T![box]));
550 let m = m.unwrap_or_else(|| p.start()); 551 let m = m.unwrap_or_else(|| p.start());
551 p.bump(); 552 p.bump_any();
552 if p.at_ts(EXPR_FIRST) { 553 if p.at_ts(EXPR_FIRST) {
553 expr(p); 554 expr(p);
554 } 555 }
555 m.complete(p, BOX_EXPR) 556 m.complete(p, BOX_EXPR)
556} 557}
558
559/// Expression from `$var` macro expansion, wrapped in dollars
560fn meta_var_expr(p: &mut Parser) -> CompletedMarker {
561 assert!(p.at(L_DOLLAR));
562 let m = p.start();
563 p.bump(L_DOLLAR);
564 let (completed, _is_block) =
565 expr_bp(p, Restrictions { forbid_structs: false, prefer_stmt: false }, 1);
566
567 match (completed, p.current()) {
568 (Some(it), R_DOLLAR) => {
569 p.bump(R_DOLLAR);
570 m.abandon(p);
571 it
572 }
573 _ => {
574 while !p.at(R_DOLLAR) {
575 p.bump_any()
576 }
577 p.bump(R_DOLLAR);
578 m.complete(p, ERROR)
579 }
580 }
581}
diff --git a/crates/ra_parser/src/grammar/items.rs b/crates/ra_parser/src/grammar/items.rs
index b4327b78f..eff9d67e4 100644
--- a/crates/ra_parser/src/grammar/items.rs
+++ b/crates/ra_parser/src/grammar/items.rs
@@ -64,7 +64,7 @@ pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemF
64 } else if p.at(T!['}']) && !stop_on_r_curly { 64 } else if p.at(T!['}']) && !stop_on_r_curly {
65 let e = p.start(); 65 let e = p.start();
66 p.error("unmatched `}`"); 66 p.error("unmatched `}`");
67 p.bump(); 67 p.bump_any();
68 e.complete(p, ERROR); 68 e.complete(p, ERROR);
69 } else if !p.at(EOF) && !p.at(T!['}']) { 69 } else if !p.at(EOF) && !p.at(T!['}']) {
70 p.err_and_bump("expected an item"); 70 p.err_and_bump("expected an item");
@@ -276,9 +276,9 @@ fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> {
276 276
277fn extern_crate_item(p: &mut Parser, m: Marker) { 277fn extern_crate_item(p: &mut Parser, m: Marker) {
278 assert!(p.at(T![extern])); 278 assert!(p.at(T![extern]));
279 p.bump(); 279 p.bump_any();
280 assert!(p.at(T![crate])); 280 assert!(p.at(T![crate]));
281 p.bump(); 281 p.bump_any();
282 name_ref(p); 282 name_ref(p);
283 opt_alias(p); 283 opt_alias(p);
284 p.expect(T![;]); 284 p.expect(T![;]);
@@ -288,7 +288,7 @@ fn extern_crate_item(p: &mut Parser, m: Marker) {
288pub(crate) fn extern_item_list(p: &mut Parser) { 288pub(crate) fn extern_item_list(p: &mut Parser) {
289 assert!(p.at(T!['{'])); 289 assert!(p.at(T!['{']));
290 let m = p.start(); 290 let m = p.start();
291 p.bump(); 291 p.bump_any();
292 mod_contents(p, true); 292 mod_contents(p, true);
293 p.expect(T!['}']); 293 p.expect(T!['}']);
294 m.complete(p, EXTERN_ITEM_LIST); 294 m.complete(p, EXTERN_ITEM_LIST);
@@ -296,7 +296,7 @@ pub(crate) fn extern_item_list(p: &mut Parser) {
296 296
297fn fn_def(p: &mut Parser, flavor: ItemFlavor) { 297fn fn_def(p: &mut Parser, flavor: ItemFlavor) {
298 assert!(p.at(T![fn])); 298 assert!(p.at(T![fn]));
299 p.bump(); 299 p.bump_any();
300 300
301 name_r(p, ITEM_RECOVERY_SET); 301 name_r(p, ITEM_RECOVERY_SET);
302 // test function_type_params 302 // test function_type_params
@@ -323,7 +323,7 @@ fn fn_def(p: &mut Parser, flavor: ItemFlavor) {
323 // test fn_decl 323 // test fn_decl
324 // trait T { fn foo(); } 324 // trait T { fn foo(); }
325 if p.at(T![;]) { 325 if p.at(T![;]) {
326 p.bump(); 326 p.bump_any();
327 } else { 327 } else {
328 expressions::block(p) 328 expressions::block(p)
329 } 329 }
@@ -333,7 +333,7 @@ fn fn_def(p: &mut Parser, flavor: ItemFlavor) {
333// type Foo = Bar; 333// type Foo = Bar;
334fn type_def(p: &mut Parser, m: Marker) { 334fn type_def(p: &mut Parser, m: Marker) {
335 assert!(p.at(T![type])); 335 assert!(p.at(T![type]));
336 p.bump(); 336 p.bump_any();
337 337
338 name(p); 338 name(p);
339 339
@@ -357,7 +357,7 @@ fn type_def(p: &mut Parser, m: Marker) {
357 357
358pub(crate) fn mod_item(p: &mut Parser, m: Marker) { 358pub(crate) fn mod_item(p: &mut Parser, m: Marker) {
359 assert!(p.at(T![mod])); 359 assert!(p.at(T![mod]));
360 p.bump(); 360 p.bump_any();
361 361
362 name(p); 362 name(p);
363 if p.at(T!['{']) { 363 if p.at(T!['{']) {
@@ -371,7 +371,7 @@ pub(crate) fn mod_item(p: &mut Parser, m: Marker) {
371pub(crate) fn mod_item_list(p: &mut Parser) { 371pub(crate) fn mod_item_list(p: &mut Parser) {
372 assert!(p.at(T!['{'])); 372 assert!(p.at(T!['{']));
373 let m = p.start(); 373 let m = p.start();
374 p.bump(); 374 p.bump_any();
375 mod_contents(p, true); 375 mod_contents(p, true);
376 p.expect(T!['}']); 376 p.expect(T!['}']);
377 m.complete(p, ITEM_LIST); 377 m.complete(p, ITEM_LIST);
@@ -412,7 +412,7 @@ pub(crate) fn token_tree(p: &mut Parser) {
412 _ => unreachable!(), 412 _ => unreachable!(),
413 }; 413 };
414 let m = p.start(); 414 let m = p.start();
415 p.bump(); 415 p.bump_any();
416 while !p.at(EOF) && !p.at(closing_paren_kind) { 416 while !p.at(EOF) && !p.at(closing_paren_kind) {
417 match p.current() { 417 match p.current() {
418 T!['{'] | T!['('] | T!['['] => token_tree(p), 418 T!['{'] | T!['('] | T!['['] => token_tree(p),
@@ -422,7 +422,7 @@ pub(crate) fn token_tree(p: &mut Parser) {
422 return; 422 return;
423 } 423 }
424 T![')'] | T![']'] => p.err_and_bump("unmatched brace"), 424 T![')'] | T![']'] => p.err_and_bump("unmatched brace"),
425 _ => p.bump_raw(), 425 _ => p.bump_any(),
426 } 426 }
427 } 427 }
428 p.expect(closing_paren_kind); 428 p.expect(closing_paren_kind);
diff --git a/crates/ra_parser/src/grammar/items/consts.rs b/crates/ra_parser/src/grammar/items/consts.rs
index b4908ebba..e11546333 100644
--- a/crates/ra_parser/src/grammar/items/consts.rs
+++ b/crates/ra_parser/src/grammar/items/consts.rs
@@ -10,7 +10,7 @@ pub(super) fn const_def(p: &mut Parser, m: Marker) {
10 10
11fn const_or_static(p: &mut Parser, m: Marker, kw: SyntaxKind, def: SyntaxKind) { 11fn const_or_static(p: &mut Parser, m: Marker, kw: SyntaxKind, def: SyntaxKind) {
12 assert!(p.at(kw)); 12 assert!(p.at(kw));
13 p.bump(); 13 p.bump_any();
14 p.eat(T![mut]); // FIXME: validator to forbid const mut 14 p.eat(T![mut]); // FIXME: validator to forbid const mut
15 name(p); 15 name(p);
16 types::ascription(p); 16 types::ascription(p);
diff --git a/crates/ra_parser/src/grammar/items/nominal.rs b/crates/ra_parser/src/grammar/items/nominal.rs
index 54f02c7c9..460acd65e 100644
--- a/crates/ra_parser/src/grammar/items/nominal.rs
+++ b/crates/ra_parser/src/grammar/items/nominal.rs
@@ -11,7 +11,7 @@ pub(super) fn struct_def(p: &mut Parser, m: Marker, kind: SyntaxKind) {
11 type_params::opt_where_clause(p); 11 type_params::opt_where_clause(p);
12 match p.current() { 12 match p.current() {
13 T![;] => { 13 T![;] => {
14 p.bump(); 14 p.bump_any();
15 } 15 }
16 T!['{'] => record_field_def_list(p), 16 T!['{'] => record_field_def_list(p),
17 _ => { 17 _ => {
@@ -21,7 +21,7 @@ pub(super) fn struct_def(p: &mut Parser, m: Marker, kind: SyntaxKind) {
21 } 21 }
22 } 22 }
23 T![;] if kind == T![struct] => { 23 T![;] if kind == T![struct] => {
24 p.bump(); 24 p.bump_any();
25 } 25 }
26 T!['{'] => record_field_def_list(p), 26 T!['{'] => record_field_def_list(p),
27 T!['('] if kind == T![struct] => { 27 T!['('] if kind == T![struct] => {
@@ -44,7 +44,7 @@ pub(super) fn struct_def(p: &mut Parser, m: Marker, kind: SyntaxKind) {
44 44
45pub(super) fn enum_def(p: &mut Parser, m: Marker) { 45pub(super) fn enum_def(p: &mut Parser, m: Marker) {
46 assert!(p.at(T![enum])); 46 assert!(p.at(T![enum]));
47 p.bump(); 47 p.bump_any();
48 name_r(p, ITEM_RECOVERY_SET); 48 name_r(p, ITEM_RECOVERY_SET);
49 type_params::opt_type_param_list(p); 49 type_params::opt_type_param_list(p);
50 type_params::opt_where_clause(p); 50 type_params::opt_where_clause(p);
@@ -59,7 +59,7 @@ pub(super) fn enum_def(p: &mut Parser, m: Marker) {
59pub(crate) fn enum_variant_list(p: &mut Parser) { 59pub(crate) fn enum_variant_list(p: &mut Parser) {
60 assert!(p.at(T!['{'])); 60 assert!(p.at(T!['{']));
61 let m = p.start(); 61 let m = p.start();
62 p.bump(); 62 p.bump_any();
63 while !p.at(EOF) && !p.at(T!['}']) { 63 while !p.at(EOF) && !p.at(T!['}']) {
64 if p.at(T!['{']) { 64 if p.at(T!['{']) {
65 error_block(p, "expected enum variant"); 65 error_block(p, "expected enum variant");
@@ -73,7 +73,7 @@ pub(crate) fn enum_variant_list(p: &mut Parser) {
73 T!['{'] => record_field_def_list(p), 73 T!['{'] => record_field_def_list(p),
74 T!['('] => tuple_field_def_list(p), 74 T!['('] => tuple_field_def_list(p),
75 T![=] => { 75 T![=] => {
76 p.bump(); 76 p.bump_any();
77 expressions::expr(p); 77 expressions::expr(p);
78 } 78 }
79 _ => (), 79 _ => (),
@@ -94,7 +94,7 @@ pub(crate) fn enum_variant_list(p: &mut Parser) {
94pub(crate) fn record_field_def_list(p: &mut Parser) { 94pub(crate) fn record_field_def_list(p: &mut Parser) {
95 assert!(p.at(T!['{'])); 95 assert!(p.at(T!['{']));
96 let m = p.start(); 96 let m = p.start();
97 p.bump(); 97 p.bump_any();
98 while !p.at(T!['}']) && !p.at(EOF) { 98 while !p.at(T!['}']) && !p.at(EOF) {
99 if p.at(T!['{']) { 99 if p.at(T!['{']) {
100 error_block(p, "expected field"); 100 error_block(p, "expected field");
diff --git a/crates/ra_parser/src/grammar/items/traits.rs b/crates/ra_parser/src/grammar/items/traits.rs
index 5fcacfbff..b49221a4b 100644
--- a/crates/ra_parser/src/grammar/items/traits.rs
+++ b/crates/ra_parser/src/grammar/items/traits.rs
@@ -5,7 +5,7 @@ use super::*;
5// trait X<U: Debug + Display>: Hash + Clone where U: Copy {} 5// trait X<U: Debug + Display>: Hash + Clone where U: Copy {}
6pub(super) fn trait_def(p: &mut Parser) { 6pub(super) fn trait_def(p: &mut Parser) {
7 assert!(p.at(T![trait])); 7 assert!(p.at(T![trait]));
8 p.bump(); 8 p.bump_any();
9 name_r(p, ITEM_RECOVERY_SET); 9 name_r(p, ITEM_RECOVERY_SET);
10 type_params::opt_type_param_list(p); 10 type_params::opt_type_param_list(p);
11 if p.at(T![:]) { 11 if p.at(T![:]) {
@@ -29,7 +29,7 @@ pub(super) fn trait_def(p: &mut Parser) {
29pub(crate) fn trait_item_list(p: &mut Parser) { 29pub(crate) fn trait_item_list(p: &mut Parser) {
30 assert!(p.at(T!['{'])); 30 assert!(p.at(T!['{']));
31 let m = p.start(); 31 let m = p.start();
32 p.bump(); 32 p.bump_any();
33 while !p.at(EOF) && !p.at(T!['}']) { 33 while !p.at(EOF) && !p.at(T!['}']) {
34 if p.at(T!['{']) { 34 if p.at(T!['{']) {
35 error_block(p, "expected an item"); 35 error_block(p, "expected an item");
@@ -45,7 +45,7 @@ pub(crate) fn trait_item_list(p: &mut Parser) {
45// impl Foo {} 45// impl Foo {}
46pub(super) fn impl_block(p: &mut Parser) { 46pub(super) fn impl_block(p: &mut Parser) {
47 assert!(p.at(T![impl])); 47 assert!(p.at(T![impl]));
48 p.bump(); 48 p.bump_any();
49 if choose_type_params_over_qpath(p) { 49 if choose_type_params_over_qpath(p) {
50 type_params::opt_type_param_list(p); 50 type_params::opt_type_param_list(p);
51 } 51 }
@@ -78,7 +78,7 @@ pub(super) fn impl_block(p: &mut Parser) {
78pub(crate) fn impl_item_list(p: &mut Parser) { 78pub(crate) fn impl_item_list(p: &mut Parser) {
79 assert!(p.at(T!['{'])); 79 assert!(p.at(T!['{']));
80 let m = p.start(); 80 let m = p.start();
81 p.bump(); 81 p.bump_any();
82 // test impl_inner_attributes 82 // test impl_inner_attributes
83 // enum F{} 83 // enum F{}
84 // impl F { 84 // impl F {
diff --git a/crates/ra_parser/src/grammar/items/use_item.rs b/crates/ra_parser/src/grammar/items/use_item.rs
index 83a65e226..f28f522b8 100644
--- a/crates/ra_parser/src/grammar/items/use_item.rs
+++ b/crates/ra_parser/src/grammar/items/use_item.rs
@@ -2,7 +2,7 @@ use super::*;
2 2
3pub(super) fn use_item(p: &mut Parser, m: Marker) { 3pub(super) fn use_item(p: &mut Parser, m: Marker) {
4 assert!(p.at(T![use])); 4 assert!(p.at(T![use]));
5 p.bump(); 5 p.bump_any();
6 use_tree(p); 6 use_tree(p);
7 p.expect(T![;]); 7 p.expect(T![;]);
8 m.complete(p, USE_ITEM); 8 m.complete(p, USE_ITEM);
@@ -13,9 +13,8 @@ pub(super) fn use_item(p: &mut Parser, m: Marker) {
13/// so handles both `some::path::{inner::path}` and `inner::path` in 13/// so handles both `some::path::{inner::path}` and `inner::path` in
14/// `use some::path::{inner::path};` 14/// `use some::path::{inner::path};`
15fn use_tree(p: &mut Parser) { 15fn use_tree(p: &mut Parser) {
16 let la = p.nth(1);
17 let m = p.start(); 16 let m = p.start();
18 match (p.current(), la) { 17 match p.current() {
19 // Finish the use_tree for cases of e.g. 18 // Finish the use_tree for cases of e.g.
20 // `use some::path::{self, *};` or `use *;` 19 // `use some::path::{self, *};` or `use *;`
21 // This does not handle cases such as `use some::path::*` 20 // This does not handle cases such as `use some::path::*`
@@ -28,15 +27,15 @@ fn use_tree(p: &mut Parser) {
28 // use ::*; 27 // use ::*;
29 // use some::path::{*}; 28 // use some::path::{*};
30 // use some::path::{::*}; 29 // use some::path::{::*};
31 (T![*], _) => p.bump(), 30 T![*] => p.bump(T![*]),
32 (T![::], T![*]) => { 31 T![:] if p.at(T![::]) && p.nth(2) == T![*] => {
33 // Parse `use ::*;`, which imports all from the crate root in Rust 2015 32 // Parse `use ::*;`, which imports all from the crate root in Rust 2015
34 // This is invalid inside a use_tree_list, (e.g. `use some::path::{::*}`) 33 // This is invalid inside a use_tree_list, (e.g. `use some::path::{::*}`)
35 // but still parses and errors later: ('crate root in paths can only be used in start position') 34 // but still parses and errors later: ('crate root in paths can only be used in start position')
36 // FIXME: Add this error (if not out of scope) 35 // FIXME: Add this error (if not out of scope)
37 // In Rust 2018, it is always invalid (see above) 36 // In Rust 2018, it is always invalid (see above)
38 p.bump(); 37 p.bump(T![::]);
39 p.bump(); 38 p.bump(T![*]);
40 } 39 }
41 // Open a use tree list 40 // Open a use tree list
42 // Handles cases such as `use {some::path};` or `{inner::path}` in 41 // Handles cases such as `use {some::path};` or `{inner::path}` in
@@ -47,10 +46,11 @@ fn use_tree(p: &mut Parser) {
47 // use {path::from::root}; // Rust 2015 46 // use {path::from::root}; // Rust 2015
48 // use ::{some::arbritrary::path}; // Rust 2015 47 // use ::{some::arbritrary::path}; // Rust 2015
49 // use ::{{{crate::export}}}; // Nonsensical but perfectly legal nestnig 48 // use ::{{{crate::export}}}; // Nonsensical but perfectly legal nestnig
50 (T!['{'], _) | (T![::], T!['{']) => { 49 T!['{'] => {
51 if p.at(T![::]) { 50 use_tree_list(p);
52 p.bump(); 51 }
53 } 52 T![:] if p.at(T![::]) && p.nth(2) == T!['{'] => {
53 p.bump(T![::]);
54 use_tree_list(p); 54 use_tree_list(p);
55 } 55 }
56 // Parse a 'standard' path. 56 // Parse a 'standard' path.
@@ -80,11 +80,11 @@ fn use_tree(p: &mut Parser) {
80 // use Trait as _; 80 // use Trait as _;
81 opt_alias(p); 81 opt_alias(p);
82 } 82 }
83 T![::] => { 83 T![:] if p.at(T![::]) => {
84 p.bump(); 84 p.bump(T![::]);
85 match p.current() { 85 match p.current() {
86 T![*] => { 86 T![*] => {
87 p.bump(); 87 p.bump_any();
88 } 88 }
89 // test use_tree_list_after_path 89 // test use_tree_list_after_path
90 // use crate::{Item}; 90 // use crate::{Item};
@@ -114,7 +114,7 @@ fn use_tree(p: &mut Parser) {
114pub(crate) fn use_tree_list(p: &mut Parser) { 114pub(crate) fn use_tree_list(p: &mut Parser) {
115 assert!(p.at(T!['{'])); 115 assert!(p.at(T!['{']));
116 let m = p.start(); 116 let m = p.start();
117 p.bump(); 117 p.bump_any();
118 while !p.at(EOF) && !p.at(T!['}']) { 118 while !p.at(EOF) && !p.at(T!['}']) {
119 use_tree(p); 119 use_tree(p);
120 if !p.at(T!['}']) { 120 if !p.at(T!['}']) {
diff --git a/crates/ra_parser/src/grammar/params.rs b/crates/ra_parser/src/grammar/params.rs
index 0b09f1874..5893b22fd 100644
--- a/crates/ra_parser/src/grammar/params.rs
+++ b/crates/ra_parser/src/grammar/params.rs
@@ -39,7 +39,7 @@ fn list_(p: &mut Parser, flavor: Flavor) {
39 let (bra, ket) = if flavor.type_required() { (T!['('], T![')']) } else { (T![|], T![|]) }; 39 let (bra, ket) = if flavor.type_required() { (T!['('], T![')']) } else { (T![|], T![|]) };
40 assert!(p.at(bra)); 40 assert!(p.at(bra));
41 let m = p.start(); 41 let m = p.start();
42 p.bump(); 42 p.bump_any();
43 if flavor.type_required() { 43 if flavor.type_required() {
44 // test self_param_outer_attr 44 // test self_param_outer_attr
45 // fn f(#[must_use] self) {} 45 // fn f(#[must_use] self) {}
@@ -80,7 +80,7 @@ fn value_parameter(p: &mut Parser, flavor: Flavor) {
80 match flavor { 80 match flavor {
81 Flavor::OptionalType | Flavor::Normal => { 81 Flavor::OptionalType | Flavor::Normal => {
82 patterns::pattern(p); 82 patterns::pattern(p);
83 if p.at(T![:]) || flavor.type_required() { 83 if p.at(T![:]) && !p.at(T![::]) || flavor.type_required() {
84 types::ascription(p) 84 types::ascription(p)
85 } 85 }
86 } 86 }
@@ -96,10 +96,11 @@ fn value_parameter(p: &mut Parser, flavor: Flavor) {
96 // trait Foo { 96 // trait Foo {
97 // fn bar(_: u64, mut x: i32); 97 // fn bar(_: u64, mut x: i32);
98 // } 98 // }
99 if (la0 == IDENT || la0 == T![_]) && la1 == T![:] 99 if (la0 == IDENT || la0 == T![_]) && la1 == T![:] && !p.nth_at(1, T![::])
100 || la0 == T![mut] && la1 == IDENT && la2 == T![:] 100 || la0 == T![mut] && la1 == IDENT && la2 == T![:]
101 || la0 == T![&] && la1 == IDENT && la2 == T![:] 101 || la0 == T![&]
102 || la0 == T![&] && la1 == T![mut] && la2 == IDENT && la3 == T![:] 102 && (la1 == IDENT && la2 == T![:] && !p.nth_at(2, T![::])
103 || la1 == T![mut] && la2 == IDENT && la3 == T![:] && !p.nth_at(3, T![::]))
103 { 104 {
104 patterns::pattern(p); 105 patterns::pattern(p);
105 types::ascription(p); 106 types::ascription(p);
@@ -146,7 +147,7 @@ fn opt_self_param(p: &mut Parser) {
146 }; 147 };
147 m = p.start(); 148 m = p.start();
148 for _ in 0..n_toks { 149 for _ in 0..n_toks {
149 p.bump(); 150 p.bump_any();
150 } 151 }
151 } 152 }
152 m.complete(p, SELF_PARAM); 153 m.complete(p, SELF_PARAM);
diff --git a/crates/ra_parser/src/grammar/paths.rs b/crates/ra_parser/src/grammar/paths.rs
index 28c35a67d..24b65128e 100644
--- a/crates/ra_parser/src/grammar/paths.rs
+++ b/crates/ra_parser/src/grammar/paths.rs
@@ -1,7 +1,7 @@
1use super::*; 1use super::*;
2 2
3pub(super) const PATH_FIRST: TokenSet = 3pub(super) const PATH_FIRST: TokenSet =
4 token_set![IDENT, SELF_KW, SUPER_KW, CRATE_KW, COLONCOLON, L_ANGLE]; 4 token_set![IDENT, SELF_KW, SUPER_KW, CRATE_KW, COLON, L_ANGLE];
5 5
6pub(super) fn is_path_start(p: &Parser) -> bool { 6pub(super) fn is_path_start(p: &Parser) -> bool {
7 is_use_path_start(p) || p.at(T![<]) 7 is_use_path_start(p) || p.at(T![<])
@@ -9,7 +9,8 @@ pub(super) fn is_path_start(p: &Parser) -> bool {
9 9
10pub(super) fn is_use_path_start(p: &Parser) -> bool { 10pub(super) fn is_use_path_start(p: &Parser) -> bool {
11 match p.current() { 11 match p.current() {
12 IDENT | T![self] | T![super] | T![crate] | T![::] => true, 12 IDENT | T![self] | T![super] | T![crate] => true,
13 T![:] if p.at(T![::]) => true,
13 _ => false, 14 _ => false,
14 } 15 }
15} 16}
@@ -38,13 +39,13 @@ fn path(p: &mut Parser, mode: Mode) {
38 path_segment(p, mode, true); 39 path_segment(p, mode, true);
39 let mut qual = path.complete(p, PATH); 40 let mut qual = path.complete(p, PATH);
40 loop { 41 loop {
41 let use_tree = match p.nth(1) { 42 let use_tree = match p.nth(2) {
42 T![*] | T!['{'] => true, 43 T![*] | T!['{'] => true,
43 _ => false, 44 _ => false,
44 }; 45 };
45 if p.at(T![::]) && !use_tree { 46 if p.at(T![::]) && !use_tree {
46 let path = qual.precede(p); 47 let path = qual.precede(p);
47 p.bump(); 48 p.bump(T![::]);
48 path_segment(p, mode, false); 49 path_segment(p, mode, false);
49 let path = path.complete(p, PATH); 50 let path = path.complete(p, PATH);
50 qual = path; 51 qual = path;
@@ -80,7 +81,7 @@ fn path_segment(p: &mut Parser, mode: Mode, first: bool) {
80 } 81 }
81 // test crate_path 82 // test crate_path
82 // use crate::foo; 83 // use crate::foo;
83 T![self] | T![super] | T![crate] => p.bump(), 84 T![self] | T![super] | T![crate] => p.bump_any(),
84 _ => { 85 _ => {
85 p.err_recover("expected identifier", items::ITEM_RECOVERY_SET); 86 p.err_recover("expected identifier", items::ITEM_RECOVERY_SET);
86 } 87 }
diff --git a/crates/ra_parser/src/grammar/patterns.rs b/crates/ra_parser/src/grammar/patterns.rs
index 32cde7de6..dd1d25b07 100644
--- a/crates/ra_parser/src/grammar/patterns.rs
+++ b/crates/ra_parser/src/grammar/patterns.rs
@@ -34,17 +34,20 @@ pub(super) fn pattern_r(p: &mut Parser, recovery_set: TokenSet) {
34 // 200 .. 301=> (), 34 // 200 .. 301=> (),
35 // } 35 // }
36 // } 36 // }
37 if p.at(T![...]) || p.at(T![..=]) || p.at(T![..]) { 37 for &range_op in [T![...], T![..=], T![..]].iter() {
38 let m = lhs.precede(p); 38 if p.at(range_op) {
39 p.bump(); 39 let m = lhs.precede(p);
40 atom_pat(p, recovery_set); 40 p.bump(range_op);
41 m.complete(p, RANGE_PAT); 41 atom_pat(p, recovery_set);
42 m.complete(p, RANGE_PAT);
43 return;
44 }
42 } 45 }
43 // test marco_pat 46 // test marco_pat
44 // fn main() { 47 // fn main() {
45 // let m!(x) = 0; 48 // let m!(x) = 0;
46 // } 49 // }
47 else if lhs.kind() == PATH_PAT && p.at(T![!]) { 50 if lhs.kind() == PATH_PAT && p.at(T![!]) {
48 let m = lhs.precede(p); 51 let m = lhs.precede(p);
49 items::macro_call_after_excl(p); 52 items::macro_call_after_excl(p);
50 m.complete(p, MACRO_CALL); 53 m.complete(p, MACRO_CALL);
@@ -56,14 +59,16 @@ const PAT_RECOVERY_SET: TokenSet =
56 token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA]; 59 token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA];
57 60
58fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> { 61fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> {
59 // Checks the token after an IDENT to see if a pattern is a path (Struct { .. }) or macro
60 // (T![x]).
61 let is_path_or_macro_pat =
62 |la1| la1 == T![::] || la1 == T!['('] || la1 == T!['{'] || la1 == T![!];
63
64 let m = match p.nth(0) { 62 let m = match p.nth(0) {
65 T![box] => box_pat(p), 63 T![box] => box_pat(p),
66 T![ref] | T![mut] | IDENT if !is_path_or_macro_pat(p.nth(1)) => bind_pat(p, true), 64 T![ref] | T![mut] => bind_pat(p, true),
65 IDENT => match p.nth(1) {
66 // Checks the token after an IDENT to see if a pattern is a path (Struct { .. }) or macro
67 // (T![x]).
68 T!['('] | T!['{'] | T![!] => path_pat(p),
69 T![:] if p.nth_at(1, T![::]) => path_pat(p),
70 _ => bind_pat(p, true),
71 },
67 72
68 _ if paths::is_use_path_start(p) => path_pat(p), 73 _ if paths::is_use_path_start(p) => path_pat(p),
69 _ if is_literal_pat_start(p) => literal_pat(p), 74 _ if is_literal_pat_start(p) => literal_pat(p),
@@ -100,7 +105,7 @@ fn literal_pat(p: &mut Parser) -> CompletedMarker {
100 assert!(is_literal_pat_start(p)); 105 assert!(is_literal_pat_start(p));
101 let m = p.start(); 106 let m = p.start();
102 if p.at(T![-]) { 107 if p.at(T![-]) {
103 p.bump(); 108 p.bump_any();
104 } 109 }
105 expressions::literal(p); 110 expressions::literal(p);
106 m.complete(p, LITERAL_PAT) 111 m.complete(p, LITERAL_PAT)
@@ -140,7 +145,7 @@ fn path_pat(p: &mut Parser) -> CompletedMarker {
140// } 145// }
141fn tuple_pat_fields(p: &mut Parser) { 146fn tuple_pat_fields(p: &mut Parser) {
142 assert!(p.at(T!['('])); 147 assert!(p.at(T!['(']));
143 p.bump(); 148 p.bump_any();
144 pat_list(p, T![')']); 149 pat_list(p, T![')']);
145 p.expect(T![')']); 150 p.expect(T![')']);
146} 151}
@@ -155,10 +160,10 @@ fn tuple_pat_fields(p: &mut Parser) {
155fn record_field_pat_list(p: &mut Parser) { 160fn record_field_pat_list(p: &mut Parser) {
156 assert!(p.at(T!['{'])); 161 assert!(p.at(T!['{']));
157 let m = p.start(); 162 let m = p.start();
158 p.bump(); 163 p.bump_any();
159 while !p.at(EOF) && !p.at(T!['}']) { 164 while !p.at(EOF) && !p.at(T!['}']) {
160 match p.current() { 165 match p.current() {
161 T![..] => p.bump(), 166 T![.] if p.at(T![..]) => p.bump(T![..]),
162 IDENT if p.nth(1) == T![:] => record_field_pat(p), 167 IDENT if p.nth(1) == T![:] => record_field_pat(p),
163 T!['{'] => error_block(p, "expected ident"), 168 T!['{'] => error_block(p, "expected ident"),
164 T![box] => { 169 T![box] => {
@@ -182,7 +187,7 @@ fn record_field_pat(p: &mut Parser) {
182 187
183 let m = p.start(); 188 let m = p.start();
184 name(p); 189 name(p);
185 p.bump(); 190 p.bump_any();
186 pattern(p); 191 pattern(p);
187 m.complete(p, RECORD_FIELD_PAT); 192 m.complete(p, RECORD_FIELD_PAT);
188} 193}
@@ -192,7 +197,7 @@ fn record_field_pat(p: &mut Parser) {
192fn placeholder_pat(p: &mut Parser) -> CompletedMarker { 197fn placeholder_pat(p: &mut Parser) -> CompletedMarker {
193 assert!(p.at(T![_])); 198 assert!(p.at(T![_]));
194 let m = p.start(); 199 let m = p.start();
195 p.bump(); 200 p.bump_any();
196 m.complete(p, PLACEHOLDER_PAT) 201 m.complete(p, PLACEHOLDER_PAT)
197} 202}
198 203
@@ -204,7 +209,7 @@ fn placeholder_pat(p: &mut Parser) -> CompletedMarker {
204fn ref_pat(p: &mut Parser) -> CompletedMarker { 209fn ref_pat(p: &mut Parser) -> CompletedMarker {
205 assert!(p.at(T![&])); 210 assert!(p.at(T![&]));
206 let m = p.start(); 211 let m = p.start();
207 p.bump(); 212 p.bump_any();
208 p.eat(T![mut]); 213 p.eat(T![mut]);
209 pattern(p); 214 pattern(p);
210 m.complete(p, REF_PAT) 215 m.complete(p, REF_PAT)
@@ -228,7 +233,7 @@ fn tuple_pat(p: &mut Parser) -> CompletedMarker {
228fn slice_pat(p: &mut Parser) -> CompletedMarker { 233fn slice_pat(p: &mut Parser) -> CompletedMarker {
229 assert!(p.at(T!['['])); 234 assert!(p.at(T!['[']));
230 let m = p.start(); 235 let m = p.start();
231 p.bump(); 236 p.bump_any();
232 pat_list(p, T![']']); 237 pat_list(p, T![']']);
233 p.expect(T![']']); 238 p.expect(T![']']);
234 m.complete(p, SLICE_PAT) 239 m.complete(p, SLICE_PAT)
@@ -237,7 +242,7 @@ fn slice_pat(p: &mut Parser) -> CompletedMarker {
237fn pat_list(p: &mut Parser, ket: SyntaxKind) { 242fn pat_list(p: &mut Parser, ket: SyntaxKind) {
238 while !p.at(EOF) && !p.at(ket) { 243 while !p.at(EOF) && !p.at(ket) {
239 match p.current() { 244 match p.current() {
240 T![..] => p.bump(), 245 T![.] if p.at(T![..]) => p.bump(T![..]),
241 _ => { 246 _ => {
242 if !p.at_ts(PATTERN_FIRST) { 247 if !p.at_ts(PATTERN_FIRST) {
243 p.error("expected a pattern"); 248 p.error("expected a pattern");
@@ -281,7 +286,7 @@ fn bind_pat(p: &mut Parser, with_at: bool) -> CompletedMarker {
281fn box_pat(p: &mut Parser) -> CompletedMarker { 286fn box_pat(p: &mut Parser) -> CompletedMarker {
282 assert!(p.at(T![box])); 287 assert!(p.at(T![box]));
283 let m = p.start(); 288 let m = p.start();
284 p.bump(); 289 p.bump_any();
285 pattern(p); 290 pattern(p);
286 m.complete(p, BOX_PAT) 291 m.complete(p, BOX_PAT)
287} 292}
diff --git a/crates/ra_parser/src/grammar/type_args.rs b/crates/ra_parser/src/grammar/type_args.rs
index 3db08b280..edc7d4ff2 100644
--- a/crates/ra_parser/src/grammar/type_args.rs
+++ b/crates/ra_parser/src/grammar/type_args.rs
@@ -2,19 +2,16 @@ use super::*;
2 2
3pub(super) fn opt_type_arg_list(p: &mut Parser, colon_colon_required: bool) { 3pub(super) fn opt_type_arg_list(p: &mut Parser, colon_colon_required: bool) {
4 let m; 4 let m;
5 match (colon_colon_required, p.nth(0), p.nth(1)) { 5 if p.at(T![::]) && p.nth(2) == T![<] {
6 (_, T![::], T![<]) => { 6 m = p.start();
7 m = p.start(); 7 p.bump(T![::]);
8 p.bump(); 8 p.bump(T![<]);
9 p.bump(); 9 } else if !colon_colon_required && p.at(T![<]) && p.nth(1) != T![=] {
10 } 10 m = p.start();
11 (false, T![<], T![=]) => return, 11 p.bump(T![<]);
12 (false, T![<], _) => { 12 } else {
13 m = p.start(); 13 return;
14 p.bump(); 14 }
15 }
16 _ => return,
17 };
18 15
19 while !p.at(EOF) && !p.at(T![>]) { 16 while !p.at(EOF) && !p.at(T![>]) {
20 type_arg(p); 17 type_arg(p);
@@ -32,19 +29,19 @@ fn type_arg(p: &mut Parser) {
32 let m = p.start(); 29 let m = p.start();
33 match p.current() { 30 match p.current() {
34 LIFETIME => { 31 LIFETIME => {
35 p.bump(); 32 p.bump_any();
36 m.complete(p, LIFETIME_ARG); 33 m.complete(p, LIFETIME_ARG);
37 } 34 }
38 // test associated_type_bounds 35 // test associated_type_bounds
39 // fn print_all<T: Iterator<Item: Display>>(printables: T) {} 36 // fn print_all<T: Iterator<Item: Display>>(printables: T) {}
40 IDENT if p.nth(1) == T![:] => { 37 IDENT if p.nth(1) == T![:] && p.nth(2) != T![:] => {
41 name_ref(p); 38 name_ref(p);
42 type_params::bounds(p); 39 type_params::bounds(p);
43 m.complete(p, ASSOC_TYPE_ARG); 40 m.complete(p, ASSOC_TYPE_ARG);
44 } 41 }
45 IDENT if p.nth(1) == T![=] => { 42 IDENT if p.nth(1) == T![=] => {
46 name_ref(p); 43 name_ref(p);
47 p.bump(); 44 p.bump_any();
48 types::type_(p); 45 types::type_(p);
49 m.complete(p, ASSOC_TYPE_ARG); 46 m.complete(p, ASSOC_TYPE_ARG);
50 } 47 }
diff --git a/crates/ra_parser/src/grammar/type_params.rs b/crates/ra_parser/src/grammar/type_params.rs
index cf54344c6..31d709d81 100644
--- a/crates/ra_parser/src/grammar/type_params.rs
+++ b/crates/ra_parser/src/grammar/type_params.rs
@@ -10,7 +10,7 @@ pub(super) fn opt_type_param_list(p: &mut Parser) {
10fn type_param_list(p: &mut Parser) { 10fn type_param_list(p: &mut Parser) {
11 assert!(p.at(T![<])); 11 assert!(p.at(T![<]));
12 let m = p.start(); 12 let m = p.start();
13 p.bump(); 13 p.bump_any();
14 14
15 while !p.at(EOF) && !p.at(T![>]) { 15 while !p.at(EOF) && !p.at(T![>]) {
16 let m = p.start(); 16 let m = p.start();
@@ -38,7 +38,7 @@ fn type_param_list(p: &mut Parser) {
38 38
39fn lifetime_param(p: &mut Parser, m: Marker) { 39fn lifetime_param(p: &mut Parser, m: Marker) {
40 assert!(p.at(LIFETIME)); 40 assert!(p.at(LIFETIME));
41 p.bump(); 41 p.bump_any();
42 if p.at(T![:]) { 42 if p.at(T![:]) {
43 lifetime_bounds(p); 43 lifetime_bounds(p);
44 } 44 }
@@ -54,7 +54,7 @@ fn type_param(p: &mut Parser, m: Marker) {
54 // test type_param_default 54 // test type_param_default
55 // struct S<T = i32>; 55 // struct S<T = i32>;
56 if p.at(T![=]) { 56 if p.at(T![=]) {
57 p.bump(); 57 p.bump_any();
58 types::type_(p) 58 types::type_(p)
59 } 59 }
60 m.complete(p, TYPE_PARAM); 60 m.complete(p, TYPE_PARAM);
@@ -64,15 +64,15 @@ fn type_param(p: &mut Parser, m: Marker) {
64// struct S<T: 'a + ?Sized + (Copy)>; 64// struct S<T: 'a + ?Sized + (Copy)>;
65pub(super) fn bounds(p: &mut Parser) { 65pub(super) fn bounds(p: &mut Parser) {
66 assert!(p.at(T![:])); 66 assert!(p.at(T![:]));
67 p.bump(); 67 p.bump_any();
68 bounds_without_colon(p); 68 bounds_without_colon(p);
69} 69}
70 70
71fn lifetime_bounds(p: &mut Parser) { 71fn lifetime_bounds(p: &mut Parser) {
72 assert!(p.at(T![:])); 72 assert!(p.at(T![:]));
73 p.bump(); 73 p.bump_any();
74 while p.at(LIFETIME) { 74 while p.at(LIFETIME) {
75 p.bump(); 75 p.bump_any();
76 if !p.eat(T![+]) { 76 if !p.eat(T![+]) {
77 break; 77 break;
78 } 78 }
@@ -99,7 +99,7 @@ fn type_bound(p: &mut Parser) -> bool {
99 let has_paren = p.eat(T!['(']); 99 let has_paren = p.eat(T!['(']);
100 p.eat(T![?]); 100 p.eat(T![?]);
101 match p.current() { 101 match p.current() {
102 LIFETIME => p.bump(), 102 LIFETIME => p.bump_any(),
103 T![for] => types::for_type(p), 103 T![for] => types::for_type(p),
104 _ if paths::is_use_path_start(p) => types::path_type_(p, false), 104 _ if paths::is_use_path_start(p) => types::path_type_(p, false),
105 _ => { 105 _ => {
@@ -128,7 +128,7 @@ pub(super) fn opt_where_clause(p: &mut Parser) {
128 return; 128 return;
129 } 129 }
130 let m = p.start(); 130 let m = p.start();
131 p.bump(); 131 p.bump_any();
132 132
133 while is_where_predicate(p) { 133 while is_where_predicate(p) {
134 where_predicate(p); 134 where_predicate(p);
@@ -166,7 +166,7 @@ fn where_predicate(p: &mut Parser) {
166 let m = p.start(); 166 let m = p.start();
167 match p.current() { 167 match p.current() {
168 LIFETIME => { 168 LIFETIME => {
169 p.bump(); 169 p.bump_any();
170 if p.at(T![:]) { 170 if p.at(T![:]) {
171 bounds(p); 171 bounds(p);
172 } else { 172 } else {
diff --git a/crates/ra_parser/src/grammar/types.rs b/crates/ra_parser/src/grammar/types.rs
index 9e321b2a6..0eb28ef09 100644
--- a/crates/ra_parser/src/grammar/types.rs
+++ b/crates/ra_parser/src/grammar/types.rs
@@ -44,7 +44,7 @@ pub(super) fn ascription(p: &mut Parser) {
44fn paren_or_tuple_type(p: &mut Parser) { 44fn paren_or_tuple_type(p: &mut Parser) {
45 assert!(p.at(T!['('])); 45 assert!(p.at(T!['(']));
46 let m = p.start(); 46 let m = p.start();
47 p.bump(); 47 p.bump_any();
48 let mut n_types: u32 = 0; 48 let mut n_types: u32 = 0;
49 let mut trailing_comma: bool = false; 49 let mut trailing_comma: bool = false;
50 while !p.at(EOF) && !p.at(T![')']) { 50 while !p.at(EOF) && !p.at(T![')']) {
@@ -79,20 +79,20 @@ fn paren_or_tuple_type(p: &mut Parser) {
79fn never_type(p: &mut Parser) { 79fn never_type(p: &mut Parser) {
80 assert!(p.at(T![!])); 80 assert!(p.at(T![!]));
81 let m = p.start(); 81 let m = p.start();
82 p.bump(); 82 p.bump_any();
83 m.complete(p, NEVER_TYPE); 83 m.complete(p, NEVER_TYPE);
84} 84}
85 85
86fn pointer_type(p: &mut Parser) { 86fn pointer_type(p: &mut Parser) {
87 assert!(p.at(T![*])); 87 assert!(p.at(T![*]));
88 let m = p.start(); 88 let m = p.start();
89 p.bump(); 89 p.bump_any();
90 90
91 match p.current() { 91 match p.current() {
92 // test pointer_type_mut 92 // test pointer_type_mut
93 // type M = *mut (); 93 // type M = *mut ();
94 // type C = *mut (); 94 // type C = *mut ();
95 T![mut] | T![const] => p.bump(), 95 T![mut] | T![const] => p.bump_any(),
96 _ => { 96 _ => {
97 // test_err pointer_type_no_mutability 97 // test_err pointer_type_no_mutability
98 // type T = *(); 98 // type T = *();
@@ -110,21 +110,21 @@ fn pointer_type(p: &mut Parser) {
110fn array_or_slice_type(p: &mut Parser) { 110fn array_or_slice_type(p: &mut Parser) {
111 assert!(p.at(T!['['])); 111 assert!(p.at(T!['[']));
112 let m = p.start(); 112 let m = p.start();
113 p.bump(); 113 p.bump_any();
114 114
115 type_(p); 115 type_(p);
116 let kind = match p.current() { 116 let kind = match p.current() {
117 // test slice_type 117 // test slice_type
118 // type T = [()]; 118 // type T = [()];
119 T![']'] => { 119 T![']'] => {
120 p.bump(); 120 p.bump_any();
121 SLICE_TYPE 121 SLICE_TYPE
122 } 122 }
123 123
124 // test array_type 124 // test array_type
125 // type T = [(); 92]; 125 // type T = [(); 92];
126 T![;] => { 126 T![;] => {
127 p.bump(); 127 p.bump_any();
128 expressions::expr(p); 128 expressions::expr(p);
129 p.expect(T![']']); 129 p.expect(T![']']);
130 ARRAY_TYPE 130 ARRAY_TYPE
@@ -146,7 +146,7 @@ fn array_or_slice_type(p: &mut Parser) {
146fn reference_type(p: &mut Parser) { 146fn reference_type(p: &mut Parser) {
147 assert!(p.at(T![&])); 147 assert!(p.at(T![&]));
148 let m = p.start(); 148 let m = p.start();
149 p.bump(); 149 p.bump_any();
150 p.eat(LIFETIME); 150 p.eat(LIFETIME);
151 p.eat(T![mut]); 151 p.eat(T![mut]);
152 type_no_bounds(p); 152 type_no_bounds(p);
@@ -158,7 +158,7 @@ fn reference_type(p: &mut Parser) {
158fn placeholder_type(p: &mut Parser) { 158fn placeholder_type(p: &mut Parser) {
159 assert!(p.at(T![_])); 159 assert!(p.at(T![_]));
160 let m = p.start(); 160 let m = p.start();
161 p.bump(); 161 p.bump_any();
162 m.complete(p, PLACEHOLDER_TYPE); 162 m.complete(p, PLACEHOLDER_TYPE);
163} 163}
164 164
@@ -193,7 +193,7 @@ fn fn_pointer_type(p: &mut Parser) {
193 193
194pub(super) fn for_binder(p: &mut Parser) { 194pub(super) fn for_binder(p: &mut Parser) {
195 assert!(p.at(T![for])); 195 assert!(p.at(T![for]));
196 p.bump(); 196 p.bump_any();
197 if p.at(T![<]) { 197 if p.at(T![<]) {
198 type_params::opt_type_param_list(p); 198 type_params::opt_type_param_list(p);
199 } else { 199 } else {
@@ -224,7 +224,7 @@ pub(super) fn for_type(p: &mut Parser) {
224fn impl_trait_type(p: &mut Parser) { 224fn impl_trait_type(p: &mut Parser) {
225 assert!(p.at(T![impl])); 225 assert!(p.at(T![impl]));
226 let m = p.start(); 226 let m = p.start();
227 p.bump(); 227 p.bump_any();
228 type_params::bounds_without_colon(p); 228 type_params::bounds_without_colon(p);
229 m.complete(p, IMPL_TRAIT_TYPE); 229 m.complete(p, IMPL_TRAIT_TYPE);
230} 230}
@@ -234,7 +234,7 @@ fn impl_trait_type(p: &mut Parser) {
234fn dyn_trait_type(p: &mut Parser) { 234fn dyn_trait_type(p: &mut Parser) {
235 assert!(p.at(T![dyn ])); 235 assert!(p.at(T![dyn ]));
236 let m = p.start(); 236 let m = p.start();
237 p.bump(); 237 p.bump_any();
238 type_params::bounds_without_colon(p); 238 type_params::bounds_without_colon(p);
239 m.complete(p, DYN_TRAIT_TYPE); 239 m.complete(p, DYN_TRAIT_TYPE);
240} 240}
diff --git a/crates/ra_parser/src/parser.rs b/crates/ra_parser/src/parser.rs
index 393586561..a2ac363fb 100644
--- a/crates/ra_parser/src/parser.rs
+++ b/crates/ra_parser/src/parser.rs
@@ -5,8 +5,8 @@ use drop_bomb::DropBomb;
5use crate::{ 5use crate::{
6 event::Event, 6 event::Event,
7 ParseError, 7 ParseError,
8 SyntaxKind::{self, EOF, ERROR, TOMBSTONE}, 8 SyntaxKind::{self, EOF, ERROR, L_DOLLAR, R_DOLLAR, TOMBSTONE},
9 Token, TokenSet, TokenSource, T, 9 TokenSet, TokenSource, T,
10}; 10};
11 11
12/// `Parser` struct provides the low-level API for 12/// `Parser` struct provides the low-level API for
@@ -40,38 +40,6 @@ impl<'t> Parser<'t> {
40 self.nth(0) 40 self.nth(0)
41 } 41 }
42 42
43 /// Returns the kinds of the current two tokens, if they are not separated
44 /// by trivia.
45 ///
46 /// Useful for parsing things like `>>`.
47 pub(crate) fn current2(&self) -> Option<(SyntaxKind, SyntaxKind)> {
48 let c1 = self.nth(0);
49 let c2 = self.nth(1);
50
51 if self.token_source.current().is_jointed_to_next {
52 Some((c1, c2))
53 } else {
54 None
55 }
56 }
57
58 /// Returns the kinds of the current three tokens, if they are not separated
59 /// by trivia.
60 ///
61 /// Useful for parsing things like `=>>`.
62 pub(crate) fn current3(&self) -> Option<(SyntaxKind, SyntaxKind, SyntaxKind)> {
63 let c1 = self.nth(0);
64 let c2 = self.nth(1);
65 let c3 = self.nth(2);
66 if self.token_source.current().is_jointed_to_next
67 && self.token_source.lookahead_nth(1).is_jointed_to_next
68 {
69 Some((c1, c2, c3))
70 } else {
71 None
72 }
73 }
74
75 /// Lookahead operation: returns the kind of the next nth 43 /// Lookahead operation: returns the kind of the next nth
76 /// token. 44 /// token.
77 pub(crate) fn nth(&self, n: usize) -> SyntaxKind { 45 pub(crate) fn nth(&self, n: usize) -> SyntaxKind {
@@ -81,33 +49,93 @@ impl<'t> Parser<'t> {
81 assert!(steps <= 10_000_000, "the parser seems stuck"); 49 assert!(steps <= 10_000_000, "the parser seems stuck");
82 self.steps.set(steps + 1); 50 self.steps.set(steps + 1);
83 51
84 // It is beecause the Dollar will appear between nth 52 self.token_source.lookahead_nth(n).kind
85 // Following code skips through it
86 let mut non_dollars_count = 0;
87 let mut i = 0;
88
89 loop {
90 let token = self.token_source.lookahead_nth(i);
91 let mut kind = token.kind;
92 if let Some((composited, step)) = self.is_composite(token, i) {
93 kind = composited;
94 i += step;
95 } else {
96 i += 1;
97 }
98
99 match kind {
100 EOF => return EOF,
101 SyntaxKind::L_DOLLAR | SyntaxKind::R_DOLLAR => {}
102 _ if non_dollars_count == n => return kind,
103 _ => non_dollars_count += 1,
104 }
105 }
106 } 53 }
107 54
108 /// Checks if the current token is `kind`. 55 /// Checks if the current token is `kind`.
109 pub(crate) fn at(&self, kind: SyntaxKind) -> bool { 56 pub(crate) fn at(&self, kind: SyntaxKind) -> bool {
110 self.current() == kind 57 self.nth_at(0, kind)
58 }
59
60 pub(crate) fn nth_at(&self, n: usize, kind: SyntaxKind) -> bool {
61 match kind {
62 T![-=] => self.at_composite2(n, T![-], T![=]),
63 T![->] => self.at_composite2(n, T![-], T![>]),
64 T![::] => self.at_composite2(n, T![:], T![:]),
65 T![!=] => self.at_composite2(n, T![!], T![=]),
66 T![..] => self.at_composite2(n, T![.], T![.]),
67 T![*=] => self.at_composite2(n, T![*], T![=]),
68 T![/=] => self.at_composite2(n, T![/], T![=]),
69 T![&&] => self.at_composite2(n, T![&], T![&]),
70 T![&=] => self.at_composite2(n, T![&], T![=]),
71 T![%=] => self.at_composite2(n, T![%], T![=]),
72 T![^=] => self.at_composite2(n, T![^], T![=]),
73 T![+=] => self.at_composite2(n, T![+], T![=]),
74 T![<<] => self.at_composite2(n, T![<], T![<]),
75 T![<=] => self.at_composite2(n, T![<], T![=]),
76 T![==] => self.at_composite2(n, T![=], T![=]),
77 T![=>] => self.at_composite2(n, T![=], T![>]),
78 T![>=] => self.at_composite2(n, T![>], T![=]),
79 T![>>] => self.at_composite2(n, T![>], T![>]),
80 T![|=] => self.at_composite2(n, T![|], T![=]),
81 T![||] => self.at_composite2(n, T![|], T![|]),
82
83 T![...] => self.at_composite3(n, T![.], T![.], T![.]),
84 T![..=] => self.at_composite3(n, T![.], T![.], T![=]),
85 T![<<=] => self.at_composite3(n, T![<], T![<], T![=]),
86 T![>>=] => self.at_composite3(n, T![>], T![>], T![=]),
87
88 _ => self.token_source.lookahead_nth(n).kind == kind,
89 }
90 }
91
92 /// Consume the next token if `kind` matches.
93 pub(crate) fn eat(&mut self, kind: SyntaxKind) -> bool {
94 if !self.at(kind) {
95 return false;
96 }
97 let n_raw_tokens = match kind {
98 T![-=]
99 | T![->]
100 | T![::]
101 | T![!=]
102 | T![..]
103 | T![*=]
104 | T![/=]
105 | T![&&]
106 | T![&=]
107 | T![%=]
108 | T![^=]
109 | T![+=]
110 | T![<<]
111 | T![<=]
112 | T![==]
113 | T![=>]
114 | T![>=]
115 | T![>>]
116 | T![|=]
117 | T![||] => 2,
118
119 T![...] | T![..=] | T![<<=] | T![>>=] => 3,
120 _ => 1,
121 };
122 self.do_bump(kind, n_raw_tokens);
123 true
124 }
125
126 fn at_composite2(&self, n: usize, k1: SyntaxKind, k2: SyntaxKind) -> bool {
127 let t1 = self.token_source.lookahead_nth(n + 0);
128 let t2 = self.token_source.lookahead_nth(n + 1);
129 t1.kind == k1 && t1.is_jointed_to_next && t2.kind == k2
130 }
131
132 fn at_composite3(&self, n: usize, k1: SyntaxKind, k2: SyntaxKind, k3: SyntaxKind) -> bool {
133 let t1 = self.token_source.lookahead_nth(n + 0);
134 let t2 = self.token_source.lookahead_nth(n + 1);
135 let t3 = self.token_source.lookahead_nth(n + 2);
136 (t1.kind == k1 && t1.is_jointed_to_next)
137 && (t2.kind == k2 && t2.is_jointed_to_next)
138 && t3.kind == k3
111 } 139 }
112 140
113 /// Checks if the current token is in `kinds`. 141 /// Checks if the current token is in `kinds`.
@@ -129,45 +157,18 @@ impl<'t> Parser<'t> {
129 Marker::new(pos) 157 Marker::new(pos)
130 } 158 }
131 159
132 /// Advances the parser by one token unconditionally 160 /// Consume the next token if `kind` matches.
133 /// Mainly use in `token_tree` parsing 161 pub(crate) fn bump(&mut self, kind: SyntaxKind) {
134 pub(crate) fn bump_raw(&mut self) { 162 assert!(self.eat(kind));
135 let mut kind = self.token_source.current().kind;
136
137 // Skip dollars, do_bump will eat these later
138 let mut i = 0;
139 while kind == SyntaxKind::L_DOLLAR || kind == SyntaxKind::R_DOLLAR {
140 kind = self.token_source.lookahead_nth(i).kind;
141 i += 1;
142 }
143
144 if kind == EOF {
145 return;
146 }
147 self.do_bump(kind, 1);
148 } 163 }
149 164
150 /// Advances the parser by one token with composite puncts handled 165 /// Advances the parser by one token with composite puncts handled
151 pub(crate) fn bump(&mut self) { 166 pub(crate) fn bump_any(&mut self) {
152 let kind = self.nth(0); 167 let kind = self.nth(0);
153 if kind == EOF { 168 if kind == EOF {
154 return; 169 return;
155 } 170 }
156 171 self.do_bump(kind, 1)
157 use SyntaxKind::*;
158
159 // Handle parser composites
160 match kind {
161 T![...] | T![..=] => {
162 self.bump_compound(kind, 3);
163 }
164 T![..] | T![::] | T![==] | T![=>] | T![!=] | T![->] => {
165 self.bump_compound(kind, 2);
166 }
167 _ => {
168 self.do_bump(kind, 1);
169 }
170 }
171 } 172 }
172 173
173 /// Advances the parser by one token, remapping its kind. 174 /// Advances the parser by one token, remapping its kind.
@@ -184,13 +185,6 @@ impl<'t> Parser<'t> {
184 self.do_bump(kind, 1); 185 self.do_bump(kind, 1);
185 } 186 }
186 187
187 /// Advances the parser by `n` tokens, remapping its kind.
188 /// This is useful to create compound tokens from parts. For
189 /// example, an `<<` token is two consecutive remapped `<` tokens
190 pub(crate) fn bump_compound(&mut self, kind: SyntaxKind, n: u8) {
191 self.do_bump(kind, n);
192 }
193
194 /// Emit error with the `message` 188 /// Emit error with the `message`
195 /// FIXME: this should be much more fancy and support 189 /// FIXME: this should be much more fancy and support
196 /// structured errors with spans and notes, like rustc 190 /// structured errors with spans and notes, like rustc
@@ -200,15 +194,6 @@ impl<'t> Parser<'t> {
200 self.push_event(Event::Error { msg }) 194 self.push_event(Event::Error { msg })
201 } 195 }
202 196
203 /// Consume the next token if `kind` matches.
204 pub(crate) fn eat(&mut self, kind: SyntaxKind) -> bool {
205 if !self.at(kind) {
206 return false;
207 }
208 self.bump();
209 true
210 }
211
212 /// Consume the next token if it is `kind` or emit an error 197 /// Consume the next token if it is `kind` or emit an error
213 /// otherwise. 198 /// otherwise.
214 pub(crate) fn expect(&mut self, kind: SyntaxKind) -> bool { 199 pub(crate) fn expect(&mut self, kind: SyntaxKind) -> bool {
@@ -226,19 +211,26 @@ impl<'t> Parser<'t> {
226 211
227 /// Create an error node and consume the next token. 212 /// Create an error node and consume the next token.
228 pub(crate) fn err_recover(&mut self, message: &str, recovery: TokenSet) { 213 pub(crate) fn err_recover(&mut self, message: &str, recovery: TokenSet) {
229 if self.at(T!['{']) || self.at(T!['}']) || self.at_ts(recovery) { 214 match self.current() {
230 self.error(message); 215 T!['{'] | T!['}'] | L_DOLLAR | R_DOLLAR => {
231 } else { 216 self.error(message);
232 let m = self.start(); 217 return;
218 }
219 _ => (),
220 }
221
222 if self.at_ts(recovery) {
233 self.error(message); 223 self.error(message);
234 self.bump(); 224 return;
235 m.complete(self, ERROR); 225 }
236 }; 226
227 let m = self.start();
228 self.error(message);
229 self.bump_any();
230 m.complete(self, ERROR);
237 } 231 }
238 232
239 fn do_bump(&mut self, kind: SyntaxKind, n_raw_tokens: u8) { 233 fn do_bump(&mut self, kind: SyntaxKind, n_raw_tokens: u8) {
240 self.eat_dollars();
241
242 for _ in 0..n_raw_tokens { 234 for _ in 0..n_raw_tokens {
243 self.token_source.bump(); 235 self.token_source.bump();
244 } 236 }
@@ -249,110 +241,6 @@ impl<'t> Parser<'t> {
249 fn push_event(&mut self, event: Event) { 241 fn push_event(&mut self, event: Event) {
250 self.events.push(event) 242 self.events.push(event)
251 } 243 }
252
253 /// helper function for check if it is composite.
254 fn is_composite(&self, first: Token, n: usize) -> Option<(SyntaxKind, usize)> {
255 // We assume the dollars will not occuried between
256 // mult-byte tokens
257
258 let jn1 = first.is_jointed_to_next;
259 if !jn1 && first.kind != T![-] {
260 return None;
261 }
262
263 let second = self.token_source.lookahead_nth(n + 1);
264 if first.kind == T![-] && second.kind == T![>] {
265 return Some((T![->], 2));
266 }
267 if !jn1 {
268 return None;
269 }
270
271 match (first.kind, second.kind) {
272 (T![:], T![:]) => return Some((T![::], 2)),
273 (T![=], T![=]) => return Some((T![==], 2)),
274 (T![=], T![>]) => return Some((T![=>], 2)),
275 (T![!], T![=]) => return Some((T![!=], 2)),
276 _ => {}
277 }
278
279 if first.kind != T![.] || second.kind != T![.] {
280 return None;
281 }
282
283 let third = self.token_source.lookahead_nth(n + 2);
284
285 let jn2 = second.is_jointed_to_next;
286 let la3 = third.kind;
287
288 if jn2 && la3 == T![.] {
289 return Some((T![...], 3));
290 }
291 if la3 == T![=] {
292 return Some((T![..=], 3));
293 }
294 return Some((T![..], 2));
295 }
296
297 fn eat_dollars(&mut self) {
298 loop {
299 match self.token_source.current().kind {
300 k @ SyntaxKind::L_DOLLAR | k @ SyntaxKind::R_DOLLAR => {
301 self.token_source.bump();
302 self.push_event(Event::Token { kind: k, n_raw_tokens: 1 });
303 }
304 _ => {
305 return;
306 }
307 }
308 }
309 }
310
311 pub(crate) fn eat_l_dollars(&mut self) -> usize {
312 let mut ate_count = 0;
313 loop {
314 match self.token_source.current().kind {
315 k @ SyntaxKind::L_DOLLAR => {
316 self.token_source.bump();
317 self.push_event(Event::Token { kind: k, n_raw_tokens: 1 });
318 ate_count += 1;
319 }
320 _ => {
321 return ate_count;
322 }
323 }
324 }
325 }
326
327 pub(crate) fn eat_r_dollars(&mut self, max_count: usize) -> usize {
328 let mut ate_count = 0;
329 loop {
330 match self.token_source.current().kind {
331 k @ SyntaxKind::R_DOLLAR => {
332 self.token_source.bump();
333 self.push_event(Event::Token { kind: k, n_raw_tokens: 1 });
334 ate_count += 1;
335
336 if max_count >= ate_count {
337 return ate_count;
338 }
339 }
340 _ => {
341 return ate_count;
342 }
343 }
344 }
345 }
346
347 pub(crate) fn at_l_dollar(&self) -> bool {
348 let kind = self.token_source.current().kind;
349 (kind == SyntaxKind::L_DOLLAR)
350 }
351
352 pub(crate) fn at_r_dollar(&self) -> bool {
353 let kind = self.token_source.current().kind;
354 (kind == SyntaxKind::R_DOLLAR)
355 }
356} 244}
357 245
358/// See `Parser::start`. 246/// See `Parser::start`.
diff --git a/crates/ra_syntax/src/tests.rs b/crates/ra_syntax/src/tests.rs
index fa5d2d5d8..458920607 100644
--- a/crates/ra_syntax/src/tests.rs
+++ b/crates/ra_syntax/src/tests.rs
@@ -16,6 +16,18 @@ fn lexer_tests() {
16} 16}
17 17
18#[test] 18#[test]
19fn parse_smoke_test() {
20 let code = r##"
21fn main() {
22 println!("Hello, world!")
23}
24 "##;
25
26 let parse = SourceFile::parse(code);
27 assert!(parse.ok().is_ok());
28}
29
30#[test]
19fn parser_tests() { 31fn parser_tests() {
20 dir_tests(&test_data_dir(), &["parser/inline/ok", "parser/ok"], |text, path| { 32 dir_tests(&test_data_dir(), &["parser/inline/ok", "parser/ok"], |text, path| {
21 let parse = SourceFile::parse(text); 33 let parse = SourceFile::parse(text);
@@ -75,7 +87,9 @@ fn self_hosting_parsing() {
75 { 87 {
76 count += 1; 88 count += 1;
77 let text = read_text(entry.path()); 89 let text = read_text(entry.path());
78 SourceFile::parse(&text).ok().expect("There should be no errors in the file"); 90 if let Err(errors) = SourceFile::parse(&text).ok() {
91 panic!("Parsing errors:\n{:?}\n{}\n", errors, entry.path().display());
92 }
79 } 93 }
80 assert!( 94 assert!(
81 count > 30, 95 count > 30,
diff --git a/crates/ra_syntax/test_data/parser/ok/0054_qual_path_in_type_arg.rs b/crates/ra_syntax/test_data/parser/ok/0054_qual_path_in_type_arg.rs
new file mode 100644
index 000000000..0d3f5722a
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/ok/0054_qual_path_in_type_arg.rs
@@ -0,0 +1,5 @@
1fn a() -> Foo<bar::Baz> {}
2
3fn b(_: impl FnMut(x::Y)) {}
4
5fn c(_: impl FnMut(&x::Y)) {}
diff --git a/crates/ra_syntax/test_data/parser/ok/0054_qual_path_in_type_arg.txt b/crates/ra_syntax/test_data/parser/ok/0054_qual_path_in_type_arg.txt
new file mode 100644
index 000000000..7e1af254c
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/ok/0054_qual_path_in_type_arg.txt
@@ -0,0 +1,126 @@
1SOURCE_FILE@[0; 88)
2 FN_DEF@[0; 26)
3 FN_KW@[0; 2) "fn"
4 WHITESPACE@[2; 3) " "
5 NAME@[3; 4)
6 IDENT@[3; 4) "a"
7 PARAM_LIST@[4; 6)
8 L_PAREN@[4; 5) "("
9 R_PAREN@[5; 6) ")"
10 WHITESPACE@[6; 7) " "
11 RET_TYPE@[7; 23)
12 THIN_ARROW@[7; 9) "->"
13 WHITESPACE@[9; 10) " "
14 PATH_TYPE@[10; 23)
15 PATH@[10; 23)
16 PATH_SEGMENT@[10; 23)
17 NAME_REF@[10; 13)
18 IDENT@[10; 13) "Foo"
19 TYPE_ARG_LIST@[13; 23)
20 L_ANGLE@[13; 14) "<"
21 TYPE_ARG@[14; 22)
22 PATH_TYPE@[14; 22)
23 PATH@[14; 22)
24 PATH@[14; 17)
25 PATH_SEGMENT@[14; 17)
26 NAME_REF@[14; 17)
27 IDENT@[14; 17) "bar"
28 COLONCOLON@[17; 19) "::"
29 PATH_SEGMENT@[19; 22)
30 NAME_REF@[19; 22)
31 IDENT@[19; 22) "Baz"
32 R_ANGLE@[22; 23) ">"
33 WHITESPACE@[23; 24) " "
34 BLOCK_EXPR@[24; 26)
35 BLOCK@[24; 26)
36 L_CURLY@[24; 25) "{"
37 R_CURLY@[25; 26) "}"
38 WHITESPACE@[26; 28) "\n\n"
39 FN_DEF@[28; 56)
40 FN_KW@[28; 30) "fn"
41 WHITESPACE@[30; 31) " "
42 NAME@[31; 32)
43 IDENT@[31; 32) "b"
44 PARAM_LIST@[32; 53)
45 L_PAREN@[32; 33) "("
46 PARAM@[33; 52)
47 PLACEHOLDER_PAT@[33; 34)
48 UNDERSCORE@[33; 34) "_"
49 COLON@[34; 35) ":"
50 WHITESPACE@[35; 36) " "
51 IMPL_TRAIT_TYPE@[36; 52)
52 IMPL_KW@[36; 40) "impl"
53 WHITESPACE@[40; 41) " "
54 TYPE_BOUND_LIST@[41; 52)
55 TYPE_BOUND@[41; 52)
56 PATH_TYPE@[41; 52)
57 PATH@[41; 52)
58 PATH_SEGMENT@[41; 52)
59 NAME_REF@[41; 46)
60 IDENT@[41; 46) "FnMut"
61 PARAM_LIST@[46; 52)
62 L_PAREN@[46; 47) "("
63 PARAM@[47; 51)
64 PATH_TYPE@[47; 51)
65 PATH@[47; 51)
66 PATH@[47; 48)
67 PATH_SEGMENT@[47; 48)
68 NAME_REF@[47; 48)
69 IDENT@[47; 48) "x"
70 COLONCOLON@[48; 50) "::"
71 PATH_SEGMENT@[50; 51)
72 NAME_REF@[50; 51)
73 IDENT@[50; 51) "Y"
74 R_PAREN@[51; 52) ")"
75 R_PAREN@[52; 53) ")"
76 WHITESPACE@[53; 54) " "
77 BLOCK_EXPR@[54; 56)
78 BLOCK@[54; 56)
79 L_CURLY@[54; 55) "{"
80 R_CURLY@[55; 56) "}"
81 WHITESPACE@[56; 58) "\n\n"
82 FN_DEF@[58; 87)
83 FN_KW@[58; 60) "fn"
84 WHITESPACE@[60; 61) " "
85 NAME@[61; 62)
86 IDENT@[61; 62) "c"
87 PARAM_LIST@[62; 84)
88 L_PAREN@[62; 63) "("
89 PARAM@[63; 83)
90 PLACEHOLDER_PAT@[63; 64)
91 UNDERSCORE@[63; 64) "_"
92 COLON@[64; 65) ":"
93 WHITESPACE@[65; 66) " "
94 IMPL_TRAIT_TYPE@[66; 83)
95 IMPL_KW@[66; 70) "impl"
96 WHITESPACE@[70; 71) " "
97 TYPE_BOUND_LIST@[71; 83)
98 TYPE_BOUND@[71; 83)
99 PATH_TYPE@[71; 83)
100 PATH@[71; 83)
101 PATH_SEGMENT@[71; 83)
102 NAME_REF@[71; 76)
103 IDENT@[71; 76) "FnMut"
104 PARAM_LIST@[76; 83)
105 L_PAREN@[76; 77) "("
106 PARAM@[77; 82)
107 REFERENCE_TYPE@[77; 82)
108 AMP@[77; 78) "&"
109 PATH_TYPE@[78; 82)
110 PATH@[78; 82)
111 PATH@[78; 79)
112 PATH_SEGMENT@[78; 79)
113 NAME_REF@[78; 79)
114 IDENT@[78; 79) "x"
115 COLONCOLON@[79; 81) "::"
116 PATH_SEGMENT@[81; 82)
117 NAME_REF@[81; 82)
118 IDENT@[81; 82) "Y"
119 R_PAREN@[82; 83) ")"
120 R_PAREN@[83; 84) ")"
121 WHITESPACE@[84; 85) " "
122 BLOCK_EXPR@[85; 87)
123 BLOCK@[85; 87)
124 L_CURLY@[85; 86) "{"
125 R_CURLY@[86; 87) "}"
126 WHITESPACE@[87; 88) "\n"
diff --git a/crates/ra_syntax/test_data/parser/ok/0055_dot_dot_dot.rs b/crates/ra_syntax/test_data/parser/ok/0055_dot_dot_dot.rs
new file mode 100644
index 000000000..cd204f65e
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/ok/0055_dot_dot_dot.rs
@@ -0,0 +1,5 @@
1type X = ();
2
3fn main() {
4 let ():::X = ();
5}
diff --git a/crates/ra_syntax/test_data/parser/ok/0055_dot_dot_dot.txt b/crates/ra_syntax/test_data/parser/ok/0055_dot_dot_dot.txt
new file mode 100644
index 000000000..d656e74b1
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/ok/0055_dot_dot_dot.txt
@@ -0,0 +1,50 @@
1SOURCE_FILE@[0; 49)
2 TYPE_ALIAS_DEF@[0; 12)
3 TYPE_KW@[0; 4) "type"
4 WHITESPACE@[4; 5) " "
5 NAME@[5; 6)
6 IDENT@[5; 6) "X"
7 WHITESPACE@[6; 7) " "
8 EQ@[7; 8) "="
9 WHITESPACE@[8; 9) " "
10 TUPLE_TYPE@[9; 11)
11 L_PAREN@[9; 10) "("
12 R_PAREN@[10; 11) ")"
13 SEMI@[11; 12) ";"
14 WHITESPACE@[12; 14) "\n\n"
15 FN_DEF@[14; 48)
16 FN_KW@[14; 16) "fn"
17 WHITESPACE@[16; 17) " "
18 NAME@[17; 21)
19 IDENT@[17; 21) "main"
20 PARAM_LIST@[21; 23)
21 L_PAREN@[21; 22) "("
22 R_PAREN@[22; 23) ")"
23 WHITESPACE@[23; 24) " "
24 BLOCK_EXPR@[24; 48)
25 BLOCK@[24; 48)
26 L_CURLY@[24; 25) "{"
27 WHITESPACE@[25; 30) "\n "
28 LET_STMT@[30; 46)
29 LET_KW@[30; 33) "let"
30 WHITESPACE@[33; 34) " "
31 TUPLE_PAT@[34; 36)
32 L_PAREN@[34; 35) "("
33 R_PAREN@[35; 36) ")"
34 COLON@[36; 37) ":"
35 PATH_TYPE@[37; 40)
36 PATH@[37; 40)
37 PATH_SEGMENT@[37; 40)
38 COLONCOLON@[37; 39) "::"
39 NAME_REF@[39; 40)
40 IDENT@[39; 40) "X"
41 WHITESPACE@[40; 41) " "
42 EQ@[41; 42) "="
43 WHITESPACE@[42; 43) " "
44 TUPLE_EXPR@[43; 45)
45 L_PAREN@[43; 44) "("
46 R_PAREN@[44; 45) ")"
47 SEMI@[45; 46) ";"
48 WHITESPACE@[46; 47) "\n"
49 R_CURLY@[47; 48) "}"
50 WHITESPACE@[48; 49) "\n"
diff --git a/crates/ra_tools/Cargo.toml b/crates/ra_tools/Cargo.toml
index b94a0b18d..848ca408d 100644
--- a/crates/ra_tools/Cargo.toml
+++ b/crates/ra_tools/Cargo.toml
@@ -8,7 +8,7 @@ publish = false
8[dependencies] 8[dependencies]
9walkdir = "2.1.3" 9walkdir = "2.1.3"
10itertools = "0.8.0" 10itertools = "0.8.0"
11clap = { version = "2.32.0", default-features = false } 11pico-args = "0.2.0"
12quote = "1.0.2" 12quote = "1.0.2"
13proc-macro2 = "1.0.1" 13proc-macro2 = "1.0.1"
14ron = "0.5.1" 14ron = "0.5.1"
diff --git a/crates/ra_tools/src/help.rs b/crates/ra_tools/src/help.rs
new file mode 100644
index 000000000..6dde6c2d2
--- /dev/null
+++ b/crates/ra_tools/src/help.rs
@@ -0,0 +1,45 @@
1pub const GLOBAL_HELP: &str = "tasks
2
3USAGE:
4 ra_tools <SUBCOMMAND>
5
6FLAGS:
7 -h, --help Prints help information
8
9SUBCOMMANDS:
10 format
11 format-hook
12 fuzz-tests
13 gen-syntax
14 gen-tests
15 install-ra
16 lint";
17
18pub const INSTALL_RA_HELP: &str = "ra_tools-install-ra
19
20USAGE:
21 ra_tools.exe install-ra [FLAGS]
22
23FLAGS:
24 --client-code
25 -h, --help Prints help information
26 --jemalloc
27 --server";
28
29pub fn print_no_param_subcommand_help(subcommand: &str) {
30 eprintln!(
31 "ra_tools-{}
32
33USAGE:
34 ra_tools {}
35
36FLAGS:
37 -h, --help Prints help information",
38 subcommand, subcommand
39 );
40}
41
42pub const INSTALL_RA_CONFLICT: &str =
43 "error: The argument `--server` cannot be used with `--client-code`
44
45For more information try --help";
diff --git a/crates/ra_tools/src/main.rs b/crates/ra_tools/src/main.rs
index 33badf290..f96f1875f 100644
--- a/crates/ra_tools/src/main.rs
+++ b/crates/ra_tools/src/main.rs
@@ -1,5 +1,8 @@
1use clap::{App, Arg, SubCommand}; 1mod help;
2
3use core::fmt::Write;
2use core::str; 4use core::str;
5use pico_args::Arguments;
3use ra_tools::{ 6use ra_tools::{
4 gen_tests, generate_boilerplate, install_format_hook, run, run_clippy, run_fuzzer, run_rustfmt, 7 gen_tests, generate_boilerplate, install_format_hook, run, run_clippy, run_fuzzer, run_rustfmt,
5 Cmd, Overwrite, Result, 8 Cmd, Overwrite, Result,
@@ -20,45 +23,95 @@ struct ServerOpt {
20} 23}
21 24
22fn main() -> Result<()> { 25fn main() -> Result<()> {
23 let matches = App::new("tasks") 26 let subcommand = match std::env::args_os().nth(1) {
24 .setting(clap::AppSettings::SubcommandRequiredElseHelp) 27 None => {
25 .subcommand(SubCommand::with_name("gen-syntax")) 28 eprintln!("{}", help::GLOBAL_HELP);
26 .subcommand(SubCommand::with_name("gen-tests")) 29 return Ok(());
27 .subcommand( 30 }
28 SubCommand::with_name("install-ra") 31 Some(s) => s,
29 .arg(Arg::with_name("server").long("--server")) 32 };
30 .arg(Arg::with_name("jemalloc").long("jemalloc")) 33 let mut matches = Arguments::from_vec(std::env::args_os().skip(2).collect());
31 .arg(Arg::with_name("client-code").long("client-code").conflicts_with("server")), 34 let subcommand = &*subcommand.to_string_lossy();
32 ) 35 match subcommand {
33 .alias("install-code") 36 "install-ra" | "install-code" => {
34 .subcommand(SubCommand::with_name("format")) 37 if matches.contains(["-h", "--help"]) {
35 .subcommand(SubCommand::with_name("format-hook")) 38 eprintln!("{}", help::INSTALL_RA_HELP);
36 .subcommand(SubCommand::with_name("fuzz-tests")) 39 return Ok(());
37 .subcommand(SubCommand::with_name("lint")) 40 }
38 .get_matches(); 41 let server = matches.contains("--server");
39 match matches.subcommand() { 42 let client_code = matches.contains("--client-code");
40 ("install-ra", Some(matches)) => { 43 if server && client_code {
44 eprintln!("{}", help::INSTALL_RA_CONFLICT);
45 return Ok(());
46 }
47 let jemalloc = matches.contains("--jemalloc");
48 matches.finish().or_else(handle_extra_flags)?;
41 let opts = InstallOpt { 49 let opts = InstallOpt {
42 client: if matches.is_present("server") { None } else { Some(ClientOpt::VsCode) }, 50 client: if server { None } else { Some(ClientOpt::VsCode) },
43 server: if matches.is_present("client-code") { 51 server: if client_code { None } else { Some(ServerOpt { jemalloc: jemalloc }) },
44 None
45 } else {
46 Some(ServerOpt { jemalloc: matches.is_present("jemalloc") })
47 },
48 }; 52 };
49 install(opts)? 53 install(opts)?
50 } 54 }
51 ("gen-tests", _) => gen_tests(Overwrite)?, 55 "gen-tests" => {
52 ("gen-syntax", _) => generate_boilerplate(Overwrite)?, 56 if matches.contains(["-h", "--help"]) {
53 ("format", _) => run_rustfmt(Overwrite)?, 57 help::print_no_param_subcommand_help(&subcommand);
54 ("format-hook", _) => install_format_hook()?, 58 return Ok(());
55 ("lint", _) => run_clippy()?, 59 }
56 ("fuzz-tests", _) => run_fuzzer()?, 60 gen_tests(Overwrite)?
57 _ => unreachable!(), 61 }
62 "gen-syntax" => {
63 if matches.contains(["-h", "--help"]) {
64 help::print_no_param_subcommand_help(&subcommand);
65 return Ok(());
66 }
67 generate_boilerplate(Overwrite)?
68 }
69 "format" => {
70 if matches.contains(["-h", "--help"]) {
71 help::print_no_param_subcommand_help(&subcommand);
72 return Ok(());
73 }
74 run_rustfmt(Overwrite)?
75 }
76 "format-hook" => {
77 if matches.contains(["-h", "--help"]) {
78 help::print_no_param_subcommand_help(&subcommand);
79 return Ok(());
80 }
81 install_format_hook()?
82 }
83 "lint" => {
84 if matches.contains(["-h", "--help"]) {
85 help::print_no_param_subcommand_help(&subcommand);
86 return Ok(());
87 }
88 run_clippy()?
89 }
90 "fuzz-tests" => {
91 if matches.contains(["-h", "--help"]) {
92 help::print_no_param_subcommand_help(&subcommand);
93 return Ok(());
94 }
95 run_fuzzer()?
96 }
97 _ => eprintln!("{}", help::GLOBAL_HELP),
58 } 98 }
59 Ok(()) 99 Ok(())
60} 100}
61 101
102fn handle_extra_flags(e: pico_args::Error) -> Result<()> {
103 if let pico_args::Error::UnusedArgsLeft(flags) = e {
104 let mut invalid_flags = String::new();
105 for flag in flags {
106 write!(&mut invalid_flags, "{}, ", flag)?;
107 }
108 let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2);
109 Err(format!("Invalid flags: {}", invalid_flags).into())
110 } else {
111 Err(e.to_string().into())
112 }
113}
114
62fn install(opts: InstallOpt) -> Result<()> { 115fn install(opts: InstallOpt) -> Result<()> {
63 if cfg!(target_os = "macos") { 116 if cfg!(target_os = "macos") {
64 fix_path_for_mac()? 117 fix_path_for_mac()?
diff --git a/docs/user/README.md b/docs/user/README.md
index 8205fa404..5101e49b8 100644
--- a/docs/user/README.md
+++ b/docs/user/README.md
@@ -130,7 +130,7 @@ Installation:
130 130
131```json 131```json
132"rust-analyzer": { 132"rust-analyzer": {
133 "command": ["rustup", "run", "stable", "ra_lsp_server"], 133 "command": ["ra_lsp_server"],
134 "languageId": "rust", 134 "languageId": "rust",
135 "scopes": ["source.rust"], 135 "scopes": ["source.rust"],
136 "syntaxes": [ 136 "syntaxes": [
@@ -141,3 +141,5 @@ Installation:
141``` 141```
142 142
143* You can now invoke the command palette and type LSP enable to locally/globally enable the rust-analyzer LSP (type LSP enable, then choose either locally or globally, then select rust-analyzer) 143* You can now invoke the command palette and type LSP enable to locally/globally enable the rust-analyzer LSP (type LSP enable, then choose either locally or globally, then select rust-analyzer)
144
145* Note that `ra_lsp_server` binary must be in `$PATH` for this to work. If it's not the case, you can specify full path to the binary, which is typically `.cargo/bin/ra_lsp_server`.