diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 20663196d7..2acd440122 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -61,9 +61,6 @@ jobs: override: true components: rustfmt, rust-src - - if: matrix.os == 'ubuntu-latest' - run: sudo chown -R $(whoami):$(id -ng) ~/.cargo/ - - name: Cache cargo directories uses: actions/cache@v2 with: @@ -108,8 +105,6 @@ jobs: override: true target: 'powerpc-unknown-linux-gnu' - - run: sudo chown -R $(whoami):$(id -ng) ~/.cargo/ - - name: Cache cargo directories uses: actions/cache@v2 with: diff --git a/Cargo.lock b/Cargo.lock index ff225399e0..dc49fc4bdc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -102,13 +102,12 @@ checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" [[package]] name = "cargo_metadata" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8de60b887edf6d74370fc8eb177040da4847d971d6234c7b13a6da324ef0caf" +checksum = "89fec17b16f1ac67908af82e47d0a90a7afd0e1827b181cd77504323d3263d35" dependencies = [ "semver", "serde", - "serde_derive", "serde_json", ] @@ -126,9 +125,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "chalk-derive" -version = "0.18.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eea3a22f0c30b2504ac4ab58934dac0d00b92a4d7788df32795cabca24c3f929" +checksum = "c1df0dbb57d74b4acd20f20fa66ab2acd09776b79eaeb9d8f947b2f3e01c40bf" dependencies = [ "proc-macro2", "quote", @@ -138,9 +137,9 @@ dependencies = [ [[package]] name = "chalk-ir" -version = "0.18.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb617b643e145e3b151502799e91a9625dd5daf1cf05dc2cb821bc75ae0c9cbd" +checksum = "44361a25dbdb1dc428f56ad7a3c21ba9ca12f3225c26a47919ff6fcb10a583d4" dependencies = [ "chalk-derive", "lazy_static", @@ -148,9 +147,9 @@ dependencies = [ [[package]] name = "chalk-recursive" -version = "0.18.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d280565c8eefbf9b2bc615df49c7dfd971faad37774bf65734e626fd23864bd6" +checksum = "dd89556b98de156d5eaf21077d297cd2198628f10f2df140798ea3a5dd84bc86" dependencies = [ "chalk-derive", "chalk-ir", @@ -161,9 +160,9 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.18.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be906fbca3f3077dce0e76d9864771d0f450c946af0d86b569fb9504148a065a" +checksum = "a886da37a0dc457057d86f78f026f7a09c6d8088aa13f4f4127fdb8dc80119a3" dependencies = [ "chalk-derive", "chalk-ir", @@ -280,9 +279,9 @@ checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" [[package]] name = "drop_bomb" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69b26e475fd29098530e709294e94e661974c851aed42512793f120fed4e199f" +checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1" [[package]] name = "either" @@ -319,9 +318,9 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.10" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "affc17579b132fc2461adf7c575cc6e8b134ebca52c51f5411388965227dc695" +checksum = "3ed85775dcc68644b5c950ac06a2b23768d3bc9390464151aaf27136998dcf9e" dependencies = [ "cfg-if", "libc", @@ -400,17 +399,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -[[package]] -name = "getrandom" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - [[package]] name = "gimli" version = "0.22.0" @@ -565,9 +553,9 @@ checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" [[package]] name = "libc" -version = "0.2.73" +version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7d4bd64732af4bf3a67f367c27df8520ad7e230c5817b8ff485864d80242b9" +checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10" [[package]] name = "libloading" @@ -619,9 +607,9 @@ dependencies = [ [[package]] name = "lsp-types" -version = "0.78.0" +version = "0.79.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2e6cf68e3492cfa2035f0382c1da1b6ab045db0320feca505b86b4f13d66c27" +checksum = "7f1f86677fdbe8df5f88b99131b1424e50aad27bbe3e5900d221bc414bd72e9b" dependencies = [ "base64", "bitflags", @@ -810,6 +798,12 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" +[[package]] +name = "oorandom" +version = "11.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a170cebd8021a008ea92e4db85a72f80b35df514ec664b296fdcbb654eac0b2c" + [[package]] name = "parking_lot" version = "0.11.0" @@ -846,6 +840,25 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +[[package]] +name = "perf-event" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76c42ba5d85a2f4472b99f475fb60cf336d9b4c85b1ea8bb300fef2e3c7c8f89" +dependencies = [ + "libc", + "perf-event-open-sys", +] + +[[package]] +name = "perf-event-open-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95db63e37862bc1b842135d2234ef9418f222cc660c6752f45e7cf9ddfb97f96" +dependencies = [ + "libc", +] + [[package]] name = "petgraph" version = "0.5.1" @@ -868,12 +881,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" -[[package]] -name = "ppv-lite86" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" - [[package]] name = "proc-macro2" version = "1.0.19" @@ -1046,6 +1053,7 @@ dependencies = [ "indexmap", "itertools", "log", + "oorandom", "ra_assists", "ra_cfg", "ra_db", @@ -1056,7 +1064,6 @@ dependencies = [ "ra_ssr", "ra_syntax", "ra_text_edit", - "rand", "rustc-hash", "stdx", "test_utils", @@ -1138,6 +1145,7 @@ dependencies = [ "cfg-if", "libc", "once_cell", + "perf-event", "ra_arena", ] @@ -1217,57 +1225,6 @@ dependencies = [ "stdx", ] -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom", - "libc", - "rand_chacha", - "rand_core", - "rand_hc", - "rand_pcg", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core", -] - -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core", -] - [[package]] name = "rayon" version = "1.3.1" @@ -1354,6 +1311,7 @@ dependencies = [ "lsp-server", "lsp-types", "mimalloc", + "oorandom", "parking_lot", "pico-args", "ra_cfg", @@ -1372,7 +1330,6 @@ dependencies = [ "ra_text_edit", "ra_toolchain", "ra_tt", - "rand", "rayon", "rustc-hash", "serde", @@ -1387,9 +1344,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_lexer" -version = "669.0.0" +version = "671.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456af5f09c006cf6c22c1a433ee0232c4bb74bdc6c647a010166a47c94ed2a63" +checksum = "22e1221f3bfa2943c942cf8da319ab2346887f8757778c29c7f1822cd27b521f" dependencies = [ "unicode-xid", ] @@ -1414,16 +1371,16 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "salsa" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "885b4b99dde959decc84e85dd943bd140b4aabd62db2f8206ef5270f77ec20b9" +checksum = "9ab29056d4fb4048a5f0d169c9b6e5526160c9ec37aded5a6879c2c9c445a8e4" dependencies = [ "crossbeam-utils", "indexmap", "lock_api", "log", + "oorandom", "parking_lot", - "rand", "rustc-hash", "salsa-macros", "smallvec", @@ -1431,9 +1388,9 @@ dependencies = [ [[package]] name = "salsa-macros" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c280ac85b15ac214b86ac4b407626a48e6a1c4f90769a582fec74aa57942b9f" +checksum = "a1c3aec007c63c4ed4cd7a018529fb0b5575c4562575fc6a40d6cd2ae0b792ef" dependencies = [ "heck", "proc-macro2", @@ -1484,9 +1441,9 @@ dependencies = [ [[package]] name = "semver" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +checksum = "394cec28fa623e00903caf7ba4fa6fb9a0e260280bb8cdbbba029611108a0190" dependencies = [ "semver-parser", "serde", @@ -1576,9 +1533,9 @@ version = "0.1.0" [[package]] name = "syn" -version = "1.0.36" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cdb98bcb1f9d81d07b536179c269ea15999b5d14ea958196413869445bb5250" +checksum = "e69abc24912995b3038597a7a593be5053eb0fb44f3cc5beec0deb421790c1f4" dependencies = [ "proc-macro2", "quote", @@ -1665,9 +1622,9 @@ checksum = "53953d2d3a5ad81d9f844a32f14ebb121f50b650cd59d0ee2a07cf13c617efed" [[package]] name = "tracing" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbdf4ccd1652592b01286a5dbe1e2a77d78afaa34beadd9872a5f7396f92aaa9" +checksum = "f0aae59226cf195d8e74d4b34beae1859257efb4e5fed3f147d2dc2c7d372178" dependencies = [ "cfg-if", "tracing-attributes", @@ -1687,9 +1644,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.11" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94ae75f0d28ae10786f3b1895c55fe72e79928fd5ccdebb5438c75e93fec178f" +checksum = "d593f98af59ebc017c0648f0117525db358745a8894a8d684e185ba3f45954f9" dependencies = [ "lazy_static", ] @@ -1717,9 +1674,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4f5dd7095c2481b7b3cbed71c8de53085fb3542bc3c2b4c73cba43e8f11c7ba" +checksum = "f7b33f8b2ef2ab0c3778c12646d9c42a24f7772bee4cdafc72199644a9f58fdc" dependencies = [ "ansi_term", "chrono", @@ -1749,6 +1706,12 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "ungrammar" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4e20e58a08ee1bcf8a4695cf74550cf054d6c489105f594beacb2c684210aad" + [[package]] name = "unicode-bidi" version = "0.3.4" @@ -1825,12 +1788,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "winapi" version = "0.2.8" @@ -1874,6 +1831,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "write-json" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06069a848f95fceae3e5e03c0ddc8cb78452b56654ee0c8e68f938cf790fb9e3" + [[package]] name = "ws2_32-sys" version = "0.2.1" @@ -1893,5 +1856,7 @@ dependencies = [ "pico-args", "proc-macro2", "quote", + "ungrammar", "walkdir", + "write-json", ] diff --git a/crates/flycheck/Cargo.toml b/crates/flycheck/Cargo.toml index bea4856948..ff8a1e5689 100644 --- a/crates/flycheck/Cargo.toml +++ b/crates/flycheck/Cargo.toml @@ -11,7 +11,7 @@ doctest = false [dependencies] crossbeam-channel = "0.4.0" log = "0.4.8" -cargo_metadata = "0.10.0" +cargo_metadata = "0.11.1" serde_json = "1.0.48" jod-thread = "0.1.1" ra_toolchain = { path = "../ra_toolchain" } diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index ad376ad185..7c38f5ef9d 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -24,6 +24,7 @@ pub enum FlycheckConfig { command: String, target_triple: Option, all_targets: bool, + no_default_features: bool, all_features: bool, features: Vec, extra_args: Vec, @@ -180,6 +181,7 @@ impl FlycheckActor { FlycheckConfig::CargoCommand { command, target_triple, + no_default_features, all_targets, all_features, extra_args, @@ -198,9 +200,14 @@ impl FlycheckActor { } if *all_features { cmd.arg("--all-features"); - } else if !features.is_empty() { - cmd.arg("--features"); - cmd.arg(features.join(" ")); + } else { + if *no_default_features { + cmd.arg("--no-default-features"); + } + if !features.is_empty() { + cmd.arg("--features"); + cmd.arg(features.join(" ")); + } } cmd.args(extra_args); cmd diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs index 3407df8562..afd3fd4b9e 100644 --- a/crates/ra_assists/src/assist_context.rs +++ b/crates/ra_assists/src/assist_context.rs @@ -73,6 +73,10 @@ impl<'a> AssistContext<'a> { self.sema.db } + pub(crate) fn source_file(&self) -> &SourceFile { + &self.source_file + } + // NB, this ignores active selection. pub(crate) fn offset(&self) -> TextSize { self.frange.range.start() diff --git a/crates/ra_assists/src/ast_transform.rs b/crates/ra_assists/src/ast_transform.rs index 01adb834cc..15ec75c956 100644 --- a/crates/ra_assists/src/ast_transform.rs +++ b/crates/ra_assists/src/ast_transform.rs @@ -32,7 +32,7 @@ impl<'a> AstTransform<'a> for NullTransformer { pub struct SubstituteTypeParams<'a> { source_scope: &'a SemanticsScope<'a>, - substs: FxHashMap, + substs: FxHashMap, previous: Box + 'a>, } @@ -41,7 +41,7 @@ impl<'a> SubstituteTypeParams<'a> { source_scope: &'a SemanticsScope<'a>, // FIXME: there's implicit invariant that `trait_` and `source_scope` match... trait_: hir::Trait, - impl_def: ast::ImplDef, + impl_def: ast::Impl, ) -> SubstituteTypeParams<'a> { let substs = get_syntactic_substs(impl_def).unwrap_or_default(); let generic_def: hir::GenericDef = trait_.into(); @@ -63,7 +63,7 @@ impl<'a> SubstituteTypeParams<'a> { let default = k.default(source_scope.db)?; Some(( k, - ast::make::type_ref( + ast::make::ty( &default .display_source_code(source_scope.db, source_scope.module()?.into()) .ok()?, @@ -79,19 +79,25 @@ impl<'a> SubstituteTypeParams<'a> { }; // FIXME: It would probably be nicer if we could get this via HIR (i.e. get the - // trait ref, and then go from the types in the substs back to the syntax) - fn get_syntactic_substs(impl_def: ast::ImplDef) -> Option> { - let target_trait = impl_def.target_trait()?; + // trait ref, and then go from the types in the substs back to the syntax). + fn get_syntactic_substs(impl_def: ast::Impl) -> Option> { + let target_trait = impl_def.trait_()?; let path_type = match target_trait { - ast::TypeRef::PathType(path) => path, + ast::Type::PathType(path) => path, _ => return None, }; - let type_arg_list = path_type.path()?.segment()?.type_arg_list()?; + let generic_arg_list = path_type.path()?.segment()?.generic_arg_list()?; + let mut result = Vec::new(); - for type_arg in type_arg_list.type_args() { - let type_arg: ast::TypeArg = type_arg; - result.push(type_arg.type_ref()?); + for generic_arg in generic_arg_list.generic_args() { + match generic_arg { + ast::GenericArg::TypeArg(type_arg) => result.push(type_arg.ty()?), + ast::GenericArg::AssocTypeArg(_) + | ast::GenericArg::LifetimeArg(_) + | ast::GenericArg::ConstArg(_) => (), + } } + Some(result) } } @@ -99,9 +105,9 @@ impl<'a> SubstituteTypeParams<'a> { &self, node: &ra_syntax::SyntaxNode, ) -> Option { - let type_ref = ast::TypeRef::cast(node.clone())?; + let type_ref = ast::Type::cast(node.clone())?; let path = match &type_ref { - ast::TypeRef::PathType(path_type) => path_type.path()?, + ast::Type::PathType(path_type) => path_type.path()?, _ => return None, }; // FIXME: use `hir::Path::from_src` instead. @@ -157,7 +163,7 @@ impl<'a> QualifyPaths<'a> { let type_args = p .segment() - .and_then(|s| s.type_arg_list()) + .and_then(|s| s.generic_arg_list()) .map(|arg_list| apply(self, arg_list)); if let Some(type_args) = type_args { let last_segment = path.segment().unwrap(); diff --git a/crates/ra_assists/src/handlers/add_custom_impl.rs b/crates/ra_assists/src/handlers/add_custom_impl.rs index acb07e36a2..b67438b6ba 100644 --- a/crates/ra_assists/src/handlers/add_custom_impl.rs +++ b/crates/ra_assists/src/handlers/add_custom_impl.rs @@ -29,8 +29,8 @@ use crate::{ // } // ``` pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { - let input = ctx.find_node_at_offset::()?; - let attr = input.syntax().parent().and_then(ast::Attr::cast)?; + let attr = ctx.find_node_at_offset::()?; + let input = attr.token_tree()?; let attr_name = attr .syntax() diff --git a/crates/ra_assists/src/handlers/add_explicit_type.rs b/crates/ra_assists/src/handlers/add_explicit_type.rs index 39a5321d17..135a2ac9c9 100644 --- a/crates/ra_assists/src/handlers/add_explicit_type.rs +++ b/crates/ra_assists/src/handlers/add_explicit_type.rs @@ -1,6 +1,6 @@ use hir::HirDisplay; use ra_syntax::{ - ast::{self, AstNode, LetStmt, NameOwner, TypeAscriptionOwner}, + ast::{self, AstNode, LetStmt, NameOwner}, TextRange, }; @@ -22,20 +22,20 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // } // ``` pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { - let stmt = ctx.find_node_at_offset::()?; - let module = ctx.sema.scope(stmt.syntax()).module()?; - let expr = stmt.initializer()?; + let let_stmt = ctx.find_node_at_offset::()?; + let module = ctx.sema.scope(let_stmt.syntax()).module()?; + let expr = let_stmt.initializer()?; // Must be a binding - let pat = match stmt.pat()? { - ast::Pat::BindPat(bind_pat) => bind_pat, + let pat = match let_stmt.pat()? { + ast::Pat::IdentPat(bind_pat) => bind_pat, _ => return None, }; let pat_range = pat.syntax().text_range(); // The binding must have a name let name = pat.name()?; let name_range = name.syntax().text_range(); - let stmt_range = stmt.syntax().text_range(); - let eq_range = stmt.eq_token()?.text_range(); + let stmt_range = let_stmt.syntax().text_range(); + let eq_range = let_stmt.eq_token()?.text_range(); // Assist should only be applicable if cursor is between 'let' and '=' let let_range = TextRange::new(stmt_range.start(), eq_range.start()); let cursor_in_range = let_range.contains_range(ctx.frange.range); @@ -44,9 +44,9 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Optio } // Assist not applicable if the type has already been specified // and it has no placeholders - let ascribed_ty = stmt.ascribed_type(); + let ascribed_ty = let_stmt.ty(); if let Some(ty) = &ascribed_ty { - if ty.syntax().descendants().find_map(ast::PlaceholderType::cast).is_none() { + if ty.syntax().descendants().find_map(ast::InferType::cast).is_none() { return None; } } diff --git a/crates/ra_assists/src/handlers/add_missing_impl_members.rs b/crates/ra_assists/src/handlers/add_missing_impl_members.rs index f185e61e59..95a750aeec 100644 --- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs @@ -111,16 +111,17 @@ fn add_missing_impl_members_inner( label: &'static str, ) -> Option<()> { let _p = ra_prof::profile("add_missing_impl_members_inner"); - let impl_def = ctx.find_node_at_offset::()?; - let impl_item_list = impl_def.item_list()?; + let impl_def = ctx.find_node_at_offset::()?; + let impl_item_list = impl_def.assoc_item_list()?; let trait_ = resolve_target_trait(&ctx.sema, &impl_def)?; let def_name = |item: &ast::AssocItem| -> Option { match item { - ast::AssocItem::FnDef(def) => def.name(), - ast::AssocItem::TypeAliasDef(def) => def.name(), - ast::AssocItem::ConstDef(def) => def.name(), + ast::AssocItem::Fn(def) => def.name(), + ast::AssocItem::TypeAlias(def) => def.name(), + ast::AssocItem::Const(def) => def.name(), + ast::AssocItem::MacroCall(_) => None, } .map(|it| it.text().clone()) }; @@ -128,13 +129,13 @@ fn add_missing_impl_members_inner( let missing_items = get_missing_assoc_items(&ctx.sema, &impl_def) .iter() .map(|i| match i { - hir::AssocItem::Function(i) => ast::AssocItem::FnDef(i.source(ctx.db()).value), - hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAliasDef(i.source(ctx.db()).value), - hir::AssocItem::Const(i) => ast::AssocItem::ConstDef(i.source(ctx.db()).value), + hir::AssocItem::Function(i) => ast::AssocItem::Fn(i.source(ctx.db()).value), + hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAlias(i.source(ctx.db()).value), + hir::AssocItem::Const(i) => ast::AssocItem::Const(i.source(ctx.db()).value), }) .filter(|t| def_name(&t).is_some()) .filter(|t| match t { - ast::AssocItem::FnDef(def) => match mode { + ast::AssocItem::Fn(def) => match mode { AddMissingImplMembersMode::DefaultMethodsOnly => def.body().is_some(), AddMissingImplMembersMode::NoDefaultMethods => def.body().is_none(), }, @@ -157,10 +158,8 @@ fn add_missing_impl_members_inner( .into_iter() .map(|it| ast_transform::apply(&*ast_transform, it)) .map(|it| match it { - ast::AssocItem::FnDef(def) => ast::AssocItem::FnDef(add_body(def)), - ast::AssocItem::TypeAliasDef(def) => { - ast::AssocItem::TypeAliasDef(def.remove_bounds()) - } + ast::AssocItem::Fn(def) => ast::AssocItem::Fn(add_body(def)), + ast::AssocItem::TypeAlias(def) => ast::AssocItem::TypeAlias(def.remove_bounds()), _ => it, }) .map(|it| edit::remove_attrs_and_docs(&it)); @@ -173,7 +172,7 @@ fn add_missing_impl_members_inner( Some(cap) => { let mut cursor = Cursor::Before(first_new_item.syntax()); let placeholder; - if let ast::AssocItem::FnDef(func) = &first_new_item { + if let ast::AssocItem::Fn(func) = &first_new_item { if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast) { if m.syntax().text() == "todo!()" { placeholder = m; @@ -191,7 +190,7 @@ fn add_missing_impl_members_inner( }) } -fn add_body(fn_def: ast::FnDef) -> ast::FnDef { +fn add_body(fn_def: ast::Fn) -> ast::Fn { if fn_def.body().is_some() { return fn_def; } diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index 947be3b9b4..01e7b7a44c 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs @@ -92,7 +92,7 @@ impl AutoImportAssets { fn for_regular_path(path_under_caret: ast::Path, ctx: &AssistContext) -> Option { let syntax_under_caret = path_under_caret.syntax().to_owned(); - if syntax_under_caret.ancestors().find_map(ast::UseItem::cast).is_some() { + if syntax_under_caret.ancestors().find_map(ast::Use::cast).is_some() { return None; } diff --git a/crates/ra_assists/src/handlers/change_return_type_to_result.rs b/crates/ra_assists/src/handlers/change_return_type_to_result.rs index def00f7d8d..b83c944049 100644 --- a/crates/ra_assists/src/handlers/change_return_type_to_result.rs +++ b/crates/ra_assists/src/handlers/change_return_type_to_result.rs @@ -20,9 +20,9 @@ use test_utils::mark; pub(crate) fn change_return_type_to_result(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { let ret_type = ctx.find_node_at_offset::()?; // FIXME: extend to lambdas as well - let fn_def = ret_type.syntax().parent().and_then(ast::FnDef::cast)?; + let fn_def = ret_type.syntax().parent().and_then(ast::Fn::cast)?; - let type_ref = &ret_type.type_ref()?; + let type_ref = &ret_type.ty()?; let ret_type_str = type_ref.syntax().text().to_string(); let first_part_ret_type = ret_type_str.splitn(2, '<').next(); if let Some(ret_type_first_part) = first_part_ret_type { @@ -74,6 +74,7 @@ impl TailReturnCollector { let expr = match &stmt { ast::Stmt::ExprStmt(stmt) => stmt.expr(), ast::Stmt::LetStmt(stmt) => stmt.initializer(), + ast::Stmt::Item(_) => continue, }; if let Some(expr) = &expr { self.handle_exprs(expr, collect_break); @@ -94,6 +95,7 @@ impl TailReturnCollector { let expr_stmt = match &expr_stmt { ast::Stmt::ExprStmt(stmt) => stmt.expr(), ast::Stmt::LetStmt(stmt) => stmt.initializer(), + ast::Stmt::Item(_) => None, }; if let Some(expr) = &expr_stmt { self.handle_exprs(expr, collect_break); @@ -239,8 +241,7 @@ fn get_tail_expr_from_block(expr: &Expr) -> Option> { Expr::ArrayExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), Expr::ParenExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), Expr::PathExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), - Expr::Label(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), - Expr::RecordLit(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), + Expr::RecordExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), Expr::IndexExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), Expr::MethodCallExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), Expr::AwaitExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), diff --git a/crates/ra_assists/src/handlers/change_visibility.rs b/crates/ra_assists/src/handlers/change_visibility.rs index 4343b423c4..724daa93f4 100644 --- a/crates/ra_assists/src/handlers/change_visibility.rs +++ b/crates/ra_assists/src/handlers/change_visibility.rs @@ -1,9 +1,7 @@ use ra_syntax::{ ast::{self, NameOwner, VisibilityOwner}, AstNode, - SyntaxKind::{ - CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STATIC_DEF, STRUCT_DEF, TRAIT_DEF, VISIBILITY, - }, + SyntaxKind::{CONST, ENUM, FN, MODULE, STATIC, STRUCT, TRAIT, VISIBILITY}, T, }; use test_utils::mark; @@ -38,7 +36,7 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { let (offset, target) = if let Some(keyword) = item_keyword { let parent = keyword.parent(); - let def_kws = vec![CONST_DEF, STATIC_DEF, FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF]; + let def_kws = vec![CONST, STATIC, FN, MODULE, STRUCT, ENUM, TRAIT]; // Parent is not a definition, can't add visibility if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) { return None; @@ -49,7 +47,7 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { } (vis_offset(&parent), keyword.text_range()) } else if let Some(field_name) = ctx.find_node_at_offset::() { - let field = field_name.syntax().ancestors().find_map(ast::RecordFieldDef::cast)?; + let field = field_name.syntax().ancestors().find_map(ast::RecordField::cast)?; if field.name()? != field_name { mark::hit!(change_visibility_field_false_positive); return None; @@ -58,7 +56,7 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { return None; } (vis_offset(field.syntax()), field_name.syntax().text_range()) - } else if let Some(field) = ctx.find_node_at_offset::() { + } else if let Some(field) = ctx.find_node_at_offset::() { if field.visibility().is_some() { return None; } diff --git a/crates/ra_assists/src/handlers/early_return.rs b/crates/ra_assists/src/handlers/early_return.rs index 330459f3c8..6816a2709e 100644 --- a/crates/ra_assists/src/handlers/early_return.rs +++ b/crates/ra_assists/src/handlers/early_return.rs @@ -8,7 +8,7 @@ use ra_syntax::{ make, }, AstNode, - SyntaxKind::{FN_DEF, LOOP_EXPR, L_CURLY, R_CURLY, WHILE_EXPR, WHITESPACE}, + SyntaxKind::{FN, LOOP_EXPR, L_CURLY, R_CURLY, WHILE_EXPR, WHITESPACE}, SyntaxNode, }; @@ -51,11 +51,11 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) // Check if there is an IfLet that we can handle. let if_let_pat = match cond.pat() { None => None, // No IfLet, supported. - Some(ast::Pat::TupleStructPat(pat)) if pat.args().count() == 1 => { + Some(ast::Pat::TupleStructPat(pat)) if pat.fields().count() == 1 => { let path = pat.path()?; match path.qualifier() { None => { - let bound_ident = pat.args().next().unwrap(); + let bound_ident = pat.fields().next().unwrap(); Some((path, bound_ident)) } Some(_) => return None, @@ -88,7 +88,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) let early_expression: ast::Expr = match parent_container.kind() { WHILE_EXPR | LOOP_EXPR => make::expr_continue(), - FN_DEF => make::expr_return(), + FN => make::expr_return(), _ => return None, }; @@ -123,7 +123,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) let happy_arm = { let pat = make::tuple_struct_pat( path, - once(make::bind_pat(make::name("it")).into()), + once(make::ident_pat(make::name("it")).into()), ); let expr = { let name_ref = make::name_ref("it"); @@ -136,7 +136,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) let sad_arm = make::match_arm( // FIXME: would be cool to use `None` or `Err(_)` if appropriate - once(make::placeholder_pat().into()), + once(make::wildcard_pat().into()), early_expression, ); @@ -144,7 +144,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) }; let let_stmt = make::let_stmt( - make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(), + make::ident_pat(make::name(&bound_ident.syntax().to_string())).into(), Some(match_expr), ); let let_stmt = let_stmt.indent(if_indent_level); diff --git a/crates/ra_assists/src/handlers/expand_glob_import.rs b/crates/ra_assists/src/handlers/expand_glob_import.rs new file mode 100644 index 0000000000..eb216a81a1 --- /dev/null +++ b/crates/ra_assists/src/handlers/expand_glob_import.rs @@ -0,0 +1,391 @@ +use hir::{AssocItem, MacroDef, ModuleDef, Name, PathResolution, ScopeDef, SemanticsScope}; +use ra_ide_db::{ + defs::{classify_name_ref, Definition, NameRefClass}, + RootDatabase, +}; +use ra_syntax::{algo, ast, match_ast, AstNode, SyntaxNode, SyntaxToken, T}; + +use crate::{ + assist_context::{AssistBuilder, AssistContext, Assists}, + AssistId, AssistKind, +}; + +use either::Either; + +// Assist: expand_glob_import +// +// Expands glob imports. +// +// ``` +// mod foo { +// pub struct Bar; +// pub struct Baz; +// } +// +// use foo::*<|>; +// +// fn qux(bar: Bar, baz: Baz) {} +// ``` +// -> +// ``` +// mod foo { +// pub struct Bar; +// pub struct Baz; +// } +// +// use foo::{Baz, Bar}; +// +// fn qux(bar: Bar, baz: Baz) {} +// ``` +pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { + let star = ctx.find_token_at_offset(T![*])?; + let mod_path = find_mod_path(&star)?; + + let source_file = ctx.source_file(); + let scope = ctx.sema.scope_at_offset(source_file.syntax(), ctx.offset()); + + let defs_in_mod = find_defs_in_mod(ctx, scope, &mod_path)?; + let name_refs_in_source_file = + source_file.syntax().descendants().filter_map(ast::NameRef::cast).collect(); + let used_names = find_used_names(ctx, defs_in_mod, name_refs_in_source_file); + + let parent = star.parent().parent()?; + acc.add( + AssistId("expand_glob_import", AssistKind::RefactorRewrite), + "Expand glob import", + parent.text_range(), + |builder| { + replace_ast(builder, &parent, mod_path, used_names); + }, + ) +} + +fn find_mod_path(star: &SyntaxToken) -> Option { + star.ancestors().find_map(|n| ast::UseTree::cast(n).and_then(|u| u.path())) +} + +#[derive(PartialEq)] +enum Def { + ModuleDef(ModuleDef), + MacroDef(MacroDef), +} + +impl Def { + fn name(&self, db: &RootDatabase) -> Option { + match self { + Def::ModuleDef(def) => def.name(db), + Def::MacroDef(def) => def.name(db), + } + } +} + +fn find_defs_in_mod( + ctx: &AssistContext, + from: SemanticsScope<'_>, + path: &ast::Path, +) -> Option> { + let hir_path = ctx.sema.lower_path(&path)?; + let module = if let Some(PathResolution::Def(ModuleDef::Module(module))) = + from.resolve_hir_path_qualifier(&hir_path) + { + module + } else { + return None; + }; + + let module_scope = module.scope(ctx.db(), from.module()); + + let mut defs = vec![]; + for (_, def) in module_scope { + match def { + ScopeDef::ModuleDef(def) => defs.push(Def::ModuleDef(def)), + ScopeDef::MacroDef(def) => defs.push(Def::MacroDef(def)), + _ => continue, + } + } + + Some(defs) +} + +fn find_used_names( + ctx: &AssistContext, + defs_in_mod: Vec, + name_refs_in_source_file: Vec, +) -> Vec { + let defs_in_source_file = name_refs_in_source_file + .iter() + .filter_map(|r| classify_name_ref(&ctx.sema, r)) + .filter_map(|rc| match rc { + NameRefClass::Definition(Definition::ModuleDef(def)) => Some(Def::ModuleDef(def)), + NameRefClass::Definition(Definition::Macro(def)) => Some(Def::MacroDef(def)), + _ => None, + }) + .collect::>(); + + defs_in_mod + .iter() + .filter(|def| { + if let Def::ModuleDef(ModuleDef::Trait(tr)) = def { + for item in tr.items(ctx.db()) { + if let AssocItem::Function(f) = item { + if defs_in_source_file.contains(&Def::ModuleDef(ModuleDef::Function(f))) { + return true; + } + } + } + } + + defs_in_source_file.contains(def) + }) + .filter_map(|d| d.name(ctx.db())) + .collect() +} + +fn replace_ast( + builder: &mut AssistBuilder, + node: &SyntaxNode, + path: ast::Path, + used_names: Vec, +) { + let replacement: Either = match used_names.as_slice() { + [name] => Either::Left(ast::make::use_tree( + ast::make::path_from_text(&format!("{}::{}", path, name)), + None, + None, + false, + )), + names => Either::Right(ast::make::use_tree_list(names.iter().map(|n| { + ast::make::use_tree(ast::make::path_from_text(&n.to_string()), None, None, false) + }))), + }; + + let mut replace_node = |replacement: Either| { + algo::diff(node, &replacement.either(|u| u.syntax().clone(), |ut| ut.syntax().clone())) + .into_text_edit(builder.text_edit_builder()); + }; + + match_ast! { + match node { + ast::UseTree(use_tree) => { + replace_node(replacement); + }, + ast::UseTreeList(use_tree_list) => { + replace_node(replacement); + }, + ast::Use(use_item) => { + builder.replace_ast(use_item, ast::make::use_(replacement.left_or_else(|ut| ast::make::use_tree(path, Some(ut), None, false)))); + }, + _ => {}, + } + } +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_assist, check_assist_not_applicable}; + + use super::*; + + #[test] + fn expanding_glob_import() { + check_assist( + expand_glob_import, + r" +mod foo { + pub struct Bar; + pub struct Baz; + pub struct Qux; + + pub fn f() {} +} + +use foo::*<|>; + +fn qux(bar: Bar, baz: Baz) { + f(); +} +", + r" +mod foo { + pub struct Bar; + pub struct Baz; + pub struct Qux; + + pub fn f() {} +} + +use foo::{Baz, Bar, f}; + +fn qux(bar: Bar, baz: Baz) { + f(); +} +", + ) + } + + #[test] + fn expanding_glob_import_with_existing_explicit_names() { + check_assist( + expand_glob_import, + r" +mod foo { + pub struct Bar; + pub struct Baz; + pub struct Qux; + + pub fn f() {} +} + +use foo::{*<|>, f}; + +fn qux(bar: Bar, baz: Baz) { + f(); +} +", + r" +mod foo { + pub struct Bar; + pub struct Baz; + pub struct Qux; + + pub fn f() {} +} + +use foo::{Baz, Bar, f}; + +fn qux(bar: Bar, baz: Baz) { + f(); +} +", + ) + } + + #[test] + fn expanding_nested_glob_import() { + check_assist( + expand_glob_import, + r" +mod foo { + mod bar { + pub struct Bar; + pub struct Baz; + pub struct Qux; + + pub fn f() {} + } + + mod baz { + pub fn g() {} + } +} + +use foo::{bar::{*<|>, f}, baz::*}; + +fn qux(bar: Bar, baz: Baz) { + f(); + g(); +} +", + r" +mod foo { + mod bar { + pub struct Bar; + pub struct Baz; + pub struct Qux; + + pub fn f() {} + } + + mod baz { + pub fn g() {} + } +} + +use foo::{bar::{Baz, Bar, f}, baz::*}; + +fn qux(bar: Bar, baz: Baz) { + f(); + g(); +} +", + ) + } + + #[test] + fn expanding_glob_import_with_macro_defs() { + check_assist( + expand_glob_import, + r" +//- /lib.rs crate:foo +#[macro_export] +macro_rules! bar { + () => () +} + +pub fn baz() {} + +//- /main.rs crate:main deps:foo +use foo::*<|>; + +fn main() { + bar!(); + baz(); +} +", + r" +use foo::{bar, baz}; + +fn main() { + bar!(); + baz(); +} +", + ) + } + + #[test] + fn expanding_glob_import_with_trait_method_uses() { + check_assist( + expand_glob_import, + r" +//- /lib.rs crate:foo +pub trait Tr { + fn method(&self) {} +} +impl Tr for () {} + +//- /main.rs crate:main deps:foo +use foo::*<|>; + +fn main() { + ().method(); +} +", + r" +use foo::Tr; + +fn main() { + ().method(); +} +", + ) + } + + #[test] + fn expanding_is_not_applicable_if_cursor_is_not_in_star_token() { + check_assist_not_applicable( + expand_glob_import, + r" + mod foo { + pub struct Bar; + pub struct Baz; + pub struct Qux; + } + + use foo::Bar<|>; + + fn qux(bar: Bar, baz: Baz) {} + ", + ) + } +} diff --git a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs index 2b8e273b3e..ccec688cae 100644 --- a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs @@ -31,7 +31,7 @@ pub(crate) fn extract_struct_from_enum_variant( acc: &mut Assists, ctx: &AssistContext, ) -> Option<()> { - let variant = ctx.find_node_at_offset::()?; + let variant = ctx.find_node_at_offset::()?; let field_list = match variant.kind() { ast::StructKind::Tuple(field_list) => field_list, _ => return None, diff --git a/crates/ra_assists/src/handlers/extract_variable.rs b/crates/ra_assists/src/handlers/extract_variable.rs index 098adf0786..cc62db0c44 100644 --- a/crates/ra_assists/src/handlers/extract_variable.rs +++ b/crates/ra_assists/src/handlers/extract_variable.rs @@ -1,7 +1,7 @@ use ra_syntax::{ ast::{self, AstNode}, SyntaxKind::{ - BLOCK_EXPR, BREAK_EXPR, COMMENT, LAMBDA_EXPR, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR, + BLOCK_EXPR, BREAK_EXPR, CLOSURE_EXPR, COMMENT, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR, }, SyntaxNode, }; @@ -45,7 +45,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option target, move |edit| { let field_shorthand = - match to_extract.syntax().parent().and_then(ast::RecordField::cast) { + match to_extract.syntax().parent().and_then(ast::RecordExprField::cast) { Some(field) => field.name_ref(), None => None, }; @@ -148,7 +148,7 @@ impl Anchor { } if let Some(parent) = node.parent() { - if parent.kind() == MATCH_ARM || parent.kind() == LAMBDA_EXPR { + if parent.kind() == MATCH_ARM || parent.kind() == CLOSURE_EXPR { return Some(Anchor::WrapInBlock(node)); } } diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs index 708e1bc6ca..6698d1a27a 100644 --- a/crates/ra_assists/src/handlers/fill_match_arms.rs +++ b/crates/ra_assists/src/handlers/fill_match_arms.rs @@ -43,7 +43,7 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option< let mut arms: Vec = match_arm_list.arms().collect(); if arms.len() == 1 { - if let Some(Pat::PlaceholderPat(..)) = arms[0].pat() { + if let Some(Pat::WildcardPat(..)) = arms[0].pat() { arms.clear(); } } @@ -116,17 +116,15 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option< match (first_new_arm, ctx.config.snippet_cap) { (Some(first_new_arm), Some(cap)) => { let extend_lifetime; - let cursor = match first_new_arm - .syntax() - .descendants() - .find_map(ast::PlaceholderPat::cast) - { - Some(it) => { - extend_lifetime = it.syntax().clone(); - Cursor::Replace(&extend_lifetime) - } - None => Cursor::Before(first_new_arm.syntax()), - }; + let cursor = + match first_new_arm.syntax().descendants().find_map(ast::WildcardPat::cast) + { + Some(it) => { + extend_lifetime = it.syntax().clone(); + Cursor::Replace(&extend_lifetime) + } + None => Cursor::Before(first_new_arm.syntax()), + }; let snippet = render_snippet(cap, new_arm_list.syntax(), cursor); builder.replace_snippet(cap, old_range, snippet); } @@ -152,7 +150,7 @@ fn does_pat_match_variant(pat: &Pat, var: &Pat) -> bool { let first_node_text = |pat: &Pat| pat.syntax().first_child().map(|node| node.text()); let pat_head = match pat { - Pat::BindPat(bind_pat) => { + Pat::IdentPat(bind_pat) => { if let Some(p) = bind_pat.pat() { first_node_text(&p) } else { @@ -199,12 +197,11 @@ fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::EnumVariant) -> O // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though let pat: ast::Pat = match var.source(db).value.kind() { ast::StructKind::Tuple(field_list) => { - let pats = - iter::repeat(make::placeholder_pat().into()).take(field_list.fields().count()); + let pats = iter::repeat(make::wildcard_pat().into()).take(field_list.fields().count()); make::tuple_struct_pat(path, pats).into() } ast::StructKind::Record(field_list) => { - let pats = field_list.fields().map(|f| make::bind_pat(f.name().unwrap()).into()); + let pats = field_list.fields().map(|f| make::ident_pat(f.name().unwrap()).into()); make::record_pat(path, pats).into() } ast::StructKind::Unit => make::path_pat(path), diff --git a/crates/ra_assists/src/handlers/fix_visibility.rs b/crates/ra_assists/src/handlers/fix_visibility.rs index 1d3ed3c6aa..1aefa79cc3 100644 --- a/crates/ra_assists/src/handlers/fix_visibility.rs +++ b/crates/ra_assists/src/handlers/fix_visibility.rs @@ -82,7 +82,7 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext) -> O } fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { - let record_field: ast::RecordField = ctx.find_node_at_offset()?; + let record_field: ast::RecordExprField = ctx.find_node_at_offset()?; let (record_field_def, _) = ctx.sema.resolve_record_field(&record_field)?; let current_module = ctx.sema.scope(record_field.syntax()).module()?; diff --git a/crates/ra_assists/src/handlers/generate_derive.rs b/crates/ra_assists/src/handlers/generate_derive.rs index 6ccf39900b..90ece9fab0 100644 --- a/crates/ra_assists/src/handlers/generate_derive.rs +++ b/crates/ra_assists/src/handlers/generate_derive.rs @@ -26,7 +26,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // ``` pub(crate) fn generate_derive(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { let cap = ctx.config.snippet_cap?; - let nominal = ctx.find_node_at_offset::()?; + let nominal = ctx.find_node_at_offset::()?; let node_start = derive_insertion_offset(&nominal)?; let target = nominal.syntax().text_range(); acc.add( @@ -58,7 +58,7 @@ pub(crate) fn generate_derive(acc: &mut Assists, ctx: &AssistContext) -> Option< } // Insert `derive` after doc comments. -fn derive_insertion_offset(nominal: &ast::NominalDef) -> Option { +fn derive_insertion_offset(nominal: &ast::AdtDef) -> Option { let non_ws_child = nominal .syntax() .children_with_tokens() diff --git a/crates/ra_assists/src/handlers/generate_from_impl_for_enum.rs b/crates/ra_assists/src/handlers/generate_from_impl_for_enum.rs index a347e3c2ef..4c1aef8a21 100644 --- a/crates/ra_assists/src/handlers/generate_from_impl_for_enum.rs +++ b/crates/ra_assists/src/handlers/generate_from_impl_for_enum.rs @@ -22,7 +22,7 @@ use crate::{utils::FamousDefs, AssistContext, AssistId, AssistKind, Assists}; // } // ``` pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { - let variant = ctx.find_node_at_offset::()?; + let variant = ctx.find_node_at_offset::()?; let variant_name = variant.name()?; let enum_name = variant.parent_enum().name()?; let field_list = match variant.kind() { @@ -32,9 +32,9 @@ pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext if field_list.fields().count() != 1 { return None; } - let field_type = field_list.fields().next()?.type_ref()?; + let field_type = field_list.fields().next()?.ty()?; let path = match field_type { - ast::TypeRef::PathType(it) => it, + ast::Type::PathType(it) => it, _ => return None, }; @@ -69,7 +69,7 @@ impl From<{0}> for {1} {{ fn existing_from_impl( sema: &'_ hir::Semantics<'_, RootDatabase>, - variant: &ast::EnumVariant, + variant: &ast::Variant, ) -> Option<()> { let variant = sema.to_def(variant)?; let enum_ = variant.parent_enum(sema.db); diff --git a/crates/ra_assists/src/handlers/generate_function.rs b/crates/ra_assists/src/handlers/generate_function.rs index b721b96bbb..acc97e6482 100644 --- a/crates/ra_assists/src/handlers/generate_function.rs +++ b/crates/ra_assists/src/handlers/generate_function.rs @@ -82,7 +82,7 @@ struct FunctionTemplate { insert_offset: TextSize, placeholder_expr: ast::MacroCall, leading_ws: String, - fn_def: ast::FnDef, + fn_def: ast::Fn, trailing_ws: String, file: FileId, } @@ -104,7 +104,7 @@ impl FunctionTemplate { struct FunctionBuilder { target: GeneratedFunctionTarget, fn_name: ast::Name, - type_params: Option, + type_params: Option, params: ast::ParamList, file: FileId, needs_pub: bool, @@ -142,7 +142,7 @@ impl FunctionBuilder { let fn_body = make::block_expr(vec![], Some(placeholder_expr)); let visibility = if self.needs_pub { Some(make::visibility_pub_crate()) } else { None }; let mut fn_def = - make::fn_def(visibility, self.fn_name, self.type_params, self.params, fn_body); + make::fn_(visibility, self.fn_name, self.type_params, self.params, fn_body); let leading_ws; let trailing_ws; @@ -200,7 +200,7 @@ fn fn_args( ctx: &AssistContext, target_module: hir::Module, call: &ast::CallExpr, -) -> Option<(Option, ast::ParamList)> { +) -> Option<(Option, ast::ParamList)> { let mut arg_names = Vec::new(); let mut arg_types = Vec::new(); for arg in call.arg_list()?.args() { diff --git a/crates/ra_assists/src/handlers/generate_impl.rs b/crates/ra_assists/src/handlers/generate_impl.rs index cbbac1d7ff..d9b87c9c0d 100644 --- a/crates/ra_assists/src/handlers/generate_impl.rs +++ b/crates/ra_assists/src/handlers/generate_impl.rs @@ -1,4 +1,4 @@ -use ra_syntax::ast::{self, AstNode, NameOwner, TypeParamsOwner}; +use ra_syntax::ast::{self, AstNode, GenericParamsOwner, NameOwner}; use stdx::{format_to, SepBy}; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -23,7 +23,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // } // ``` pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { - let nominal = ctx.find_node_at_offset::()?; + let nominal = ctx.find_node_at_offset::()?; let name = nominal.name()?; let target = nominal.syntax().text_range(); acc.add( @@ -31,7 +31,7 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<() format!("Generate impl for `{}`", name), target, |edit| { - let type_params = nominal.type_param_list(); + let type_params = nominal.generic_param_list(); let start_offset = nominal.syntax().text_range().end(); let mut buf = String::new(); buf.push_str("\n\nimpl"); diff --git a/crates/ra_assists/src/handlers/generate_new.rs b/crates/ra_assists/src/handlers/generate_new.rs index e27def1d8a..b84aa24b6c 100644 --- a/crates/ra_assists/src/handlers/generate_new.rs +++ b/crates/ra_assists/src/handlers/generate_new.rs @@ -1,8 +1,6 @@ use hir::Adt; use ra_syntax::{ - ast::{ - self, AstNode, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner, VisibilityOwner, - }, + ast::{self, AstNode, GenericParamsOwner, NameOwner, StructKind, VisibilityOwner}, T, }; use stdx::{format_to, SepBy}; @@ -30,7 +28,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // // ``` pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { - let strukt = ctx.find_node_at_offset::()?; + let strukt = ctx.find_node_at_offset::()?; // We want to only apply this to non-union structs with named fields let field_list = match strukt.kind() { @@ -53,9 +51,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> let params = field_list .fields() - .filter_map(|f| { - Some(format!("{}: {}", f.name()?.syntax(), f.ascribed_type()?.syntax())) - }) + .filter_map(|f| Some(format!("{}: {}", f.name()?.syntax(), f.ty()?.syntax()))) .sep_by(", "); let fields = field_list.fields().filter_map(|f| f.name()).sep_by(", "); @@ -90,8 +86,8 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> // Generates the surrounding `impl Type { }` including type and lifetime // parameters -fn generate_impl_text(strukt: &ast::StructDef, code: &str) -> String { - let type_params = strukt.type_param_list(); +fn generate_impl_text(strukt: &ast::Struct, code: &str) -> String { + let type_params = strukt.generic_param_list(); let mut buf = String::with_capacity(code.len()); buf.push_str("\n\nimpl"); if let Some(type_params) = &type_params { @@ -121,7 +117,7 @@ fn generate_impl_text(strukt: &ast::StructDef, code: &str) -> String { // // FIXME: change the new fn checking to a more semantic approach when that's more // viable (e.g. we process proc macros, etc) -fn find_struct_impl(ctx: &AssistContext, strukt: &ast::StructDef) -> Option> { +fn find_struct_impl(ctx: &AssistContext, strukt: &ast::Struct) -> Option> { let db = ctx.db(); let module = strukt.syntax().ancestors().find(|node| { ast::Module::can_cast(node.kind()) || ast::SourceFile::can_cast(node.kind()) @@ -129,7 +125,7 @@ fn find_struct_impl(ctx: &AssistContext, strukt: &ast::StructDef) -> Option; impl S {}` @@ -157,10 +153,10 @@ fn find_struct_impl(ctx: &AssistContext, strukt: &ast::StructDef) -> Option bool { - if let Some(il) = imp.item_list() { +fn has_new_fn(imp: &ast::Impl) -> bool { + if let Some(il) = imp.assoc_item_list() { for item in il.assoc_items() { - if let ast::AssocItem::FnDef(f) = item { + if let ast::AssocItem::Fn(f) = item { if let Some(name) = f.name() { if name.text().eq_ignore_ascii_case("new") { return true; diff --git a/crates/ra_assists/src/handlers/inline_local_variable.rs b/crates/ra_assists/src/handlers/inline_local_variable.rs index 2fdfabaf53..3c58020f80 100644 --- a/crates/ra_assists/src/handlers/inline_local_variable.rs +++ b/crates/ra_assists/src/handlers/inline_local_variable.rs @@ -29,7 +29,7 @@ use crate::{ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { let let_stmt = ctx.find_node_at_offset::()?; let bind_pat = match let_stmt.pat()? { - ast::Pat::BindPat(pat) => pat, + ast::Pat::IdentPat(pat) => pat, _ => return None, }; if bind_pat.mut_token().is_some() { diff --git a/crates/ra_assists/src/handlers/introduce_named_lifetime.rs b/crates/ra_assists/src/handlers/introduce_named_lifetime.rs index 967593031c..fbaf3c06b5 100644 --- a/crates/ra_assists/src/handlers/introduce_named_lifetime.rs +++ b/crates/ra_assists/src/handlers/introduce_named_lifetime.rs @@ -1,5 +1,5 @@ use ra_syntax::{ - ast::{self, NameOwner, TypeAscriptionOwner, TypeParamsOwner}, + ast::{self, GenericParamsOwner, NameOwner}, AstNode, SyntaxKind, TextRange, TextSize, }; use rustc_hash::FxHashSet; @@ -38,9 +38,9 @@ pub(crate) fn introduce_named_lifetime(acc: &mut Assists, ctx: &AssistContext) - let lifetime_token = ctx .find_token_at_offset(SyntaxKind::LIFETIME) .filter(|lifetime| lifetime.text() == "'_")?; - if let Some(fn_def) = lifetime_token.ancestors().find_map(ast::FnDef::cast) { + if let Some(fn_def) = lifetime_token.ancestors().find_map(ast::Fn::cast) { generate_fn_def_assist(acc, &fn_def, lifetime_token.text_range()) - } else if let Some(impl_def) = lifetime_token.ancestors().find_map(ast::ImplDef::cast) { + } else if let Some(impl_def) = lifetime_token.ancestors().find_map(ast::Impl::cast) { generate_impl_def_assist(acc, &impl_def, lifetime_token.text_range()) } else { None @@ -50,11 +50,11 @@ pub(crate) fn introduce_named_lifetime(acc: &mut Assists, ctx: &AssistContext) - /// Generate the assist for the fn def case fn generate_fn_def_assist( acc: &mut Assists, - fn_def: &ast::FnDef, + fn_def: &ast::Fn, lifetime_loc: TextRange, ) -> Option<()> { let param_list: ast::ParamList = fn_def.param_list()?; - let new_lifetime_param = generate_unique_lifetime_param_name(&fn_def.type_param_list())?; + let new_lifetime_param = generate_unique_lifetime_param_name(&fn_def.generic_param_list())?; let end_of_fn_ident = fn_def.name()?.ident_token()?.text_range().end(); let self_param = // use the self if it's a reference and has no explicit lifetime @@ -67,8 +67,8 @@ fn generate_fn_def_assist( // otherwise, if there's a single reference parameter without a named liftime, use that let fn_params_without_lifetime: Vec<_> = param_list .params() - .filter_map(|param| match param.ascribed_type() { - Some(ast::TypeRef::ReferenceType(ascribed_type)) + .filter_map(|param| match param.ty() { + Some(ast::Type::RefType(ascribed_type)) if ascribed_type.lifetime_token() == None => { Some(ascribed_type.amp_token()?.text_range().end()) @@ -93,10 +93,10 @@ fn generate_fn_def_assist( /// Generate the assist for the impl def case fn generate_impl_def_assist( acc: &mut Assists, - impl_def: &ast::ImplDef, + impl_def: &ast::Impl, lifetime_loc: TextRange, ) -> Option<()> { - let new_lifetime_param = generate_unique_lifetime_param_name(&impl_def.type_param_list())?; + let new_lifetime_param = generate_unique_lifetime_param_name(&impl_def.generic_param_list())?; let end_of_impl_kw = impl_def.impl_token()?.text_range().end(); acc.add(AssistId(ASSIST_NAME, AssistKind::Refactor), ASSIST_LABEL, lifetime_loc, |builder| { add_lifetime_param(impl_def, builder, end_of_impl_kw, new_lifetime_param); @@ -107,7 +107,7 @@ fn generate_impl_def_assist( /// Given a type parameter list, generate a unique lifetime parameter name /// which is not in the list fn generate_unique_lifetime_param_name( - existing_type_param_list: &Option, + existing_type_param_list: &Option, ) -> Option { match existing_type_param_list { Some(type_params) => { @@ -123,13 +123,13 @@ fn generate_unique_lifetime_param_name( /// Add the lifetime param to `builder`. If there are type parameters in `type_params_owner`, add it to the end. Otherwise /// add new type params brackets with the lifetime parameter at `new_type_params_loc`. -fn add_lifetime_param( +fn add_lifetime_param( type_params_owner: &TypeParamsOwner, builder: &mut AssistBuilder, new_type_params_loc: TextSize, new_lifetime_param: char, ) { - match type_params_owner.type_param_list() { + match type_params_owner.generic_param_list() { // add the new lifetime parameter to an existing type param list Some(type_params) => { builder.insert( diff --git a/crates/ra_assists/src/handlers/merge_imports.rs b/crates/ra_assists/src/handlers/merge_imports.rs index 1beccb61c0..c775fe25c5 100644 --- a/crates/ra_assists/src/handlers/merge_imports.rs +++ b/crates/ra_assists/src/handlers/merge_imports.rs @@ -28,7 +28,7 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<() let mut rewriter = SyntaxRewriter::default(); let mut offset = ctx.offset(); - if let Some(use_item) = tree.syntax().parent().and_then(ast::UseItem::cast) { + if let Some(use_item) = tree.syntax().parent().and_then(ast::Use::cast) { let (merged, to_delete) = next_prev() .filter_map(|dir| neighbor(&use_item, dir)) .filter_map(|it| Some((it.clone(), it.use_tree()?))) diff --git a/crates/ra_assists/src/handlers/merge_match_arms.rs b/crates/ra_assists/src/handlers/merge_match_arms.rs index 186a1f6183..5632922823 100644 --- a/crates/ra_assists/src/handlers/merge_match_arms.rs +++ b/crates/ra_assists/src/handlers/merge_match_arms.rs @@ -86,7 +86,7 @@ pub(crate) fn merge_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option } fn contains_placeholder(a: &ast::MatchArm) -> bool { - matches!(a.pat(), Some(ast::Pat::PlaceholderPat(..))) + matches!(a.pat(), Some(ast::Pat::WildcardPat(..))) } #[cfg(test)] diff --git a/crates/ra_assists/src/handlers/move_bounds.rs b/crates/ra_assists/src/handlers/move_bounds.rs index ba3dafb995..6d394443eb 100644 --- a/crates/ra_assists/src/handlers/move_bounds.rs +++ b/crates/ra_assists/src/handlers/move_bounds.rs @@ -23,7 +23,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // } // ``` pub(crate) fn move_bounds_to_where_clause(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { - let type_param_list = ctx.find_node_at_offset::()?; + let type_param_list = ctx.find_node_at_offset::()?; let mut type_params = type_param_list.type_params(); if type_params.all(|p| p.type_bound_list().is_none()) { @@ -37,13 +37,13 @@ pub(crate) fn move_bounds_to_where_clause(acc: &mut Assists, ctx: &AssistContext let anchor = match_ast! { match parent { - ast::FnDef(it) => it.body()?.syntax().clone().into(), - ast::TraitDef(it) => it.item_list()?.syntax().clone().into(), - ast::ImplDef(it) => it.item_list()?.syntax().clone().into(), - ast::EnumDef(it) => it.variant_list()?.syntax().clone().into(), - ast::StructDef(it) => { + ast::Fn(it) => it.body()?.syntax().clone().into(), + ast::Trait(it) => it.assoc_item_list()?.syntax().clone().into(), + ast::Impl(it) => it.assoc_item_list()?.syntax().clone().into(), + ast::Enum(it) => it.variant_list()?.syntax().clone().into(), + ast::Struct(it) => { it.syntax().children_with_tokens() - .find(|it| it.kind() == RECORD_FIELD_DEF_LIST || it.kind() == T![;])? + .find(|it| it.kind() == RECORD_FIELD_LIST || it.kind() == T![;])? }, _ => return None } diff --git a/crates/ra_assists/src/handlers/raw_string.rs b/crates/ra_assists/src/handlers/raw_string.rs index 4e8a0c2db6..4c797178f1 100644 --- a/crates/ra_assists/src/handlers/raw_string.rs +++ b/crates/ra_assists/src/handlers/raw_string.rs @@ -173,7 +173,7 @@ fn test_required_hashes() { } #[cfg(test)] -mod test { +mod tests { use test_utils::mark; use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; diff --git a/crates/ra_assists/src/handlers/remove_dbg.rs b/crates/ra_assists/src/handlers/remove_dbg.rs index a616cca579..9430ce1b5b 100644 --- a/crates/ra_assists/src/handlers/remove_dbg.rs +++ b/crates/ra_assists/src/handlers/remove_dbg.rs @@ -1,6 +1,6 @@ use ra_syntax::{ ast::{self, AstNode}, - TextSize, T, + TextRange, TextSize, T, }; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -27,19 +27,33 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { return None; } - let macro_range = macro_call.syntax().text_range(); + let is_leaf = macro_call.syntax().next_sibling().is_none(); - let macro_content = { - let macro_args = macro_call.token_tree()?.syntax().clone(); + let macro_end = if macro_call.semicolon_token().is_some() { + macro_call.syntax().text_range().end() - TextSize::of(';') + } else { + macro_call.syntax().text_range().end() + }; - let text = macro_args.text(); - let without_parens = TextSize::of('(')..text.len() - TextSize::of(')'); - text.slice(without_parens).to_string() + // macro_range determines what will be deleted and replaced with macro_content + let macro_range = TextRange::new(macro_call.syntax().text_range().start(), macro_end); + let paste_instead_of_dbg = { + let text = macro_call.token_tree()?.syntax().text(); + + // leafiness determines if we should include the parenthesis or not + let slice_index: TextRange = if is_leaf { + // leaf means - we can extract the contents of the dbg! in text + TextRange::new(TextSize::of('('), text.len() - TextSize::of(')')) + } else { + // not leaf - means we should keep the parens + TextRange::up_to(text.len()) + }; + text.slice(slice_index).to_string() }; let target = macro_call.syntax().text_range(); acc.add(AssistId("remove_dbg", AssistKind::Refactor), "Remove dbg!()", target, |builder| { - builder.replace(macro_range, macro_content); + builder.replace(macro_range, paste_instead_of_dbg); }) } @@ -99,6 +113,7 @@ fn foo(n: usize) { ", ); } + #[test] fn test_remove_dbg_with_brackets_and_braces() { check_assist(remove_dbg, "dbg![<|>1 + 1]", "1 + 1"); @@ -113,7 +128,7 @@ fn foo(n: usize) { } #[test] - fn remove_dbg_target() { + fn test_remove_dbg_target() { check_assist_target( remove_dbg, " @@ -126,4 +141,65 @@ fn foo(n: usize) { "dbg!(n.checked_sub(4))", ); } + + #[test] + fn test_remove_dbg_keep_semicolon() { + // https://github.com/rust-analyzer/rust-analyzer/issues/5129#issuecomment-651399779 + // not quite though + // adding a comment at the end of the line makes + // the ast::MacroCall to include the semicolon at the end + check_assist( + remove_dbg, + r#"let res = <|>dbg!(1 * 20); // needless comment"#, + r#"let res = 1 * 20; // needless comment"#, + ); + } + + #[test] + fn test_remove_dbg_keep_expression() { + check_assist( + remove_dbg, + r#"let res = <|>dbg!(a + b).foo();"#, + r#"let res = (a + b).foo();"#, + ); + } + + #[test] + fn test_remove_dbg_from_inside_fn() { + check_assist_target( + remove_dbg, + r#" +fn square(x: u32) -> u32 { + x * x +} + +fn main() { + let x = square(dbg<|>!(5 + 10)); + println!("{}", x); +}"#, + "dbg!(5 + 10)", + ); + + check_assist( + remove_dbg, + r#" +fn square(x: u32) -> u32 { + x * x +} + +fn main() { + let x = square(dbg<|>!(5 + 10)); + println!("{}", x); +}"#, + r#" +fn square(x: u32) -> u32 { + x * x +} + +fn main() { + let x = square(5 + 10); + println!("{}", x); +}"#, + ); + } } diff --git a/crates/ra_assists/src/handlers/reorder_fields.rs b/crates/ra_assists/src/handlers/reorder_fields.rs index 2ac1c56cf5..c9b743a06b 100644 --- a/crates/ra_assists/src/handlers/reorder_fields.rs +++ b/crates/ra_assists/src/handlers/reorder_fields.rs @@ -23,7 +23,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // ``` // pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { - reorder::(acc, ctx).or_else(|| reorder::(acc, ctx)) + reorder::(acc, ctx).or_else(|| reorder::(acc, ctx)) } fn reorder(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { @@ -56,8 +56,8 @@ fn reorder(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { fn get_fields_kind(node: &SyntaxNode) -> Vec { match node.kind() { - RECORD_LIT => vec![RECORD_FIELD], - RECORD_PAT => vec![RECORD_FIELD_PAT, BIND_PAT], + RECORD_EXPR => vec![RECORD_EXPR_FIELD], + RECORD_PAT => vec![RECORD_PAT_FIELD, IDENT_PAT], _ => vec![], } } @@ -65,8 +65,8 @@ fn get_fields_kind(node: &SyntaxNode) -> Vec { fn get_field_name(node: &SyntaxNode) -> String { let res = match_ast! { match node { - ast::RecordField(field) => field.field_name().map(|it| it.to_string()), - ast::RecordFieldPat(field) => field.field_name().map(|it| it.to_string()), + ast::RecordExprField(field) => field.field_name().map(|it| it.to_string()), + ast::RecordPatField(field) => field.field_name().map(|it| it.to_string()), _ => None, } }; diff --git a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs index b7e30a7f27..ecafb74a1e 100644 --- a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs +++ b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs @@ -65,7 +65,7 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext) .type_of_pat(&pat) .and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty)) .map(|it| it.sad_pattern()) - .unwrap_or_else(|| make::placeholder_pat().into()); + .unwrap_or_else(|| make::wildcard_pat().into()); let else_expr = unwrap_trivial_block(else_block); make::match_arm(vec![pattern], else_expr) }; diff --git a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs index a49292c970..e4d436decc 100644 --- a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs +++ b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs @@ -50,10 +50,10 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext) -> target, |edit| { let with_placeholder: ast::Pat = match happy_variant { - None => make::placeholder_pat().into(), + None => make::wildcard_pat().into(), Some(var_name) => make::tuple_struct_pat( make::path_unqualified(make::path_segment(make::name_ref(var_name))), - once(make::placeholder_pat().into()), + once(make::wildcard_pat().into()), ) .into(), }; @@ -62,8 +62,7 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext) -> let if_ = make::expr_if(make::condition(init, Some(with_placeholder)), block); let stmt = make::expr_stmt(if_); - let placeholder = - stmt.syntax().descendants().find_map(ast::PlaceholderPat::cast).unwrap(); + let placeholder = stmt.syntax().descendants().find_map(ast::WildcardPat::cast).unwrap(); let stmt = stmt.replace_descendant(placeholder.into(), original_pat); edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt)); diff --git a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs index 3d51faa543..da0a860c59 100644 --- a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs +++ b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs @@ -25,7 +25,7 @@ pub(crate) fn replace_qualified_name_with_use( ) -> Option<()> { let path: ast::Path = ctx.find_node_at_offset()?; // We don't want to mess with use statements - if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() { + if path.syntax().ancestors().find_map(ast::Use::cast).is_some() { return None; } @@ -85,7 +85,7 @@ fn shorten_paths(rewriter: &mut SyntaxRewriter<'static>, node: SyntaxNode, path: match child { // Don't modify `use` items, as this can break the `use` item when injecting a new // import into the use tree. - ast::UseItem(_it) => continue, + ast::Use(_it) => continue, // Don't descend into submodules, they don't have the same `use` items in scope. ast::Module(_it) => continue, @@ -639,6 +639,48 @@ use std::fmt::{self, Display}; fn main() { fmt; +} + ", + ); + } + + #[test] + fn does_not_replace_pub_use() { + check_assist( + replace_qualified_name_with_use, + r" +pub use std::fmt; + +impl std::io<|> for Foo { +} + ", + r" +use std::io; + +pub use std::fmt; + +impl io for Foo { +} + ", + ); + } + + #[test] + fn does_not_replace_pub_crate_use() { + check_assist( + replace_qualified_name_with_use, + r" +pub(crate) use std::fmt; + +impl std::io<|> for Foo { +} + ", + r" +use std::io; + +pub(crate) use std::fmt; + +impl io for Foo { } ", ); diff --git a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs index e5a4bb23c3..d69f2c1b0e 100644 --- a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs +++ b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs @@ -52,7 +52,7 @@ pub(crate) fn replace_unwrap_with_match(acc: &mut Assists, ctx: &AssistContext) target, |builder| { let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant))); - let it = make::bind_pat(make::name("a")).into(); + let it = make::ident_pat(make::name("a")).into(); let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into(); let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a"))); @@ -60,7 +60,7 @@ pub(crate) fn replace_unwrap_with_match(acc: &mut Assists, ctx: &AssistContext) let unreachable_call = make::expr_unreachable(); let err_arm = - make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call); + make::match_arm(iter::once(make::wildcard_pat().into()), unreachable_call); let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]); let match_expr = make::expr_match(caller.clone(), match_arm_list) diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 465b904151..507646cc80 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs @@ -140,6 +140,7 @@ mod handlers { mod change_return_type_to_result; mod change_visibility; mod early_return; + mod expand_glob_import; mod extract_struct_from_enum_variant; mod extract_variable; mod fill_match_arms; @@ -181,6 +182,7 @@ mod handlers { change_return_type_to_result::change_return_type_to_result, change_visibility::change_visibility, early_return::convert_to_guarded_return, + expand_glob_import::expand_glob_import, extract_struct_from_enum_variant::extract_struct_from_enum_variant, extract_variable::extract_variable, fill_match_arms::fill_match_arms, diff --git a/crates/ra_assists/src/tests/generated.rs b/crates/ra_assists/src/tests/generated.rs index eff7feded6..97978e7a2e 100644 --- a/crates/ra_assists/src/tests/generated.rs +++ b/crates/ra_assists/src/tests/generated.rs @@ -228,6 +228,33 @@ fn main() { ) } +#[test] +fn doctest_expand_glob_import() { + check_doc_test( + "expand_glob_import", + r#####" +mod foo { + pub struct Bar; + pub struct Baz; +} + +use foo::*<|>; + +fn qux(bar: Bar, baz: Baz) {} +"#####, + r#####" +mod foo { + pub struct Bar; + pub struct Baz; +} + +use foo::{Baz, Bar}; + +fn qux(bar: Bar, baz: Baz) {} +"#####, + ) +} + #[test] fn doctest_extract_struct_from_enum_variant() { check_doc_test( diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs index 02de902d6e..54d5678d14 100644 --- a/crates/ra_assists/src/utils.rs +++ b/crates/ra_assists/src/utils.rs @@ -56,33 +56,34 @@ pub(crate) fn render_snippet(_cap: SnippetCap, node: &SyntaxNode, cursor: Cursor pub fn get_missing_assoc_items( sema: &Semantics, - impl_def: &ast::ImplDef, + impl_def: &ast::Impl, ) -> Vec { // Names must be unique between constants and functions. However, type aliases // may share the same name as a function or constant. let mut impl_fns_consts = FxHashSet::default(); let mut impl_type = FxHashSet::default(); - if let Some(item_list) = impl_def.item_list() { + if let Some(item_list) = impl_def.assoc_item_list() { for item in item_list.assoc_items() { match item { - ast::AssocItem::FnDef(f) => { + ast::AssocItem::Fn(f) => { if let Some(n) = f.name() { impl_fns_consts.insert(n.syntax().to_string()); } } - ast::AssocItem::TypeAliasDef(t) => { + ast::AssocItem::TypeAlias(t) => { if let Some(n) = t.name() { impl_type.insert(n.syntax().to_string()); } } - ast::AssocItem::ConstDef(c) => { + ast::AssocItem::Const(c) => { if let Some(n) = c.name() { impl_fns_consts.insert(n.syntax().to_string()); } } + ast::AssocItem::MacroCall(_) => (), } } } @@ -108,13 +109,10 @@ pub fn get_missing_assoc_items( pub(crate) fn resolve_target_trait( sema: &Semantics, - impl_def: &ast::ImplDef, + impl_def: &ast::Impl, ) -> Option { - let ast_path = impl_def - .target_trait() - .map(|it| it.syntax().clone()) - .and_then(ast::PathType::cast)? - .path()?; + let ast_path = + impl_def.trait_().map(|it| it.syntax().clone()).and_then(ast::PathType::cast)?.path()?; match sema.resolve_path(&ast_path) { Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => Some(def), @@ -183,10 +181,10 @@ impl TryEnum { match self { TryEnum::Result => make::tuple_struct_pat( make::path_unqualified(make::path_segment(make::name_ref("Err"))), - iter::once(make::placeholder_pat().into()), + iter::once(make::wildcard_pat().into()), ) .into(), - TryEnum::Option => make::bind_pat(make::name("None")).into(), + TryEnum::Option => make::ident_pat(make::name("None")).into(), } } diff --git a/crates/ra_assists/src/utils/insert_use.rs b/crates/ra_assists/src/utils/insert_use.rs index 8c4f33e59a..32780fceb5 100644 --- a/crates/ra_assists/src/utils/insert_use.rs +++ b/crates/ra_assists/src/utils/insert_use.rs @@ -4,7 +4,7 @@ use hir::{self, ModPath}; use ra_syntax::{ - ast::{self, NameOwner}, + ast::{self, NameOwner, VisibilityOwner}, AstNode, Direction, SmolStr, SyntaxKind::{PATH, PATH_SEGMENT}, SyntaxNode, T, @@ -215,7 +215,7 @@ fn walk_use_tree_for_best_action( let prev_len = current_path_segments.len(); let tree_list = current_use_tree.use_tree_list(); - let alias = current_use_tree.alias(); + let alias = current_use_tree.rename(); let path = match current_use_tree.path() { Some(path) => path, @@ -225,7 +225,7 @@ fn walk_use_tree_for_best_action( current_use_tree .syntax() .ancestors() - .find_map(ast::UseItem::cast) + .find_map(ast::Use::cast) .map(|it| it.syntax().clone()), true, ); @@ -254,7 +254,7 @@ fn walk_use_tree_for_best_action( current_use_tree .syntax() .ancestors() - .find_map(ast::UseItem::cast) + .find_map(ast::Use::cast) .map(|it| it.syntax().clone()), true, ), @@ -304,7 +304,7 @@ fn walk_use_tree_for_best_action( current_use_tree .syntax() .ancestors() - .find_map(ast::UseItem::cast) + .find_map(ast::Use::cast) .map(|it| it.syntax().clone()), true, ); @@ -377,7 +377,8 @@ fn best_action_for_target( let mut storage = Vec::with_capacity(16); // this should be the only allocation let best_action = container .children() - .filter_map(ast::UseItem::cast) + .filter_map(ast::Use::cast) + .filter(|u| u.visibility().is_none()) .filter_map(|it| it.use_tree()) .map(|u| walk_use_tree_for_best_action(&mut storage, None, u, target)) .fold(None, |best, a| match best { diff --git a/crates/ra_db/Cargo.toml b/crates/ra_db/Cargo.toml index 5f334d04f1..fe73dc0157 100644 --- a/crates/ra_db/Cargo.toml +++ b/crates/ra_db/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" doctest = false [dependencies] -salsa = "0.15.0" +salsa = "0.15.2" rustc-hash = "1.1.0" ra_syntax = { path = "../ra_syntax" } diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 859bdfb3bc..27cdabea03 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -361,8 +361,8 @@ pub struct Field { #[derive(Debug, PartialEq, Eq)] pub enum FieldSource { - Named(ast::RecordFieldDef), - Pos(ast::TupleFieldDef), + Named(ast::RecordField), + Pos(ast::TupleField), } impl Field { @@ -1002,7 +1002,7 @@ impl Local { Type::new(db, krate, def, ty) } - pub fn source(self, db: &dyn HirDatabase) -> InFile> { + pub fn source(self, db: &dyn HirDatabase) -> InFile> { let (_body, source_map) = db.body_with_source_map(self.parent.into()); let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm... let root = src.file_syntax(db.upcast()); diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index a2b9f3e35c..07333c453f 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -13,14 +13,7 @@ pub use hir_expand::db::{ AstDatabase, AstDatabaseStorage, AstIdMapQuery, InternEagerExpansionQuery, InternMacroQuery, MacroArgTextQuery, MacroDefQuery, MacroExpandQuery, ParseMacroQuery, }; -pub use hir_ty::db::{ - AssociatedTyDataQuery, AssociatedTyValueQuery, CallableItemSignatureQuery, FieldTypesQuery, - GenericDefaultsQuery, GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase, - HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, InferQueryQuery, - InherentImplsInCrateQuery, InternTypeParamIdQuery, ReturnTypeImplTraitsQuery, StructDatumQuery, - TraitDatumQuery, TraitImplsInCrateQuery, TraitImplsInDepsQuery, TraitSolveQuery, TyQuery, - ValueTyQuery, -}; +pub use hir_ty::db::*; #[test] fn hir_database_is_object_safe() { diff --git a/crates/ra_hir/src/has_source.rs b/crates/ra_hir/src/has_source.rs index 4fd6750399..db9228d67c 100644 --- a/crates/ra_hir/src/has_source.rs +++ b/crates/ra_hir/src/has_source.rs @@ -57,56 +57,56 @@ impl HasSource for Field { } } impl HasSource for Struct { - type Ast = ast::StructDef; - fn source(self, db: &dyn HirDatabase) -> InFile { + type Ast = ast::Struct; + fn source(self, db: &dyn HirDatabase) -> InFile { self.id.lookup(db.upcast()).source(db.upcast()) } } impl HasSource for Union { - type Ast = ast::UnionDef; - fn source(self, db: &dyn HirDatabase) -> InFile { + type Ast = ast::Union; + fn source(self, db: &dyn HirDatabase) -> InFile { self.id.lookup(db.upcast()).source(db.upcast()) } } impl HasSource for Enum { - type Ast = ast::EnumDef; - fn source(self, db: &dyn HirDatabase) -> InFile { + type Ast = ast::Enum; + fn source(self, db: &dyn HirDatabase) -> InFile { self.id.lookup(db.upcast()).source(db.upcast()) } } impl HasSource for EnumVariant { - type Ast = ast::EnumVariant; - fn source(self, db: &dyn HirDatabase) -> InFile { + type Ast = ast::Variant; + fn source(self, db: &dyn HirDatabase) -> InFile { self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone()) } } impl HasSource for Function { - type Ast = ast::FnDef; - fn source(self, db: &dyn HirDatabase) -> InFile { + type Ast = ast::Fn; + fn source(self, db: &dyn HirDatabase) -> InFile { self.id.lookup(db.upcast()).source(db.upcast()) } } impl HasSource for Const { - type Ast = ast::ConstDef; - fn source(self, db: &dyn HirDatabase) -> InFile { + type Ast = ast::Const; + fn source(self, db: &dyn HirDatabase) -> InFile { self.id.lookup(db.upcast()).source(db.upcast()) } } impl HasSource for Static { - type Ast = ast::StaticDef; - fn source(self, db: &dyn HirDatabase) -> InFile { + type Ast = ast::Static; + fn source(self, db: &dyn HirDatabase) -> InFile { self.id.lookup(db.upcast()).source(db.upcast()) } } impl HasSource for Trait { - type Ast = ast::TraitDef; - fn source(self, db: &dyn HirDatabase) -> InFile { + type Ast = ast::Trait; + fn source(self, db: &dyn HirDatabase) -> InFile { self.id.lookup(db.upcast()).source(db.upcast()) } } impl HasSource for TypeAlias { - type Ast = ast::TypeAliasDef; - fn source(self, db: &dyn HirDatabase) -> InFile { + type Ast = ast::TypeAlias; + fn source(self, db: &dyn HirDatabase) -> InFile { self.id.lookup(db.upcast()).source(db.upcast()) } } @@ -120,14 +120,14 @@ impl HasSource for MacroDef { } } impl HasSource for ImplDef { - type Ast = ast::ImplDef; - fn source(self, db: &dyn HirDatabase) -> InFile { + type Ast = ast::Impl; + fn source(self, db: &dyn HirDatabase) -> InFile { self.id.lookup(db.upcast()).source(db.upcast()) } } impl HasSource for TypeParam { - type Ast = Either; + type Ast = Either; fn source(self, db: &dyn HirDatabase) -> InFile { let child_source = self.id.parent.child_source(db.upcast()); child_source.map(|it| it[self.id.local_id].clone()) diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 1436b1afee..307b336f20 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs @@ -209,11 +209,14 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.resolve_field(field) } - pub fn resolve_record_field(&self, field: &ast::RecordField) -> Option<(Field, Option)> { + pub fn resolve_record_field( + &self, + field: &ast::RecordExprField, + ) -> Option<(Field, Option)> { self.imp.resolve_record_field(field) } - pub fn resolve_record_field_pat(&self, field: &ast::RecordFieldPat) -> Option { + pub fn resolve_record_field_pat(&self, field: &ast::RecordPatField) -> Option { self.imp.resolve_record_field_pat(field) } @@ -225,7 +228,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.resolve_path(path) } - pub fn resolve_variant(&self, record_lit: ast::RecordLit) -> Option { + pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option { self.imp.resolve_variant(record_lit).map(VariantDef::from) } @@ -233,14 +236,14 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.lower_path(path) } - pub fn resolve_bind_pat_to_const(&self, pat: &ast::BindPat) -> Option { + pub fn resolve_bind_pat_to_const(&self, pat: &ast::IdentPat) -> Option { self.imp.resolve_bind_pat_to_const(pat) } // FIXME: use this instead? // pub fn resolve_name_ref(&self, name_ref: &ast::NameRef) -> Option; - pub fn record_literal_missing_fields(&self, literal: &ast::RecordLit) -> Vec<(Field, Type)> { + pub fn record_literal_missing_fields(&self, literal: &ast::RecordExpr) -> Vec<(Field, Type)> { self.imp.record_literal_missing_fields(literal) } @@ -422,11 +425,11 @@ impl<'db> SemanticsImpl<'db> { self.analyze(field.syntax()).resolve_field(self.db, field) } - fn resolve_record_field(&self, field: &ast::RecordField) -> Option<(Field, Option)> { + fn resolve_record_field(&self, field: &ast::RecordExprField) -> Option<(Field, Option)> { self.analyze(field.syntax()).resolve_record_field(self.db, field) } - fn resolve_record_field_pat(&self, field: &ast::RecordFieldPat) -> Option { + fn resolve_record_field_pat(&self, field: &ast::RecordPatField) -> Option { self.analyze(field.syntax()).resolve_record_field_pat(self.db, field) } @@ -440,7 +443,7 @@ impl<'db> SemanticsImpl<'db> { self.analyze(path.syntax()).resolve_path(self.db, path) } - fn resolve_variant(&self, record_lit: ast::RecordLit) -> Option { + fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option { self.analyze(record_lit.syntax()).resolve_variant(self.db, record_lit) } @@ -449,11 +452,11 @@ impl<'db> SemanticsImpl<'db> { Path::from_src(path.clone(), &Hygiene::new(self.db.upcast(), src.file_id.into())) } - fn resolve_bind_pat_to_const(&self, pat: &ast::BindPat) -> Option { + fn resolve_bind_pat_to_const(&self, pat: &ast::IdentPat) -> Option { self.analyze(pat.syntax()).resolve_bind_pat_to_const(self.db, pat) } - fn record_literal_missing_fields(&self, literal: &ast::RecordLit) -> Vec<(Field, Type)> { + fn record_literal_missing_fields(&self, literal: &ast::RecordExpr) -> Vec<(Field, Type)> { self.analyze(literal.syntax()) .record_literal_missing_fields(self.db, literal) .unwrap_or_default() @@ -577,21 +580,21 @@ macro_rules! to_def_impls { to_def_impls![ (crate::Module, ast::Module, module_to_def), - (crate::Struct, ast::StructDef, struct_to_def), - (crate::Enum, ast::EnumDef, enum_to_def), - (crate::Union, ast::UnionDef, union_to_def), - (crate::Trait, ast::TraitDef, trait_to_def), - (crate::ImplDef, ast::ImplDef, impl_to_def), - (crate::TypeAlias, ast::TypeAliasDef, type_alias_to_def), - (crate::Const, ast::ConstDef, const_to_def), - (crate::Static, ast::StaticDef, static_to_def), - (crate::Function, ast::FnDef, fn_to_def), - (crate::Field, ast::RecordFieldDef, record_field_to_def), - (crate::Field, ast::TupleFieldDef, tuple_field_to_def), - (crate::EnumVariant, ast::EnumVariant, enum_variant_to_def), + (crate::Struct, ast::Struct, struct_to_def), + (crate::Enum, ast::Enum, enum_to_def), + (crate::Union, ast::Union, union_to_def), + (crate::Trait, ast::Trait, trait_to_def), + (crate::ImplDef, ast::Impl, impl_to_def), + (crate::TypeAlias, ast::TypeAlias, type_alias_to_def), + (crate::Const, ast::Const, const_to_def), + (crate::Static, ast::Static, static_to_def), + (crate::Function, ast::Fn, fn_to_def), + (crate::Field, ast::RecordField, record_field_to_def), + (crate::Field, ast::TupleField, tuple_field_to_def), + (crate::EnumVariant, ast::Variant, enum_variant_to_def), (crate::TypeParam, ast::TypeParam, type_param_to_def), (crate::MacroDef, ast::MacroCall, macro_call_to_def), // this one is dubious, not all calls are macros - (crate::Local, ast::BindPat, bind_pat_to_def), + (crate::Local, ast::IdentPat, bind_pat_to_def), ]; fn find_root(node: &SyntaxNode) -> SyntaxNode { diff --git a/crates/ra_hir/src/semantics/source_to_def.rs b/crates/ra_hir/src/semantics/source_to_def.rs index 42e5a1bdbe..863e8e5ff7 100644 --- a/crates/ra_hir/src/semantics/source_to_def.rs +++ b/crates/ra_hir/src/semantics/source_to_def.rs @@ -65,57 +65,48 @@ impl SourceToDefCtx<'_, '_> { Some(ModuleId { krate: parent_module.krate, local_id: child_id }) } - pub(super) fn trait_to_def(&mut self, src: InFile) -> Option { + pub(super) fn trait_to_def(&mut self, src: InFile) -> Option { self.to_def(src, keys::TRAIT) } - pub(super) fn impl_to_def(&mut self, src: InFile) -> Option { + pub(super) fn impl_to_def(&mut self, src: InFile) -> Option { self.to_def(src, keys::IMPL) } - pub(super) fn fn_to_def(&mut self, src: InFile) -> Option { + pub(super) fn fn_to_def(&mut self, src: InFile) -> Option { self.to_def(src, keys::FUNCTION) } - pub(super) fn struct_to_def(&mut self, src: InFile) -> Option { + pub(super) fn struct_to_def(&mut self, src: InFile) -> Option { self.to_def(src, keys::STRUCT) } - pub(super) fn enum_to_def(&mut self, src: InFile) -> Option { + pub(super) fn enum_to_def(&mut self, src: InFile) -> Option { self.to_def(src, keys::ENUM) } - pub(super) fn union_to_def(&mut self, src: InFile) -> Option { + pub(super) fn union_to_def(&mut self, src: InFile) -> Option { self.to_def(src, keys::UNION) } - pub(super) fn static_to_def(&mut self, src: InFile) -> Option { + pub(super) fn static_to_def(&mut self, src: InFile) -> Option { self.to_def(src, keys::STATIC) } - pub(super) fn const_to_def(&mut self, src: InFile) -> Option { + pub(super) fn const_to_def(&mut self, src: InFile) -> Option { self.to_def(src, keys::CONST) } - pub(super) fn type_alias_to_def( - &mut self, - src: InFile, - ) -> Option { + pub(super) fn type_alias_to_def(&mut self, src: InFile) -> Option { self.to_def(src, keys::TYPE_ALIAS) } - pub(super) fn record_field_to_def( - &mut self, - src: InFile, - ) -> Option { + pub(super) fn record_field_to_def(&mut self, src: InFile) -> Option { self.to_def(src, keys::RECORD_FIELD) } - pub(super) fn tuple_field_to_def( - &mut self, - src: InFile, - ) -> Option { + pub(super) fn tuple_field_to_def(&mut self, src: InFile) -> Option { self.to_def(src, keys::TUPLE_FIELD) } pub(super) fn enum_variant_to_def( &mut self, - src: InFile, + src: InFile, ) -> Option { - self.to_def(src, keys::ENUM_VARIANT) + self.to_def(src, keys::VARIANT) } pub(super) fn bind_pat_to_def( &mut self, - src: InFile, + src: InFile, ) -> Option<(DefWithBodyId, PatId)> { let container = self.find_pat_container(src.as_ref().map(|it| it.syntax()))?; let (_body, source_map) = self.db.body_with_source_map(container); @@ -163,39 +154,39 @@ impl SourceToDefCtx<'_, '_> { let def = self.module_to_def(container.with_value(it))?; def.into() }, - ast::TraitDef(it) => { + ast::Trait(it) => { let def = self.trait_to_def(container.with_value(it))?; def.into() }, - ast::ImplDef(it) => { + ast::Impl(it) => { let def = self.impl_to_def(container.with_value(it))?; def.into() }, - ast::FnDef(it) => { + ast::Fn(it) => { let def = self.fn_to_def(container.with_value(it))?; DefWithBodyId::from(def).into() }, - ast::StructDef(it) => { + ast::Struct(it) => { let def = self.struct_to_def(container.with_value(it))?; VariantId::from(def).into() }, - ast::EnumDef(it) => { + ast::Enum(it) => { let def = self.enum_to_def(container.with_value(it))?; def.into() }, - ast::UnionDef(it) => { + ast::Union(it) => { let def = self.union_to_def(container.with_value(it))?; VariantId::from(def).into() }, - ast::StaticDef(it) => { + ast::Static(it) => { let def = self.static_to_def(container.with_value(it))?; DefWithBodyId::from(def).into() }, - ast::ConstDef(it) => { + ast::Const(it) => { let def = self.const_to_def(container.with_value(it))?; DefWithBodyId::from(def).into() }, - ast::TypeAliasDef(it) => { + ast::TypeAlias(it) => { let def = self.type_alias_to_def(container.with_value(it))?; def.into() }, @@ -213,12 +204,12 @@ impl SourceToDefCtx<'_, '_> { for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) { let res: GenericDefId = match_ast! { match (container.value) { - ast::FnDef(it) => self.fn_to_def(container.with_value(it))?.into(), - ast::StructDef(it) => self.struct_to_def(container.with_value(it))?.into(), - ast::EnumDef(it) => self.enum_to_def(container.with_value(it))?.into(), - ast::TraitDef(it) => self.trait_to_def(container.with_value(it))?.into(), - ast::TypeAliasDef(it) => self.type_alias_to_def(container.with_value(it))?.into(), - ast::ImplDef(it) => self.impl_to_def(container.with_value(it))?.into(), + ast::Fn(it) => self.fn_to_def(container.with_value(it))?.into(), + ast::Struct(it) => self.struct_to_def(container.with_value(it))?.into(), + ast::Enum(it) => self.enum_to_def(container.with_value(it))?.into(), + ast::Trait(it) => self.trait_to_def(container.with_value(it))?.into(), + ast::TypeAlias(it) => self.type_alias_to_def(container.with_value(it))?.into(), + ast::Impl(it) => self.impl_to_def(container.with_value(it))?.into(), _ => continue, } }; @@ -231,9 +222,9 @@ impl SourceToDefCtx<'_, '_> { for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) { let res: DefWithBodyId = match_ast! { match (container.value) { - ast::ConstDef(it) => self.const_to_def(container.with_value(it))?.into(), - ast::StaticDef(it) => self.static_to_def(container.with_value(it))?.into(), - ast::FnDef(it) => self.fn_to_def(container.with_value(it))?.into(), + ast::Const(it) => self.const_to_def(container.with_value(it))?.into(), + ast::Static(it) => self.static_to_def(container.with_value(it))?.into(), + ast::Fn(it) => self.fn_to_def(container.with_value(it))?.into(), _ => continue, } }; diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index 86a47a9e54..d0cb62ef01 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs @@ -159,7 +159,7 @@ impl SourceAnalyzer { pub(crate) fn resolve_record_field( &self, db: &dyn HirDatabase, - field: &ast::RecordField, + field: &ast::RecordExprField, ) -> Option<(Field, Option)> { let expr = field.expr()?; let expr_id = self.expr_id(db, &expr)?; @@ -182,7 +182,7 @@ impl SourceAnalyzer { pub(crate) fn resolve_record_field_pat( &self, _db: &dyn HirDatabase, - field: &ast::RecordFieldPat, + field: &ast::RecordPatField, ) -> Option { let pat_id = self.pat_id(&field.pat()?)?; let struct_field = self.infer.as_ref()?.record_field_pat_resolution(pat_id)?; @@ -202,7 +202,7 @@ impl SourceAnalyzer { pub(crate) fn resolve_bind_pat_to_const( &self, db: &dyn HirDatabase, - pat: &ast::BindPat, + pat: &ast::IdentPat, ) -> Option { let pat_id = self.pat_id(&pat.clone().into())?; let body = self.body.as_ref()?; @@ -246,7 +246,7 @@ impl SourceAnalyzer { } } - if let Some(rec_lit) = path.syntax().parent().and_then(ast::RecordLit::cast) { + if let Some(rec_lit) = path.syntax().parent().and_then(ast::RecordExpr::cast) { let expr_id = self.expr_id(db, &rec_lit.into())?; if let Some(VariantId::EnumVariantId(variant)) = self.infer.as_ref()?.variant_resolution_for_expr(expr_id) @@ -284,7 +284,7 @@ impl SourceAnalyzer { pub(crate) fn record_literal_missing_fields( &self, db: &dyn HirDatabase, - literal: &ast::RecordLit, + literal: &ast::RecordExpr, ) -> Option> { let krate = self.resolver.krate()?; let body = self.body.as_ref()?; @@ -358,7 +358,7 @@ impl SourceAnalyzer { pub(crate) fn resolve_variant( &self, db: &dyn HirDatabase, - record_lit: ast::RecordLit, + record_lit: ast::RecordExpr, ) -> Option { let infer = self.infer.as_ref()?; let expr_id = self.expr_id(db, &record_lit.into())?; @@ -405,8 +405,7 @@ fn scope_for_offset( ) }) .map(|(expr_range, scope)| { - adjust(db, scopes, source_map, expr_range, offset.file_id, offset.value) - .unwrap_or(*scope) + adjust(db, scopes, source_map, expr_range, offset).unwrap_or(*scope) }) } @@ -417,8 +416,7 @@ fn adjust( scopes: &ExprScopes, source_map: &BodySourceMap, expr_range: TextRange, - file_id: HirFileId, - offset: TextSize, + offset: InFile, ) -> Option { let child_scopes = scopes .scope_by_expr() @@ -426,7 +424,7 @@ fn adjust( .filter_map(|(id, scope)| { let source = source_map.expr_syntax(*id).ok()?; // FIXME: correctly handle macro expansion - if source.file_id != file_id { + if source.file_id != offset.file_id { return None; } let root = source.file_syntax(db.upcast()); @@ -434,7 +432,7 @@ fn adjust( Some((node.syntax().text_range(), scope)) }) .filter(|&(range, _)| { - range.start() <= offset && expr_range.contains_range(range) && range != expr_range + range.start() <= offset.value && expr_range.contains_range(range) && range != expr_range }); child_scopes diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs index 4994a21253..6cb56a1cd0 100644 --- a/crates/ra_hir_def/src/adt.rs +++ b/crates/ra_hir_def/src/adt.rs @@ -8,7 +8,7 @@ use hir_expand::{ InFile, }; use ra_arena::{map::ArenaMap, Arena}; -use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner}; +use ra_syntax::ast::{self, NameOwner, VisibilityOwner}; use crate::{ body::{CfgExpander, LowerCtx}, @@ -112,7 +112,7 @@ impl EnumData { impl HasChildSource for EnumId { type ChildId = LocalEnumVariantId; - type Value = ast::EnumVariant; + type Value = ast::Variant; fn child_source(&self, db: &dyn DefDatabase) -> InFile> { let src = self.lookup(db).source(db); let mut trace = Trace::new_for_map(); @@ -123,8 +123,8 @@ impl HasChildSource for EnumId { fn lower_enum( db: &dyn DefDatabase, - trace: &mut Trace, - ast: &InFile, + trace: &mut Trace, + ast: &InFile, module_id: ModuleId, ) { let expander = CfgExpander::new(db, ast.file_id, module_id.krate); @@ -179,7 +179,7 @@ impl VariantData { impl HasChildSource for VariantId { type ChildId = LocalFieldId; - type Value = Either; + type Value = Either; fn child_source(&self, db: &dyn DefDatabase) -> InFile> { let (src, module_id) = match self { @@ -194,7 +194,7 @@ impl HasChildSource for VariantId { } VariantId::UnionId(it) => ( it.lookup(db).source(db).map(|it| { - it.record_field_def_list() + it.record_field_list() .map(ast::StructKind::Record) .unwrap_or(ast::StructKind::Unit) }), @@ -218,7 +218,7 @@ pub enum StructKind { fn lower_struct( db: &dyn DefDatabase, expander: &mut CfgExpander, - trace: &mut Trace>, + trace: &mut Trace>, ast: &InFile, ) -> StructKind { let ctx = LowerCtx::new(db, ast.file_id); @@ -234,7 +234,7 @@ fn lower_struct( || Either::Left(fd.clone()), || FieldData { name: Name::new_tuple_field(i), - type_ref: TypeRef::from_ast_opt(&ctx, fd.type_ref()), + type_ref: TypeRef::from_ast_opt(&ctx, fd.ty()), visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), }, ); @@ -251,7 +251,7 @@ fn lower_struct( || Either::Right(fd.clone()), || FieldData { name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), - type_ref: TypeRef::from_ast_opt(&ctx, fd.ascribed_type()), + type_ref: TypeRef::from_ast_opt(&ctx, fd.ty()), visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), }, ); diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs index 70ccd43052..050832ce01 100644 --- a/crates/ra_hir_def/src/attr.rs +++ b/crates/ra_hir_def/src/attr.rs @@ -151,18 +151,15 @@ pub enum AttrInput { impl Attr { fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option { let path = ModPath::from_src(ast.path()?, hygiene)?; - let input = match ast.input() { - None => None, - Some(ast::AttrInput::Literal(lit)) => { - // FIXME: escape? raw string? - let value = lit.syntax().first_token()?.text().trim_matches('"').into(); - Some(AttrInput::Literal(value)) - } - Some(ast::AttrInput::TokenTree(tt)) => { - Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0)) - } + let input = if let Some(lit) = ast.literal() { + // FIXME: escape? raw string? + let value = lit.syntax().first_token()?.text().trim_matches('"').into(); + Some(AttrInput::Literal(value)) + } else if let Some(tt) = ast.token_tree() { + Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0)) + } else { + None }; - Some(Attr { path, input }) } } diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 2fe04db2ba..d5f18b9201 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs @@ -216,7 +216,7 @@ pub struct BodySourceMap { expr_map_back: ArenaMap>, pat_map: FxHashMap, pat_map_back: ArenaMap>, - field_map: FxHashMap<(ExprId, usize), InFile>>, + field_map: FxHashMap<(ExprId, usize), InFile>>, expansions: FxHashMap>, HirFileId>, } @@ -314,7 +314,7 @@ impl BodySourceMap { self.pat_map.get(&src).cloned() } - pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile> { + pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile> { self.field_map[&(expr, field)].clone() } } diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index c6bc85e2f1..f5c37edb30 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -1,6 +1,8 @@ //! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr` //! representation. +use std::{any::type_name, sync::Arc}; + use either::Either; use hir_expand::{ hygiene::Hygiene, @@ -10,11 +12,12 @@ use hir_expand::{ use ra_arena::Arena; use ra_syntax::{ ast::{ - self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, ModuleItemOwner, NameOwner, - SlicePatComponents, TypeAscriptionOwner, + self, ArgListOwner, ArrayExprKind, AstChildren, LiteralKind, LoopBodyOwner, NameOwner, + SlicePatComponents, }, AstNode, AstPtr, }; +use rustc_hash::FxHashMap; use test_utils::mark; use crate::{ @@ -35,9 +38,6 @@ use crate::{ }; use super::{ExprSource, PatSource}; -use ast::AstChildren; -use rustc_hash::FxHashMap; -use std::{any::type_name, sync::Arc}; pub(crate) struct LowerCtx { hygiene: Hygiene, @@ -224,9 +224,22 @@ impl ExprCollector<'_> { self.alloc_expr(Expr::Unsafe { body }, syntax_ptr) } // FIXME: we need to record these effects somewhere... - ast::Effect::Async(_) | ast::Effect::Label(_) => { - self.collect_block_opt(e.block_expr()) - } + ast::Effect::Label(label) => match e.block_expr() { + Some(block) => { + let res = self.collect_block(block); + match &mut self.body.exprs[res] { + Expr::Block { label: block_label, .. } => { + *block_label = + label.lifetime_token().map(|t| Name::new_lifetime(&t)) + } + _ => unreachable!(), + } + res + } + None => self.missing_expr(), + }, + // FIXME: we need to record these effects somewhere... + ast::Effect::Async(_) => self.collect_block_opt(e.block_expr()), }, ast::Expr::BlockExpr(e) => self.collect_block(e), ast::Expr::LoopExpr(e) => { @@ -324,7 +337,7 @@ impl ExprCollector<'_> { }; let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); let generic_args = - e.type_arg_list().and_then(|it| GenericArgs::from_ast(&self.ctx(), it)); + e.generic_arg_list().and_then(|it| GenericArgs::from_ast(&self.ctx(), it)); self.alloc_expr( Expr::MethodCall { receiver, method_name, args, generic_args }, syntax_ptr, @@ -379,10 +392,10 @@ impl ExprCollector<'_> { let expr = e.expr().map(|e| self.collect_expr(e)); self.alloc_expr(Expr::Return { expr }, syntax_ptr) } - ast::Expr::RecordLit(e) => { + ast::Expr::RecordExpr(e) => { let path = e.path().and_then(|path| self.expander.parse_path(path)); let mut field_ptrs = Vec::new(); - let record_lit = if let Some(nfl) = e.record_field_list() { + let record_lit = if let Some(nfl) = e.record_expr_field_list() { let fields = nfl .fields() .inspect(|field| field_ptrs.push(AstPtr::new(field))) @@ -432,7 +445,7 @@ impl ExprCollector<'_> { } ast::Expr::CastExpr(e) => { let expr = self.collect_expr_opt(e.expr()); - let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.type_ref()); + let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.ty()); self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr) } ast::Expr::RefExpr(e) => { @@ -460,22 +473,19 @@ impl ExprCollector<'_> { self.alloc_expr(Expr::Missing, syntax_ptr) } } - ast::Expr::LambdaExpr(e) => { + ast::Expr::ClosureExpr(e) => { let mut args = Vec::new(); let mut arg_types = Vec::new(); if let Some(pl) = e.param_list() { for param in pl.params() { let pat = self.collect_pat_opt(param.pat()); - let type_ref = - param.ascribed_type().map(|it| TypeRef::from_ast(&self.ctx(), it)); + let type_ref = param.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); args.push(pat); arg_types.push(type_ref); } } - let ret_type = e - .ret_type() - .and_then(|r| r.type_ref()) - .map(|it| TypeRef::from_ast(&self.ctx(), it)); + let ret_type = + e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&self.ctx(), it)); let body = self.collect_expr_opt(e.body()); self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr) } @@ -486,7 +496,7 @@ impl ExprCollector<'_> { self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr) } ast::Expr::TupleExpr(e) => { - let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect(); + let exprs = e.fields().map(|expr| self.collect_expr(expr)).collect(); self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr) } ast::Expr::BoxExpr(e) => { @@ -559,9 +569,6 @@ impl ExprCollector<'_> { } } } - - // FIXME implement HIR for these: - ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), } } @@ -604,76 +611,84 @@ impl ExprCollector<'_> { self.collect_block_items(&block); let statements = block .statements() - .map(|s| match s { - ast::Stmt::LetStmt(stmt) => { - let pat = self.collect_pat_opt(stmt.pat()); - let type_ref = - stmt.ascribed_type().map(|it| TypeRef::from_ast(&self.ctx(), it)); - let initializer = stmt.initializer().map(|e| self.collect_expr(e)); - Statement::Let { pat, type_ref, initializer } - } - ast::Stmt::ExprStmt(stmt) => Statement::Expr(self.collect_expr_opt(stmt.expr())), + .filter_map(|s| { + let stmt = match s { + ast::Stmt::LetStmt(stmt) => { + let pat = self.collect_pat_opt(stmt.pat()); + let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); + let initializer = stmt.initializer().map(|e| self.collect_expr(e)); + Statement::Let { pat, type_ref, initializer } + } + ast::Stmt::ExprStmt(stmt) => { + Statement::Expr(self.collect_expr_opt(stmt.expr())) + } + ast::Stmt::Item(_) => return None, + }; + Some(stmt) }) .collect(); let tail = block.expr().map(|e| self.collect_expr(e)); - let label = block.label().and_then(|l| l.lifetime_token()).map(|t| Name::new_lifetime(&t)); - self.alloc_expr(Expr::Block { statements, tail, label }, syntax_node_ptr) + self.alloc_expr(Expr::Block { statements, tail, label: None }, syntax_node_ptr) } fn collect_block_items(&mut self, block: &ast::BlockExpr) { let container = ContainerId::DefWithBodyId(self.def); let items = block - .items() + .statements() + .filter_map(|stmt| match stmt { + ast::Stmt::Item(it) => Some(it), + ast::Stmt::LetStmt(_) | ast::Stmt::ExprStmt(_) => None, + }) .filter_map(|item| { let (def, name): (ModuleDefId, Option) = match item { - ast::ModuleItem::FnDef(def) => { + ast::Item::Fn(def) => { let id = self.find_inner_item(&def)?; ( FunctionLoc { container: container.into(), id }.intern(self.db).into(), def.name(), ) } - ast::ModuleItem::TypeAliasDef(def) => { + ast::Item::TypeAlias(def) => { let id = self.find_inner_item(&def)?; ( TypeAliasLoc { container: container.into(), id }.intern(self.db).into(), def.name(), ) } - ast::ModuleItem::ConstDef(def) => { + ast::Item::Const(def) => { let id = self.find_inner_item(&def)?; ( ConstLoc { container: container.into(), id }.intern(self.db).into(), def.name(), ) } - ast::ModuleItem::StaticDef(def) => { + ast::Item::Static(def) => { let id = self.find_inner_item(&def)?; (StaticLoc { container, id }.intern(self.db).into(), def.name()) } - ast::ModuleItem::StructDef(def) => { + ast::Item::Struct(def) => { let id = self.find_inner_item(&def)?; (StructLoc { container, id }.intern(self.db).into(), def.name()) } - ast::ModuleItem::EnumDef(def) => { + ast::Item::Enum(def) => { let id = self.find_inner_item(&def)?; (EnumLoc { container, id }.intern(self.db).into(), def.name()) } - ast::ModuleItem::UnionDef(def) => { + ast::Item::Union(def) => { let id = self.find_inner_item(&def)?; (UnionLoc { container, id }.intern(self.db).into(), def.name()) } - ast::ModuleItem::TraitDef(def) => { + ast::Item::Trait(def) => { let id = self.find_inner_item(&def)?; (TraitLoc { container, id }.intern(self.db).into(), def.name()) } - ast::ModuleItem::ExternBlock(_) => return None, // FIXME: collect from extern blocks - ast::ModuleItem::ImplDef(_) - | ast::ModuleItem::UseItem(_) - | ast::ModuleItem::ExternCrateItem(_) - | ast::ModuleItem::Module(_) - | ast::ModuleItem::MacroCall(_) => return None, + ast::Item::ExternBlock(_) => return None, // FIXME: collect from extern blocks + ast::Item::Impl(_) + | ast::Item::Use(_) + | ast::Item::ExternCrate(_) + | ast::Item::Module(_) + | ast::Item::MacroCall(_) => return None, }; Some((def, name)) @@ -708,7 +723,7 @@ impl ExprCollector<'_> { fn collect_pat(&mut self, pat: ast::Pat) -> PatId { let pattern = match &pat { - ast::Pat::BindPat(bp) => { + ast::Pat::IdentPat(bp) => { let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); let annotation = BindingAnnotation::new(bp.mut_token().is_some(), bp.ref_token().is_some()); @@ -747,7 +762,7 @@ impl ExprCollector<'_> { } ast::Pat::TupleStructPat(p) => { let path = p.path().and_then(|path| self.expander.parse_path(path)); - let (args, ellipsis) = self.collect_tuple_pat(p.args()); + let (args, ellipsis) = self.collect_tuple_pat(p.fields()); Pat::TupleStruct { path, args, ellipsis } } ast::Pat::RefPat(p) => { @@ -765,40 +780,36 @@ impl ExprCollector<'_> { } ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat()), ast::Pat::TuplePat(p) => { - let (args, ellipsis) = self.collect_tuple_pat(p.args()); + let (args, ellipsis) = self.collect_tuple_pat(p.fields()); Pat::Tuple { args, ellipsis } } - ast::Pat::PlaceholderPat(_) => Pat::Wild, + ast::Pat::WildcardPat(_) => Pat::Wild, ast::Pat::RecordPat(p) => { let path = p.path().and_then(|path| self.expander.parse_path(path)); - let record_field_pat_list = - p.record_field_pat_list().expect("every struct should have a field list"); - let mut fields: Vec<_> = record_field_pat_list - .bind_pats() - .filter_map(|bind_pat| { - let ast_pat = - ast::Pat::cast(bind_pat.syntax().clone()).expect("bind pat is a pat"); + let args: Vec<_> = p + .record_pat_field_list() + .expect("every struct should have a field list") + .fields() + .filter_map(|f| { + let ast_pat = f.pat()?; let pat = self.collect_pat(ast_pat); - let name = bind_pat.name()?.as_name(); + let name = f.field_name()?.as_name(); Some(RecordFieldPat { name, pat }) }) .collect(); - let iter = record_field_pat_list.record_field_pats().filter_map(|f| { - let ast_pat = f.pat()?; - let pat = self.collect_pat(ast_pat); - let name = f.field_name()?.as_name(); - Some(RecordFieldPat { name, pat }) - }); - fields.extend(iter); - let ellipsis = record_field_pat_list.dotdot_token().is_some(); + let ellipsis = p + .record_pat_field_list() + .expect("every struct should have a field list") + .dotdot_token() + .is_some(); - Pat::Record { path, args: fields, ellipsis } + Pat::Record { path, args, ellipsis } } ast::Pat::SlicePat(p) => { let SlicePatComponents { prefix, slice, suffix } = p.components(); - // FIXME properly handle `DotDotPat` + // FIXME properly handle `RestPat` Pat::Slice { prefix: prefix.into_iter().map(|p| self.collect_pat(p)).collect(), slice: slice.map(|p| self.collect_pat(p)), @@ -815,10 +826,10 @@ impl ExprCollector<'_> { Pat::Missing } } - ast::Pat::DotDotPat(_) => { - // `DotDotPat` requires special handling and should not be mapped + ast::Pat::RestPat(_) => { + // `RestPat` requires special handling and should not be mapped // to a Pat. Here we are using `Pat::Missing` as a fallback for - // when `DotDotPat` is mapped to `Pat`, which can easily happen + // when `RestPat` is mapped to `Pat`, which can easily happen // when the source code being analyzed has a malformed pattern // which includes `..` in a place where it isn't valid. @@ -842,10 +853,10 @@ impl ExprCollector<'_> { fn collect_tuple_pat(&mut self, args: AstChildren) -> (Vec, Option) { // Find the location of the `..`, if there is one. Note that we do not // consider the possiblity of there being multiple `..` here. - let ellipsis = args.clone().position(|p| matches!(p, ast::Pat::DotDotPat(_))); + let ellipsis = args.clone().position(|p| matches!(p, ast::Pat::RestPat(_))); // We want to skip the `..` pattern here, since we account for it above. let args = args - .filter(|p| !matches!(p, ast::Pat::DotDotPat(_))) + .filter(|p| !matches!(p, ast::Pat::RestPat(_))) .map(|p| self.collect_pat(p)) .collect(); diff --git a/crates/ra_hir_def/src/child_by_source.rs b/crates/ra_hir_def/src/child_by_source.rs index a885ec96d6..dcb00a1d9a 100644 --- a/crates/ra_hir_def/src/child_by_source.rs +++ b/crates/ra_hir_def/src/child_by_source.rs @@ -162,7 +162,7 @@ impl ChildBySource for EnumId { let arena_map = arena_map.as_ref(); for (local_id, source) in arena_map.value.iter() { let id = EnumVariantId { parent: *self, local_id }; - res[keys::ENUM_VARIANT].insert(arena_map.with_value(source.clone()), id) + res[keys::VARIANT].insert(arena_map.with_value(source.clone()), id) } res diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs index 6a0f493a79..699ba9c923 100644 --- a/crates/ra_hir_def/src/generics.rs +++ b/crates/ra_hir_def/src/generics.rs @@ -12,7 +12,7 @@ use hir_expand::{ use ra_arena::{map::ArenaMap, Arena}; use ra_db::FileId; use ra_prof::profile; -use ra_syntax::ast::{self, NameOwner, TypeBoundsOwner, TypeParamsOwner}; +use ra_syntax::ast::{self, GenericParamsOwner, NameOwner, TypeBoundsOwner}; use crate::{ body::LowerCtx, @@ -66,7 +66,7 @@ pub enum WherePredicateTarget { TypeParam(LocalTypeParamId), } -type SourceMap = ArenaMap>; +type SourceMap = ArenaMap>; impl GenericParams { pub(crate) fn generic_params_query( @@ -205,9 +205,9 @@ impl GenericParams { &mut self, lower_ctx: &LowerCtx, sm: &mut SourceMap, - node: &dyn TypeParamsOwner, + node: &dyn GenericParamsOwner, ) { - if let Some(params) = node.type_param_list() { + if let Some(params) = node.generic_param_list() { self.fill_params(lower_ctx, sm, params) } if let Some(where_clause) = node.where_clause() { @@ -232,7 +232,7 @@ impl GenericParams { &mut self, lower_ctx: &LowerCtx, sm: &mut SourceMap, - params: ast::TypeParamList, + params: ast::GenericParamList, ) { for type_param in params.type_params() { let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); @@ -253,7 +253,7 @@ impl GenericParams { fn fill_where_predicates(&mut self, lower_ctx: &LowerCtx, where_clause: ast::WhereClause) { for pred in where_clause.predicates() { - let type_ref = match pred.type_ref() { + let type_ref = match pred.ty() { Some(type_ref) => type_ref, None => continue, }; @@ -270,7 +270,7 @@ impl GenericParams { bound: ast::TypeBound, type_ref: TypeRef, ) { - if bound.question_token().is_some() { + if bound.question_mark_token().is_some() { // FIXME: remove this bound return; } @@ -317,7 +317,7 @@ impl GenericParams { impl HasChildSource for GenericDefId { type ChildId = LocalTypeParamId; - type Value = Either; + type Value = Either; fn child_source(&self, db: &dyn DefDatabase) -> InFile { let (_, sm) = GenericParams::new(db, *self); sm diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index da79d8ffd8..a67e75dac0 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -13,7 +13,7 @@ use std::{ sync::Arc, }; -use ast::{AstNode, AttrsOwner, NameOwner, StructKind, TypeAscriptionOwner}; +use ast::{AstNode, AttrsOwner, NameOwner, StructKind}; use either::Either; use hir_expand::{ ast_id_map::FileAstId, @@ -70,7 +70,7 @@ impl GenericParamsId { pub struct ItemTree { top_level: SmallVec<[ModItem; 1]>, attrs: FxHashMap, - inner_items: FxHashMap, SmallVec<[ModItem; 1]>>, + inner_items: FxHashMap, SmallVec<[ModItem; 1]>>, data: Option>, } @@ -187,7 +187,7 @@ impl ItemTree { /// /// Most AST items are lowered to a single `ModItem`, but some (eg. `use` items) may be lowered /// to multiple items in the `ItemTree`. - pub fn inner_items(&self, ast: FileAstId) -> &[ModItem] { + pub fn inner_items(&self, ast: FileAstId) -> &[ModItem] { &self.inner_items[&ast] } @@ -310,7 +310,7 @@ from_attrs!(ModItem(ModItem), Variant(Idx), Field(Idx)); /// Trait implemented by all item nodes in the item tree. pub trait ItemTreeNode: Clone { - type Source: AstNode + Into; + type Source: AstNode + Into; fn ast_id(&self) -> FileAstId; @@ -411,17 +411,17 @@ macro_rules! mod_items { } mod_items! { - Import in imports -> ast::UseItem, - ExternCrate in extern_crates -> ast::ExternCrateItem, - Function in functions -> ast::FnDef, - Struct in structs -> ast::StructDef, - Union in unions -> ast::UnionDef, - Enum in enums -> ast::EnumDef, - Const in consts -> ast::ConstDef, - Static in statics -> ast::StaticDef, - Trait in traits -> ast::TraitDef, - Impl in impls -> ast::ImplDef, - TypeAlias in type_aliases -> ast::TypeAliasDef, + Import in imports -> ast::Use, + ExternCrate in extern_crates -> ast::ExternCrate, + Function in functions -> ast::Fn, + Struct in structs -> ast::Struct, + Union in unions -> ast::Union, + Enum in enums -> ast::Enum, + Const in consts -> ast::Const, + Static in statics -> ast::Static, + Trait in traits -> ast::Trait, + Impl in impls -> ast::Impl, + TypeAlias in type_aliases -> ast::TypeAlias, Mod in mods -> ast::Module, MacroCall in macro_calls -> ast::MacroCall, } @@ -482,7 +482,7 @@ pub struct Import { pub is_prelude: bool, /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many /// `Import`s can map to the same `use` item. - pub ast_id: FileAstId, + pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -492,7 +492,7 @@ pub struct ExternCrate { pub visibility: RawVisibilityId, /// Whether this is a `#[macro_use] extern crate ...`. pub is_macro_use: bool, - pub ast_id: FileAstId, + pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -505,7 +505,7 @@ pub struct Function { pub params: Box<[TypeRef]>, pub is_varargs: bool, pub ret_type: TypeRef, - pub ast_id: FileAstId, + pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -514,7 +514,7 @@ pub struct Struct { pub visibility: RawVisibilityId, pub generic_params: GenericParamsId, pub fields: Fields, - pub ast_id: FileAstId, + pub ast_id: FileAstId, pub kind: StructDefKind, } @@ -534,7 +534,7 @@ pub struct Union { pub visibility: RawVisibilityId, pub generic_params: GenericParamsId, pub fields: Fields, - pub ast_id: FileAstId, + pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -543,7 +543,7 @@ pub struct Enum { pub visibility: RawVisibilityId, pub generic_params: GenericParamsId, pub variants: IdRange, - pub ast_id: FileAstId, + pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -552,7 +552,7 @@ pub struct Const { pub name: Option, pub visibility: RawVisibilityId, pub type_ref: TypeRef, - pub ast_id: FileAstId, + pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -561,7 +561,7 @@ pub struct Static { pub visibility: RawVisibilityId, pub mutable: bool, pub type_ref: TypeRef, - pub ast_id: FileAstId, + pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -571,7 +571,7 @@ pub struct Trait { pub generic_params: GenericParamsId, pub auto: bool, pub items: Box<[AssocItem]>, - pub ast_id: FileAstId, + pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -581,7 +581,7 @@ pub struct Impl { pub target_type: TypeRef, pub is_negative: bool, pub items: Box<[AssocItem]>, - pub ast_id: FileAstId, + pub ast_id: FileAstId, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -592,7 +592,7 @@ pub struct TypeAlias { pub bounds: Box<[TypeBound]>, pub generic_params: GenericParamsId, pub type_ref: Option, - pub ast_id: FileAstId, + pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs index f79b8fca3d..450ef87981 100644 --- a/crates/ra_hir_def/src/item_tree/lower.rs +++ b/crates/ra_hir_def/src/item_tree/lower.rs @@ -1,10 +1,7 @@ //! AST -> `ItemTree` lowering code. -use super::*; -use crate::{ - attr::Attrs, - generics::{GenericParams, TypeParamData, TypeParamProvenance}, -}; +use std::{collections::hash_map::Entry, mem, sync::Arc}; + use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId}; use ra_arena::map::ArenaMap; use ra_syntax::{ @@ -12,7 +9,13 @@ use ra_syntax::{ SyntaxNode, }; use smallvec::SmallVec; -use std::{collections::hash_map::Entry, mem, sync::Arc}; + +use crate::{ + attr::Attrs, + generics::{GenericParams, TypeParamData, TypeParamProvenance}, +}; + +use super::*; fn id(index: Idx) -> FileItemTreeId { FileItemTreeId { index, _p: PhantomData } @@ -70,19 +73,19 @@ impl Ctx { self.tree.data_mut() } - fn lower_mod_item(&mut self, item: &ast::ModuleItem, inner: bool) -> Option { + fn lower_mod_item(&mut self, item: &ast::Item, inner: bool) -> Option { assert!(inner || self.inner_items.is_empty()); // Collect inner items for 1-to-1-lowered items. match item { - ast::ModuleItem::StructDef(_) - | ast::ModuleItem::UnionDef(_) - | ast::ModuleItem::EnumDef(_) - | ast::ModuleItem::FnDef(_) - | ast::ModuleItem::TypeAliasDef(_) - | ast::ModuleItem::ConstDef(_) - | ast::ModuleItem::StaticDef(_) - | ast::ModuleItem::MacroCall(_) => { + ast::Item::Struct(_) + | ast::Item::Union(_) + | ast::Item::Enum(_) + | ast::Item::Fn(_) + | ast::Item::TypeAlias(_) + | ast::Item::Const(_) + | ast::Item::Static(_) + | ast::Item::MacroCall(_) => { // Skip this if we're already collecting inner items. We'll descend into all nodes // already. if !inner { @@ -92,34 +95,30 @@ impl Ctx { // These are handled in their respective `lower_X` method (since we can't just blindly // walk them). - ast::ModuleItem::TraitDef(_) - | ast::ModuleItem::ImplDef(_) - | ast::ModuleItem::ExternBlock(_) => {} + ast::Item::Trait(_) | ast::Item::Impl(_) | ast::Item::ExternBlock(_) => {} // These don't have inner items. - ast::ModuleItem::Module(_) - | ast::ModuleItem::ExternCrateItem(_) - | ast::ModuleItem::UseItem(_) => {} + ast::Item::Module(_) | ast::Item::ExternCrate(_) | ast::Item::Use(_) => {} }; let attrs = Attrs::new(item, &self.hygiene); let items = match item { - ast::ModuleItem::StructDef(ast) => self.lower_struct(ast).map(Into::into), - ast::ModuleItem::UnionDef(ast) => self.lower_union(ast).map(Into::into), - ast::ModuleItem::EnumDef(ast) => self.lower_enum(ast).map(Into::into), - ast::ModuleItem::FnDef(ast) => self.lower_function(ast).map(Into::into), - ast::ModuleItem::TypeAliasDef(ast) => self.lower_type_alias(ast).map(Into::into), - ast::ModuleItem::StaticDef(ast) => self.lower_static(ast).map(Into::into), - ast::ModuleItem::ConstDef(ast) => Some(self.lower_const(ast).into()), - ast::ModuleItem::Module(ast) => self.lower_module(ast).map(Into::into), - ast::ModuleItem::TraitDef(ast) => self.lower_trait(ast).map(Into::into), - ast::ModuleItem::ImplDef(ast) => self.lower_impl(ast).map(Into::into), - ast::ModuleItem::UseItem(ast) => Some(ModItems( + ast::Item::Struct(ast) => self.lower_struct(ast).map(Into::into), + ast::Item::Union(ast) => self.lower_union(ast).map(Into::into), + ast::Item::Enum(ast) => self.lower_enum(ast).map(Into::into), + ast::Item::Fn(ast) => self.lower_function(ast).map(Into::into), + ast::Item::TypeAlias(ast) => self.lower_type_alias(ast).map(Into::into), + ast::Item::Static(ast) => self.lower_static(ast).map(Into::into), + ast::Item::Const(ast) => Some(self.lower_const(ast).into()), + ast::Item::Module(ast) => self.lower_module(ast).map(Into::into), + ast::Item::Trait(ast) => self.lower_trait(ast).map(Into::into), + ast::Item::Impl(ast) => self.lower_impl(ast).map(Into::into), + ast::Item::Use(ast) => Some(ModItems( self.lower_use(ast).into_iter().map(Into::into).collect::>(), )), - ast::ModuleItem::ExternCrateItem(ast) => self.lower_extern_crate(ast).map(Into::into), - ast::ModuleItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), - ast::ModuleItem::ExternBlock(ast) => { + ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast).map(Into::into), + ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), + ast::Item::ExternBlock(ast) => { Some(ModItems(self.lower_extern_block(ast).into_iter().collect::>())) } }; @@ -147,27 +146,26 @@ impl Ctx { fn collect_inner_items(&mut self, container: &SyntaxNode) { let forced_vis = self.forced_visibility.take(); let mut inner_items = mem::take(&mut self.tree.inner_items); - inner_items.extend( - container.descendants().skip(1).filter_map(ast::ModuleItem::cast).filter_map(|item| { + inner_items.extend(container.descendants().skip(1).filter_map(ast::Item::cast).filter_map( + |item| { let ast_id = self.source_ast_id_map.ast_id(&item); Some((ast_id, self.lower_mod_item(&item, true)?.0)) - }), - ); + }, + )); self.tree.inner_items = inner_items; self.forced_visibility = forced_vis; } - fn lower_assoc_item(&mut self, item: &ast::ModuleItem) -> Option { + fn lower_assoc_item(&mut self, item: &ast::AssocItem) -> Option { match item { - ast::ModuleItem::FnDef(ast) => self.lower_function(ast).map(Into::into), - ast::ModuleItem::TypeAliasDef(ast) => self.lower_type_alias(ast).map(Into::into), - ast::ModuleItem::ConstDef(ast) => Some(self.lower_const(ast).into()), - ast::ModuleItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), - _ => None, + ast::AssocItem::Fn(ast) => self.lower_function(ast).map(Into::into), + ast::AssocItem::TypeAlias(ast) => self.lower_type_alias(ast).map(Into::into), + ast::AssocItem::Const(ast) => Some(self.lower_const(ast).into()), + ast::AssocItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), } } - fn lower_struct(&mut self, strukt: &ast::StructDef) -> Option> { + fn lower_struct(&mut self, strukt: &ast::Struct) -> Option> { let visibility = self.lower_visibility(strukt); let name = strukt.name()?.as_name(); let generic_params = self.lower_generic_params(GenericsOwner::Struct, strukt); @@ -196,7 +194,7 @@ impl Ctx { } } - fn lower_record_fields(&mut self, fields: &ast::RecordFieldDefList) -> IdRange { + fn lower_record_fields(&mut self, fields: &ast::RecordFieldList) -> IdRange { let start = self.next_field_idx(); for field in fields.fields() { if let Some(data) = self.lower_record_field(&field) { @@ -208,15 +206,15 @@ impl Ctx { IdRange::new(start..end) } - fn lower_record_field(&mut self, field: &ast::RecordFieldDef) -> Option { + fn lower_record_field(&mut self, field: &ast::RecordField) -> Option { let name = field.name()?.as_name(); let visibility = self.lower_visibility(field); - let type_ref = self.lower_type_ref_opt(field.ascribed_type()); + let type_ref = self.lower_type_ref_opt(field.ty()); let res = Field { name, type_ref, visibility }; Some(res) } - fn lower_tuple_fields(&mut self, fields: &ast::TupleFieldDefList) -> IdRange { + fn lower_tuple_fields(&mut self, fields: &ast::TupleFieldList) -> IdRange { let start = self.next_field_idx(); for (i, field) in fields.fields().enumerate() { let data = self.lower_tuple_field(i, &field); @@ -227,22 +225,20 @@ impl Ctx { IdRange::new(start..end) } - fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleFieldDef) -> Field { + fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleField) -> Field { let name = Name::new_tuple_field(idx); let visibility = self.lower_visibility(field); - let type_ref = self.lower_type_ref_opt(field.type_ref()); + let type_ref = self.lower_type_ref_opt(field.ty()); let res = Field { name, type_ref, visibility }; res } - fn lower_union(&mut self, union: &ast::UnionDef) -> Option> { + fn lower_union(&mut self, union: &ast::Union) -> Option> { let visibility = self.lower_visibility(union); let name = union.name()?.as_name(); let generic_params = self.lower_generic_params(GenericsOwner::Union, union); - let fields = match union.record_field_def_list() { - Some(record_field_def_list) => { - self.lower_fields(&StructKind::Record(record_field_def_list)) - } + let fields = match union.record_field_list() { + Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)), None => Fields::Record(IdRange::new(self.next_field_idx()..self.next_field_idx())), }; let ast_id = self.source_ast_id_map.ast_id(union); @@ -250,7 +246,7 @@ impl Ctx { Some(id(self.data().unions.alloc(res))) } - fn lower_enum(&mut self, enum_: &ast::EnumDef) -> Option> { + fn lower_enum(&mut self, enum_: &ast::Enum) -> Option> { let visibility = self.lower_visibility(enum_); let name = enum_.name()?.as_name(); let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_); @@ -263,7 +259,7 @@ impl Ctx { Some(id(self.data().enums.alloc(res))) } - fn lower_variants(&mut self, variants: &ast::EnumVariantList) -> IdRange { + fn lower_variants(&mut self, variants: &ast::VariantList) -> IdRange { let start = self.next_variant_idx(); for variant in variants.variants() { if let Some(data) = self.lower_variant(&variant) { @@ -275,14 +271,14 @@ impl Ctx { IdRange::new(start..end) } - fn lower_variant(&mut self, variant: &ast::EnumVariant) -> Option { + fn lower_variant(&mut self, variant: &ast::Variant) -> Option { let name = variant.name()?.as_name(); let fields = self.lower_fields(&variant.kind()); let res = Variant { name, fields }; Some(res) } - fn lower_function(&mut self, func: &ast::FnDef) -> Option> { + fn lower_function(&mut self, func: &ast::Fn) -> Option> { let visibility = self.lower_visibility(func); let name = func.name()?.as_name(); @@ -290,7 +286,7 @@ impl Ctx { let mut has_self_param = false; if let Some(param_list) = func.param_list() { if let Some(self_param) = param_list.self_param() { - let self_type = match self_param.ascribed_type() { + let self_type = match self_param.ty() { Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref), None => { let self_type = TypeRef::Path(name![Self].into()); @@ -309,7 +305,7 @@ impl Ctx { has_self_param = true; } for param in param_list.params() { - let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ascribed_type()); + let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty()); params.push(type_ref); } } @@ -321,7 +317,7 @@ impl Ctx { } } - let ret_type = match func.ret_type().and_then(|rt| rt.type_ref()) { + let ret_type = match func.ret_type().and_then(|rt| rt.ty()) { Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref), _ => TypeRef::unit(), }; @@ -353,10 +349,10 @@ impl Ctx { fn lower_type_alias( &mut self, - type_alias: &ast::TypeAliasDef, + type_alias: &ast::TypeAlias, ) -> Option> { let name = type_alias.name()?.as_name(); - let type_ref = type_alias.type_ref().map(|it| self.lower_type_ref(&it)); + let type_ref = type_alias.ty().map(|it| self.lower_type_ref(&it)); let visibility = self.lower_visibility(type_alias); let bounds = self.lower_type_bounds(type_alias); let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias); @@ -372,9 +368,9 @@ impl Ctx { Some(id(self.data().type_aliases.alloc(res))) } - fn lower_static(&mut self, static_: &ast::StaticDef) -> Option> { + fn lower_static(&mut self, static_: &ast::Static) -> Option> { let name = static_.name()?.as_name(); - let type_ref = self.lower_type_ref_opt(static_.ascribed_type()); + let type_ref = self.lower_type_ref_opt(static_.ty()); let visibility = self.lower_visibility(static_); let mutable = static_.mut_token().is_some(); let ast_id = self.source_ast_id_map.ast_id(static_); @@ -382,9 +378,9 @@ impl Ctx { Some(id(self.data().statics.alloc(res))) } - fn lower_const(&mut self, konst: &ast::ConstDef) -> FileItemTreeId { + fn lower_const(&mut self, konst: &ast::Const) -> FileItemTreeId { let name = konst.name().map(|it| it.as_name()); - let type_ref = self.lower_type_ref_opt(konst.ascribed_type()); + let type_ref = self.lower_type_ref_opt(konst.ty()); let visibility = self.lower_visibility(konst); let ast_id = self.source_ast_id_map.ast_id(konst); let res = Const { name, visibility, type_ref, ast_id }; @@ -417,15 +413,15 @@ impl Ctx { Some(id(self.data().mods.alloc(res))) } - fn lower_trait(&mut self, trait_def: &ast::TraitDef) -> Option> { + fn lower_trait(&mut self, trait_def: &ast::Trait) -> Option> { let name = trait_def.name()?.as_name(); let visibility = self.lower_visibility(trait_def); let generic_params = self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def); let auto = trait_def.auto_token().is_some(); - let items = trait_def.item_list().map(|list| { + let items = trait_def.assoc_item_list().map(|list| { self.with_inherited_visibility(visibility, |this| { - list.items() + list.assoc_items() .filter_map(|item| { let attrs = Attrs::new(&item, &this.hygiene); this.collect_inner_items(item.syntax()); @@ -449,18 +445,18 @@ impl Ctx { Some(id(self.data().traits.alloc(res))) } - fn lower_impl(&mut self, impl_def: &ast::ImplDef) -> Option> { + fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option> { let generic_params = self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def); - let target_trait = impl_def.target_trait().map(|tr| self.lower_type_ref(&tr)); - let target_type = self.lower_type_ref(&impl_def.target_type()?); + let target_trait = impl_def.trait_().map(|tr| self.lower_type_ref(&tr)); + let target_type = self.lower_type_ref(&impl_def.self_ty()?); let is_negative = impl_def.excl_token().is_some(); // We cannot use `assoc_items()` here as that does not include macro calls. let items = impl_def - .item_list() + .assoc_item_list() .into_iter() - .flat_map(|it| it.items()) + .flat_map(|it| it.assoc_items()) .filter_map(|item| { self.collect_inner_items(item.syntax()); let assoc = self.lower_assoc_item(&item)?; @@ -474,7 +470,7 @@ impl Ctx { Some(id(self.data().impls.alloc(res))) } - fn lower_use(&mut self, use_item: &ast::UseItem) -> Vec> { + fn lower_use(&mut self, use_item: &ast::Use) -> Vec> { // FIXME: cfg_attr let is_prelude = use_item.has_atom_attr("prelude_import"); let visibility = self.lower_visibility(use_item); @@ -503,10 +499,10 @@ impl Ctx { fn lower_extern_crate( &mut self, - extern_crate: &ast::ExternCrateItem, + extern_crate: &ast::ExternCrate, ) -> Option> { let path = ModPath::from_name_ref(&extern_crate.name_ref()?); - let alias = extern_crate.alias().map(|a| { + let alias = extern_crate.rename().map(|a| { a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) }); let visibility = self.lower_visibility(extern_crate); @@ -552,15 +548,16 @@ impl Ctx { self.collect_inner_items(item.syntax()); let attrs = Attrs::new(&item, &self.hygiene); let id: ModItem = match item { - ast::ExternItem::FnDef(ast) => { + ast::ExternItem::Fn(ast) => { let func = self.lower_function(&ast)?; self.data().functions[func.index].is_unsafe = true; func.into() } - ast::ExternItem::StaticDef(ast) => { + ast::ExternItem::Static(ast) => { let statik = self.lower_static(&ast)?; statik.into() } + ast::ExternItem::MacroCall(_) => return None, }; self.add_attrs(id.into(), attrs); Some(id) @@ -573,10 +570,10 @@ impl Ctx { fn lower_generic_params_and_inner_items( &mut self, owner: GenericsOwner<'_>, - node: &impl ast::TypeParamsOwner, + node: &impl ast::GenericParamsOwner, ) -> GenericParamsId { // Generics are part of item headers and may contain inner items we need to collect. - if let Some(params) = node.type_param_list() { + if let Some(params) = node.generic_param_list() { self.collect_inner_items(params.syntax()); } if let Some(clause) = node.where_clause() { @@ -589,7 +586,7 @@ impl Ctx { fn lower_generic_params( &mut self, owner: GenericsOwner<'_>, - node: &impl ast::TypeParamsOwner, + node: &impl ast::GenericParamsOwner, ) -> GenericParamsId { let mut sm = &mut ArenaMap::default(); let mut generics = GenericParams::default(); @@ -651,10 +648,10 @@ impl Ctx { self.data().vis.alloc(vis) } - fn lower_type_ref(&self, type_ref: &ast::TypeRef) -> TypeRef { + fn lower_type_ref(&self, type_ref: &ast::Type) -> TypeRef { TypeRef::from_ast(&self.body_ctx, type_ref.clone()) } - fn lower_type_ref_opt(&self, type_ref: Option) -> TypeRef { + fn lower_type_ref_opt(&self, type_ref: Option) -> TypeRef { type_ref.map(|ty| self.lower_type_ref(&ty)).unwrap_or(TypeRef::Error) } @@ -702,7 +699,7 @@ enum GenericsOwner<'a> { Enum, Union, /// The `TraitDef` is needed to fill the source map for the implicit `Self` parameter. - Trait(&'a ast::TraitDef), + Trait(&'a ast::Trait), TypeAlias, Impl, } diff --git a/crates/ra_hir_def/src/item_tree/tests.rs b/crates/ra_hir_def/src/item_tree/tests.rs index f26982985f..a81497fa8a 100644 --- a/crates/ra_hir_def/src/item_tree/tests.rs +++ b/crates/ra_hir_def/src/item_tree/tests.rs @@ -21,7 +21,7 @@ fn test_inner_items(ra_fixture: &str) { let mut outer_items = FxHashSet::default(); let mut worklist = tree.top_level_items().to_vec(); while let Some(item) = worklist.pop() { - let node: ast::ModuleItem = match item { + let node: ast::Item = match item { ModItem::Import(it) => tree.source(&db, InFile::new(file_id, it)).into(), ModItem::ExternCrate(it) => tree.source(&db, InFile::new(file_id, it)).into(), ModItem::Function(it) => tree.source(&db, InFile::new(file_id, it)).into(), @@ -53,7 +53,7 @@ fn test_inner_items(ra_fixture: &str) { // Now descend the root node and check that all `ast::ModuleItem`s are either recorded above, or // registered as inner items. - for item in root.descendants().skip(1).filter_map(ast::ModuleItem::cast) { + for item in root.descendants().skip(1).filter_map(ast::Item::cast) { if outer_items.contains(&item) { continue; } @@ -228,31 +228,31 @@ fn smoke() { top-level items: #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }] - Import { path: ModPath { kind: Plain, segments: [Name(Text("a"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: false, is_prelude: false, ast_id: FileAstId::(0) } + Import { path: ModPath { kind: Plain, segments: [Name(Text("a"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: false, is_prelude: false, ast_id: FileAstId::(0) } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }] - Import { path: ModPath { kind: Plain, segments: [Name(Text("b"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: true, is_prelude: false, ast_id: FileAstId::(0) } + Import { path: ModPath { kind: Plain, segments: [Name(Text("b"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: true, is_prelude: false, ast_id: FileAstId::(0) } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("ext_crate"))] }, input: None }]) }] - ExternCrate { path: ModPath { kind: Plain, segments: [Name(Text("krate"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_macro_use: false, ast_id: FileAstId::(1) } + ExternCrate { path: ModPath { kind: Plain, segments: [Name(Text("krate"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_macro_use: false, ast_id: FileAstId::(1) } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_trait"))] }, input: None }]) }] - Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(0), auto: false, items: [TypeAlias(Idx::(0)), Const(Idx::(0)), Function(Idx::(0)), Function(Idx::(1))], ast_id: FileAstId::(2) } + Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(0), auto: false, items: [TypeAlias(Idx::(0)), Const(Idx::(0)), Function(Idx::(0)), Function(Idx::(1))], ast_id: FileAstId::(2) } > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_ty"))] }, input: None }]) }] - > TypeAlias { name: Name(Text("AssocTy")), visibility: RawVisibilityId("pub(self)"), bounds: [Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Tr"))] }, generic_args: [Some(GenericArgs { args: [Type(Tuple([]))], has_self_type: false, bindings: [] })] })], generic_params: GenericParamsId(4294967295), type_ref: None, ast_id: FileAstId::(8) } + > TypeAlias { name: Name(Text("AssocTy")), visibility: RawVisibilityId("pub(self)"), bounds: [Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Tr"))] }, generic_args: [Some(GenericArgs { args: [Type(Tuple([]))], has_self_type: false, bindings: [] })] })], generic_params: GenericParamsId(4294967295), type_ref: None, ast_id: FileAstId::(8) } > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_const"))] }, input: None }]) }] - > Const { name: Some(Name(Text("CONST"))), visibility: RawVisibilityId("pub(self)"), type_ref: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("u8"))] }, generic_args: [None] }), ast_id: FileAstId::(9) } + > Const { name: Some(Name(Text("CONST"))), visibility: RawVisibilityId("pub(self)"), type_ref: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("u8"))] }, generic_args: [None] }), ast_id: FileAstId::(9) } > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_method"))] }, input: None }]) }] - > Function { name: Name(Text("method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Shared)], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::(10) } + > Function { name: Name(Text("method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Shared)], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::(10) } > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_dfl_method"))] }, input: None }]) }] - > Function { name: Name(Text("dfl_method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Mut)], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::(11) } + > Function { name: Name(Text("dfl_method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Mut)], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::(11) } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct0"))] }, input: None }]) }] - Struct { name: Name(Text("Struct0")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(1), fields: Unit, ast_id: FileAstId::(3), kind: Unit } + Struct { name: Name(Text("Struct0")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(1), fields: Unit, ast_id: FileAstId::(3), kind: Unit } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct1"))] }, input: None }]) }] - Struct { name: Name(Text("Struct1")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(2), fields: Tuple(IdRange::(0..1)), ast_id: FileAstId::(4), kind: Tuple } + Struct { name: Name(Text("Struct1")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(2), fields: Tuple(IdRange::(0..1)), ast_id: FileAstId::(4), kind: Tuple } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct2"))] }, input: None }]) }] - Struct { name: Name(Text("Struct2")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(3), fields: Record(IdRange::(1..2)), ast_id: FileAstId::(5), kind: Record } + Struct { name: Name(Text("Struct2")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(3), fields: Record(IdRange::(1..2)), ast_id: FileAstId::(5), kind: Record } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("en"))] }, input: None }]) }] - Enum { name: Name(Text("En")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), variants: IdRange::(0..1), ast_id: FileAstId::(6) } + Enum { name: Name(Text("En")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), variants: IdRange::(0..1), ast_id: FileAstId::(6) } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("un"))] }, input: None }]) }] - Union { name: Name(Text("Un")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), fields: Record(IdRange::(3..4)), ast_id: FileAstId::(7) } + Union { name: Name(Text("Un")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), fields: Record(IdRange::(3..4)), ast_id: FileAstId::(7) } "##]], ); } @@ -274,13 +274,13 @@ fn simple_inner_items() { inner attrs: Attrs { entries: None } top-level items: - Impl { generic_params: GenericParamsId(0), target_trait: Some(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("D"))] }, generic_args: [None] })), target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Response"))] }, generic_args: [Some(GenericArgs { args: [Type(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("T"))] }, generic_args: [None] }))], has_self_type: false, bindings: [] })] }), is_negative: false, items: [Function(Idx::(1))], ast_id: FileAstId::(0) } - > Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::(1) } + Impl { generic_params: GenericParamsId(0), target_trait: Some(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("D"))] }, generic_args: [None] })), target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Response"))] }, generic_args: [Some(GenericArgs { args: [Type(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("T"))] }, generic_args: [None] }))], has_self_type: false, bindings: [] })] }), is_negative: false, items: [Function(Idx::(1))], ast_id: FileAstId::(0) } + > Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::(1) } inner items: - for AST FileAstId::(2): - Function { name: Name(Text("end")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(1), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::(2) } + for AST FileAstId::(2): + Function { name: Name(Text("end")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(1), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::(2) } "#]], ); @@ -303,9 +303,9 @@ fn extern_attrs() { top-level items: #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }, Attr { path: ModPath { kind: Plain, segments: [Name(Text("block_attr"))] }, input: None }]) }] - Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: true, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::(1) } + Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: true, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::(1) } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }, Attr { path: ModPath { kind: Plain, segments: [Name(Text("block_attr"))] }, input: None }]) }] - Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: true, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::(2) } + Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: true, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::(2) } "##]], ); } @@ -327,11 +327,11 @@ fn trait_attrs() { top-level items: #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("trait_attr"))] }, input: None }]) }] - Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(0), auto: false, items: [Function(Idx::(0)), Function(Idx::(1))], ast_id: FileAstId::(0) } + Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(0), auto: false, items: [Function(Idx::(0)), Function(Idx::(1))], ast_id: FileAstId::(0) } > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }]) }] - > Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::(1) } + > Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::(1) } > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }]) }] - > Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::(2) } + > Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::(2) } "##]], ); } @@ -353,11 +353,11 @@ fn impl_attrs() { top-level items: #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("impl_attr"))] }, input: None }]) }] - Impl { generic_params: GenericParamsId(4294967295), target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Ty"))] }, generic_args: [None] }), is_negative: false, items: [Function(Idx::(0)), Function(Idx::(1))], ast_id: FileAstId::(0) } + Impl { generic_params: GenericParamsId(4294967295), target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Ty"))] }, generic_args: [None] }), is_negative: false, items: [Function(Idx::(0)), Function(Idx::(1))], ast_id: FileAstId::(0) } > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }]) }] - > Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::(1) } + > Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::(1) } > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }]) }] - > Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::(2) } + > Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::(2) } "##]], ); } @@ -408,13 +408,13 @@ fn inner_item_attrs() { inner attrs: Attrs { entries: None } top-level items: - Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::(0) } + Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::(0) } inner items: - for AST FileAstId::(1): + for AST FileAstId::(1): #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_inner"))] }, input: None }]) }] - Function { name: Name(Text("inner")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::(1) } + Function { name: Name(Text("inner")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::(1) } "##]], ); @@ -432,7 +432,7 @@ fn assoc_item_macros() { inner attrs: Attrs { entries: None } top-level items: - Impl { generic_params: GenericParamsId(4294967295), target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("S"))] }, generic_args: [None] }), is_negative: false, items: [MacroCall(Idx::(0))], ast_id: FileAstId::(0) } + Impl { generic_params: GenericParamsId(4294967295), target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("S"))] }, generic_args: [None] }), is_negative: false, items: [MacroCall(Idx::(0))], ast_id: FileAstId::(0) } > MacroCall { name: None, path: ModPath { kind: Plain, segments: [Name(Text("items"))] }, is_export: false, is_local_inner: false, is_builtin: false, ast_id: FileAstId::(1) } "#]], ); diff --git a/crates/ra_hir_def/src/keys.rs b/crates/ra_hir_def/src/keys.rs index a7349a21db..441bdbead8 100644 --- a/crates/ra_hir_def/src/keys.rs +++ b/crates/ra_hir_def/src/keys.rs @@ -14,19 +14,19 @@ use crate::{ pub type Key = crate::dyn_map::Key, V, AstPtrPolicy>; -pub const FUNCTION: Key = Key::new(); -pub const CONST: Key = Key::new(); -pub const STATIC: Key = Key::new(); -pub const TYPE_ALIAS: Key = Key::new(); -pub const IMPL: Key = Key::new(); -pub const TRAIT: Key = Key::new(); -pub const STRUCT: Key = Key::new(); -pub const UNION: Key = Key::new(); -pub const ENUM: Key = Key::new(); +pub const FUNCTION: Key = Key::new(); +pub const CONST: Key = Key::new(); +pub const STATIC: Key = Key::new(); +pub const TYPE_ALIAS: Key = Key::new(); +pub const IMPL: Key = Key::new(); +pub const TRAIT: Key = Key::new(); +pub const STRUCT: Key = Key::new(); +pub const UNION: Key = Key::new(); +pub const ENUM: Key = Key::new(); -pub const ENUM_VARIANT: Key = Key::new(); -pub const TUPLE_FIELD: Key = Key::new(); -pub const RECORD_FIELD: Key = Key::new(); +pub const VARIANT: Key = Key::new(); +pub const TUPLE_FIELD: Key = Key::new(); +pub const RECORD_FIELD: Key = Key::new(); pub const TYPE_PARAM: Key = Key::new(); pub const MACRO: Key = Key::new(); diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 87000fe987..237b1038af 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -521,7 +521,7 @@ impl AsMacroCall for AstIdWithPath { } } -impl AsMacroCall for AstIdWithPath { +impl AsMacroCall for AstIdWithPath { fn as_call_id( &self, db: &dyn db::DefDatabase, diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index a030cab471..28b7a20c55 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs @@ -170,7 +170,7 @@ struct MacroDirective { #[derive(Clone, Debug, Eq, PartialEq)] struct DeriveDirective { module_id: LocalModuleId, - ast_id: AstIdWithPath, + ast_id: AstIdWithPath, } struct DefData<'a> { @@ -1100,7 +1100,7 @@ impl ModCollector<'_, '_> { res } - fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId) { + fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId) { for derive_subtree in attrs.by_key("derive").tt_values() { // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree for tt in &derive_subtree.token_trees { diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index 190d6d98d4..cc1726e9e0 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs @@ -67,7 +67,7 @@ impl ModPath { /// Calls `cb` with all paths, represented by this use item. pub(crate) fn expand_use_item( - item_src: InFile, + item_src: InFile, hygiene: &Hygiene, mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option), ) { @@ -258,7 +258,7 @@ impl<'a> PathSegments<'a> { } impl GenericArgs { - pub(crate) fn from_ast(lower_ctx: &LowerCtx, node: ast::TypeArgList) -> Option { + pub(crate) fn from_ast(lower_ctx: &LowerCtx, node: ast::GenericArgList) -> Option { lower::lower_generic_args(lower_ctx, node) } diff --git a/crates/ra_hir_def/src/path/lower.rs b/crates/ra_hir_def/src/path/lower.rs index 6a0c019fdf..d09fc66e4d 100644 --- a/crates/ra_hir_def/src/path/lower.rs +++ b/crates/ra_hir_def/src/path/lower.rs @@ -9,7 +9,7 @@ use hir_expand::{ hygiene::Hygiene, name::{name, AsName}, }; -use ra_syntax::ast::{self, AstNode, TypeAscriptionOwner, TypeBoundsOwner}; +use ra_syntax::ast::{self, AstNode, TypeBoundsOwner}; use super::AssociatedTypeBinding; use crate::{ @@ -41,7 +41,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option match hygiene.name_ref_to_name(name_ref) { Either::Left(name) => { let args = segment - .type_arg_list() + .generic_arg_list() .and_then(|it| lower_generic_args(&ctx, it)) .or_else(|| { lower_generic_args_from_fn_path( @@ -148,33 +148,37 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option pub(super) fn lower_generic_args( lower_ctx: &LowerCtx, - node: ast::TypeArgList, + node: ast::GenericArgList, ) -> Option { let mut args = Vec::new(); - for type_arg in node.type_args() { - let type_ref = TypeRef::from_ast_opt(lower_ctx, type_arg.type_ref()); - args.push(GenericArg::Type(type_ref)); - } - // lifetimes ignored for now let mut bindings = Vec::new(); - for assoc_type_arg in node.assoc_type_args() { - let assoc_type_arg: ast::AssocTypeArg = assoc_type_arg; - if let Some(name_ref) = assoc_type_arg.name_ref() { - let name = name_ref.as_name(); - let type_ref = assoc_type_arg.type_ref().map(|it| TypeRef::from_ast(lower_ctx, it)); - let bounds = if let Some(l) = assoc_type_arg.type_bound_list() { - l.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect() - } else { - Vec::new() - }; - bindings.push(AssociatedTypeBinding { name, type_ref, bounds }); + for generic_arg in node.generic_args() { + match generic_arg { + ast::GenericArg::TypeArg(type_arg) => { + let type_ref = TypeRef::from_ast_opt(lower_ctx, type_arg.ty()); + args.push(GenericArg::Type(type_ref)); + } + ast::GenericArg::AssocTypeArg(assoc_type_arg) => { + if let Some(name_ref) = assoc_type_arg.name_ref() { + let name = name_ref.as_name(); + let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it)); + let bounds = if let Some(l) = assoc_type_arg.type_bound_list() { + l.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect() + } else { + Vec::new() + }; + bindings.push(AssociatedTypeBinding { name, type_ref, bounds }); + } + } + // Lifetimes and constants are ignored for now. + ast::GenericArg::LifetimeArg(_) | ast::GenericArg::ConstArg(_) => (), } } + if args.is_empty() && bindings.is_empty() { - None - } else { - Some(GenericArgs { args, has_self_type: false, bindings }) + return None; } + Some(GenericArgs { args, has_self_type: false, bindings }) } /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y) @@ -189,14 +193,14 @@ fn lower_generic_args_from_fn_path( if let Some(params) = params { let mut param_types = Vec::new(); for param in params.params() { - let type_ref = TypeRef::from_ast_opt(&ctx, param.ascribed_type()); + let type_ref = TypeRef::from_ast_opt(&ctx, param.ty()); param_types.push(type_ref); } let arg = GenericArg::Type(TypeRef::Tuple(param_types)); args.push(arg); } if let Some(ret_type) = ret_type { - let type_ref = TypeRef::from_ast_opt(&ctx, ret_type.type_ref()); + let type_ref = TypeRef::from_ast_opt(&ctx, ret_type.ty()); bindings.push(AssociatedTypeBinding { name: name![Output], type_ref: Some(type_ref), diff --git a/crates/ra_hir_def/src/path/lower/lower_use.rs b/crates/ra_hir_def/src/path/lower/lower_use.rs index 7cc655487e..794be45e89 100644 --- a/crates/ra_hir_def/src/path/lower/lower_use.rs +++ b/crates/ra_hir_def/src/path/lower/lower_use.rs @@ -31,7 +31,7 @@ pub(crate) fn lower_use_tree( lower_use_tree(prefix.clone(), child_tree, hygiene, cb); } } else { - let alias = tree.alias().map(|a| { + let alias = tree.rename().map(|a| { a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) }); let is_glob = tree.star_token().is_some(); diff --git a/crates/ra_hir_def/src/type_ref.rs b/crates/ra_hir_def/src/type_ref.rs index e90b2a0b92..6f7884ffe5 100644 --- a/crates/ra_hir_def/src/type_ref.rs +++ b/crates/ra_hir_def/src/type_ref.rs @@ -1,7 +1,6 @@ //! HIR for references to types. Paths in these are not yet resolved. They can //! be directly created from an ast::TypeRef, without further queries. - -use ra_syntax::ast::{self, TypeAscriptionOwner, TypeBoundsOwner}; +use ra_syntax::ast::{self}; use crate::{body::LowerCtx, path::Path}; @@ -80,14 +79,14 @@ pub enum TypeBound { impl TypeRef { /// Converts an `ast::TypeRef` to a `hir::TypeRef`. - pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::TypeRef) -> Self { + pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self { match node { - ast::TypeRef::ParenType(inner) => TypeRef::from_ast_opt(&ctx, inner.type_ref()), - ast::TypeRef::TupleType(inner) => { + ast::Type::ParenType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()), + ast::Type::TupleType(inner) => { TypeRef::Tuple(inner.fields().map(|it| TypeRef::from_ast(ctx, it)).collect()) } - ast::TypeRef::NeverType(..) => TypeRef::Never, - ast::TypeRef::PathType(inner) => { + ast::Type::NeverType(..) => TypeRef::Never, + ast::Type::PathType(inner) => { // FIXME: Use `Path::from_src` inner .path() @@ -95,27 +94,27 @@ impl TypeRef { .map(TypeRef::Path) .unwrap_or(TypeRef::Error) } - ast::TypeRef::PointerType(inner) => { - let inner_ty = TypeRef::from_ast_opt(&ctx, inner.type_ref()); + ast::Type::PtrType(inner) => { + let inner_ty = TypeRef::from_ast_opt(&ctx, inner.ty()); let mutability = Mutability::from_mutable(inner.mut_token().is_some()); TypeRef::RawPtr(Box::new(inner_ty), mutability) } - ast::TypeRef::ArrayType(inner) => { - TypeRef::Array(Box::new(TypeRef::from_ast_opt(&ctx, inner.type_ref()))) + ast::Type::ArrayType(inner) => { + TypeRef::Array(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty()))) } - ast::TypeRef::SliceType(inner) => { - TypeRef::Slice(Box::new(TypeRef::from_ast_opt(&ctx, inner.type_ref()))) + ast::Type::SliceType(inner) => { + TypeRef::Slice(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty()))) } - ast::TypeRef::ReferenceType(inner) => { - let inner_ty = TypeRef::from_ast_opt(&ctx, inner.type_ref()); + ast::Type::RefType(inner) => { + let inner_ty = TypeRef::from_ast_opt(&ctx, inner.ty()); let mutability = Mutability::from_mutable(inner.mut_token().is_some()); TypeRef::Reference(Box::new(inner_ty), mutability) } - ast::TypeRef::PlaceholderType(_inner) => TypeRef::Placeholder, - ast::TypeRef::FnPointerType(inner) => { + ast::Type::InferType(_inner) => TypeRef::Placeholder, + ast::Type::FnPtrType(inner) => { let ret_ty = inner .ret_type() - .and_then(|rt| rt.type_ref()) + .and_then(|rt| rt.ty()) .map(|it| TypeRef::from_ast(ctx, it)) .unwrap_or_else(|| TypeRef::Tuple(Vec::new())); let mut is_varargs = false; @@ -124,10 +123,7 @@ impl TypeRef { is_varargs = param.dotdotdot_token().is_some(); } - pl.params() - .map(|p| p.ascribed_type()) - .map(|it| TypeRef::from_ast_opt(&ctx, it)) - .collect() + pl.params().map(|p| p.ty()).map(|it| TypeRef::from_ast_opt(&ctx, it)).collect() } else { Vec::new() }; @@ -135,17 +131,17 @@ impl TypeRef { TypeRef::Fn(params, is_varargs) } // for types are close enough for our purposes to the inner type for now... - ast::TypeRef::ForType(inner) => TypeRef::from_ast_opt(&ctx, inner.type_ref()), - ast::TypeRef::ImplTraitType(inner) => { + ast::Type::ForType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()), + ast::Type::ImplTraitType(inner) => { TypeRef::ImplTrait(type_bounds_from_ast(ctx, inner.type_bound_list())) } - ast::TypeRef::DynTraitType(inner) => { + ast::Type::DynTraitType(inner) => { TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list())) } } } - pub(crate) fn from_ast_opt(ctx: &LowerCtx, node: Option) -> Self { + pub(crate) fn from_ast_opt(ctx: &LowerCtx, node: Option) -> Self { if let Some(node) = node { TypeRef::from_ast(ctx, node) } else { diff --git a/crates/ra_hir_expand/src/ast_id_map.rs b/crates/ra_hir_expand/src/ast_id_map.rs index f4d31526a6..8bfe1b4ba7 100644 --- a/crates/ra_hir_expand/src/ast_id_map.rs +++ b/crates/ra_hir_expand/src/ast_id_map.rs @@ -73,7 +73,7 @@ impl AstIdMap { // change parent's id. This means that, say, adding a new function to a // trait does not change ids of top-level items, which helps caching. bfs(node, |it| { - if let Some(module_item) = ast::ModuleItem::cast(it) { + if let Some(module_item) = ast::Item::cast(it) { res.alloc(module_item.syntax()); } }); diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs index f2d6648638..69fa907cb8 100644 --- a/crates/ra_hir_expand/src/builtin_derive.rs +++ b/crates/ra_hir_expand/src/builtin_derive.rs @@ -4,7 +4,7 @@ use log::debug; use ra_parser::FragmentKind; use ra_syntax::{ - ast::{self, AstNode, ModuleItemOwner, NameOwner, TypeParamsOwner}, + ast::{self, AstNode, GenericParamsOwner, ModuleItemOwner, NameOwner}, match_ast, }; @@ -72,9 +72,9 @@ fn parse_adt(tt: &tt::Subtree) -> Result { let node = item.syntax(); let (name, params) = match_ast! { match node { - ast::StructDef(it) => (it.name(), it.type_param_list()), - ast::EnumDef(it) => (it.name(), it.type_param_list()), - ast::UnionDef(it) => (it.name(), it.type_param_list()), + ast::Struct(it) => (it.name(), it.generic_param_list()), + ast::Enum(it) => (it.name(), it.generic_param_list()), + ast::Union(it) => (it.name(), it.generic_param_list()), _ => { debug!("unexpected node is {:?}", node); return Err(mbe::ExpandError::ConversionError) @@ -276,7 +276,7 @@ mod tests { let file_id = file_pos.file_id; let parsed = db.parse(file_id); let items: Vec<_> = - parsed.syntax_node().descendants().filter_map(ast::ModuleItem::cast).collect(); + parsed.syntax_node().descendants().filter_map(ast::Item::cast).collect(); let ast_id_map = db.ast_id_map(file_id.into()); diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs index e0ad1567f6..f3b7cd492c 100644 --- a/crates/ra_hir_expand/src/db.rs +++ b/crates/ra_hir_expand/src/db.rs @@ -379,14 +379,14 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind { FOR_EXPR => FragmentKind::Expr, PATH_EXPR => FragmentKind::Expr, - LAMBDA_EXPR => FragmentKind::Expr, + CLOSURE_EXPR => FragmentKind::Expr, CONDITION => FragmentKind::Expr, BREAK_EXPR => FragmentKind::Expr, RETURN_EXPR => FragmentKind::Expr, MATCH_EXPR => FragmentKind::Expr, MATCH_ARM => FragmentKind::Expr, MATCH_GUARD => FragmentKind::Expr, - RECORD_FIELD => FragmentKind::Expr, + RECORD_EXPR_FIELD => FragmentKind::Expr, CALL_EXPR => FragmentKind::Expr, INDEX_EXPR => FragmentKind::Expr, METHOD_CALL_EXPR => FragmentKind::Expr, diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index d9e31ac20b..2e8d636917 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs @@ -159,7 +159,7 @@ impl HirFileId { } /// Indicate it is macro file generated for builtin derive - pub fn is_builtin_derive(&self, db: &dyn db::AstDatabase) -> Option> { + pub fn is_builtin_derive(&self, db: &dyn db::AstDatabase) -> Option> { match self.0 { HirFileIdRepr::FileId(_) => None, HirFileIdRepr::MacroFile(macro_file) => { @@ -174,7 +174,7 @@ impl HirFileId { MacroDefKind::BuiltInDerive(_) => loc.kind.node(db), _ => return None, }; - Some(item.with_value(ast::ModuleItem::cast(item.value.clone())?)) + Some(item.with_value(ast::Item::cast(item.value.clone())?)) } } } @@ -258,7 +258,7 @@ pub struct MacroCallLoc { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum MacroCallKind { FnLike(AstId), - Attr(AstId, String), + Attr(AstId, String), } impl MacroCallKind { diff --git a/crates/ra_hir_expand/src/proc_macro.rs b/crates/ra_hir_expand/src/proc_macro.rs index 04c0260046..2c0ec41d24 100644 --- a/crates/ra_hir_expand/src/proc_macro.rs +++ b/crates/ra_hir_expand/src/proc_macro.rs @@ -101,7 +101,7 @@ fn remove_derive_attrs(tt: &tt::Subtree) -> Option { } #[cfg(test)] -mod test { +mod tests { use super::*; use test_utils::assert_eq_text; diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml index 7242e2cb6d..83397d5793 100644 --- a/crates/ra_hir_ty/Cargo.toml +++ b/crates/ra_hir_ty/Cargo.toml @@ -28,9 +28,9 @@ test_utils = { path = "../test_utils" } scoped-tls = "1" -chalk-solve = { version = "0.18.0" } -chalk-ir = { version = "0.18.0" } -chalk-recursive = { version = "0.18.0" } +chalk-solve = { version = "0.21.0" } +chalk-ir = { version = "0.21.0" } +chalk-recursive = { version = "0.21.0" } [dev-dependencies] expect = { path = "../expect" } diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs index 885abbaf2d..977c0525b5 100644 --- a/crates/ra_hir_ty/src/diagnostics.rs +++ b/crates/ra_hir_ty/src/diagnostics.rs @@ -29,7 +29,7 @@ pub fn validate_body(db: &dyn HirDatabase, owner: DefWithBodyId, sink: &mut Diag #[derive(Debug)] pub struct NoSuchField { pub file: HirFileId, - pub field: AstPtr, + pub field: AstPtr, } impl Diagnostic for NoSuchField { @@ -47,19 +47,19 @@ impl Diagnostic for NoSuchField { } impl AstDiagnostic for NoSuchField { - type AST = ast::RecordField; + type AST = ast::RecordExprField; fn ast(&self, db: &dyn AstDatabase) -> Self::AST { let root = db.parse_or_expand(self.source().file_id).unwrap(); let node = self.source().value.to_node(&root); - ast::RecordField::cast(node).unwrap() + ast::RecordExprField::cast(node).unwrap() } } #[derive(Debug)] pub struct MissingFields { pub file: HirFileId, - pub field_list: AstPtr, + pub field_list: AstPtr, pub missed_fields: Vec, } @@ -80,19 +80,19 @@ impl Diagnostic for MissingFields { } impl AstDiagnostic for MissingFields { - type AST = ast::RecordFieldList; + type AST = ast::RecordExprFieldList; fn ast(&self, db: &dyn AstDatabase) -> Self::AST { let root = db.parse_or_expand(self.source().file_id).unwrap(); let node = self.source().value.to_node(&root); - ast::RecordFieldList::cast(node).unwrap() + ast::RecordExprFieldList::cast(node).unwrap() } } #[derive(Debug)] pub struct MissingPatFields { pub file: HirFileId, - pub field_list: AstPtr, + pub field_list: AstPtr, pub missed_fields: Vec, } diff --git a/crates/ra_hir_ty/src/diagnostics/expr.rs b/crates/ra_hir_ty/src/diagnostics/expr.rs index fd930eab1a..95bbf2d955 100644 --- a/crates/ra_hir_ty/src/diagnostics/expr.rs +++ b/crates/ra_hir_ty/src/diagnostics/expr.rs @@ -100,8 +100,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> { if let Ok(source_ptr) = source_map.expr_syntax(id) { let root = source_ptr.file_syntax(db.upcast()); - if let ast::Expr::RecordLit(record_lit) = &source_ptr.value.to_node(&root) { - if let Some(field_list) = record_lit.record_field_list() { + if let ast::Expr::RecordExpr(record_lit) = &source_ptr.value.to_node(&root) { + if let Some(field_list) = record_lit.record_expr_field_list() { let variant_data = variant_data(db.upcast(), variant_def); let missed_fields = missed_fields .into_iter() @@ -131,7 +131,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { if let Some(expr) = source_ptr.value.as_ref().left() { let root = source_ptr.file_syntax(db.upcast()); if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { - if let Some(field_list) = record_pat.record_field_pat_list() { + if let Some(field_list) = record_pat.record_pat_field_list() { let variant_data = variant_data(db.upcast(), variant_def); let missed_fields = missed_fields .into_iter() diff --git a/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs b/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs index 5cc76bdce4..61ffbf5d15 100644 --- a/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs +++ b/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs @@ -6,6 +6,7 @@ use std::sync::Arc; use hir_def::{ body::Body, expr::{Expr, ExprId, UnaryOp}, + resolver::{resolver_for_expr, ResolveValueResult, ValueNs}, DefWithBodyId, }; use hir_expand::diagnostics::DiagnosticSink; @@ -70,7 +71,7 @@ pub fn unsafe_expressions( ) -> Vec { let mut unsafe_exprs = vec![]; let body = db.body(def); - walk_unsafe(&mut unsafe_exprs, db, infer, &body, body.body_expr, false); + walk_unsafe(&mut unsafe_exprs, db, infer, def, &body, body.body_expr, false); unsafe_exprs } @@ -79,6 +80,7 @@ fn walk_unsafe( unsafe_exprs: &mut Vec, db: &dyn HirDatabase, infer: &InferenceResult, + def: DefWithBodyId, body: &Body, current: ExprId, inside_unsafe_block: bool, @@ -97,6 +99,15 @@ fn walk_unsafe( } } } + Expr::Path(path) => { + let resolver = resolver_for_expr(db.upcast(), def, current); + let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path.mod_path()); + if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id))) = value_or_partial { + if db.static_data(id).mutable { + unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); + } + } + } Expr::MethodCall { .. } => { if infer .method_resolution(current) @@ -112,13 +123,13 @@ fn walk_unsafe( } } Expr::Unsafe { body: child } => { - return walk_unsafe(unsafe_exprs, db, infer, body, *child, true); + return walk_unsafe(unsafe_exprs, db, infer, def, body, *child, true); } _ => {} } expr.walk_child_exprs(|child| { - walk_unsafe(unsafe_exprs, db, infer, body, child, inside_unsafe_block); + walk_unsafe(unsafe_exprs, db, infer, def, body, child, inside_unsafe_block); }); } @@ -167,6 +178,27 @@ fn main() { HasUnsafe.unsafe_fn(); } } +"#, + ); + } + + #[test] + fn missing_unsafe_diagnostic_with_static_mut() { + check_diagnostics( + r#" +struct Ty { + a: u8, +} + +static mut static_mut: Ty = Ty { a: 0 }; + +fn main() { + let x = static_mut.a; + //^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block + unsafe { + let x = static_mut.a; + } +} "#, ); } diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 28f32a0a4d..3d12039a6d 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -440,6 +440,12 @@ impl<'a> InferenceContext<'a> { let ty = self.insert_type_vars(ty.subst(&substs)); forbid_unresolved_segments((ty, Some(strukt.into())), unresolved) } + TypeNs::AdtId(AdtId::UnionId(u)) => { + let substs = Ty::substs_from_path(&ctx, path, u.into(), true); + let ty = self.db.ty(u.into()); + let ty = self.insert_type_vars(ty.subst(&substs)); + forbid_unresolved_segments((ty, Some(u.into())), unresolved) + } TypeNs::EnumVariantId(var) => { let substs = Ty::substs_from_path(&ctx, path, var.into(), true); let ty = self.db.ty(var.parent.into()); @@ -490,10 +496,7 @@ impl<'a> InferenceContext<'a> { // FIXME potentially resolve assoc type (Ty::Unknown, None) } - TypeNs::AdtId(AdtId::EnumId(_)) - | TypeNs::AdtId(AdtId::UnionId(_)) - | TypeNs::BuiltinType(_) - | TypeNs::TraitId(_) => { + TypeNs::AdtId(AdtId::EnumId(_)) | TypeNs::BuiltinType(_) | TypeNs::TraitId(_) => { // FIXME diagnostic (Ty::Unknown, None) } diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 1eacc6f95e..7638f167b5 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -518,6 +518,7 @@ impl Ty { let (segment, generic_def) = match resolved { ValueTyDefId::FunctionId(it) => (last, Some(it.into())), ValueTyDefId::StructId(it) => (last, Some(it.into())), + ValueTyDefId::UnionId(it) => (last, Some(it.into())), ValueTyDefId::ConstId(it) => (last, Some(it.into())), ValueTyDefId::StaticId(_) => (last, None), ValueTyDefId::EnumVariantId(var) => { @@ -1148,11 +1149,12 @@ impl_from!(BuiltinType, AdtId(StructId, EnumId, UnionId), TypeAliasId for TyDefI pub enum ValueTyDefId { FunctionId(FunctionId), StructId(StructId), + UnionId(UnionId), EnumVariantId(EnumVariantId), ConstId(ConstId), StaticId(StaticId), } -impl_from!(FunctionId, StructId, EnumVariantId, ConstId, StaticId for ValueTyDefId); +impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId); /// Build the declared type of an item. This depends on the namespace; e.g. for /// `struct Foo(usize)`, we have two types: The type of the struct itself, and @@ -1179,6 +1181,7 @@ pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Binders match def { ValueTyDefId::FunctionId(it) => type_for_fn(db, it), ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it), + ValueTyDefId::UnionId(it) => type_for_adt(db, it.into()), ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it), ValueTyDefId::ConstId(it) => type_for_const(db, it), ValueTyDefId::StaticId(it) => type_for_static(db, it), diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index 45bc14c37f..016e689fff 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs @@ -81,7 +81,7 @@ fn check_types_impl(ra_fixture: &str, display_source: bool) { fn type_at_range(db: &TestDB, pos: FileRange) -> Ty { let file = db.parse(pos.file_id).ok().unwrap(); let expr = algo::find_node_at_range::(file.syntax(), pos.range).unwrap(); - let fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); + let fn_def = expr.syntax().ancestors().find_map(ast::Fn::cast).unwrap(); let module = db.module_for_file(pos.file_id); let func = *module.child_by_source(db)[keys::FUNCTION] .get(&InFile::new(pos.file_id.into(), fn_def)) diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index 3fd7d5cd4f..5a7cf9455b 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs @@ -334,16 +334,44 @@ fn infer_union() { bar: f32, } + fn test() { + let u = MyUnion { foo: 0 }; + unsafe { baz(u); } + let u = MyUnion { bar: 0.0 }; + unsafe { baz(u); } + } + unsafe fn baz(u: MyUnion) { let inner = u.foo; + let inner = u.bar; } "#, expect![[r#" - 61..62 'u': MyUnion - 73..99 '{ ...foo; }': () - 83..88 'inner': u32 - 91..92 'u': MyUnion - 91..96 'u.foo': u32 + 57..172 '{ ...); } }': () + 67..68 'u': MyUnion + 71..89 'MyUnio...o: 0 }': MyUnion + 86..87 '0': u32 + 95..113 'unsafe...(u); }': () + 102..113 '{ baz(u); }': () + 104..107 'baz': fn baz(MyUnion) + 104..110 'baz(u)': () + 108..109 'u': MyUnion + 122..123 'u': MyUnion + 126..146 'MyUnio... 0.0 }': MyUnion + 141..144 '0.0': f32 + 152..170 'unsafe...(u); }': () + 159..170 '{ baz(u); }': () + 161..164 'baz': fn baz(MyUnion) + 161..167 'baz(u)': () + 165..166 'u': MyUnion + 188..189 'u': MyUnion + 200..249 '{ ...bar; }': () + 210..215 'inner': u32 + 218..219 'u': MyUnion + 218..223 'u.foo': u32 + 233..238 'inner': f32 + 241..242 'u': MyUnion + 241..246 'u.bar': f32 "#]], ); } diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index 5298dbecf9..1c70653644 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -183,6 +183,7 @@ impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> { .collect(), 1, ), + where_clauses: make_binders(vec![], 0), }; let num_vars = datas.num_binders; Arc::new(OpaqueTyDatum { opaque_ty_id: id, bound: make_binders(bound, num_vars) }) @@ -193,15 +194,6 @@ impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> { Ty::Unknown.to_chalk(self.db) } - fn force_impl_for( - &self, - _well_known: rust_ir::WellKnownTrait, - _ty: &chalk_ir::TyData, - ) -> Option { - // this method is mostly for rustc - None - } - fn is_object_safe(&self, _trait_id: chalk_ir::TraitId) -> bool { // FIXME: implement actual object safety true @@ -547,8 +539,13 @@ pub(crate) fn fn_def_datum_query( ), where_clauses, }; - let datum = - FnDefDatum { id: fn_def_id, binders: make_binders(bound, sig.num_binders), abi: () }; + let datum = FnDefDatum { + id: fn_def_id, + abi: (), + safety: chalk_ir::Safety::Safe, + variadic: sig.value.is_varargs, + binders: make_binders(bound, sig.num_binders), + }; Arc::new(datum) } diff --git a/crates/ra_hir_ty/src/traits/chalk/mapping.rs b/crates/ra_hir_ty/src/traits/chalk/mapping.rs index 09d8347caa..b3e92993d2 100644 --- a/crates/ra_hir_ty/src/traits/chalk/mapping.rs +++ b/crates/ra_hir_ty/src/traits/chalk/mapping.rs @@ -30,11 +30,16 @@ impl ToChalk for Ty { Ty::Apply(apply_ty) => match apply_ty.ctor { TypeCtor::Ref(m) => ref_to_chalk(db, m, apply_ty.parameters), TypeCtor::Array => array_to_chalk(db, apply_ty.parameters), - TypeCtor::FnPtr { num_args: _, is_varargs: _ } => { - // FIXME: handle is_varargs + TypeCtor::FnPtr { num_args: _, is_varargs } => { let substitution = apply_ty.parameters.to_chalk(db).shifted_in(&Interner); - chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: 0, substitution }) - .intern(&Interner) + chalk_ir::TyData::Function(chalk_ir::FnPointer { + num_binders: 0, + abi: (), + safety: chalk_ir::Safety::Safe, + variadic: is_varargs, + substitution, + }) + .intern(&Interner) } _ => { let name = apply_ty.ctor.to_chalk(db); @@ -118,7 +123,12 @@ impl ToChalk for Ty { let parameters = from_chalk(db, opaque_ty.substitution); Ty::Opaque(OpaqueTy { opaque_ty_id: impl_trait_id, parameters }) } - chalk_ir::TyData::Function(chalk_ir::Fn { num_binders, substitution }) => { + chalk_ir::TyData::Function(chalk_ir::FnPointer { + num_binders, + variadic, + substitution, + .. + }) => { assert_eq!(num_binders, 0); let parameters: Substs = from_chalk( db, @@ -127,7 +137,7 @@ impl ToChalk for Ty { Ty::Apply(ApplicationTy { ctor: TypeCtor::FnPtr { num_args: (parameters.len() - 1) as u16, - is_varargs: false, + is_varargs: variadic, }, parameters, }) diff --git a/crates/ra_ide/Cargo.toml b/crates/ra_ide/Cargo.toml index 6f81074912..f4181c4eb8 100644 --- a/crates/ra_ide/Cargo.toml +++ b/crates/ra_ide/Cargo.toml @@ -17,7 +17,7 @@ indexmap = "1.3.2" itertools = "0.9.0" log = "0.4.8" rustc-hash = "1.1.0" -rand = { version = "0.7.3", features = ["small_rng"] } +oorandom = "11.1.2" stdx = { path = "../stdx" } diff --git a/crates/ra_ide/src/call_hierarchy.rs b/crates/ra_ide/src/call_hierarchy.rs index c28af8ab33..1fcaf4a32b 100644 --- a/crates/ra_ide/src/call_hierarchy.rs +++ b/crates/ra_ide/src/call_hierarchy.rs @@ -59,7 +59,7 @@ pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Optio if let Some(nav) = syntax.ancestors().find_map(|node| { match_ast! { match node { - ast::FnDef(it) => { + ast::Fn(it) => { let def = sema.to_def(&it)?; Some(def.to_nav(sema.db)) }, @@ -181,8 +181,8 @@ fn caller() { call<|>ee(); } "#, - "callee FN_DEF FileId(1) 0..14 3..9", - &["caller FN_DEF FileId(1) 15..44 18..24 : [33..39]"], + "callee FN FileId(1) 0..14 3..9", + &["caller FN FileId(1) 15..44 18..24 : [33..39]"], &[], ); } @@ -197,8 +197,8 @@ fn caller() { callee(); } "#, - "callee FN_DEF FileId(1) 0..14 3..9", - &["caller FN_DEF FileId(1) 15..44 18..24 : [33..39]"], + "callee FN FileId(1) 0..14 3..9", + &["caller FN FileId(1) 15..44 18..24 : [33..39]"], &[], ); } @@ -214,8 +214,8 @@ fn caller() { callee(); } "#, - "callee FN_DEF FileId(1) 0..14 3..9", - &["caller FN_DEF FileId(1) 15..58 18..24 : [33..39, 47..53]"], + "callee FN FileId(1) 0..14 3..9", + &["caller FN FileId(1) 15..58 18..24 : [33..39, 47..53]"], &[], ); } @@ -234,10 +234,10 @@ fn caller2() { callee(); } "#, - "callee FN_DEF FileId(1) 0..14 3..9", + "callee FN FileId(1) 0..14 3..9", &[ - "caller1 FN_DEF FileId(1) 15..45 18..25 : [34..40]", - "caller2 FN_DEF FileId(1) 47..77 50..57 : [66..72]", + "caller1 FN FileId(1) 15..45 18..25 : [34..40]", + "caller2 FN FileId(1) 47..77 50..57 : [66..72]", ], &[], ); @@ -263,10 +263,10 @@ mod tests { } } "#, - "callee FN_DEF FileId(1) 0..14 3..9", + "callee FN FileId(1) 0..14 3..9", &[ - "caller1 FN_DEF FileId(1) 15..45 18..25 : [34..40]", - "test_caller FN_DEF FileId(1) 95..149 110..121 : [134..140]", + "caller1 FN FileId(1) 15..45 18..25 : [34..40]", + "test_caller FN FileId(1) 95..149 110..121 : [134..140]", ], &[], ); @@ -287,8 +287,8 @@ fn caller() { //- /foo/mod.rs pub fn callee() {} "#, - "callee FN_DEF FileId(2) 0..18 7..13", - &["caller FN_DEF FileId(1) 27..56 30..36 : [45..51]"], + "callee FN FileId(2) 0..18 7..13", + &["caller FN FileId(1) 27..56 30..36 : [45..51]"], &[], ); } @@ -304,9 +304,9 @@ fn call<|>er() { callee(); } "#, - "caller FN_DEF FileId(1) 15..58 18..24", + "caller FN FileId(1) 15..58 18..24", &[], - &["callee FN_DEF FileId(1) 0..14 3..9 : [33..39, 47..53]"], + &["callee FN FileId(1) 0..14 3..9 : [33..39, 47..53]"], ); } @@ -325,9 +325,9 @@ fn call<|>er() { //- /foo/mod.rs pub fn callee() {} "#, - "caller FN_DEF FileId(1) 27..56 30..36", + "caller FN FileId(1) 27..56 30..36", &[], - &["callee FN_DEF FileId(2) 0..18 7..13 : [45..51]"], + &["callee FN FileId(2) 0..18 7..13 : [45..51]"], ); } @@ -348,9 +348,9 @@ fn caller3() { } "#, - "caller2 FN_DEF FileId(1) 33..64 36..43", - &["caller1 FN_DEF FileId(1) 0..31 3..10 : [19..26]"], - &["caller3 FN_DEF FileId(1) 66..83 69..76 : [52..59]"], + "caller2 FN FileId(1) 33..64 36..43", + &["caller1 FN FileId(1) 0..31 3..10 : [19..26]"], + &["caller3 FN FileId(1) 66..83 69..76 : [52..59]"], ); } @@ -368,9 +368,9 @@ fn main() { a<|>() } "#, - "a FN_DEF FileId(1) 0..18 3..4", - &["main FN_DEF FileId(1) 31..52 34..38 : [47..48]"], - &["b FN_DEF FileId(1) 20..29 23..24 : [13..14]"], + "a FN FileId(1) 0..18 3..4", + &["main FN FileId(1) 31..52 34..38 : [47..48]"], + &["b FN FileId(1) 20..29 23..24 : [13..14]"], ); check_hierarchy( @@ -385,8 +385,8 @@ fn main() { a() } "#, - "b FN_DEF FileId(1) 20..29 23..24", - &["a FN_DEF FileId(1) 0..18 3..4 : [13..14]"], + "b FN FileId(1) 20..29 23..24", + &["a FN FileId(1) 0..18 3..4 : [13..14]"], &[], ); } diff --git a/crates/ra_ide/src/completion/complete_attribute.rs b/crates/ra_ide/src/completion/complete_attribute.rs index 7a42746451..089d806d8c 100644 --- a/crates/ra_ide/src/completion/complete_attribute.rs +++ b/crates/ra_ide/src/completion/complete_attribute.rs @@ -16,25 +16,23 @@ use crate::completion::UNSTABLE_FEATURE_DESCRIPTOR; pub(super) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { let attribute = ctx.attribute_under_caret.as_ref()?; - match (attribute.path(), attribute.input()) { - (Some(path), Some(ast::AttrInput::TokenTree(token_tree))) - if path.to_string() == "derive" => - { + match (attribute.path(), attribute.token_tree()) { + (Some(path), Some(token_tree)) if path.to_string() == "derive" => { complete_derive(acc, ctx, token_tree) } - (Some(path), Some(ast::AttrInput::TokenTree(token_tree))) + (Some(path), Some(token_tree)) if path.to_string() == "feature" => { complete_lint(acc, ctx, token_tree, UNSTABLE_FEATURE_DESCRIPTOR); } - (Some(path), Some(ast::AttrInput::TokenTree(token_tree))) + (Some(path), Some(token_tree)) if ["allow", "warn", "deny", "forbid"] .iter() .any(|lint_level| lint_level == &path.to_string()) => { complete_lint(acc, ctx, token_tree, DEFAULT_LINT_COMPLETIONS) } - (_, Some(ast::AttrInput::TokenTree(_token_tree))) => {} + (_, Some(_token_tree)) => {} _ => complete_attribute_start(acc, ctx, attribute), } Some(()) diff --git a/crates/ra_ide/src/completion/complete_fn_param.rs b/crates/ra_ide/src/completion/complete_fn_param.rs index db2abb4f13..4063342572 100644 --- a/crates/ra_ide/src/completion/complete_fn_param.rs +++ b/crates/ra_ide/src/completion/complete_fn_param.rs @@ -18,26 +18,36 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext) } let mut params = FxHashMap::default(); - let me = ctx.token.ancestors().find_map(ast::FnDef::cast); + + let me = ctx.token.ancestors().find_map(ast::Fn::cast); + let mut process_fn = |func: ast::Fn| { + if Some(&func) == me.as_ref() { + return; + } + func.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| { + let text = param.syntax().text().to_string(); + params.entry(text).or_insert(param); + }) + }; + for node in ctx.token.parent().ancestors() { - let items = match_ast! { + match_ast! { match node { - ast::SourceFile(it) => it.items(), - ast::ItemList(it) => it.items(), + ast::SourceFile(it) => it.items().filter_map(|item| match item { + ast::Item::Fn(it) => Some(it), + _ => None, + }).for_each(&mut process_fn), + ast::ItemList(it) => it.items().filter_map(|item| match item { + ast::Item::Fn(it) => Some(it), + _ => None, + }).for_each(&mut process_fn), + ast::AssocItemList(it) => it.assoc_items().filter_map(|item| match item { + ast::AssocItem::Fn(it) => Some(it), + _ => None, + }).for_each(&mut process_fn), _ => continue, } }; - for item in items { - if let ast::ModuleItem::FnDef(func) = item { - if Some(&func) == me.as_ref() { - continue; - } - func.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| { - let text = param.syntax().text().to_string(); - params.entry(text).or_insert(param); - }) - } - } } params diff --git a/crates/ra_ide/src/completion/complete_keyword.rs b/crates/ra_ide/src/completion/complete_keyword.rs index fcdaeef49b..b62064797b 100644 --- a/crates/ra_ide/src/completion/complete_keyword.rs +++ b/crates/ra_ide/src/completion/complete_keyword.rs @@ -66,27 +66,24 @@ pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte add_keyword(ctx, acc, "fn", "fn $0() {}") } - if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent) - || ctx.block_expr_parent - { + if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { add_keyword(ctx, acc, "trait", "trait $0 {}"); add_keyword(ctx, acc, "impl", "impl $0 {}"); } return; } - if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent { + if ctx.has_item_list_or_source_file_parent || has_trait_or_impl_parent || ctx.block_expr_parent + { add_keyword(ctx, acc, "fn", "fn $0() {}"); } - if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent) - || ctx.block_expr_parent - { + if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { add_keyword(ctx, acc, "use", "use "); add_keyword(ctx, acc, "impl", "impl $0 {}"); add_keyword(ctx, acc, "trait", "trait $0 {}"); } - if ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent { + if ctx.has_item_list_or_source_file_parent { add_keyword(ctx, acc, "enum", "enum $0 {}"); add_keyword(ctx, acc, "struct", "struct $0"); add_keyword(ctx, acc, "union", "union $0 {}"); @@ -108,29 +105,28 @@ pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte add_keyword(ctx, acc, "else", "else {$0}"); add_keyword(ctx, acc, "else if", "else if $0 {}"); } - if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent) - || ctx.block_expr_parent - { + if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { add_keyword(ctx, acc, "mod", "mod $0 {}"); } if ctx.bind_pat_parent || ctx.ref_pat_parent { add_keyword(ctx, acc, "mut", "mut "); } - if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent { + if ctx.has_item_list_or_source_file_parent || has_trait_or_impl_parent || ctx.block_expr_parent + { add_keyword(ctx, acc, "const", "const "); add_keyword(ctx, acc, "type", "type "); } - if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent) - || ctx.block_expr_parent - { + if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { add_keyword(ctx, acc, "static", "static "); }; - if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent) - || ctx.block_expr_parent - { + if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { add_keyword(ctx, acc, "extern", "extern "); } - if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent || ctx.is_match_arm { + if ctx.has_item_list_or_source_file_parent + || has_trait_or_impl_parent + || ctx.block_expr_parent + || ctx.is_match_arm + { add_keyword(ctx, acc, "unsafe", "unsafe "); } if ctx.in_loop_body { @@ -142,7 +138,7 @@ pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte add_keyword(ctx, acc, "break", "break"); } } - if ctx.has_item_list_or_source_file_parent && !ctx.has_trait_parent { + if ctx.has_item_list_or_source_file_parent || ctx.has_impl_parent { add_keyword(ctx, acc, "pub", "pub ") } @@ -173,7 +169,7 @@ fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet fn complete_return( ctx: &CompletionContext, - fn_def: &ast::FnDef, + fn_def: &ast::Fn, can_be_stmt: bool, ) -> Option { let snip = match (can_be_stmt, fn_def.ret_type().is_some()) { diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index cf716540f5..d9a0ef167d 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -2,8 +2,8 @@ //! //! This module adds the completion items related to implementing associated //! items within a `impl Trait for Struct` block. The current context node -//! must be within either a `FN_DEF`, `TYPE_ALIAS_DEF`, or `CONST_DEF` node -//! and an direct child of an `IMPL_DEF`. +//! must be within either a `FN`, `TYPE_ALIAS`, or `CONST` node +//! and an direct child of an `IMPL`. //! //! # Examples //! @@ -34,7 +34,7 @@ use hir::{self, Docs, HasSource}; use ra_assists::utils::get_missing_assoc_items; use ra_syntax::{ - ast::{self, edit, ImplDef}, + ast::{self, edit, Impl}, AstNode, SyntaxKind, SyntaxNode, TextRange, T, }; use ra_text_edit::TextEdit; @@ -63,7 +63,7 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext } }), - SyntaxKind::FN_DEF => { + SyntaxKind::FN => { for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def) .into_iter() .filter_map(|item| match item { @@ -75,7 +75,7 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext } } - SyntaxKind::TYPE_ALIAS_DEF => { + SyntaxKind::TYPE_ALIAS => { for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def) .into_iter() .filter_map(|item| match item { @@ -87,7 +87,7 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext } } - SyntaxKind::CONST_DEF => { + SyntaxKind::CONST => { for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def) .into_iter() .filter_map(|item| match item { @@ -104,18 +104,17 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext } } -fn completion_match(ctx: &CompletionContext) -> Option<(SyntaxNode, ImplDef)> { +fn completion_match(ctx: &CompletionContext) -> Option<(SyntaxNode, Impl)> { let (trigger, impl_def_offset) = ctx.token.ancestors().find_map(|p| match p.kind() { - SyntaxKind::FN_DEF - | SyntaxKind::TYPE_ALIAS_DEF - | SyntaxKind::CONST_DEF - | SyntaxKind::BLOCK_EXPR => Some((p, 2)), + SyntaxKind::FN | SyntaxKind::TYPE_ALIAS | SyntaxKind::CONST | SyntaxKind::BLOCK_EXPR => { + Some((p, 2)) + } SyntaxKind::NAME_REF => Some((p, 5)), _ => None, })?; let impl_def = (0..impl_def_offset - 1) .try_fold(trigger.parent()?, |t, _| t.parent()) - .and_then(ast::ImplDef::cast)?; + .and_then(ast::Impl::cast)?; Some((trigger, impl_def)) } @@ -201,7 +200,7 @@ fn add_const_impl( } } -fn make_const_compl_syntax(const_: &ast::ConstDef) -> String { +fn make_const_compl_syntax(const_: &ast::Const) -> String { let const_ = edit::remove_attrs_and_docs(const_); let const_start = const_.syntax().text_range().start(); diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index c84d43d773..6b03b30bb5 100644 --- a/crates/ra_ide/src/completion/completion_context.rs +++ b/crates/ra_ide/src/completion/completion_context.rs @@ -35,12 +35,12 @@ pub(crate) struct CompletionContext<'a> { pub(super) krate: Option, pub(super) expected_type: Option, pub(super) name_ref_syntax: Option, - pub(super) function_syntax: Option, - pub(super) use_item_syntax: Option, - pub(super) record_lit_syntax: Option, + pub(super) function_syntax: Option, + pub(super) use_item_syntax: Option, + pub(super) record_lit_syntax: Option, pub(super) record_pat_syntax: Option, - pub(super) record_field_syntax: Option, - pub(super) impl_def: Option, + pub(super) record_field_syntax: Option, + pub(super) impl_def: Option, /// FIXME: `ActiveParameter` is string-based, which is very very wrong pub(super) active_parameter: Option, pub(super) is_param: bool, @@ -265,7 +265,7 @@ impl<'a> CompletionContext<'a> { return; } // FIXME: remove this (V) duplication and make the check more precise - if name_ref.syntax().ancestors().find_map(ast::RecordFieldPatList::cast).is_some() { + if name_ref.syntax().ancestors().find_map(ast::RecordPatFieldList::cast).is_some() { self.record_pat_syntax = self.sema.find_node_at_offset_with_macros(&original_file, offset); } @@ -275,7 +275,7 @@ impl<'a> CompletionContext<'a> { // Otherwise, see if this is a declaration. We can use heuristics to // suggest declaration names, see `CompletionKind::Magic`. if let Some(name) = find_node_at_offset::(&file_with_fake_ident, offset) { - if let Some(bind_pat) = name.syntax().ancestors().find_map(ast::BindPat::cast) { + if let Some(bind_pat) = name.syntax().ancestors().find_map(ast::IdentPat::cast) { self.is_pat_binding_or_const = true; if bind_pat.at_token().is_some() || bind_pat.ref_token().is_some() @@ -283,7 +283,7 @@ impl<'a> CompletionContext<'a> { { self.is_pat_binding_or_const = false; } - if bind_pat.syntax().parent().and_then(ast::RecordFieldPatList::cast).is_some() { + if bind_pat.syntax().parent().and_then(ast::RecordPatFieldList::cast).is_some() { self.is_pat_binding_or_const = false; } if let Some(let_stmt) = bind_pat.syntax().ancestors().find_map(ast::LetStmt::cast) { @@ -300,7 +300,7 @@ impl<'a> CompletionContext<'a> { return; } // FIXME: remove this (^) duplication and make the check more precise - if name.syntax().ancestors().find_map(ast::RecordFieldPatList::cast).is_some() { + if name.syntax().ancestors().find_map(ast::RecordPatFieldList::cast).is_some() { self.record_pat_syntax = self.sema.find_node_at_offset_with_macros(&original_file, offset); } @@ -316,7 +316,7 @@ impl<'a> CompletionContext<'a> { self.name_ref_syntax = find_node_at_offset(&original_file, name_ref.syntax().text_range().start()); let name_range = name_ref.syntax().text_range(); - if ast::RecordField::for_field_name(&name_ref).is_some() { + if ast::RecordExprField::for_field_name(&name_ref).is_some() { self.record_lit_syntax = self.sema.find_node_at_offset_with_macros(&original_file, offset); } @@ -325,7 +325,7 @@ impl<'a> CompletionContext<'a> { .sema .ancestors_with_macros(self.token.parent()) .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) - .find_map(ast::ImplDef::cast); + .find_map(ast::Impl::cast); let top_node = name_ref .syntax() @@ -343,13 +343,13 @@ impl<'a> CompletionContext<'a> { } self.use_item_syntax = - self.sema.ancestors_with_macros(self.token.parent()).find_map(ast::UseItem::cast); + self.sema.ancestors_with_macros(self.token.parent()).find_map(ast::Use::cast); self.function_syntax = self .sema .ancestors_with_macros(self.token.parent()) .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) - .find_map(ast::FnDef::cast); + .find_map(ast::Fn::cast); self.record_field_syntax = self .sema @@ -357,7 +357,7 @@ impl<'a> CompletionContext<'a> { .take_while(|it| { it.kind() != SOURCE_FILE && it.kind() != MODULE && it.kind() != CALL_EXPR }) - .find_map(ast::RecordField::cast); + .find_map(ast::RecordExprField::cast); let parent = match name_ref.syntax().parent() { Some(it) => it, @@ -377,7 +377,7 @@ impl<'a> CompletionContext<'a> { path.syntax().parent().and_then(ast::TupleStructPat::cast).is_some(); self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some(); - self.has_type_args = segment.type_arg_list().is_some(); + self.has_type_args = segment.generic_arg_list().is_some(); #[allow(deprecated)] if let Some(path) = hir::Path::from_ast(path.clone()) { diff --git a/crates/ra_ide/src/completion/patterns.rs b/crates/ra_ide/src/completion/patterns.rs index b2fe13280a..7c4feff6d1 100644 --- a/crates/ra_ide/src/completion/patterns.rs +++ b/crates/ra_ide/src/completion/patterns.rs @@ -13,9 +13,9 @@ use crate::completion::test_utils::check_pattern_is_applicable; pub(crate) fn has_trait_parent(element: SyntaxElement) -> bool { not_same_range_ancestor(element) - .filter(|it| it.kind() == ITEM_LIST) + .filter(|it| it.kind() == ASSOC_ITEM_LIST) .and_then(|it| it.parent()) - .filter(|it| it.kind() == TRAIT_DEF) + .filter(|it| it.kind() == TRAIT) .is_some() } #[test] @@ -25,9 +25,9 @@ fn test_has_trait_parent() { pub(crate) fn has_impl_parent(element: SyntaxElement) -> bool { not_same_range_ancestor(element) - .filter(|it| it.kind() == ITEM_LIST) + .filter(|it| it.kind() == ASSOC_ITEM_LIST) .and_then(|it| it.parent()) - .filter(|it| it.kind() == IMPL_DEF) + .filter(|it| it.kind() == IMPL) .is_some() } #[test] @@ -44,7 +44,7 @@ fn test_has_block_expr_parent() { } pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool { - element.ancestors().find(|it| it.kind() == BIND_PAT).is_some() + element.ancestors().find(|it| it.kind() == IDENT_PAT).is_some() } #[test] fn test_has_bind_pat_parent() { @@ -73,7 +73,7 @@ pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> boo #[test] fn test_has_item_list_or_source_file_parent() { check_pattern_is_applicable(r"i<|>", has_item_list_or_source_file_parent); - check_pattern_is_applicable(r"impl { f<|> }", has_item_list_or_source_file_parent); + check_pattern_is_applicable(r"mod foo { f<|> }", has_item_list_or_source_file_parent); } pub(crate) fn is_match_arm(element: SyntaxElement) -> bool { @@ -113,7 +113,7 @@ fn test_if_is_prev() { } pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool { - previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == TRAIT_DEF).is_some() + previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == TRAIT).is_some() } #[test] fn test_has_trait_as_prev_sibling() { @@ -121,7 +121,7 @@ fn test_has_trait_as_prev_sibling() { } pub(crate) fn has_impl_as_prev_sibling(element: SyntaxElement) -> bool { - previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == IMPL_DEF).is_some() + previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == IMPL).is_some() } #[test] fn test_has_impl_as_prev_sibling() { @@ -134,7 +134,7 @@ pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool { NodeOrToken::Token(token) => token.parent(), }; for node in leaf.ancestors() { - if node.kind() == FN_DEF || node.kind() == LAMBDA_EXPR { + if node.kind() == FN || node.kind() == CLOSURE_EXPR { break; } let loop_body = match_ast! { diff --git a/crates/ra_ide/src/completion/unstable_feature_descriptor.rs b/crates/ra_ide/src/completion/unstable_feature_descriptor.rs index ae7fc1cfb4..a40071a26f 100644 --- a/crates/ra_ide/src/completion/unstable_feature_descriptor.rs +++ b/crates/ra_ide/src/completion/unstable_feature_descriptor.rs @@ -1,4 +1,4 @@ //! Generated file, do not edit by hand, see `xtask/src/codegen` use crate::completion::LintCompletion; -const UNSTABLE_FEATURE_DESCRIPTOR : & [ LintCompletion ] = & [ LintCompletion { label : "crate_visibility_modifier" , description : "# `crate_visibility_modifier`\n\nThe tracking issue for this feature is: [#53120]\n\n[#53120]: https://github.com/rust-lang/rust/issues/53120\n\n-----\n\nThe `crate_visibility_modifier` feature allows the `crate` keyword to be used\nas a visibility modifier synonymous to `pub(crate)`, indicating that a type\n(function, _&c._) is to be visible to the entire enclosing crate, but not to\nother crates.\n\n```rust\n#![feature(crate_visibility_modifier)]\n\ncrate struct Foo {\n bar: usize,\n}\n```\n" } , LintCompletion { label : "abi_thiscall" , description : "# `abi_thiscall`\n\nThe tracking issue for this feature is: [#42202]\n\n[#42202]: https://github.com/rust-lang/rust/issues/42202\n\n------------------------\n\nThe MSVC ABI on x86 Windows uses the `thiscall` calling convention for C++\ninstance methods by default; it is identical to the usual (C) calling\nconvention on x86 Windows except that the first parameter of the method,\nthe `this` pointer, is passed in the ECX register.\n" } , LintCompletion { label : "infer_static_outlives_requirements" , description : "# `infer_static_outlives_requirements`\n\nThe tracking issue for this feature is: [#54185]\n\n[#54185]: https://github.com/rust-lang/rust/issues/54185\n\n------------------------\nThe `infer_static_outlives_requirements` feature indicates that certain\n`'static` outlives requirements can be inferred by the compiler rather than\nstating them explicitly.\n\nNote: It is an accompanying feature to `infer_outlives_requirements`,\nwhich must be enabled to infer outlives requirements.\n\nFor example, currently generic struct definitions that contain\nreferences, require where-clauses of the form T: 'static. By using\nthis feature the outlives predicates will be inferred, although\nthey may still be written explicitly.\n\n```rust,ignore (pseudo-Rust)\nstruct Foo where U: 'static { // <-- currently required\n bar: Bar\n}\nstruct Bar {\n x: T,\n}\n```\n\n\n## Examples:\n\n```rust,ignore (pseudo-Rust)\n#![feature(infer_outlives_requirements)]\n#![feature(infer_static_outlives_requirements)]\n\n#[rustc_outlives]\n// Implicitly infer U: 'static\nstruct Foo {\n bar: Bar\n}\nstruct Bar {\n x: T,\n}\n```\n\n" } , LintCompletion { label : "repr128" , description : "# `repr128`\n\nThe tracking issue for this feature is: [#56071]\n\n[#56071]: https://github.com/rust-lang/rust/issues/56071\n\n------------------------\n\nThe `repr128` feature adds support for `#[repr(u128)]` on `enum`s.\n\n```rust\n#![feature(repr128)]\n\n#[repr(u128)]\nenum Foo {\n Bar(u64),\n}\n```\n" } , LintCompletion { label : "doc_masked" , description : "# `doc_masked`\n\nThe tracking issue for this feature is: [#44027]\n\n-----\n\nThe `doc_masked` feature allows a crate to exclude types from a given crate from appearing in lists\nof trait implementations. The specifics of the feature are as follows:\n\n1. When rustdoc encounters an `extern crate` statement annotated with a `#[doc(masked)]` attribute,\n it marks the crate as being masked.\n\n2. When listing traits a given type implements, rustdoc ensures that traits from masked crates are\n not emitted into the documentation.\n\n3. When listing types that implement a given trait, rustdoc ensures that types from masked crates\n are not emitted into the documentation.\n\nThis feature was introduced in PR [#44026] to ensure that compiler-internal and\nimplementation-specific types and traits were not included in the standard library's documentation.\nSuch types would introduce broken links into the documentation.\n\n[#44026]: https://github.com/rust-lang/rust/pull/44026\n[#44027]: https://github.com/rust-lang/rust/pull/44027\n" } , LintCompletion { label : "link_args" , description : "# `link_args`\n\nThe tracking issue for this feature is: [#29596]\n\n[#29596]: https://github.com/rust-lang/rust/issues/29596\n\n------------------------\n\nYou can tell `rustc` how to customize linking, and that is via the `link_args`\nattribute. This attribute is applied to `extern` blocks and specifies raw flags\nwhich need to get passed to the linker when producing an artifact. An example\nusage would be:\n\n```rust,no_run\n#![feature(link_args)]\n\n#[link_args = \"-foo -bar -baz\"]\nextern {}\n# fn main() {}\n```\n\nNote that this feature is currently hidden behind the `feature(link_args)` gate\nbecause this is not a sanctioned way of performing linking. Right now `rustc`\nshells out to the system linker (`gcc` on most systems, `link.exe` on MSVC), so\nit makes sense to provide extra command line arguments, but this will not\nalways be the case. In the future `rustc` may use LLVM directly to link native\nlibraries, in which case `link_args` will have no meaning. You can achieve the\nsame effect as the `link_args` attribute with the `-C link-args` argument to\n`rustc`.\n\nIt is highly recommended to *not* use this attribute, and rather use the more\nformal `#[link(...)]` attribute on `extern` blocks instead.\n" } , LintCompletion { label : "cfg_version" , description : "# `cfg_version`\n\nThe tracking issue for this feature is: [#64796]\n\n[#64796]: https://github.com/rust-lang/rust/issues/64796\n\n------------------------\n\nThe `cfg_version` feature makes it possible to execute different code\ndepending on the compiler version.\n\n## Examples\n\n```rust\n#![feature(cfg_version)]\n\n#[cfg(version(\"1.42\"))]\nfn a() {\n // ...\n}\n\n#[cfg(not(version(\"1.42\")))]\nfn a() {\n // ...\n}\n\nfn b() {\n if cfg!(version(\"1.42\")) {\n // ...\n } else {\n // ...\n }\n}\n```\n" } , LintCompletion { label : "ffi_const" , description : "# `ffi_const`\n\nThe `#[ffi_const]` attribute applies clang's `const` attribute to foreign\nfunctions declarations.\n\nThat is, `#[ffi_const]` functions shall have no effects except for its return\nvalue, which can only depend on the values of the function parameters, and is\nnot affected by changes to the observable state of the program.\n\nApplying the `#[ffi_const]` attribute to a function that violates these\nrequirements is undefined behaviour.\n\nThis attribute enables Rust to perform common optimizations, like sub-expression\nelimination, and it can avoid emitting some calls in repeated invocations of the\nfunction with the same argument values regardless of other operations being\nperformed in between these functions calls (as opposed to `#[ffi_pure]`\nfunctions).\n\n## Pitfalls\n\nA `#[ffi_const]` function can only read global memory that would not affect\nits return value for the whole execution of the program (e.g. immutable global\nmemory). `#[ffi_const]` functions are referentially-transparent and therefore\nmore strict than `#[ffi_pure]` functions.\n\nA common pitfall involves applying the `#[ffi_const]` attribute to a\nfunction that reads memory through pointer arguments which do not necessarily\npoint to immutable global memory.\n\nA `#[ffi_const]` function that returns unit has no effect on the abstract\nmachine's state, and a `#[ffi_const]` function cannot be `#[ffi_pure]`.\n\nA `#[ffi_const]` function must not diverge, neither via a side effect (e.g. a\ncall to `abort`) nor by infinite loops.\n\nWhen translating C headers to Rust FFI, it is worth verifying for which targets\nthe `const` attribute is enabled in those headers, and using the appropriate\n`cfg` macros in the Rust side to match those definitions. While the semantics of\n`const` are implemented identically by many C and C++ compilers, e.g., clang,\n[GCC], [ARM C/C++ compiler], [IBM ILE C/C++], etc. they are not necessarily\nimplemented in this way on all of them. It is therefore also worth verifying\nthat the semantics of the C toolchain used to compile the binary being linked\nagainst are compatible with those of the `#[ffi_const]`.\n\n[ARM C/C++ compiler]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/Cacgigch.html\n[GCC]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-const-function-attribute\n[IBM ILE C/C++]: https://www.ibm.com/support/knowledgecenter/fr/ssw_ibm_i_71/rzarg/fn_attrib_const.htm\n" } , LintCompletion { label : "doc_cfg" , description : "# `doc_cfg`\n\nThe tracking issue for this feature is: [#43781]\n\n------\n\nThe `doc_cfg` feature allows an API be documented as only available in some specific platforms.\nThis attribute has two effects:\n\n1. In the annotated item's documentation, there will be a message saying \"This is supported on\n (platform) only\".\n\n2. The item's doc-tests will only run on the specific platform.\n\nIn addition to allowing the use of the `#[doc(cfg)]` attribute, this feature enables the use of a\nspecial conditional compilation flag, `#[cfg(doc)]`, set whenever building documentation on your\ncrate.\n\nThis feature was introduced as part of PR [#43348] to allow the platform-specific parts of the\nstandard library be documented.\n\n```rust\n#![feature(doc_cfg)]\n\n#[cfg(any(windows, doc))]\n#[doc(cfg(windows))]\n/// The application's icon in the notification area (a.k.a. system tray).\n///\n/// # Examples\n///\n/// ```no_run\n/// extern crate my_awesome_ui_library;\n/// use my_awesome_ui_library::current_app;\n/// use my_awesome_ui_library::windows::notification;\n///\n/// let icon = current_app().get::();\n/// icon.show();\n/// icon.show_message(\"Hello\");\n/// ```\npub struct Icon {\n // ...\n}\n```\n\n[#43781]: https://github.com/rust-lang/rust/issues/43781\n[#43348]: https://github.com/rust-lang/rust/issues/43348\n" } , LintCompletion { label : "unsized_tuple_coercion" , description : "# `unsized_tuple_coercion`\n\nThe tracking issue for this feature is: [#42877]\n\n[#42877]: https://github.com/rust-lang/rust/issues/42877\n\n------------------------\n\nThis is a part of [RFC0401]. According to the RFC, there should be an implementation like this:\n\n```rust,ignore\nimpl<..., T, U: ?Sized> Unsized<(..., U)> for (..., T) where T: Unsized {}\n```\n\nThis implementation is currently gated behind `#[feature(unsized_tuple_coercion)]` to avoid insta-stability. Therefore you can use it like this:\n\n```rust\n#![feature(unsized_tuple_coercion)]\n\nfn main() {\n let x : ([i32; 3], [i32; 3]) = ([1, 2, 3], [4, 5, 6]);\n let y : &([i32; 3], [i32]) = &x;\n assert_eq!(y.1[0], 4);\n}\n```\n\n[RFC0401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md\n" } , LintCompletion { label : "abi_msp430_interrupt" , description : "# `abi_msp430_interrupt`\n\nThe tracking issue for this feature is: [#38487]\n\n[#38487]: https://github.com/rust-lang/rust/issues/38487\n\n------------------------\n\nIn the MSP430 architecture, interrupt handlers have a special calling\nconvention. You can use the `\"msp430-interrupt\"` ABI to make the compiler apply\nthe right calling convention to the interrupt handlers you define.\n\n\n\n``` rust,ignore\n#![feature(abi_msp430_interrupt)]\n#![no_std]\n\n// Place the interrupt handler at the appropriate memory address\n// (Alternatively, you can use `#[used]` and remove `pub` and `#[no_mangle]`)\n#[link_section = \"__interrupt_vector_10\"]\n#[no_mangle]\npub static TIM0_VECTOR: extern \"msp430-interrupt\" fn() = tim0;\n\n// The interrupt handler\nextern \"msp430-interrupt\" fn tim0() {\n // ..\n}\n```\n\n``` text\n$ msp430-elf-objdump -CD ./target/msp430/release/app\nDisassembly of section __interrupt_vector_10:\n\n0000fff2 :\n fff2: 00 c0 interrupt service routine at 0xc000\n\nDisassembly of section .text:\n\n0000c000 :\n c000: 00 13 reti\n```\n" } , LintCompletion { label : "generators" , description : "# `generators`\n\nThe tracking issue for this feature is: [#43122]\n\n[#43122]: https://github.com/rust-lang/rust/issues/43122\n\n------------------------\n\nThe `generators` feature gate in Rust allows you to define generator or\ncoroutine literals. A generator is a \"resumable function\" that syntactically\nresembles a closure but compiles to much different semantics in the compiler\nitself. The primary feature of a generator is that it can be suspended during\nexecution to be resumed at a later date. Generators use the `yield` keyword to\n\"return\", and then the caller can `resume` a generator to resume execution just\nafter the `yield` keyword.\n\nGenerators are an extra-unstable feature in the compiler right now. Added in\n[RFC 2033] they're mostly intended right now as a information/constraint\ngathering phase. The intent is that experimentation can happen on the nightly\ncompiler before actual stabilization. A further RFC will be required to\nstabilize generators/coroutines and will likely contain at least a few small\ntweaks to the overall design.\n\n[RFC 2033]: https://github.com/rust-lang/rfcs/pull/2033\n\nA syntactical example of a generator is:\n\n```rust\n#![feature(generators, generator_trait)]\n\nuse std::ops::{Generator, GeneratorState};\nuse std::pin::Pin;\n\nfn main() {\n let mut generator = || {\n yield 1;\n return \"foo\"\n };\n\n match Pin::new(&mut generator).resume(()) {\n GeneratorState::Yielded(1) => {}\n _ => panic!(\"unexpected value from resume\"),\n }\n match Pin::new(&mut generator).resume(()) {\n GeneratorState::Complete(\"foo\") => {}\n _ => panic!(\"unexpected value from resume\"),\n }\n}\n```\n\nGenerators are closure-like literals which can contain a `yield` statement. The\n`yield` statement takes an optional expression of a value to yield out of the\ngenerator. All generator literals implement the `Generator` trait in the\n`std::ops` module. The `Generator` trait has one main method, `resume`, which\nresumes execution of the generator at the previous suspension point.\n\nAn example of the control flow of generators is that the following example\nprints all numbers in order:\n\n```rust\n#![feature(generators, generator_trait)]\n\nuse std::ops::Generator;\nuse std::pin::Pin;\n\nfn main() {\n let mut generator = || {\n println!(\"2\");\n yield;\n println!(\"4\");\n };\n\n println!(\"1\");\n Pin::new(&mut generator).resume(());\n println!(\"3\");\n Pin::new(&mut generator).resume(());\n println!(\"5\");\n}\n```\n\nAt this time the main intended use case of generators is an implementation\nprimitive for async/await syntax, but generators will likely be extended to\nergonomic implementations of iterators and other primitives in the future.\nFeedback on the design and usage is always appreciated!\n\n### The `Generator` trait\n\nThe `Generator` trait in `std::ops` currently looks like:\n\n```rust\n# #![feature(arbitrary_self_types, generator_trait)]\n# use std::ops::GeneratorState;\n# use std::pin::Pin;\n\npub trait Generator {\n type Yield;\n type Return;\n fn resume(self: Pin<&mut Self>, resume: R) -> GeneratorState;\n}\n```\n\nThe `Generator::Yield` type is the type of values that can be yielded with the\n`yield` statement. The `Generator::Return` type is the returned type of the\ngenerator. This is typically the last expression in a generator's definition or\nany value passed to `return` in a generator. The `resume` function is the entry\npoint for executing the `Generator` itself.\n\nThe return value of `resume`, `GeneratorState`, looks like:\n\n```rust\npub enum GeneratorState {\n Yielded(Y),\n Complete(R),\n}\n```\n\nThe `Yielded` variant indicates that the generator can later be resumed. This\ncorresponds to a `yield` point in a generator. The `Complete` variant indicates\nthat the generator is complete and cannot be resumed again. Calling `resume`\nafter a generator has returned `Complete` will likely result in a panic of the\nprogram.\n\n### Closure-like semantics\n\nThe closure-like syntax for generators alludes to the fact that they also have\nclosure-like semantics. Namely:\n\n* When created, a generator executes no code. A closure literal does not\n actually execute any of the closure's code on construction, and similarly a\n generator literal does not execute any code inside the generator when\n constructed.\n\n* Generators can capture outer variables by reference or by move, and this can\n be tweaked with the `move` keyword at the beginning of the closure. Like\n closures all generators will have an implicit environment which is inferred by\n the compiler. Outer variables can be moved into a generator for use as the\n generator progresses.\n\n* Generator literals produce a value with a unique type which implements the\n `std::ops::Generator` trait. This allows actual execution of the generator\n through the `Generator::resume` method as well as also naming it in return\n types and such.\n\n* Traits like `Send` and `Sync` are automatically implemented for a `Generator`\n depending on the captured variables of the environment. Unlike closures,\n generators also depend on variables live across suspension points. This means\n that although the ambient environment may be `Send` or `Sync`, the generator\n itself may not be due to internal variables live across `yield` points being\n not-`Send` or not-`Sync`. Note that generators do\n not implement traits like `Copy` or `Clone` automatically.\n\n* Whenever a generator is dropped it will drop all captured environment\n variables.\n\n### Generators as state machines\n\nIn the compiler, generators are currently compiled as state machines. Each\n`yield` expression will correspond to a different state that stores all live\nvariables over that suspension point. Resumption of a generator will dispatch on\nthe current state and then execute internally until a `yield` is reached, at\nwhich point all state is saved off in the generator and a value is returned.\n\nLet's take a look at an example to see what's going on here:\n\n```rust\n#![feature(generators, generator_trait)]\n\nuse std::ops::Generator;\nuse std::pin::Pin;\n\nfn main() {\n let ret = \"foo\";\n let mut generator = move || {\n yield 1;\n return ret\n };\n\n Pin::new(&mut generator).resume(());\n Pin::new(&mut generator).resume(());\n}\n```\n\nThis generator literal will compile down to something similar to:\n\n```rust\n#![feature(arbitrary_self_types, generators, generator_trait)]\n\nuse std::ops::{Generator, GeneratorState};\nuse std::pin::Pin;\n\nfn main() {\n let ret = \"foo\";\n let mut generator = {\n enum __Generator {\n Start(&'static str),\n Yield1(&'static str),\n Done,\n }\n\n impl Generator for __Generator {\n type Yield = i32;\n type Return = &'static str;\n\n fn resume(mut self: Pin<&mut Self>, resume: ()) -> GeneratorState {\n use std::mem;\n match mem::replace(&mut *self, __Generator::Done) {\n __Generator::Start(s) => {\n *self = __Generator::Yield1(s);\n GeneratorState::Yielded(1)\n }\n\n __Generator::Yield1(s) => {\n *self = __Generator::Done;\n GeneratorState::Complete(s)\n }\n\n __Generator::Done => {\n panic!(\"generator resumed after completion\")\n }\n }\n }\n }\n\n __Generator::Start(ret)\n };\n\n Pin::new(&mut generator).resume(());\n Pin::new(&mut generator).resume(());\n}\n```\n\nNotably here we can see that the compiler is generating a fresh type,\n`__Generator` in this case. This type has a number of states (represented here\nas an `enum`) corresponding to each of the conceptual states of the generator.\nAt the beginning we're closing over our outer variable `foo` and then that\nvariable is also live over the `yield` point, so it's stored in both states.\n\nWhen the generator starts it'll immediately yield 1, but it saves off its state\njust before it does so indicating that it has reached the yield point. Upon\nresuming again we'll execute the `return ret` which returns the `Complete`\nstate.\n\nHere we can also note that the `Done` state, if resumed, panics immediately as\nit's invalid to resume a completed generator. It's also worth noting that this\nis just a rough desugaring, not a normative specification for what the compiler\ndoes.\n" } , LintCompletion { label : "marker_trait_attr" , description : "# `marker_trait_attr`\n\nThe tracking issue for this feature is: [#29864]\n\n[#29864]: https://github.com/rust-lang/rust/issues/29864\n\n------------------------\n\nNormally, Rust keeps you from adding trait implementations that could\noverlap with each other, as it would be ambiguous which to use. This\nfeature, however, carves out an exception to that rule: a trait can\nopt-in to having overlapping implementations, at the cost that those\nimplementations are not allowed to override anything (and thus the\ntrait itself cannot have any associated items, as they're pointless\nwhen they'd need to do the same thing for every type anyway).\n\n```rust\n#![feature(marker_trait_attr)]\n\n#[marker] trait CheapToClone: Clone {}\n\nimpl CheapToClone for T {}\n\n// These could potentially overlap with the blanket implementation above,\n// so are only allowed because CheapToClone is a marker trait.\nimpl CheapToClone for (T, U) {}\nimpl CheapToClone for std::ops::Range {}\n\nfn cheap_clone(t: T) -> T {\n t.clone()\n}\n```\n\nThis is expected to replace the unstable `overlapping_marker_traits`\nfeature, which applied to all empty traits (without needing an opt-in).\n" } , LintCompletion { label : "const_in_array_repeat_expressions" , description : "# `const_in_array_repeat_expressions`\n\nThe tracking issue for this feature is: [#49147]\n\n[#49147]: https://github.com/rust-lang/rust/issues/49147\n\n------------------------\n\nRelaxes the rules for repeat expressions, `[x; N]` such that `x` may also be `const` (strictly\nspeaking rvalue promotable), in addition to `typeof(x): Copy`. The result of `[x; N]` where `x` is\n`const` is itself also `const`.\n" } , LintCompletion { label : "external_doc" , description : "# `external_doc`\n\nThe tracking issue for this feature is: [#44732]\n\nThe `external_doc` feature allows the use of the `include` parameter to the `#[doc]` attribute, to\ninclude external files in documentation. Use the attribute in place of, or in addition to, regular\ndoc comments and `#[doc]` attributes, and `rustdoc` will load the given file when it renders\ndocumentation for your crate.\n\nWith the following files in the same directory:\n\n`external-doc.md`:\n\n```markdown\n# My Awesome Type\n\nThis is the documentation for this spectacular type.\n```\n\n`lib.rs`:\n\n```no_run (needs-external-files)\n#![feature(external_doc)]\n\n#[doc(include = \"external-doc.md\")]\npub struct MyAwesomeType;\n```\n\n`rustdoc` will load the file `external-doc.md` and use it as the documentation for the `MyAwesomeType`\nstruct.\n\nWhen locating files, `rustdoc` will base paths in the `src/` directory, as if they were alongside the\n`lib.rs` for your crate. So if you want a `docs/` folder to live alongside the `src/` directory,\nstart your paths with `../docs/` for `rustdoc` to properly find the file.\n\nThis feature was proposed in [RFC #1990] and initially implemented in PR [#44781].\n\n[#44732]: https://github.com/rust-lang/rust/issues/44732\n[RFC #1990]: https://github.com/rust-lang/rfcs/pull/1990\n[#44781]: https://github.com/rust-lang/rust/pull/44781\n" } , LintCompletion { label : "unsized_locals" , description : "# `unsized_locals`\n\nThe tracking issue for this feature is: [#48055]\n\n[#48055]: https://github.com/rust-lang/rust/issues/48055\n\n------------------------\n\nThis implements [RFC1909]. When turned on, you can have unsized arguments and locals:\n\n[RFC1909]: https://github.com/rust-lang/rfcs/blob/master/text/1909-unsized-rvalues.md\n\n```rust\n#![feature(unsized_locals)]\n\nuse std::any::Any;\n\nfn main() {\n let x: Box = Box::new(42);\n let x: dyn Any = *x;\n // ^ unsized local variable\n // ^^ unsized temporary\n foo(x);\n}\n\nfn foo(_: dyn Any) {}\n// ^^^^^^ unsized argument\n```\n\nThe RFC still forbids the following unsized expressions:\n\n```rust,ignore\n#![feature(unsized_locals)]\n\nuse std::any::Any;\n\nstruct MyStruct {\n content: T,\n}\n\nstruct MyTupleStruct(T);\n\nfn answer() -> Box {\n Box::new(42)\n}\n\nfn main() {\n // You CANNOT have unsized statics.\n static X: dyn Any = *answer(); // ERROR\n const Y: dyn Any = *answer(); // ERROR\n\n // You CANNOT have struct initialized unsized.\n MyStruct { content: *answer() }; // ERROR\n MyTupleStruct(*answer()); // ERROR\n (42, *answer()); // ERROR\n\n // You CANNOT have unsized return types.\n fn my_function() -> dyn Any { *answer() } // ERROR\n\n // You CAN have unsized local variables...\n let mut x: dyn Any = *answer(); // OK\n // ...but you CANNOT reassign to them.\n x = *answer(); // ERROR\n\n // You CANNOT even initialize them separately.\n let y: dyn Any; // OK\n y = *answer(); // ERROR\n\n // Not mentioned in the RFC, but by-move captured variables are also Sized.\n let x: dyn Any = *answer();\n (move || { // ERROR\n let y = x;\n })();\n\n // You CAN create a closure with unsized arguments,\n // but you CANNOT call it.\n // This is an implementation detail and may be changed in the future.\n let f = |x: dyn Any| {};\n f(*answer()); // ERROR\n}\n```\n\n## By-value trait objects\n\nWith this feature, you can have by-value `self` arguments without `Self: Sized` bounds.\n\n```rust\n#![feature(unsized_locals)]\n\ntrait Foo {\n fn foo(self) {}\n}\n\nimpl Foo for T {}\n\nfn main() {\n let slice: Box<[i32]> = Box::new([1, 2, 3]);\n <[i32] as Foo>::foo(*slice);\n}\n```\n\nAnd `Foo` will also be object-safe.\n\n```rust\n#![feature(unsized_locals)]\n\ntrait Foo {\n fn foo(self) {}\n}\n\nimpl Foo for T {}\n\nfn main () {\n let slice: Box = Box::new([1, 2, 3]);\n // doesn't compile yet\n ::foo(*slice);\n}\n```\n\nOne of the objectives of this feature is to allow `Box`.\n\n## Variable length arrays\n\nThe RFC also describes an extension to the array literal syntax: `[e; dyn n]`. In the syntax, `n` isn't necessarily a constant expression. The array is dynamically allocated on the stack and has the type of `[T]`, instead of `[T; n]`.\n\n```rust,ignore\n#![feature(unsized_locals)]\n\nfn mergesort(a: &mut [T]) {\n let mut tmp = [T; dyn a.len()];\n // ...\n}\n\nfn main() {\n let mut a = [3, 1, 5, 6];\n mergesort(&mut a);\n assert_eq!(a, [1, 3, 5, 6]);\n}\n```\n\nVLAs are not implemented yet. The syntax isn't final, either. We may need an alternative syntax for Rust 2015 because, in Rust 2015, expressions like `[e; dyn(1)]` would be ambiguous. One possible alternative proposed in the RFC is `[e; n]`: if `n` captures one or more local variables, then it is considered as `[e; dyn n]`.\n\n## Advisory on stack usage\n\nIt's advised not to casually use the `#![feature(unsized_locals)]` feature. Typical use-cases are:\n\n- When you need a by-value trait objects.\n- When you really need a fast allocation of small temporary arrays.\n\nAnother pitfall is repetitive allocation and temporaries. Currently the compiler simply extends the stack frame every time it encounters an unsized assignment. So for example, the code\n\n```rust\n#![feature(unsized_locals)]\n\nfn main() {\n let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]);\n let _x = {{{{{{{{{{*x}}}}}}}}}};\n}\n```\n\nand the code\n\n```rust\n#![feature(unsized_locals)]\n\nfn main() {\n for _ in 0..10 {\n let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]);\n let _x = *x;\n }\n}\n```\n\nwill unnecessarily extend the stack frame.\n" } , LintCompletion { label : "or_patterns" , description : "# `or_patterns`\n\nThe tracking issue for this feature is: [#54883]\n\n[#54883]: https://github.com/rust-lang/rust/issues/54883\n\n------------------------\n\nThe `or_pattern` language feature allows `|` to be arbitrarily nested within\na pattern, for example, `Some(A(0) | B(1 | 2))` becomes a valid pattern.\n\n## Examples\n\n```rust,ignore\n#![feature(or_patterns)]\n\npub enum Foo {\n Bar,\n Baz,\n Quux,\n}\n\npub fn example(maybe_foo: Option) {\n match maybe_foo {\n Some(Foo::Bar | Foo::Baz) => {\n println!(\"The value contained `Bar` or `Baz`\");\n }\n Some(_) => {\n println!(\"The value did not contain `Bar` or `Baz`\");\n }\n None => {\n println!(\"The value was `None`\");\n }\n }\n}\n```\n" } , LintCompletion { label : "member_constraints" , description : "# `member_constraints`\n\nThe tracking issue for this feature is: [#61997]\n\n[#61997]: https://github.com/rust-lang/rust/issues/61997\n\n------------------------\n\nThe `member_constraints` feature gate lets you use `impl Trait` syntax with\nmultiple unrelated lifetime parameters.\n\nA simple example is:\n\n```rust\n#![feature(member_constraints)]\n\ntrait Trait<'a, 'b> { }\nimpl Trait<'_, '_> for T {}\n\nfn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {\n (x, y)\n}\n\nfn main() { }\n```\n\nWithout the `member_constraints` feature gate, the above example is an\nerror because both `'a` and `'b` appear in the impl Trait bounds, but\nneither outlives the other.\n" } , LintCompletion { label : "optin_builtin_traits" , description : "# `optin_builtin_traits`\n\nThe tracking issue for this feature is [#13231] \n\n[#13231]: https://github.com/rust-lang/rust/issues/13231\n\n----\n\nThe `optin_builtin_traits` feature gate allows you to define auto traits.\n\nAuto traits, like [`Send`] or [`Sync`] in the standard library, are marker traits\nthat are automatically implemented for every type, unless the type, or a type it contains, \nhas explicitly opted out via a negative impl. (Negative impls are separately controlled\nby the `negative_impls` feature.)\n\n[`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html\n[`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html\n\n```rust,ignore\nimpl !Trait for Type\n```\n\nExample:\n\n```rust\n#![feature(negative_impls)]\n#![feature(optin_builtin_traits)]\n\nauto trait Valid {}\n\nstruct True;\nstruct False;\n\nimpl !Valid for False {}\n\nstruct MaybeValid(T);\n\nfn must_be_valid(_t: T) { }\n\nfn main() {\n // works\n must_be_valid( MaybeValid(True) );\n \n // compiler error - trait bound not satisfied\n // must_be_valid( MaybeValid(False) );\n}\n```\n\n## Automatic trait implementations\n\nWhen a type is declared as an `auto trait`, we will automatically\ncreate impls for every struct/enum/union, unless an explicit impl is\nprovided. These automatic impls contain a where clause for each field\nof the form `T: AutoTrait`, where `T` is the type of the field and\n`AutoTrait` is the auto trait in question. As an example, consider the\nstruct `List` and the auto trait `Send`:\n\n```rust\nstruct List {\n data: T,\n next: Option>>,\n}\n```\n\nPresuming that there is no explicit impl of `Send` for `List`, the\ncompiler will supply an automatic impl of the form:\n\n```rust\nstruct List {\n data: T,\n next: Option>>,\n}\n\nunsafe impl Send for List\nwhere\n T: Send, // from the field `data`\n Option>>: Send, // from the field `next`\n{ }\n```\n\nExplicit impls may be either positive or negative. They take the form:\n\n```rust,ignore\nimpl<...> AutoTrait for StructName<..> { }\nimpl<...> !AutoTrait for StructName<..> { }\n```\n\n## Coinduction: Auto traits permit cyclic matching\n\nUnlike ordinary trait matching, auto traits are **coinductive**. This\nmeans, in short, that cycles which occur in trait matching are\nconsidered ok. As an example, consider the recursive struct `List`\nintroduced in the previous section. In attempting to determine whether\n`List: Send`, we would wind up in a cycle: to apply the impl, we must\nshow that `Option>: Send`, which will in turn require\n`Box: Send` and then finally `List: Send` again. Under ordinary\ntrait matching, this cycle would be an error, but for an auto trait it\nis considered a successful match.\n\n## Items\n\nAuto traits cannot have any trait items, such as methods or associated types. This ensures that we can generate default implementations.\n\n## Supertraits\n\nAuto traits cannot have supertraits. This is for soundness reasons, as the interaction of coinduction with implied bounds is difficult to reconcile.\n\n" } , LintCompletion { label : "rustc_attrs" , description : "# `rustc_attrs`\n\nThis feature has no tracking issue, and is therefore internal to\nthe compiler, not being intended for general use.\n\nNote: `rustc_attrs` enables many rustc-internal attributes and this page\nonly discuss a few of them.\n\n------------------------\n\nThe `rustc_attrs` feature allows debugging rustc type layouts by using\n`#[rustc_layout(...)]` to debug layout at compile time (it even works\nwith `cargo check`) as an alternative to `rustc -Z print-type-sizes`\nthat is way more verbose.\n\nOptions provided by `#[rustc_layout(...)]` are `debug`, `size`, `abi`.\nNote that it only work best with sized type without generics.\n\n## Examples\n\n```rust,ignore\n#![feature(rustc_attrs)]\n\n#[rustc_layout(abi, size)]\npub enum X {\n Y(u8, u8, u8),\n Z(isize),\n}\n```\n\nWhen that is compiled, the compiler will error with something like\n\n```text\nerror: abi: Aggregate { sized: true }\n --> src/lib.rs:4:1\n |\n4 | / pub enum T {\n5 | | Y(u8, u8, u8),\n6 | | Z(isize),\n7 | | }\n | |_^\n\nerror: size: Size { raw: 16 }\n --> src/lib.rs:4:1\n |\n4 | / pub enum T {\n5 | | Y(u8, u8, u8),\n6 | | Z(isize),\n7 | | }\n | |_^\n\nerror: aborting due to 2 previous errors\n```\n" } , LintCompletion { label : "non_ascii_idents" , description : "# `non_ascii_idents`\n\nThe tracking issue for this feature is: [#55467]\n\n[#55467]: https://github.com/rust-lang/rust/issues/55467\n\n------------------------\n\nThe `non_ascii_idents` feature adds support for non-ASCII identifiers.\n\n## Examples\n\n```rust\n#![feature(non_ascii_idents)]\n\nconst ε: f64 = 0.00001f64;\nconst Π: f64 = 3.14f64;\n```\n\n## Changes to the language reference\n\n> **Lexer:** \n> IDENTIFIER : \n>       XID_start XID_continue\\* \n>    | `_` XID_continue+ \n\nAn identifier is any nonempty Unicode string of the following form:\n\nEither\n\n * The first character has property [`XID_start`]\n * The remaining characters have property [`XID_continue`]\n\nOr\n\n * The first character is `_`\n * The identifier is more than one character, `_` alone is not an identifier\n * The remaining characters have property [`XID_continue`]\n\nthat does _not_ occur in the set of [strict keywords].\n\n> **Note**: [`XID_start`] and [`XID_continue`] as character properties cover the\n> character ranges used to form the more familiar C and Java language-family\n> identifiers.\n\n[`XID_start`]: http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AXID_Start%3A%5D&abb=on&g=&i=\n[`XID_continue`]: http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AXID_Continue%3A%5D&abb=on&g=&i=\n[strict keywords]: ../../reference/keywords.md#strict-keywords\n" } , LintCompletion { label : "box_syntax" , description : "# `box_syntax`\n\nThe tracking issue for this feature is: [#49733]\n\n[#49733]: https://github.com/rust-lang/rust/issues/49733\n\nSee also [`box_patterns`](box-patterns.md)\n\n------------------------\n\nCurrently the only stable way to create a `Box` is via the `Box::new` method.\nAlso it is not possible in stable Rust to destructure a `Box` in a match\npattern. The unstable `box` keyword can be used to create a `Box`. An example\nusage would be:\n\n```rust\n#![feature(box_syntax)]\n\nfn main() {\n let b = box 5;\n}\n```\n" } , LintCompletion { label : "no_sanitize" , description : "# `no_sanitize`\n\nThe tracking issue for this feature is: [#39699]\n\n[#39699]: https://github.com/rust-lang/rust/issues/39699\n\n------------------------\n\nThe `no_sanitize` attribute can be used to selectively disable sanitizer\ninstrumentation in an annotated function. This might be useful to: avoid\ninstrumentation overhead in a performance critical function, or avoid\ninstrumenting code that contains constructs unsupported by given sanitizer.\n\nThe precise effect of this annotation depends on particular sanitizer in use.\nFor example, with `no_sanitize(thread)`, the thread sanitizer will no longer\ninstrument non-atomic store / load operations, but it will instrument atomic\noperations to avoid reporting false positives and provide meaning full stack\ntraces.\n\n## Examples\n\n``` rust\n#![feature(no_sanitize)]\n\n#[no_sanitize(address)]\nfn foo() {\n // ...\n}\n```\n" } , LintCompletion { label : "trait_alias" , description : "# `trait_alias`\n\nThe tracking issue for this feature is: [#41517]\n\n[#41517]: https://github.com/rust-lang/rust/issues/41517\n\n------------------------\n\nThe `trait_alias` feature adds support for trait aliases. These allow aliases\nto be created for one or more traits (currently just a single regular trait plus\nany number of auto-traits), and used wherever traits would normally be used as\neither bounds or trait objects.\n\n```rust\n#![feature(trait_alias)]\n\ntrait Foo = std::fmt::Debug + Send;\ntrait Bar = Foo + Sync;\n\n// Use trait alias as bound on type parameter.\nfn foo(v: &T) {\n println!(\"{:?}\", v);\n}\n\npub fn main() {\n foo(&1);\n\n // Use trait alias for trait objects.\n let a: &Bar = &123;\n println!(\"{:?}\", a);\n let b = Box::new(456) as Box;\n println!(\"{:?}\", b);\n}\n```\n" } , LintCompletion { label : "unboxed_closures" , description : "# `unboxed_closures`\n\nThe tracking issue for this feature is [#29625]\n\nSee Also: [`fn_traits`](../library-features/fn-traits.md)\n\n[#29625]: https://github.com/rust-lang/rust/issues/29625\n\n----\n\nThe `unboxed_closures` feature allows you to write functions using the `\"rust-call\"` ABI,\nrequired for implementing the [`Fn*`] family of traits. `\"rust-call\"` functions must have \nexactly one (non self) argument, a tuple representing the argument list.\n\n[`Fn*`]: https://doc.rust-lang.org/std/ops/trait.Fn.html\n\n```rust\n#![feature(unboxed_closures)]\n\nextern \"rust-call\" fn add_args(args: (u32, u32)) -> u32 {\n args.0 + args.1\n}\n\nfn main() {}\n```\n" } , LintCompletion { label : "lang_items" , description : "# `lang_items`\n\nThe tracking issue for this feature is: None.\n\n------------------------\n\nThe `rustc` compiler has certain pluggable operations, that is,\nfunctionality that isn't hard-coded into the language, but is\nimplemented in libraries, with a special marker to tell the compiler\nit exists. The marker is the attribute `#[lang = \"...\"]` and there are\nvarious different values of `...`, i.e. various different 'lang\nitems'.\n\nFor example, `Box` pointers require two lang items, one for allocation\nand one for deallocation. A freestanding program that uses the `Box`\nsugar for dynamic allocations via `malloc` and `free`:\n\n```rust,ignore\n#![feature(lang_items, box_syntax, start, libc, core_intrinsics)]\n#![no_std]\nuse core::intrinsics;\nuse core::panic::PanicInfo;\n\nextern crate libc;\n\n#[lang = \"owned_box\"]\npub struct Box(*mut T);\n\n#[lang = \"exchange_malloc\"]\nunsafe fn allocate(size: usize, _align: usize) -> *mut u8 {\n let p = libc::malloc(size as libc::size_t) as *mut u8;\n\n // Check if `malloc` failed:\n if p as usize == 0 {\n intrinsics::abort();\n }\n\n p\n}\n\n#[lang = \"box_free\"]\nunsafe fn box_free(ptr: *mut T) {\n libc::free(ptr as *mut libc::c_void)\n}\n\n#[start]\nfn main(_argc: isize, _argv: *const *const u8) -> isize {\n let _x = box 1;\n\n 0\n}\n\n#[lang = \"eh_personality\"] extern fn rust_eh_personality() {}\n#[lang = \"panic_impl\"] extern fn rust_begin_panic(info: &PanicInfo) -> ! { unsafe { intrinsics::abort() } }\n#[no_mangle] pub extern fn rust_eh_register_frames () {}\n#[no_mangle] pub extern fn rust_eh_unregister_frames () {}\n```\n\nNote the use of `abort`: the `exchange_malloc` lang item is assumed to\nreturn a valid pointer, and so needs to do the check internally.\n\nOther features provided by lang items include:\n\n- overloadable operators via traits: the traits corresponding to the\n `==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all\n marked with lang items; those specific four are `eq`, `ord`,\n `deref`, and `add` respectively.\n- stack unwinding and general failure; the `eh_personality`,\n `panic` and `panic_bounds_checks` lang items.\n- the traits in `std::marker` used to indicate types of\n various kinds; lang items `send`, `sync` and `copy`.\n- the marker types and variance indicators found in\n `std::marker`; lang items `covariant_type`,\n `contravariant_lifetime`, etc.\n\nLang items are loaded lazily by the compiler; e.g. if one never uses\n`Box` then there is no need to define functions for `exchange_malloc`\nand `box_free`. `rustc` will emit an error when an item is needed\nbut not found in the current crate or any that it depends on.\n\nMost lang items are defined by `libcore`, but if you're trying to build\nan executable without the standard library, you'll run into the need\nfor lang items. The rest of this page focuses on this use-case, even though\nlang items are a bit broader than that.\n\n### Using libc\n\nIn order to build a `#[no_std]` executable we will need libc as a dependency.\nWe can specify this using our `Cargo.toml` file:\n\n```toml\n[dependencies]\nlibc = { version = \"0.2.14\", default-features = false }\n```\n\nNote that the default features have been disabled. This is a critical step -\n**the default features of libc include the standard library and so must be\ndisabled.**\n\n### Writing an executable without stdlib\n\nControlling the entry point is possible in two ways: the `#[start]` attribute,\nor overriding the default shim for the C `main` function with your own.\n\nThe function marked `#[start]` is passed the command line parameters\nin the same format as C:\n\n```rust,ignore\n#![feature(lang_items, core_intrinsics)]\n#![feature(start)]\n#![no_std]\nuse core::intrinsics;\nuse core::panic::PanicInfo;\n\n// Pull in the system libc library for what crt0.o likely requires.\nextern crate libc;\n\n// Entry point for this program.\n#[start]\nfn start(_argc: isize, _argv: *const *const u8) -> isize {\n 0\n}\n\n// These functions are used by the compiler, but not\n// for a bare-bones hello world. These are normally\n// provided by libstd.\n#[lang = \"eh_personality\"]\n#[no_mangle]\npub extern fn rust_eh_personality() {\n}\n\n#[lang = \"panic_impl\"]\n#[no_mangle]\npub extern fn rust_begin_panic(info: &PanicInfo) -> ! {\n unsafe { intrinsics::abort() }\n}\n```\n\nTo override the compiler-inserted `main` shim, one has to disable it\nwith `#![no_main]` and then create the appropriate symbol with the\ncorrect ABI and the correct name, which requires overriding the\ncompiler's name mangling too:\n\n```rust,ignore\n#![feature(lang_items, core_intrinsics)]\n#![feature(start)]\n#![no_std]\n#![no_main]\nuse core::intrinsics;\nuse core::panic::PanicInfo;\n\n// Pull in the system libc library for what crt0.o likely requires.\nextern crate libc;\n\n// Entry point for this program.\n#[no_mangle] // ensure that this symbol is called `main` in the output\npub extern fn main(_argc: i32, _argv: *const *const u8) -> i32 {\n 0\n}\n\n// These functions are used by the compiler, but not\n// for a bare-bones hello world. These are normally\n// provided by libstd.\n#[lang = \"eh_personality\"]\n#[no_mangle]\npub extern fn rust_eh_personality() {\n}\n\n#[lang = \"panic_impl\"]\n#[no_mangle]\npub extern fn rust_begin_panic(info: &PanicInfo) -> ! {\n unsafe { intrinsics::abort() }\n}\n```\n\nIn many cases, you may need to manually link to the `compiler_builtins` crate\nwhen building a `no_std` binary. You may observe this via linker error messages\nsuch as \"```undefined reference to `__rust_probestack'```\".\n\n## More about the language items\n\nThe compiler currently makes a few assumptions about symbols which are\navailable in the executable to call. Normally these functions are provided by\nthe standard library, but without it you must define your own. These symbols\nare called \"language items\", and they each have an internal name, and then a\nsignature that an implementation must conform to.\n\nThe first of these functions, `rust_eh_personality`, is used by the failure\nmechanisms of the compiler. This is often mapped to GCC's personality function\n(see the [libstd implementation][unwind] for more information), but crates\nwhich do not trigger a panic can be assured that this function is never\ncalled. The language item's name is `eh_personality`.\n\n[unwind]: https://github.com/rust-lang/rust/blob/master/src/libpanic_unwind/gcc.rs\n\nThe second function, `rust_begin_panic`, is also used by the failure mechanisms of the\ncompiler. When a panic happens, this controls the message that's displayed on\nthe screen. While the language item's name is `panic_impl`, the symbol name is\n`rust_begin_panic`.\n\nFinally, a `eh_catch_typeinfo` static is needed for certain targets which\nimplement Rust panics on top of C++ exceptions.\n\n## List of all language items\n\nThis is a list of all language items in Rust along with where they are located in\nthe source code.\n\n- Primitives\n - `i8`: `libcore/num/mod.rs`\n - `i16`: `libcore/num/mod.rs`\n - `i32`: `libcore/num/mod.rs`\n - `i64`: `libcore/num/mod.rs`\n - `i128`: `libcore/num/mod.rs`\n - `isize`: `libcore/num/mod.rs`\n - `u8`: `libcore/num/mod.rs`\n - `u16`: `libcore/num/mod.rs`\n - `u32`: `libcore/num/mod.rs`\n - `u64`: `libcore/num/mod.rs`\n - `u128`: `libcore/num/mod.rs`\n - `usize`: `libcore/num/mod.rs`\n - `f32`: `libstd/f32.rs`\n - `f64`: `libstd/f64.rs`\n - `char`: `libcore/char.rs`\n - `slice`: `liballoc/slice.rs`\n - `str`: `liballoc/str.rs`\n - `const_ptr`: `libcore/ptr.rs`\n - `mut_ptr`: `libcore/ptr.rs`\n - `unsafe_cell`: `libcore/cell.rs`\n- Runtime\n - `start`: `libstd/rt.rs`\n - `eh_personality`: `libpanic_unwind/emcc.rs` (EMCC)\n - `eh_personality`: `libpanic_unwind/gcc.rs` (GNU)\n - `eh_personality`: `libpanic_unwind/seh.rs` (SEH)\n - `eh_catch_typeinfo`: `libpanic_unwind/emcc.rs` (EMCC)\n - `panic`: `libcore/panicking.rs`\n - `panic_bounds_check`: `libcore/panicking.rs`\n - `panic_impl`: `libcore/panicking.rs`\n - `panic_impl`: `libstd/panicking.rs`\n- Allocations\n - `owned_box`: `liballoc/boxed.rs`\n - `exchange_malloc`: `liballoc/heap.rs`\n - `box_free`: `liballoc/heap.rs`\n- Operands\n - `not`: `libcore/ops/bit.rs`\n - `bitand`: `libcore/ops/bit.rs`\n - `bitor`: `libcore/ops/bit.rs`\n - `bitxor`: `libcore/ops/bit.rs`\n - `shl`: `libcore/ops/bit.rs`\n - `shr`: `libcore/ops/bit.rs`\n - `bitand_assign`: `libcore/ops/bit.rs`\n - `bitor_assign`: `libcore/ops/bit.rs`\n - `bitxor_assign`: `libcore/ops/bit.rs`\n - `shl_assign`: `libcore/ops/bit.rs`\n - `shr_assign`: `libcore/ops/bit.rs`\n - `deref`: `libcore/ops/deref.rs`\n - `deref_mut`: `libcore/ops/deref.rs`\n - `index`: `libcore/ops/index.rs`\n - `index_mut`: `libcore/ops/index.rs`\n - `add`: `libcore/ops/arith.rs`\n - `sub`: `libcore/ops/arith.rs`\n - `mul`: `libcore/ops/arith.rs`\n - `div`: `libcore/ops/arith.rs`\n - `rem`: `libcore/ops/arith.rs`\n - `neg`: `libcore/ops/arith.rs`\n - `add_assign`: `libcore/ops/arith.rs`\n - `sub_assign`: `libcore/ops/arith.rs`\n - `mul_assign`: `libcore/ops/arith.rs`\n - `div_assign`: `libcore/ops/arith.rs`\n - `rem_assign`: `libcore/ops/arith.rs`\n - `eq`: `libcore/cmp.rs`\n - `ord`: `libcore/cmp.rs`\n- Functions\n - `fn`: `libcore/ops/function.rs`\n - `fn_mut`: `libcore/ops/function.rs`\n - `fn_once`: `libcore/ops/function.rs`\n - `generator_state`: `libcore/ops/generator.rs`\n - `generator`: `libcore/ops/generator.rs`\n- Other\n - `coerce_unsized`: `libcore/ops/unsize.rs`\n - `drop`: `libcore/ops/drop.rs`\n - `drop_in_place`: `libcore/ptr.rs`\n - `clone`: `libcore/clone.rs`\n - `copy`: `libcore/marker.rs`\n - `send`: `libcore/marker.rs`\n - `sized`: `libcore/marker.rs`\n - `unsize`: `libcore/marker.rs`\n - `sync`: `libcore/marker.rs`\n - `phantom_data`: `libcore/marker.rs`\n - `discriminant_kind`: `libcore/marker.rs`\n - `freeze`: `libcore/marker.rs`\n - `debug_trait`: `libcore/fmt/mod.rs`\n - `non_zero`: `libcore/nonzero.rs`\n - `arc`: `liballoc/sync.rs`\n - `rc`: `liballoc/rc.rs`\n" } , LintCompletion { label : "negative_impls" , description : "# `negative_impls`\n\nThe tracking issue for this feature is [#68318].\n\n[#68318]: https://github.com/rust-lang/rust/issues/68318\n\n----\n\nWith the feature gate `negative_impls`, you can write negative impls as well as positive ones:\n\n```rust\n#![feature(negative_impls)]\ntrait DerefMut { }\nimpl !DerefMut for &T { }\n```\n\nNegative impls indicate a semver guarantee that the given trait will not be implemented for the given types. Negative impls play an additional purpose for auto traits, described below.\n\nNegative impls have the following characteristics:\n\n* They do not have any items.\n* They must obey the orphan rules as if they were a positive impl.\n* They cannot \"overlap\" with any positive impls.\n\n## Semver interaction\n\nIt is a breaking change to remove a negative impl. Negative impls are a commitment not to implement the given trait for the named types.\n\n## Orphan and overlap rules\n\nNegative impls must obey the same orphan rules as a positive impl. This implies you cannot add a negative impl for types defined in upstream crates and so forth.\n\nSimilarly, negative impls cannot overlap with positive impls, again using the same \"overlap\" check that we ordinarily use to determine if two impls overlap. (Note that positive impls typically cannot overlap with one another either, except as permitted by specialization.)\n\n## Interaction with auto traits\n\nDeclaring a negative impl `impl !SomeAutoTrait for SomeType` for an\nauto-trait serves two purposes:\n\n* as with any trait, it declares that `SomeType` will never implement `SomeAutoTrait`;\n* it disables the automatic `SomeType: SomeAutoTrait` impl that would otherwise have been generated.\n\nNote that, at present, there is no way to indicate that a given type\ndoes not implement an auto trait *but that it may do so in the\nfuture*. For ordinary types, this is done by simply not declaring any\nimpl at all, but that is not an option for auto traits. A workaround\nis that one could embed a marker type as one of the fields, where the\nmarker type is `!AutoTrait`.\n\n## Immediate uses\n\nNegative impls are used to declare that `&T: !DerefMut` and `&mut T: !Clone`, as required to fix the soundness of `Pin` described in [#66544](https://github.com/rust-lang/rust/issues/66544).\n\nThis serves two purposes:\n\n* For proving the correctness of unsafe code, we can use that impl as evidence that no `DerefMut` or `Clone` impl exists.\n* It prevents downstream crates from creating such impls.\n" } , LintCompletion { label : "abi_ptx" , description : "# `abi_ptx`\n\nThe tracking issue for this feature is: [#38788]\n\n[#38788]: https://github.com/rust-lang/rust/issues/38788\n\n------------------------\n\nWhen emitting PTX code, all vanilla Rust functions (`fn`) get translated to\n\"device\" functions. These functions are *not* callable from the host via the\nCUDA API so a crate with only device functions is not too useful!\n\nOTOH, \"global\" functions *can* be called by the host; you can think of them\nas the real public API of your crate. To produce a global function use the\n`\"ptx-kernel\"` ABI.\n\n\n\n``` rust,ignore\n#![feature(abi_ptx)]\n#![no_std]\n\npub unsafe extern \"ptx-kernel\" fn global_function() {\n device_function();\n}\n\npub fn device_function() {\n // ..\n}\n```\n\n``` text\n$ xargo rustc --target nvptx64-nvidia-cuda --release -- --emit=asm\n\n$ cat $(find -name '*.s')\n//\n// Generated by LLVM NVPTX Back-End\n//\n\n.version 3.2\n.target sm_20\n.address_size 64\n\n // .globl _ZN6kernel15global_function17h46111ebe6516b382E\n\n.visible .entry _ZN6kernel15global_function17h46111ebe6516b382E()\n{\n\n\n ret;\n}\n\n // .globl _ZN6kernel15device_function17hd6a0e4993bbf3f78E\n.visible .func _ZN6kernel15device_function17hd6a0e4993bbf3f78E()\n{\n\n\n ret;\n}\n```\n" } , LintCompletion { label : "try_blocks" , description : "# `try_blocks`\n\nThe tracking issue for this feature is: [#31436]\n\n[#31436]: https://github.com/rust-lang/rust/issues/31436\n\n------------------------\n\nThe `try_blocks` feature adds support for `try` blocks. A `try`\nblock creates a new scope one can use the `?` operator in.\n\n```rust,edition2018\n#![feature(try_blocks)]\n\nuse std::num::ParseIntError;\n\nlet result: Result = try {\n \"1\".parse::()?\n + \"2\".parse::()?\n + \"3\".parse::()?\n};\nassert_eq!(result, Ok(6));\n\nlet result: Result = try {\n \"1\".parse::()?\n + \"foo\".parse::()?\n + \"3\".parse::()?\n};\nassert!(result.is_err());\n```\n" } , LintCompletion { label : "profiler_runtime" , description : "# `profiler_runtime`\n\nThe tracking issue for this feature is: [#42524](https://github.com/rust-lang/rust/issues/42524).\n\n------------------------\n" } , LintCompletion { label : "compiler_builtins" , description : "# `compiler_builtins`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "doc_spotlight" , description : "# `doc_spotlight`\n\nThe tracking issue for this feature is: [#45040]\n\nThe `doc_spotlight` feature allows the use of the `spotlight` parameter to the `#[doc]` attribute,\nto \"spotlight\" a specific trait on the return values of functions. Adding a `#[doc(spotlight)]`\nattribute to a trait definition will make rustdoc print extra information for functions which return\na type that implements that trait. This attribute is applied to the `Iterator`, `io::Read`, and\n`io::Write` traits in the standard library.\n\nYou can do this on your own traits, like this:\n\n```\n#![feature(doc_spotlight)]\n\n#[doc(spotlight)]\npub trait MyTrait {}\n\npub struct MyStruct;\nimpl MyTrait for MyStruct {}\n\n/// The docs for this function will have an extra line about `MyStruct` implementing `MyTrait`,\n/// without having to write that yourself!\npub fn my_fn() -> MyStruct { MyStruct }\n```\n\nThis feature was originally implemented in PR [#45039].\n\n[#45040]: https://github.com/rust-lang/rust/issues/45040\n[#45039]: https://github.com/rust-lang/rust/pull/45039\n" } , LintCompletion { label : "box_patterns" , description : "# `box_patterns`\n\nThe tracking issue for this feature is: [#29641]\n\n[#29641]: https://github.com/rust-lang/rust/issues/29641\n\nSee also [`box_syntax`](box-syntax.md)\n\n------------------------\n\nBox patterns let you match on `Box`s:\n\n\n```rust\n#![feature(box_patterns)]\n\nfn main() {\n let b = Some(Box::new(5));\n match b {\n Some(box n) if n < 0 => {\n println!(\"Box contains negative number {}\", n);\n },\n Some(box n) if n >= 0 => {\n println!(\"Box contains non-negative number {}\", n);\n },\n None => {\n println!(\"No box\");\n },\n _ => unreachable!()\n }\n}\n```\n" } , LintCompletion { label : "const_eval_limit" , description : "# `const_eval_limit`\n\nThe tracking issue for this feature is: [#67217]\n\n[#67217]: https://github.com/rust-lang/rust/issues/67217\n\nThe `const_eval_limit` allows someone to limit the evaluation steps the CTFE undertakes to evaluate a `const fn`.\n" } , LintCompletion { label : "arbitrary_enum_discriminant" , description : "# `arbitrary_enum_discriminant`\n\nThe tracking issue for this feature is: [#60553]\n\n[#60553]: https://github.com/rust-lang/rust/issues/60553\n\n------------------------\n\nThe `arbitrary_enum_discriminant` feature permits tuple-like and\nstruct-like enum variants with `#[repr()]` to have explicit discriminants.\n\n## Examples\n\n```rust\n#![feature(arbitrary_enum_discriminant)]\n\n#[allow(dead_code)]\n#[repr(u8)]\nenum Enum {\n Unit = 3,\n Tuple(u16) = 2,\n Struct {\n a: u8,\n b: u16,\n } = 1,\n}\n\nimpl Enum {\n fn tag(&self) -> u8 {\n unsafe { *(self as *const Self as *const u8) }\n }\n}\n\nassert_eq!(3, Enum::Unit.tag());\nassert_eq!(2, Enum::Tuple(5).tag());\nassert_eq!(1, Enum::Struct{a: 7, b: 11}.tag());\n```\n" } , LintCompletion { label : "custom_test_frameworks" , description : "# `custom_test_frameworks`\n\nThe tracking issue for this feature is: [#50297]\n\n[#50297]: https://github.com/rust-lang/rust/issues/50297\n\n------------------------\n\nThe `custom_test_frameworks` feature allows the use of `#[test_case]` and `#![test_runner]`.\nAny function, const, or static can be annotated with `#[test_case]` causing it to be aggregated (like `#[test]`)\nand be passed to the test runner determined by the `#![test_runner]` crate attribute.\n\n```rust\n#![feature(custom_test_frameworks)]\n#![test_runner(my_runner)]\n\nfn my_runner(tests: &[&i32]) {\n for t in tests {\n if **t == 0 {\n println!(\"PASSED\");\n } else {\n println!(\"FAILED\");\n }\n }\n}\n\n#[test_case]\nconst WILL_PASS: i32 = 0;\n\n#[test_case]\nconst WILL_FAIL: i32 = 4;\n```\n\n" } , LintCompletion { label : "plugin_registrar" , description : "# `plugin_registrar`\n\nThe tracking issue for this feature is: [#29597]\n\n[#29597]: https://github.com/rust-lang/rust/issues/29597\n\nThis feature is part of \"compiler plugins.\" It will often be used with the\n[`plugin`] and `rustc_private` features as well. For more details, see\ntheir docs.\n\n[`plugin`]: plugin.md\n\n------------------------\n" } , LintCompletion { label : "impl_trait_in_bindings" , description : "# `impl_trait_in_bindings`\n\nThe tracking issue for this feature is: [#63065]\n\n[#63065]: https://github.com/rust-lang/rust/issues/63065\n\n------------------------\n\nThe `impl_trait_in_bindings` feature gate lets you use `impl Trait` syntax in\n`let`, `static`, and `const` bindings.\n\nA simple example is:\n\n```rust\n#![feature(impl_trait_in_bindings)]\n\nuse std::fmt::Debug;\n\nfn main() {\n let a: impl Debug + Clone = 42;\n let b = a.clone();\n println!(\"{:?}\", b); // prints `42`\n}\n```\n\nNote however that because the types of `a` and `b` are opaque in the above\nexample, calling inherent methods or methods outside of the specified traits\n(e.g., `a.abs()` or `b.abs()`) is not allowed, and yields an error.\n" } , LintCompletion { label : "ffi_pure" , description : "# `ffi_pure`\n\nThe `#[ffi_pure]` attribute applies clang's `pure` attribute to foreign\nfunctions declarations.\n\nThat is, `#[ffi_pure]` functions shall have no effects except for its return\nvalue, which shall not change across two consecutive function calls with\nthe same parameters.\n\nApplying the `#[ffi_pure]` attribute to a function that violates these\nrequirements is undefined behavior.\n\nThis attribute enables Rust to perform common optimizations, like sub-expression\nelimination and loop optimizations. Some common examples of pure functions are\n`strlen` or `memcmp`.\n\nThese optimizations are only applicable when the compiler can prove that no\nprogram state observable by the `#[ffi_pure]` function has changed between calls\nof the function, which could alter the result. See also the `#[ffi_const]`\nattribute, which provides stronger guarantees regarding the allowable behavior\nof a function, enabling further optimization.\n\n## Pitfalls\n\nA `#[ffi_pure]` function can read global memory through the function\nparameters (e.g. pointers), globals, etc. `#[ffi_pure]` functions are not\nreferentially-transparent, and are therefore more relaxed than `#[ffi_const]`\nfunctions.\n\nHowever, accesing global memory through volatile or atomic reads can violate the\nrequirement that two consecutive function calls shall return the same value.\n\nA `pure` function that returns unit has no effect on the abstract machine's\nstate.\n\nA `#[ffi_pure]` function must not diverge, neither via a side effect (e.g. a\ncall to `abort`) nor by infinite loops.\n\nWhen translating C headers to Rust FFI, it is worth verifying for which targets\nthe `pure` attribute is enabled in those headers, and using the appropriate\n`cfg` macros in the Rust side to match those definitions. While the semantics of\n`pure` are implemented identically by many C and C++ compilers, e.g., clang,\n[GCC], [ARM C/C++ compiler], [IBM ILE C/C++], etc. they are not necessarily\nimplemented in this way on all of them. It is therefore also worth verifying\nthat the semantics of the C toolchain used to compile the binary being linked\nagainst are compatible with those of the `#[ffi_pure]`.\n\n\n[ARM C/C++ compiler]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/Cacigdac.html\n[GCC]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-pure-function-attribute\n[IBM ILE C/C++]: https://www.ibm.com/support/knowledgecenter/fr/ssw_ibm_i_71/rzarg/fn_attrib_pure.htm\n" } , LintCompletion { label : "const_fn" , description : "# `const_fn`\n\nThe tracking issue for this feature is: [#57563]\n\n[#57563]: https://github.com/rust-lang/rust/issues/57563\n\n------------------------\n\nThe `const_fn` feature allows marking free functions and inherent methods as\n`const`, enabling them to be called in constants contexts, with constant\narguments.\n\n## Examples\n\n```rust\n#![feature(const_fn)]\n\nconst fn double(x: i32) -> i32 {\n x * 2\n}\n\nconst FIVE: i32 = 5;\nconst TEN: i32 = double(FIVE);\n\nfn main() {\n assert_eq!(5, FIVE);\n assert_eq!(10, TEN);\n}\n```\n" } , LintCompletion { label : "intrinsics" , description : "# `intrinsics`\n\nThe tracking issue for this feature is: None.\n\nIntrinsics are never intended to be stable directly, but intrinsics are often\nexported in some sort of stable manner. Prefer using the stable interfaces to\nthe intrinsic directly when you can.\n\n------------------------\n\n\nThese are imported as if they were FFI functions, with the special\n`rust-intrinsic` ABI. For example, if one was in a freestanding\ncontext, but wished to be able to `transmute` between types, and\nperform efficient pointer arithmetic, one would import those functions\nvia a declaration like\n\n```rust\n#![feature(intrinsics)]\n# fn main() {}\n\nextern \"rust-intrinsic\" {\n fn transmute(x: T) -> U;\n\n fn offset(dst: *const T, offset: isize) -> *const T;\n}\n```\n\nAs with any other FFI functions, these are always `unsafe` to call.\n\n" } , LintCompletion { label : "c_variadic" , description : "# `c_variadic`\n\nThe tracking issue for this feature is: [#44930]\n\n[#44930]: https://github.com/rust-lang/rust/issues/44930\n\n------------------------\n\nThe `c_variadic` language feature enables C-variadic functions to be\ndefined in Rust. The may be called both from within Rust and via FFI.\n\n## Examples\n\n```rust\n#![feature(c_variadic)]\n\npub unsafe extern \"C\" fn add(n: usize, mut args: ...) -> usize {\n let mut sum = 0;\n for _ in 0..n {\n sum += args.arg::();\n }\n sum\n}\n```\n" } , LintCompletion { label : "cfg_sanitize" , description : "# `cfg_sanitize`\n\nThe tracking issue for this feature is: [#39699]\n\n[#39699]: https://github.com/rust-lang/rust/issues/39699\n\n------------------------\n\nThe `cfg_sanitize` feature makes it possible to execute different code\ndepending on whether a particular sanitizer is enabled or not.\n\n## Examples\n\n```rust\n#![feature(cfg_sanitize)]\n\n#[cfg(sanitize = \"thread\")]\nfn a() {\n // ...\n}\n\n#[cfg(not(sanitize = \"thread\"))]\nfn a() {\n // ...\n}\n\nfn b() {\n if cfg!(sanitize = \"leak\") {\n // ...\n } else {\n // ...\n }\n}\n```\n" } , LintCompletion { label : "allocator_internals" , description : "# `allocator_internals`\n\nThis feature does not have a tracking issue, it is an unstable implementation\ndetail of the `global_allocator` feature not intended for use outside the\ncompiler.\n\n------------------------\n" } , LintCompletion { label : "doc_alias" , description : "# `doc_alias`\n\nThe tracking issue for this feature is: [#50146]\n\n[#50146]: https://github.com/rust-lang/rust/issues/50146\n\n------------------------\n\nYou can add alias(es) to an item when using the `rustdoc` search through the\n`doc(alias)` attribute. Example:\n\n```rust,no_run\n#![feature(doc_alias)]\n\n#[doc(alias = \"x\")]\n#[doc(alias = \"big\")]\npub struct BigX;\n```\n\nThen, when looking for it through the `rustdoc` search, if you enter \"x\" or\n\"big\", search will show the `BigX` struct first.\n\nNote that this feature is currently hidden behind the `feature(doc_alias)` gate.\n" } , LintCompletion { label : "link_cfg" , description : "# `link_cfg`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "transparent_unions" , description : "# `transparent_unions`\n\nThe tracking issue for this feature is [#60405]\n\n[#60405]: https://github.com/rust-lang/rust/issues/60405\n\n----\n\nThe `transparent_unions` feature allows you mark `union`s as\n`#[repr(transparent)]`. A `union` may be `#[repr(transparent)]` in exactly the\nsame conditions in which a `struct` may be `#[repr(transparent)]` (generally,\nthis means the `union` must have exactly one non-zero-sized field). Some\nconcrete illustrations follow.\n\n```rust\n#![feature(transparent_unions)]\n\n// This union has the same representation as `f32`.\n#[repr(transparent)]\nunion SingleFieldUnion {\n field: f32,\n}\n\n// This union has the same representation as `usize`.\n#[repr(transparent)]\nunion MultiFieldUnion {\n field: usize,\n nothing: (),\n}\n```\n\nFor consistency with transparent `struct`s, `union`s must have exactly one\nnon-zero-sized field. If all fields are zero-sized, the `union` must not be\n`#[repr(transparent)]`:\n\n```rust\n#![feature(transparent_unions)]\n\n// This (non-transparent) union is already valid in stable Rust:\npub union GoodUnion {\n pub nothing: (),\n}\n\n// Error: transparent union needs exactly one non-zero-sized field, but has 0\n// #[repr(transparent)]\n// pub union BadUnion {\n// pub nothing: (),\n// }\n```\n\nThe one exception is if the `union` is generic over `T` and has a field of type\n`T`, it may be `#[repr(transparent)]` even if `T` is a zero-sized type:\n\n```rust\n#![feature(transparent_unions)]\n\n// This union has the same representation as `T`.\n#[repr(transparent)]\npub union GenericUnion { // Unions with non-`Copy` fields are unstable.\n pub field: T,\n pub nothing: (),\n}\n\n// This is okay even though `()` is a zero-sized type.\npub const THIS_IS_OKAY: GenericUnion<()> = GenericUnion { field: () };\n```\n\nLike transarent `struct`s, a transparent `union` of type `U` has the same\nlayout, size, and ABI as its single non-ZST field. If it is generic over a type\n`T`, and all its fields are ZSTs except for exactly one field of type `T`, then\nit has the same layout and ABI as `T` (even if `T` is a ZST when monomorphized).\n\nLike transparent `struct`s, transparent `union`s are FFI-safe if and only if\ntheir underlying representation type is also FFI-safe.\n\nA `union` may not be eligible for the same nonnull-style optimizations that a\n`struct` or `enum` (with the same fields) are eligible for. Adding\n`#[repr(transparent)]` to `union` does not change this. To give a more concrete\nexample, it is unspecified whether `size_of::()` is equal to\n`size_of::>()`, where `T` is a `union` (regardless of whether or not\nit is transparent). The Rust compiler is free to perform this optimization if\npossible, but is not required to, and different compiler versions may differ in\ntheir application of these optimizations.\n" } , LintCompletion { label : "plugin" , description : "# `plugin`\n\nThe tracking issue for this feature is: [#29597]\n\n[#29597]: https://github.com/rust-lang/rust/issues/29597\n\n\nThis feature is part of \"compiler plugins.\" It will often be used with the\n[`plugin_registrar`] and `rustc_private` features.\n\n[`plugin_registrar`]: plugin-registrar.md\n\n------------------------\n\n`rustc` can load compiler plugins, which are user-provided libraries that\nextend the compiler's behavior with new lint checks, etc.\n\nA plugin is a dynamic library crate with a designated *registrar* function that\nregisters extensions with `rustc`. Other crates can load these extensions using\nthe crate attribute `#![plugin(...)]`. See the\n`rustc_driver::plugin` documentation for more about the\nmechanics of defining and loading a plugin.\n\nIn the vast majority of cases, a plugin should *only* be used through\n`#![plugin]` and not through an `extern crate` item. Linking a plugin would\npull in all of librustc_ast and librustc as dependencies of your crate. This is\ngenerally unwanted unless you are building another plugin.\n\nThe usual practice is to put compiler plugins in their own crate, separate from\nany `macro_rules!` macros or ordinary Rust code meant to be used by consumers\nof a library.\n\n# Lint plugins\n\nPlugins can extend [Rust's lint\ninfrastructure](../../reference/attributes/diagnostics.md#lint-check-attributes) with\nadditional checks for code style, safety, etc. Now let's write a plugin\n[`lint-plugin-test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs)\nthat warns about any item named `lintme`.\n\n```rust,ignore\n#![feature(plugin_registrar)]\n#![feature(box_syntax, rustc_private)]\n\nextern crate rustc_ast;\n\n// Load rustc as a plugin to get macros\nextern crate rustc_driver;\n#[macro_use]\nextern crate rustc_lint;\n#[macro_use]\nextern crate rustc_session;\n\nuse rustc_driver::plugin::Registry;\nuse rustc_lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};\nuse rustc_ast::ast;\ndeclare_lint!(TEST_LINT, Warn, \"Warn about items named 'lintme'\");\n\ndeclare_lint_pass!(Pass => [TEST_LINT]);\n\nimpl EarlyLintPass for Pass {\n fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) {\n if it.ident.name.as_str() == \"lintme\" {\n cx.lint(TEST_LINT, |lint| {\n lint.build(\"item is named 'lintme'\").set_span(it.span).emit()\n });\n }\n }\n}\n\n#[plugin_registrar]\npub fn plugin_registrar(reg: &mut Registry) {\n reg.lint_store.register_lints(&[&TEST_LINT]);\n reg.lint_store.register_early_pass(|| box Pass);\n}\n```\n\nThen code like\n\n```rust,ignore\n#![feature(plugin)]\n#![plugin(lint_plugin_test)]\n\nfn lintme() { }\n```\n\nwill produce a compiler warning:\n\n```txt\nfoo.rs:4:1: 4:16 warning: item is named 'lintme', #[warn(test_lint)] on by default\nfoo.rs:4 fn lintme() { }\n ^~~~~~~~~~~~~~~\n```\n\nThe components of a lint plugin are:\n\n* one or more `declare_lint!` invocations, which define static `Lint` structs;\n\n* a struct holding any state needed by the lint pass (here, none);\n\n* a `LintPass`\n implementation defining how to check each syntax element. A single\n `LintPass` may call `span_lint` for several different `Lint`s, but should\n register them all through the `get_lints` method.\n\nLint passes are syntax traversals, but they run at a late stage of compilation\nwhere type information is available. `rustc`'s [built-in\nlints](https://github.com/rust-lang/rust/blob/master/src/librustc_session/lint/builtin.rs)\nmostly use the same infrastructure as lint plugins, and provide examples of how\nto access type information.\n\nLints defined by plugins are controlled by the usual [attributes and compiler\nflags](../../reference/attributes/diagnostics.md#lint-check-attributes), e.g.\n`#[allow(test_lint)]` or `-A test-lint`. These identifiers are derived from the\nfirst argument to `declare_lint!`, with appropriate case and punctuation\nconversion.\n\nYou can run `rustc -W help foo.rs` to see a list of lints known to `rustc`,\nincluding those provided by plugins loaded by `foo.rs`.\n" } , LintCompletion { label : "concat_idents" , description : "# `concat_idents`\n\nThe tracking issue for this feature is: [#29599]\n\n[#29599]: https://github.com/rust-lang/rust/issues/29599\n\n------------------------\n\nThe `concat_idents` feature adds a macro for concatenating multiple identifiers\ninto one identifier.\n\n## Examples\n\n```rust\n#![feature(concat_idents)]\n\nfn main() {\n fn foobar() -> u32 { 23 }\n let f = concat_idents!(foo, bar);\n assert_eq!(f(), 23);\n}\n```" } , LintCompletion { label : "update_panic_count" , description : "# `update_panic_count`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "fn_traits" , description : "# `fn_traits`\n\nThe tracking issue for this feature is [#29625]\n\nSee Also: [`unboxed_closures`](../language-features/unboxed-closures.md)\n\n[#29625]: https://github.com/rust-lang/rust/issues/29625\n\n----\n\nThe `fn_traits` feature allows for implementation of the [`Fn*`] traits\nfor creating custom closure-like types.\n\n[`Fn*`]: https://doc.rust-lang.org/std/ops/trait.Fn.html\n\n```rust\n#![feature(unboxed_closures)]\n#![feature(fn_traits)]\n\nstruct Adder {\n a: u32\n}\n\nimpl FnOnce<(u32, )> for Adder {\n type Output = u32;\n extern \"rust-call\" fn call_once(self, b: (u32, )) -> Self::Output {\n self.a + b.0\n }\n}\n\nfn main() {\n let adder = Adder { a: 3 };\n assert_eq!(adder(2), 5);\n}\n```\n" } , LintCompletion { label : "try_trait" , description : "# `try_trait`\n\nThe tracking issue for this feature is: [#42327]\n\n[#42327]: https://github.com/rust-lang/rust/issues/42327\n\n------------------------\n\nThis introduces a new trait `Try` for extending the `?` operator to types\nother than `Result` (a part of [RFC 1859]). The trait provides the canonical\nway to _view_ a type in terms of a success/failure dichotomy. This will\nallow `?` to supplant the `try_opt!` macro on `Option` and the `try_ready!`\nmacro on `Poll`, among other things.\n\n[RFC 1859]: https://github.com/rust-lang/rfcs/pull/1859\n\nHere's an example implementation of the trait:\n\n```rust,ignore\n/// A distinct type to represent the `None` value of an `Option`.\n///\n/// This enables using the `?` operator on `Option`; it's rarely useful alone.\n#[derive(Debug)]\n#[unstable(feature = \"try_trait\", issue = \"42327\")]\npub struct None { _priv: () }\n\n#[unstable(feature = \"try_trait\", issue = \"42327\")]\nimpl ops::Try for Option {\n type Ok = T;\n type Error = None;\n\n fn into_result(self) -> Result {\n self.ok_or(None { _priv: () })\n }\n\n fn from_ok(v: T) -> Self {\n Some(v)\n }\n\n fn from_error(_: None) -> Self {\n None\n }\n}\n```\n\nNote the `Error` associated type here is a new marker. The `?` operator\nallows interconversion between different `Try` implementers only when\nthe error type can be converted `Into` the error type of the enclosing\nfunction (or catch block). Having a distinct error type (as opposed to\njust `()`, or similar) restricts this to where it's semantically meaningful.\n" } , LintCompletion { label : "rt" , description : "# `rt`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "default_free_fn" , description : "# `default_free_fn`\n\nThe tracking issue for this feature is: [#73014]\n\n[#73014]: https://github.com/rust-lang/rust/issues/73014\n\n------------------------\n\nAdds a free `default()` function to the `std::default` module. This function\njust forwards to [`Default::default()`], but may remove repetition of the word\n\"default\" from the call site.\n\nHere is an example:\n\n```rust\n#![feature(default_free_fn)]\nuse std::default::default;\n\n#[derive(Default)]\nstruct AppConfig {\n foo: FooConfig,\n bar: BarConfig,\n}\n\n#[derive(Default)]\nstruct FooConfig {\n foo: i32,\n}\n\n#[derive(Default)]\nstruct BarConfig {\n bar: f32,\n baz: u8,\n}\n\nfn main() {\n let options = AppConfig {\n foo: default(),\n bar: BarConfig {\n bar: 10.1,\n ..default()\n },\n };\n}\n```\n" } , LintCompletion { label : "libstd_sys_internals" , description : "# `libstd_sys_internals`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "fd" , description : "# `fd`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "dec2flt" , description : "# `dec2flt`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "fmt_internals" , description : "# `fmt_internals`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "int_error_internals" , description : "# `int_error_internals`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "libstd_thread_internals" , description : "# `libstd_thread_internals`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "windows_net" , description : "# `windows_net`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "core_intrinsics" , description : "# `core_intrinsics`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "global_asm" , description : "# `global_asm`\n\nThe tracking issue for this feature is: [#35119]\n\n[#35119]: https://github.com/rust-lang/rust/issues/35119\n\n------------------------\n\nThe `global_asm!` macro allows the programmer to write arbitrary\nassembly outside the scope of a function body, passing it through\n`rustc` and `llvm` to the assembler. The macro is a no-frills\ninterface to LLVM's concept of [module-level inline assembly]. That is,\nall caveats applicable to LLVM's module-level inline assembly apply\nto `global_asm!`.\n\n[module-level inline assembly]: http://llvm.org/docs/LangRef.html#module-level-inline-assembly\n\n`global_asm!` fills a role not currently satisfied by either `asm!`\nor `#[naked]` functions. The programmer has _all_ features of the\nassembler at their disposal. The linker will expect to resolve any\nsymbols defined in the inline assembly, modulo any symbols marked as\nexternal. It also means syntax for directives and assembly follow the\nconventions of the assembler in your toolchain.\n\nA simple usage looks like this:\n\n```rust,ignore\n# #![feature(global_asm)]\n# you also need relevant target_arch cfgs\nglobal_asm!(include_str!(\"something_neato.s\"));\n```\n\nAnd a more complicated usage looks like this:\n\n```rust,ignore\n# #![feature(global_asm)]\n# #![cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\n\npub mod sally {\n global_asm!(r#\"\n .global foo\n foo:\n jmp baz\n \"#);\n\n #[no_mangle]\n pub unsafe extern \"C\" fn baz() {}\n}\n\n// the symbols `foo` and `bar` are global, no matter where\n// `global_asm!` was used.\nextern \"C\" {\n fn foo();\n fn bar();\n}\n\npub mod harry {\n global_asm!(r#\"\n .global bar\n bar:\n jmp quux\n \"#);\n\n #[no_mangle]\n pub unsafe extern \"C\" fn quux() {}\n}\n```\n\nYou may use `global_asm!` multiple times, anywhere in your crate, in\nwhatever way suits you. The effect is as if you concatenated all\nusages and placed the larger, single usage in the crate root.\n\n------------------------\n\nIf you don't need quite as much power and flexibility as\n`global_asm!` provides, and you don't mind restricting your inline\nassembly to `fn` bodies only, you might try the\n[asm](asm.md) feature instead.\n" } , LintCompletion { label : "sort_internals" , description : "# `sort_internals`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "test" , description : "# `test`\n\nThe tracking issue for this feature is: None.\n\n------------------------\n\nThe internals of the `test` crate are unstable, behind the `test` flag. The\nmost widely used part of the `test` crate are benchmark tests, which can test\nthe performance of your code. Let's make our `src/lib.rs` look like this\n(comments elided):\n\n```rust,ignore\n#![feature(test)]\n\nextern crate test;\n\npub fn add_two(a: i32) -> i32 {\n a + 2\n}\n\n#[cfg(test)]\nmod tests {\n use super::*;\n use test::Bencher;\n\n #[test]\n fn it_works() {\n assert_eq!(4, add_two(2));\n }\n\n #[bench]\n fn bench_add_two(b: &mut Bencher) {\n b.iter(|| add_two(2));\n }\n}\n```\n\nNote the `test` feature gate, which enables this unstable feature.\n\nWe've imported the `test` crate, which contains our benchmarking support.\nWe have a new function as well, with the `bench` attribute. Unlike regular\ntests, which take no arguments, benchmark tests take a `&mut Bencher`. This\n`Bencher` provides an `iter` method, which takes a closure. This closure\ncontains the code we'd like to benchmark.\n\nWe can run benchmark tests with `cargo bench`:\n\n```bash\n$ cargo bench\n Compiling adder v0.0.1 (file:///home/steve/tmp/adder)\n Running target/release/adder-91b3e234d4ed382a\n\nrunning 2 tests\ntest tests::it_works ... ignored\ntest tests::bench_add_two ... bench: 1 ns/iter (+/- 0)\n\ntest result: ok. 0 passed; 0 failed; 1 ignored; 1 measured\n```\n\nOur non-benchmark test was ignored. You may have noticed that `cargo bench`\ntakes a bit longer than `cargo test`. This is because Rust runs our benchmark\na number of times, and then takes the average. Because we're doing so little\nwork in this example, we have a `1 ns/iter (+/- 0)`, but this would show\nthe variance if there was one.\n\nAdvice on writing benchmarks:\n\n\n* Move setup code outside the `iter` loop; only put the part you want to measure inside\n* Make the code do \"the same thing\" on each iteration; do not accumulate or change state\n* Make the outer function idempotent too; the benchmark runner is likely to run\n it many times\n* Make the inner `iter` loop short and fast so benchmark runs are fast and the\n calibrator can adjust the run-length at fine resolution\n* Make the code in the `iter` loop do something simple, to assist in pinpointing\n performance improvements (or regressions)\n\n## Gotcha: optimizations\n\nThere's another tricky part to writing benchmarks: benchmarks compiled with\noptimizations activated can be dramatically changed by the optimizer so that\nthe benchmark is no longer benchmarking what one expects. For example, the\ncompiler might recognize that some calculation has no external effects and\nremove it entirely.\n\n```rust,ignore\n#![feature(test)]\n\nextern crate test;\nuse test::Bencher;\n\n#[bench]\nfn bench_xor_1000_ints(b: &mut Bencher) {\n b.iter(|| {\n (0..1000).fold(0, |old, new| old ^ new);\n });\n}\n```\n\ngives the following results\n\n```text\nrunning 1 test\ntest bench_xor_1000_ints ... bench: 0 ns/iter (+/- 0)\n\ntest result: ok. 0 passed; 0 failed; 0 ignored; 1 measured\n```\n\nThe benchmarking runner offers two ways to avoid this. Either, the closure that\nthe `iter` method receives can return an arbitrary value which forces the\noptimizer to consider the result used and ensures it cannot remove the\ncomputation entirely. This could be done for the example above by adjusting the\n`b.iter` call to\n\n```rust\n# struct X;\n# impl X { fn iter(&self, _: F) where F: FnMut() -> T {} } let b = X;\nb.iter(|| {\n // Note lack of `;` (could also use an explicit `return`).\n (0..1000).fold(0, |old, new| old ^ new)\n});\n```\n\nOr, the other option is to call the generic `test::black_box` function, which\nis an opaque \"black box\" to the optimizer and so forces it to consider any\nargument as used.\n\n```rust\n#![feature(test)]\n\nextern crate test;\n\n# fn main() {\n# struct X;\n# impl X { fn iter(&self, _: F) where F: FnMut() -> T {} } let b = X;\nb.iter(|| {\n let n = test::black_box(1000);\n\n (0..n).fold(0, |a, b| a ^ b)\n})\n# }\n```\n\nNeither of these read or modify the value, and are very cheap for small values.\nLarger values can be passed indirectly to reduce overhead (e.g.\n`black_box(&huge_struct)`).\n\nPerforming either of the above changes gives the following benchmarking results\n\n```text\nrunning 1 test\ntest bench_xor_1000_ints ... bench: 131 ns/iter (+/- 3)\n\ntest result: ok. 0 passed; 0 failed; 0 ignored; 1 measured\n```\n\nHowever, the optimizer can still modify a testcase in an undesirable manner\neven when using either of the above.\n" } , LintCompletion { label : "windows_stdio" , description : "# `windows_stdio`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "allocator_api" , description : "# `allocator_api`\n\nThe tracking issue for this feature is [#32838]\n\n[#32838]: https://github.com/rust-lang/rust/issues/32838\n\n------------------------\n\nSometimes you want the memory for one collection to use a different\nallocator than the memory for another collection. In this case,\nreplacing the global allocator is not a workable option. Instead,\nyou need to pass in an instance of an `AllocRef` to each collection\nfor which you want a custom allocator.\n\nTBD\n" } , LintCompletion { label : "asm" , description : "# `asm`\n\nThe tracking issue for this feature is: [#72016]\n\n[#72016]: https://github.com/rust-lang/rust/issues/72016\n\n------------------------\n\nFor extremely low-level manipulations and performance reasons, one\nmight wish to control the CPU directly. Rust supports using inline\nassembly to do this via the `asm!` macro.\n\n# Guide-level explanation\n[guide-level-explanation]: #guide-level-explanation\n\nRust provides support for inline assembly via the `asm!` macro.\nIt can be used to embed handwritten assembly in the assembly output generated by the compiler.\nGenerally this should not be necessary, but might be where the required performance or timing\ncannot be otherwise achieved. Accessing low level hardware primitives, e.g. in kernel code, may also demand this functionality.\n\n> **Note**: the examples here are given in x86/x86-64 assembly, but ARM, AArch64 and RISC-V are also supported.\n\n## Basic usage\n\nLet us start with the simplest possible example:\n\n```rust,allow_fail\n# #![feature(asm)]\nunsafe {\n asm!(\"nop\");\n}\n```\n\nThis will insert a NOP (no operation) instruction into the assembly generated by the compiler.\nNote that all `asm!` invocations have to be inside an `unsafe` block, as they could insert\narbitrary instructions and break various invariants. The instructions to be inserted are listed\nin the first argument of the `asm!` macro as a string literal.\n\n## Inputs and outputs\n\nNow inserting an instruction that does nothing is rather boring. Let us do something that\nactually acts on data:\n\n```rust,allow_fail\n# #![feature(asm)]\nlet x: u64;\nunsafe {\n asm!(\"mov {}, 5\", out(reg) x);\n}\nassert_eq!(x, 5);\n```\n\nThis will write the value `5` into the `u64` variable `x`.\nYou can see that the string literal we use to specify instructions is actually a template string.\nIt is governed by the same rules as Rust [format strings][format-syntax].\nThe arguments that are inserted into the template however look a bit different then you may\nbe familiar with. First we need to specify if the variable is an input or an output of the\ninline assembly. In this case it is an output. We declared this by writing `out`.\nWe also need to specify in what kind of register the assembly expects the variable.\nIn this case we put it in an arbitrary general purpose register by specifying `reg`.\nThe compiler will choose an appropriate register to insert into\nthe template and will read the variable from there after the inline assembly finishes executing.\n\nLet us see another example that also uses an input:\n\n```rust,allow_fail\n# #![feature(asm)]\nlet i: u64 = 3;\nlet o: u64;\nunsafe {\n asm!(\n \"mov {0}, {1}\",\n \"add {0}, {number}\",\n out(reg) o,\n in(reg) i,\n number = const 5,\n );\n}\nassert_eq!(o, 8);\n```\n\nThis will add `5` to the input in variable `i` and write the result to variable `o`.\nThe particular way this assembly does this is first copying the value from `i` to the output,\nand then adding `5` to it.\n\nThe example shows a few things:\n\nFirst, we can see that `asm!` allows multiple template string arguments; each\none is treated as a separate line of assembly code, as if they were all joined\ntogether with newlines between them. This makes it easy to format assembly\ncode.\n\nSecond, we can see that inputs are declared by writing `in` instead of `out`.\n\nThird, one of our operands has a type we haven't seen yet, `const`.\nThis tells the compiler to expand this argument to value directly inside the assembly template.\nThis is only possible for constants and literals.\n\nFourth, we can see that we can specify an argument number, or name as in any format string.\nFor inline assembly templates this is particularly useful as arguments are often used more than once.\nFor more complex inline assembly using this facility is generally recommended, as it improves\nreadability, and allows reordering instructions without changing the argument order.\n\nWe can further refine the above example to avoid the `mov` instruction:\n\n```rust,allow_fail\n# #![feature(asm)]\nlet mut x: u64 = 3;\nunsafe {\n asm!(\"add {0}, {number}\", inout(reg) x, number = const 5);\n}\nassert_eq!(x, 8);\n```\n\nWe can see that `inout` is used to specify an argument that is both input and output.\nThis is different from specifying an input and output separately in that it is guaranteed to assign both to the same register.\n\nIt is also possible to specify different variables for the input and output parts of an `inout` operand:\n\n```rust,allow_fail\n# #![feature(asm)]\nlet x: u64 = 3;\nlet y: u64;\nunsafe {\n asm!(\"add {0}, {number}\", inout(reg) x => y, number = const 5);\n}\nassert_eq!(y, 8);\n```\n\n## Late output operands\n\nThe Rust compiler is conservative with its allocation of operands. It is assumed that an `out`\ncan be written at any time, and can therefore not share its location with any other argument.\nHowever, to guarantee optimal performance it is important to use as few registers as possible,\nso they won't have to be saved and reloaded around the inline assembly block.\nTo achieve this Rust provides a `lateout` specifier. This can be used on any output that is\nwritten only after all inputs have been consumed.\nThere is also a `inlateout` variant of this specifier.\n\nHere is an example where `inlateout` *cannot* be used:\n\n```rust,allow_fail\n# #![feature(asm)]\nlet mut a: u64 = 4;\nlet b: u64 = 4;\nlet c: u64 = 4;\nunsafe {\n asm!(\n \"add {0}, {1}\",\n \"add {0}, {2}\",\n inout(reg) a,\n in(reg) b,\n in(reg) c,\n );\n}\nassert_eq!(a, 12);\n```\n\nHere the compiler is free to allocate the same register for inputs `b` and `c` since it knows they have the same value. However it must allocate a separate register for `a` since it uses `inout` and not `inlateout`. If `inlateout` was used, then `a` and `c` could be allocated to the same register, in which case the first instruction to overwrite the value of `c` and cause the assembly code to produce the wrong result.\n\nHowever the following example can use `inlateout` since the output is only modified after all input registers have been read:\n\n```rust,allow_fail\n# #![feature(asm)]\nlet mut a: u64 = 4;\nlet b: u64 = 4;\nunsafe {\n asm!(\"add {0}, {1}\", inlateout(reg) a, in(reg) b);\n}\nassert_eq!(a, 8);\n```\n\nAs you can see, this assembly fragment will still work correctly if `a` and `b` are assigned to the same register.\n\n## Explicit register operands\n\nSome instructions require that the operands be in a specific register.\nTherefore, Rust inline assembly provides some more specific constraint specifiers.\nWhile `reg` is generally available on any architecture, these are highly architecture specific. E.g. for x86 the general purpose registers `eax`, `ebx`, `ecx`, `edx`, `ebp`, `esi`, and `edi`\namong others can be addressed by their name.\n\n```rust,allow_fail,no_run\n# #![feature(asm)]\nlet cmd = 0xd1;\nunsafe {\n asm!(\"out 0x64, eax\", in(\"eax\") cmd);\n}\n```\n\nIn this example we call the `out` instruction to output the content of the `cmd` variable\nto port `0x64`. Since the `out` instruction only accepts `eax` (and its sub registers) as operand\nwe had to use the `eax` constraint specifier.\n\nNote that unlike other operand types, explicit register operands cannot be used in the template string: you can't use `{}` and should write the register name directly instead. Also, they must appear at the end of the operand list after all other operand types.\n\nConsider this example which uses the x86 `mul` instruction:\n\n```rust,allow_fail\n# #![feature(asm)]\nfn mul(a: u64, b: u64) -> u128 {\n let lo: u64;\n let hi: u64;\n\n unsafe {\n asm!(\n // The x86 mul instruction takes rax as an implicit input and writes\n // the 128-bit result of the multiplication to rax:rdx.\n \"mul {}\",\n in(reg) a,\n inlateout(\"rax\") b => lo,\n lateout(\"rdx\") hi\n );\n }\n\n ((hi as u128) << 64) + lo as u128\n}\n```\n\nThis uses the `mul` instruction to multiply two 64-bit inputs with a 128-bit result.\nThe only explicit operand is a register, that we fill from the variable `a`.\nThe second operand is implicit, and must be the `rax` register, which we fill from the variable `b`.\nThe lower 64 bits of the result are stored in `rax` from which we fill the variable `lo`.\nThe higher 64 bits are stored in `rdx` from which we fill the variable `hi`.\n\n## Clobbered registers\n\nIn many cases inline assembly will modify state that is not needed as an output.\nUsually this is either because we have to use a scratch register in the assembly,\nor instructions modify state that we don't need to further examine.\nThis state is generally referred to as being \"clobbered\".\nWe need to tell the compiler about this since it may need to save and restore this state\naround the inline assembly block.\n\n```rust,allow_fail\n# #![feature(asm)]\nlet ebx: u32;\nlet ecx: u32;\n\nunsafe {\n asm!(\n \"cpuid\",\n // EAX 4 selects the \"Deterministic Cache Parameters\" CPUID leaf\n inout(\"eax\") 4 => _,\n // ECX 0 selects the L0 cache information.\n inout(\"ecx\") 0 => ecx,\n lateout(\"ebx\") ebx,\n lateout(\"edx\") _,\n );\n}\n\nprintln!(\n \"L1 Cache: {}\",\n ((ebx >> 22) + 1) * (((ebx >> 12) & 0x3ff) + 1) * ((ebx & 0xfff) + 1) * (ecx + 1)\n);\n```\n\nIn the example above we use the `cpuid` instruction to get the L1 cache size.\nThis instruction writes to `eax`, `ebx`, `ecx`, and `edx`, but for the cache size we only care about the contents of `ebx` and `ecx`.\n\nHowever we still need to tell the compiler that `eax` and `edx` have been modified so that it can save any values that were in these registers before the asm. This is done by declaring these as outputs but with `_` instead of a variable name, which indicates that the output value is to be discarded.\n\nThis can also be used with a general register class (e.g. `reg`) to obtain a scratch register for use inside the asm code:\n\n```rust,allow_fail\n# #![feature(asm)]\n// Multiply x by 6 using shifts and adds\nlet mut x: u64 = 4;\nunsafe {\n asm!(\n \"mov {tmp}, {x}\",\n \"shl {tmp}, 1\",\n \"shl {x}, 2\",\n \"add {x}, {tmp}\",\n x = inout(reg) x,\n tmp = out(reg) _,\n );\n}\nassert_eq!(x, 4 * 6);\n```\n\n## Symbol operands\n\nA special operand type, `sym`, allows you to use the symbol name of a `fn` or `static` in inline assembly code.\nThis allows you to call a function or access a global variable without needing to keep its address in a register.\n\n```rust,allow_fail\n# #![feature(asm)]\nextern \"C\" fn foo(arg: i32) {\n println!(\"arg = {}\", arg);\n}\n\nfn call_foo(arg: i32) {\n unsafe {\n asm!(\n \"call {}\",\n sym foo,\n // 1st argument in rdi, which is caller-saved\n inout(\"rdi\") arg => _,\n // All caller-saved registers must be marked as clobberred\n out(\"rax\") _, out(\"rcx\") _, out(\"rdx\") _, out(\"rsi\") _,\n out(\"r8\") _, out(\"r9\") _, out(\"r10\") _, out(\"r11\") _,\n out(\"xmm0\") _, out(\"xmm1\") _, out(\"xmm2\") _, out(\"xmm3\") _,\n out(\"xmm4\") _, out(\"xmm5\") _, out(\"xmm6\") _, out(\"xmm7\") _,\n out(\"xmm8\") _, out(\"xmm9\") _, out(\"xmm10\") _, out(\"xmm11\") _,\n out(\"xmm12\") _, out(\"xmm13\") _, out(\"xmm14\") _, out(\"xmm15\") _,\n )\n }\n}\n```\n\nNote that the `fn` or `static` item does not need to be public or `#[no_mangle]`:\nthe compiler will automatically insert the appropriate mangled symbol name into the assembly code.\n\n## Register template modifiers\n\nIn some cases, fine control is needed over the way a register name is formatted when inserted into the template string. This is needed when an architecture's assembly language has several names for the same register, each typically being a \"view\" over a subset of the register (e.g. the low 32 bits of a 64-bit register).\n\nBy default the compiler will always choose the name that refers to the full register size (e.g. `rax` on x86-64, `eax` on x86, etc).\n\nThis default can be overriden by using modifiers on the template string operands, just like you would with format strings:\n\n```rust,allow_fail\n# #![feature(asm)]\nlet mut x: u16 = 0xab;\n\nunsafe {\n asm!(\"mov {0:h}, {0:l}\", inout(reg_abcd) x);\n}\n\nassert_eq!(x, 0xabab);\n```\n\nIn this example, we use the `reg_abcd` register class to restrict the register allocator to the 4 legacy x86 register (`ax`, `bx`, `cx`, `dx`) of which the first two bytes can be addressed independently.\n\nLet us assume that the register allocator has chosen to allocate `x` in the `ax` register.\nThe `h` modifier will emit the register name for the high byte of that register and the `l` modifier will emit the register name for the low byte. The asm code will therefore be expanded as `mov ah, al` which copies the low byte of the value into the high byte.\n\nIf you use a smaller data type (e.g. `u16`) with an operand and forget the use template modifiers, the compiler will emit a warning and suggest the correct modifier to use.\n\n## Options\n\nBy default, an inline assembly block is treated the same way as an external FFI function call with a custom calling convention: it may read/write memory, have observable side effects, etc. However in many cases, it is desirable to give the compiler more information about what the assembly code is actually doing so that it can optimize better.\n\nLet's take our previous example of an `add` instruction:\n\n```rust,allow_fail\n# #![feature(asm)]\nlet mut a: u64 = 4;\nlet b: u64 = 4;\nunsafe {\n asm!(\n \"add {0}, {1}\",\n inlateout(reg) a, in(reg) b,\n options(pure, nomem, nostack),\n );\n}\nassert_eq!(a, 8);\n```\n\nOptions can be provided as an optional final argument to the `asm!` macro. We specified three options here:\n- `pure` means that the asm code has no observable side effects and that its output depends only on its inputs. This allows the compiler optimizer to call the inline asm fewer times or even eliminate it entirely.\n- `nomem` means that the asm code does not read or write to memory. By default the compiler will assume that inline assembly can read or write any memory address that is accessible to it (e.g. through a pointer passed as an operand, or a global).\n- `nostack` means that the asm code does not push any data onto the stack. This allows the compiler to use optimizations such as the stack red zone on x86-64 to avoid stack pointer adjustments.\n\nThese allow the compiler to better optimize code using `asm!`, for example by eliminating pure `asm!` blocks whose outputs are not needed.\n\nSee the reference for the full list of available options and their effects.\n\n# Reference-level explanation\n[reference-level-explanation]: #reference-level-explanation\n\nInline assembler is implemented as an unsafe macro `asm!()`.\nThe first argument to this macro is a template string literal used to build the final assembly.\nThe following arguments specify input and output operands.\nWhen required, options are specified as the final argument.\n\nThe following ABNF specifies the general syntax:\n\n```ignore\ndir_spec := \"in\" / \"out\" / \"lateout\" / \"inout\" / \"inlateout\"\nreg_spec := / \"\"\noperand_expr := expr / \"_\" / expr \"=>\" expr / expr \"=>\" \"_\"\nreg_operand := dir_spec \"(\" reg_spec \")\" operand_expr\noperand := reg_operand / \"const\" const_expr / \"sym\" path\noption := \"pure\" / \"nomem\" / \"readonly\" / \"preserves_flags\" / \"noreturn\" / \"att_syntax\"\noptions := \"options(\" option *[\",\" option] [\",\"] \")\"\nasm := \"asm!(\" format_string *(\",\" format_string) *(\",\" [ident \"=\"] operand) [\",\" options] [\",\"] \")\"\n```\n\nThe macro will initially be supported only on ARM, AArch64, Hexagon, x86, x86-64 and RISC-V targets. Support for more targets may be added in the future. The compiler will emit an error if `asm!` is used on an unsupported target.\n\n[format-syntax]: https://doc.rust-lang.org/std/fmt/#syntax\n\n## Template string arguments\n\nThe assembler template uses the same syntax as [format strings][format-syntax] (i.e. placeholders are specified by curly braces). The corresponding arguments are accessed in order, by index, or by name. However, implicit named arguments (introduced by [RFC #2795][rfc-2795]) are not supported.\n\nAn `asm!` invocation may have one or more template string arguments; an `asm!` with multiple template string arguments is treated as if all the strings were concatenated with a `\\n` between them. The expected usage is for each template string argument to correspond to a line of assembly code. All template string arguments must appear before any other arguments.\n\nAs with format strings, named arguments must appear after positional arguments. Explicit register operands must appear at the end of the operand list, after named arguments if any.\n\nExplicit register operands cannot be used by placeholders in the template string. All other named and positional operands must appear at least once in the template string, otherwise a compiler error is generated.\n\nThe exact assembly code syntax is target-specific and opaque to the compiler except for the way operands are substituted into the template string to form the code passed to the assembler.\n\nThe 5 targets specified in this RFC (x86, ARM, AArch64, RISC-V, Hexagon) all use the assembly code syntax of the GNU assembler (GAS). On x86, the `.intel_syntax noprefix` mode of GAS is used by default. On ARM, the `.syntax unified` mode is used. These targets impose an additional restriction on the assembly code: any assembler state (e.g. the current section which can be changed with `.section`) must be restored to its original value at the end of the asm string. Assembly code that does not conform to the GAS syntax will result in assembler-specific behavior.\n\n[rfc-2795]: https://github.com/rust-lang/rfcs/pull/2795\n\n## Operand type\n\nSeveral types of operands are supported:\n\n* `in() `\n - `` can refer to a register class or an explicit register. The allocated register name is substituted into the asm template string.\n - The allocated register will contain the value of `` at the start of the asm code.\n - The allocated register must contain the same value at the end of the asm code (except if a `lateout` is allocated to the same register).\n* `out() `\n - `` can refer to a register class or an explicit register. The allocated register name is substituted into the asm template string.\n - The allocated register will contain an undefined value at the start of the asm code.\n - `` must be a (possibly uninitialized) place expression, to which the contents of the allocated register is written to at the end of the asm code.\n - An underscore (`_`) may be specified instead of an expression, which will cause the contents of the register to be discarded at the end of the asm code (effectively acting as a clobber).\n* `lateout() `\n - Identical to `out` except that the register allocator can reuse a register allocated to an `in`.\n - You should only write to the register after all inputs are read, otherwise you may clobber an input.\n* `inout() `\n - `` can refer to a register class or an explicit register. The allocated register name is substituted into the asm template string.\n - The allocated register will contain the value of `` at the start of the asm code.\n - `` must be a mutable initialized place expression, to which the contents of the allocated register is written to at the end of the asm code.\n* `inout() => `\n - Same as `inout` except that the initial value of the register is taken from the value of ``.\n - `` must be a (possibly uninitialized) place expression, to which the contents of the allocated register is written to at the end of the asm code.\n - An underscore (`_`) may be specified instead of an expression for ``, which will cause the contents of the register to be discarded at the end of the asm code (effectively acting as a clobber).\n - `` and `` may have different types.\n* `inlateout() ` / `inlateout() => `\n - Identical to `inout` except that the register allocator can reuse a register allocated to an `in` (this can happen if the compiler knows the `in` has the same initial value as the `inlateout`).\n - You should only write to the register after all inputs are read, otherwise you may clobber an input.\n* `const `\n - `` must be an integer or floating-point constant expression.\n - The value of the expression is formatted as a string and substituted directly into the asm template string.\n* `sym `\n - `` must refer to a `fn` or `static`.\n - A mangled symbol name referring to the item is substituted into the asm template string.\n - The substituted string does not include any modifiers (e.g. GOT, PLT, relocations, etc).\n - `` is allowed to point to a `#[thread_local]` static, in which case the asm code can combine the symbol with relocations (e.g. `@plt`, `@TPOFF`) to read from thread-local data.\n\nOperand expressions are evaluated from left to right, just like function call arguments. After the `asm!` has executed, outputs are written to in left to right order. This is significant if two outputs point to the same place: that place will contain the value of the rightmost output.\n\n## Register operands\n\nInput and output operands can be specified either as an explicit register or as a register class from which the register allocator can select a register. Explicit registers are specified as string literals (e.g. `\"eax\"`) while register classes are specified as identifiers (e.g. `reg`). Using string literals for register names enables support for architectures that use special characters in register names, such as MIPS (`$0`, `$1`, etc).\n\nNote that explicit registers treat register aliases (e.g. `r14` vs `lr` on ARM) and smaller views of a register (e.g. `eax` vs `rax`) as equivalent to the base register. It is a compile-time error to use the same explicit register for two input operands or two output operands. Additionally, it is also a compile-time error to use overlapping registers (e.g. ARM VFP) in input operands or in output operands.\n\nOnly the following types are allowed as operands for inline assembly:\n- Integers (signed and unsigned)\n- Floating-point numbers\n- Pointers (thin only)\n- Function pointers\n- SIMD vectors (structs defined with `#[repr(simd)]` and which implement `Copy`). This includes architecture-specific vector types defined in `std::arch` such as `__m128` (x86) or `int8x16_t` (ARM).\n\nHere is the list of currently supported register classes:\n\n| Architecture | Register class | Registers | LLVM constraint code |\n| ------------ | -------------- | --------- | -------------------- |\n| x86 | `reg` | `ax`, `bx`, `cx`, `dx`, `si`, `di`, `r[8-15]` (x86-64 only) | `r` |\n| x86 | `reg_abcd` | `ax`, `bx`, `cx`, `dx` | `Q` |\n| x86-32 | `reg_byte` | `al`, `bl`, `cl`, `dl`, `ah`, `bh`, `ch`, `dh` | `q` |\n| x86-64 | `reg_byte` | `al`, `bl`, `cl`, `dl`, `sil`, `dil`, `r[8-15]b`, `ah`\\*, `bh`\\*, `ch`\\*, `dh`\\* | `q` |\n| x86 | `xmm_reg` | `xmm[0-7]` (x86) `xmm[0-15]` (x86-64) | `x` |\n| x86 | `ymm_reg` | `ymm[0-7]` (x86) `ymm[0-15]` (x86-64) | `x` |\n| x86 | `zmm_reg` | `zmm[0-7]` (x86) `zmm[0-31]` (x86-64) | `v` |\n| x86 | `kreg` | `k[1-7]` | `Yk` |\n| AArch64 | `reg` | `x[0-28]`, `x30` | `r` |\n| AArch64 | `vreg` | `v[0-31]` | `w` |\n| AArch64 | `vreg_low16` | `v[0-15]` | `x` |\n| ARM | `reg` | `r[0-5]` `r7`\\*, `r[8-10]`, `r11`\\*, `r12`, `r14` | `r` |\n| ARM (Thumb) | `reg_thumb` | `r[0-r7]` | `l` |\n| ARM (ARM) | `reg_thumb` | `r[0-r10]`, `r12`, `r14` | `l` |\n| ARM | `sreg` | `s[0-31]` | `t` |\n| ARM | `sreg_low16` | `s[0-15]` | `x` |\n| ARM | `dreg` | `d[0-31]` | `w` |\n| ARM | `dreg_low16` | `d[0-15]` | `t` |\n| ARM | `dreg_low8` | `d[0-8]` | `x` |\n| ARM | `qreg` | `q[0-15]` | `w` |\n| ARM | `qreg_low8` | `q[0-7]` | `t` |\n| ARM | `qreg_low4` | `q[0-3]` | `x` |\n| NVPTX | `reg16` | None\\* | `h` |\n| NVPTX | `reg32` | None\\* | `r` |\n| NVPTX | `reg64` | None\\* | `l` |\n| RISC-V | `reg` | `x1`, `x[5-7]`, `x[9-15]`, `x[16-31]` (non-RV32E) | `r` |\n| RISC-V | `freg` | `f[0-31]` | `f` |\n| Hexagon | `reg` | `r[0-28]` | `r` |\n\n> **Note**: On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register.\n>\n> Note #2: On x86-64 the high byte registers (e.g. `ah`) are only available when used as an explicit register. Specifying the `reg_byte` register class for an operand will always allocate a low byte register.\n>\n> Note #3: NVPTX doesn't have a fixed register set, so named registers are not supported.\n>\n> Note #4: On ARM the frame pointer is either `r7` or `r11` depending on the platform.\n\nAdditional register classes may be added in the future based on demand (e.g. MMX, x87, etc).\n\nEach register class has constraints on which value types they can be used with. This is necessary because the way a value is loaded into a register depends on its type. For example, on big-endian systems, loading a `i32x4` and a `i8x16` into a SIMD register may result in different register contents even if the byte-wise memory representation of both values is identical. The availability of supported types for a particular register class may depend on what target features are currently enabled.\n\n| Architecture | Register class | Target feature | Allowed types |\n| ------------ | -------------- | -------------- | ------------- |\n| x86-32 | `reg` | None | `i16`, `i32`, `f32` |\n| x86-64 | `reg` | None | `i16`, `i32`, `f32`, `i64`, `f64` |\n| x86 | `reg_byte` | None | `i8` |\n| x86 | `xmm_reg` | `sse` | `i32`, `f32`, `i64`, `f64`,
`i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` |\n| x86 | `ymm_reg` | `avx` | `i32`, `f32`, `i64`, `f64`,
`i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2`
`i8x32`, `i16x16`, `i32x8`, `i64x4`, `f32x8`, `f64x4` |\n| x86 | `zmm_reg` | `avx512f` | `i32`, `f32`, `i64`, `f64`,
`i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2`
`i8x32`, `i16x16`, `i32x8`, `i64x4`, `f32x8`, `f64x4`
`i8x64`, `i16x32`, `i32x16`, `i64x8`, `f32x16`, `f64x8` |\n| x86 | `kreg` | `axv512f` | `i8`, `i16` |\n| x86 | `kreg` | `axv512bw` | `i32`, `i64` |\n| AArch64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |\n| AArch64 | `vreg` | `fp` | `i8`, `i16`, `i32`, `f32`, `i64`, `f64`,
`i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2`, `f64x1`,
`i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` |\n| ARM | `reg` | None | `i8`, `i16`, `i32`, `f32` |\n| ARM | `sreg` | `vfp2` | `i32`, `f32` |\n| ARM | `dreg` | `vfp2` | `i64`, `f64`, `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2` |\n| ARM | `qreg` | `neon` | `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4` |\n| NVPTX | `reg16` | None | `i8`, `i16` |\n| NVPTX | `reg32` | None | `i8`, `i16`, `i32`, `f32` |\n| NVPTX | `reg64` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |\n| RISC-V32 | `reg` | None | `i8`, `i16`, `i32`, `f32` |\n| RISC-V64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |\n| RISC-V | `freg` | `f` | `f32` |\n| RISC-V | `freg` | `d` | `f64` |\n| Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` |\n\n> **Note**: For the purposes of the above table pointers, function pointers and `isize`/`usize` are treated as the equivalent integer type (`i16`/`i32`/`i64` depending on the target).\n\nIf a value is of a smaller size than the register it is allocated in then the upper bits of that register will have an undefined value for inputs and will be ignored for outputs. The only exception is the `freg` register class on RISC-V where `f32` values are NaN-boxed in a `f64` as required by the RISC-V architecture.\n\nWhen separate input and output expressions are specified for an `inout` operand, both expressions must have the same type. The only exception is if both operands are pointers or integers, in which case they are only required to have the same size. This restriction exists because the register allocators in LLVM and GCC sometimes cannot handle tied operands with different types.\n\n## Register names\n\nSome registers have multiple names. These are all treated by the compiler as identical to the base register name. Here is the list of all supported register aliases:\n\n| Architecture | Base register | Aliases |\n| ------------ | ------------- | ------- |\n| x86 | `ax` | `eax`, `rax` |\n| x86 | `bx` | `ebx`, `rbx` |\n| x86 | `cx` | `ecx`, `rcx` |\n| x86 | `dx` | `edx`, `rdx` |\n| x86 | `si` | `esi`, `rsi` |\n| x86 | `di` | `edi`, `rdi` |\n| x86 | `bp` | `bpl`, `ebp`, `rbp` |\n| x86 | `sp` | `spl`, `esp`, `rsp` |\n| x86 | `ip` | `eip`, `rip` |\n| x86 | `st(0)` | `st` |\n| x86 | `r[8-15]` | `r[8-15]b`, `r[8-15]w`, `r[8-15]d` |\n| x86 | `xmm[0-31]` | `ymm[0-31]`, `zmm[0-31]` |\n| AArch64 | `x[0-30]` | `w[0-30]` |\n| AArch64 | `x29` | `fp` |\n| AArch64 | `x30` | `lr` |\n| AArch64 | `sp` | `wsp` |\n| AArch64 | `xzr` | `wzr` |\n| AArch64 | `v[0-31]` | `b[0-31]`, `h[0-31]`, `s[0-31]`, `d[0-31]`, `q[0-31]` |\n| ARM | `r[0-3]` | `a[1-4]` |\n| ARM | `r[4-9]` | `v[1-6]` |\n| ARM | `r9` | `rfp` |\n| ARM | `r10` | `sl` |\n| ARM | `r11` | `fp` |\n| ARM | `r12` | `ip` |\n| ARM | `r13` | `sp` |\n| ARM | `r14` | `lr` |\n| ARM | `r15` | `pc` |\n| RISC-V | `x0` | `zero` |\n| RISC-V | `x1` | `ra` |\n| RISC-V | `x2` | `sp` |\n| RISC-V | `x3` | `gp` |\n| RISC-V | `x4` | `tp` |\n| RISC-V | `x[5-7]` | `t[0-2]` |\n| RISC-V | `x8` | `fp`, `s0` |\n| RISC-V | `x9` | `s1` |\n| RISC-V | `x[10-17]` | `a[0-7]` |\n| RISC-V | `x[18-27]` | `s[2-11]` |\n| RISC-V | `x[28-31]` | `t[3-6]` |\n| RISC-V | `f[0-7]` | `ft[0-7]` |\n| RISC-V | `f[8-9]` | `fs[0-1]` |\n| RISC-V | `f[10-17]` | `fa[0-7]` |\n| RISC-V | `f[18-27]` | `fs[2-11]` |\n| RISC-V | `f[28-31]` | `ft[8-11]` |\n| Hexagon | `r29` | `sp` |\n| Hexagon | `r30` | `fr` |\n| Hexagon | `r31` | `lr` |\n\nSome registers cannot be used for input or output operands:\n\n| Architecture | Unsupported register | Reason |\n| ------------ | -------------------- | ------ |\n| All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. |\n| All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon) | The frame pointer cannot be used as an input or output. |\n| ARM | `r7` or `r11` | On ARM the frame pointer can be either `r7` or `r11` depending on the target. The frame pointer cannot be used as an input or output. |\n| ARM | `r6` | `r6` is used internally by LLVM as a base pointer and therefore cannot be used as an input or output. |\n| x86 | `k0` | This is a constant zero register which can't be modified. |\n| x86 | `ip` | This is the program counter, not a real register. |\n| x86 | `mm[0-7]` | MMX registers are not currently supported (but may be in the future). |\n| x86 | `st([0-7])` | x87 registers are not currently supported (but may be in the future). |\n| AArch64 | `xzr` | This is a constant zero register which can't be modified. |\n| ARM | `pc` | This is the program counter, not a real register. |\n| RISC-V | `x0` | This is a constant zero register which can't be modified. |\n| RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. |\n| Hexagon | `lr` | This is the link register which cannot be used as an input or output. |\n\n## Template modifiers\n\nThe placeholders can be augmented by modifiers which are specified after the `:` in the curly braces. These modifiers do not affect register allocation, but change the way operands are formatted when inserted into the template string. Only one modifier is allowed per template placeholder.\n\nThe supported modifiers are a subset of LLVM's (and GCC's) [asm template argument modifiers][llvm-argmod], but do not use the same letter codes.\n\n| Architecture | Register class | Modifier | Example output | LLVM modifier |\n| ------------ | -------------- | -------- | -------------- | ------------- |\n| x86-32 | `reg` | None | `eax` | `k` |\n| x86-64 | `reg` | None | `rax` | `q` |\n| x86-32 | `reg_abcd` | `l` | `al` | `b` |\n| x86-64 | `reg` | `l` | `al` | `b` |\n| x86 | `reg_abcd` | `h` | `ah` | `h` |\n| x86 | `reg` | `x` | `ax` | `w` |\n| x86 | `reg` | `e` | `eax` | `k` |\n| x86-64 | `reg` | `r` | `rax` | `q` |\n| x86 | `reg_byte` | None | `al` / `ah` | None |\n| x86 | `xmm_reg` | None | `xmm0` | `x` |\n| x86 | `ymm_reg` | None | `ymm0` | `t` |\n| x86 | `zmm_reg` | None | `zmm0` | `g` |\n| x86 | `*mm_reg` | `x` | `xmm0` | `x` |\n| x86 | `*mm_reg` | `y` | `ymm0` | `t` |\n| x86 | `*mm_reg` | `z` | `zmm0` | `g` |\n| x86 | `kreg` | None | `k1` | None |\n| AArch64 | `reg` | None | `x0` | `x` |\n| AArch64 | `reg` | `w` | `w0` | `w` |\n| AArch64 | `reg` | `x` | `x0` | `x` |\n| AArch64 | `vreg` | None | `v0` | None |\n| AArch64 | `vreg` | `v` | `v0` | None |\n| AArch64 | `vreg` | `b` | `b0` | `b` |\n| AArch64 | `vreg` | `h` | `h0` | `h` |\n| AArch64 | `vreg` | `s` | `s0` | `s` |\n| AArch64 | `vreg` | `d` | `d0` | `d` |\n| AArch64 | `vreg` | `q` | `q0` | `q` |\n| ARM | `reg` | None | `r0` | None |\n| ARM | `sreg` | None | `s0` | None |\n| ARM | `dreg` | None | `d0` | `P` |\n| ARM | `qreg` | None | `q0` | `q` |\n| ARM | `qreg` | `e` / `f` | `d0` / `d1` | `e` / `f` |\n| NVPTX | `reg16` | None | `rs0` | None |\n| NVPTX | `reg32` | None | `r0` | None |\n| NVPTX | `reg64` | None | `rd0` | None |\n| RISC-V | `reg` | None | `x1` | None |\n| RISC-V | `freg` | None | `f0` | None |\n| Hexagon | `reg` | None | `r0` | None |\n\n> Notes:\n> - on ARM `e` / `f`: this prints the low or high doubleword register name of a NEON quad (128-bit) register.\n> - on x86: our behavior for `reg` with no modifiers differs from what GCC does. GCC will infer the modifier based on the operand value type, while we default to the full register size.\n> - on x86 `xmm_reg`: the `x`, `t` and `g` LLVM modifiers are not yet implemented in LLVM (they are supported by GCC only), but this should be a simple change.\n\nAs stated in the previous section, passing an input value smaller than the register width will result in the upper bits of the register containing undefined values. This is not a problem if the inline asm only accesses the lower bits of the register, which can be done by using a template modifier to use a subregister name in the asm code (e.g. `ax` instead of `rax`). Since this an easy pitfall, the compiler will suggest a template modifier to use where appropriate given the input type. If all references to an operand already have modifiers then the warning is suppressed for that operand.\n\n[llvm-argmod]: http://llvm.org/docs/LangRef.html#asm-template-argument-modifiers\n\n## Options\n\nFlags are used to further influence the behavior of the inline assembly block.\nCurrently the following options are defined:\n- `pure`: The `asm` block has no side effects, and its outputs depend only on its direct inputs (i.e. the values themselves, not what they point to) or values read from memory (unless the `nomem` options is also set). This allows the compiler to execute the `asm` block fewer times than specified in the program (e.g. by hoisting it out of a loop) or even eliminate it entirely if the outputs are not used.\n- `nomem`: The `asm` blocks does not read or write to any memory. This allows the compiler to cache the values of modified global variables in registers across the `asm` block since it knows that they are not read or written to by the `asm`.\n- `readonly`: The `asm` block does not write to any memory. This allows the compiler to cache the values of unmodified global variables in registers across the `asm` block since it knows that they are not written to by the `asm`.\n- `preserves_flags`: The `asm` block does not modify the flags register (defined in the rules below). This allows the compiler to avoid recomputing the condition flags after the `asm` block.\n- `noreturn`: The `asm` block never returns, and its return type is defined as `!` (never). Behavior is undefined if execution falls through past the end of the asm code. A `noreturn` asm block behaves just like a function which doesn't return; notably, local variables in scope are not dropped before it is invoked.\n- `nostack`: The `asm` block does not push data to the stack, or write to the stack red-zone (if supported by the target). If this option is *not* used then the stack pointer is guaranteed to be suitably aligned (according to the target ABI) for a function call.\n- `att_syntax`: This option is only valid on x86, and causes the assembler to use the `.att_syntax prefix` mode of the GNU assembler. Register operands are substituted in with a leading `%`.\n\nThe compiler performs some additional checks on options:\n- The `nomem` and `readonly` options are mutually exclusive: it is a compile-time error to specify both.\n- The `pure` option must be combined with either the `nomem` or `readonly` options, otherwise a compile-time error is emitted.\n- It is a compile-time error to specify `pure` on an asm block with no outputs or only discarded outputs (`_`).\n- It is a compile-time error to specify `noreturn` on an asm block with outputs.\n\n## Rules for inline assembly\n\n- Any registers not specified as inputs will contain an undefined value on entry to the asm block.\n - An \"undefined value\" in the context of inline assembly means that the register can (non-deterministically) have any one of the possible values allowed by the architecture. Notably it is not the same as an LLVM `undef` which can have a different value every time you read it (since such a concept does not exist in assembly code).\n- Any registers not specified as outputs must have the same value upon exiting the asm block as they had on entry, otherwise behavior is undefined.\n - This only applies to registers which can be specified as an input or output. Other registers follow target-specific rules.\n - Note that a `lateout` may be allocated to the same register as an `in`, in which case this rule does not apply. Code should not rely on this however since it depends on the results of register allocation.\n- Behavior is undefined if execution unwinds out of an asm block.\n - This also applies if the assembly code calls a function which then unwinds.\n- The set of memory locations that assembly code is allowed the read and write are the same as those allowed for an FFI function.\n - Refer to the unsafe code guidelines for the exact rules.\n - If the `readonly` option is set, then only memory reads are allowed.\n - If the `nomem` option is set then no reads or writes to memory are allowed.\n - These rules do not apply to memory which is private to the asm code, such as stack space allocated within the asm block.\n- The compiler cannot assume that the instructions in the asm are the ones that will actually end up executed.\n - This effectively means that the compiler must treat the `asm!` as a black box and only take the interface specification into account, not the instructions themselves.\n - Runtime code patching is allowed, via target-specific mechanisms (outside the scope of this RFC).\n- Unless the `nostack` option is set, asm code is allowed to use stack space below the stack pointer.\n - On entry to the asm block the stack pointer is guaranteed to be suitably aligned (according to the target ABI) for a function call.\n - You are responsible for making sure you don't overflow the stack (e.g. use stack probing to ensure you hit a guard page).\n - You should adjust the stack pointer when allocating stack memory as required by the target ABI.\n - The stack pointer must be restored to its original value before leaving the asm block.\n- If the `noreturn` option is set then behavior is undefined if execution falls through to the end of the asm block.\n- If the `pure` option is set then behavior is undefined if the `asm` has side-effects other than its direct outputs. Behavior is also undefined if two executions of the `asm` code with the same inputs result in different outputs.\n - When used with the `nomem` option, \"inputs\" are just the direct inputs of the `asm!`.\n - When used with the `readonly` option, \"inputs\" comprise the direct inputs of the `asm!` and any memory that the `asm!` block is allowed to read.\n- These flags registers must be restored upon exiting the asm block if the `preserves_flags` option is set:\n - x86\n - Status flags in `EFLAGS` (CF, PF, AF, ZF, SF, OF).\n - Floating-point status word (all).\n - Floating-point exception flags in `MXCSR` (PE, UE, OE, ZE, DE, IE).\n - ARM\n - Condition flags in `CPSR` (N, Z, C, V)\n - Saturation flag in `CPSR` (Q)\n - Greater than or equal flags in `CPSR` (GE).\n - Condition flags in `FPSCR` (N, Z, C, V)\n - Saturation flag in `FPSCR` (QC)\n - Floating-point exception flags in `FPSCR` (IDC, IXC, UFC, OFC, DZC, IOC).\n - AArch64\n - Condition flags (`NZCV` register).\n - Floating-point status (`FPSR` register).\n - RISC-V\n - Floating-point exception flags in `fcsr` (`fflags`).\n- On x86, the direction flag (DF in `EFLAGS`) is clear on entry to an asm block and must be clear on exit.\n - Behavior is undefined if the direction flag is set on exiting an asm block.\n- The requirement of restoring the stack pointer and non-output registers to their original value only applies when exiting an `asm!` block.\n - This means that `asm!` blocks that never return (even if not marked `noreturn`) don't need to preserve these registers.\n - When returning to a different `asm!` block than you entered (e.g. for context switching), these registers must contain the value they had upon entering the `asm!` block that you are *exiting*.\n - You cannot exit an `asm!` block that has not been entered. Neither can you exit an `asm!` block that has already been exited.\n - You are responsible for switching any target-specific state (e.g. thread-local storage, stack bounds).\n - The set of memory locations that you may access is the intersection of those allowed by the `asm!` blocks you entered and exited.\n- You cannot assume that an `asm!` block will appear exactly once in the output binary. The compiler is allowed to instantiate multiple copies of the `asm!` block, for example when the function containing it is inlined in multiple places.\n - As a consequence, you should only use [local labels] inside inline assembly code. Defining symbols in assembly code may lead to assembler and/or linker errors due to duplicate symbol definitions.\n\n> **Note**: As a general rule, the flags covered by `preserves_flags` are those which are *not* preserved when performing a function call.\n\n[local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels\n" } , LintCompletion { label : "is_sorted" , description : "# `is_sorted`\n\nThe tracking issue for this feature is: [#53485]\n\n[#53485]: https://github.com/rust-lang/rust/issues/53485\n\n------------------------\n\nAdd the methods `is_sorted`, `is_sorted_by` and `is_sorted_by_key` to `[T]`;\nadd the methods `is_sorted`, `is_sorted_by` and `is_sorted_by_key` to\n`Iterator`.\n" } , LintCompletion { label : "derive_clone_copy" , description : "# `derive_clone_copy`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "print_internals" , description : "# `print_internals`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "set_stdio" , description : "# `set_stdio`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "windows_handle" , description : "# `windows_handle`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "thread_local_internals" , description : "# `thread_local_internals`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "profiler_runtime_lib" , description : "# `profiler_runtime_lib`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "windows_c" , description : "# `windows_c`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "fd_read" , description : "# `fd_read`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "c_void_variant" , description : "# `c_void_variant`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "flt2dec" , description : "# `flt2dec`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "core_private_bignum" , description : "# `core_private_bignum`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "format_args_capture" , description : "# `format_args_capture`\n\nThe tracking issue for this feature is: [#67984]\n\n[#67984]: https://github.com/rust-lang/rust/issues/67984\n\n------------------------\n\nEnables `format_args!` (and macros which use `format_args!` in their implementation, such\nas `format!`, `print!` and `panic!`) to capture variables from the surrounding scope.\nThis avoids the need to pass named parameters when the binding in question\nalready exists in scope.\n\n```rust\n#![feature(format_args_capture)]\n\nlet (person, species, name) = (\"Charlie Brown\", \"dog\", \"Snoopy\");\n\n// captures named argument `person`\nprint!(\"Hello {person}\");\n\n// captures named arguments `species` and `name`\nformat!(\"The {species}'s name is {name}.\");\n```\n\nThis also works for formatting parameters such as width and precision:\n\n```rust\n#![feature(format_args_capture)]\n\nlet precision = 2;\nlet s = format!(\"{:.precision$}\", 1.324223);\n\nassert_eq!(&s, \"1.32\");\n```\n\nA non-exhaustive list of macros which benefit from this functionality include:\n- `format!`\n- `print!` and `println!`\n- `eprint!` and `eprintln!`\n- `write!` and `writeln!`\n- `panic!`\n- `unreachable!`\n- `unimplemented!`\n- `todo!`\n- `assert!` and similar\n- macros in many thirdparty crates, such as `log`\n" } , LintCompletion { label : "libstd_io_internals" , description : "# `libstd_io_internals`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "derive_eq" , description : "# `derive_eq`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "c_variadic" , description : "# `c_variadic`\n\nThe tracking issue for this feature is: [#44930]\n\n[#44930]: https://github.com/rust-lang/rust/issues/44930\n\n------------------------\n\nThe `c_variadic` library feature exposes the `VaList` structure,\nRust's analogue of C's `va_list` type.\n\n## Examples\n\n```rust\n#![feature(c_variadic)]\n\nuse std::ffi::VaList;\n\npub unsafe extern \"C\" fn vadd(n: usize, mut args: VaList) -> usize {\n let mut sum = 0;\n for _ in 0..n {\n sum += args.arg::();\n }\n sum\n}\n```\n" } , LintCompletion { label : "trace_macros" , description : "# `trace_macros`\n\nThe tracking issue for this feature is [#29598].\n\n[#29598]: https://github.com/rust-lang/rust/issues/29598\n\n------------------------\n\nWith `trace_macros` you can trace the expansion of macros in your code.\n\n## Examples\n\n```rust\n#![feature(trace_macros)]\n\nfn main() {\n trace_macros!(true);\n println!(\"Hello, Rust!\");\n trace_macros!(false);\n}\n```\n\nThe `cargo build` output:\n\n```txt\nnote: trace_macro\n --> src/main.rs:5:5\n |\n5 | println!(\"Hello, Rust!\");\n | ^^^^^^^^^^^^^^^^^^^^^^^^^\n |\n = note: expanding `println! { \"Hello, Rust!\" }`\n = note: to `print ! ( concat ! ( \"Hello, Rust!\" , \"\\n\" ) )`\n = note: expanding `print! { concat ! ( \"Hello, Rust!\" , \"\\n\" ) }`\n = note: to `$crate :: io :: _print ( format_args ! ( concat ! ( \"Hello, Rust!\" , \"\\n\" ) )\n )`\n\n Finished dev [unoptimized + debuginfo] target(s) in 0.60 secs\n```\n" } , LintCompletion { label : "core_private_diy_float" , description : "# `core_private_diy_float`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "core_panic" , description : "# `core_panic`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "str_internals" , description : "# `str_internals`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "char_error_internals" , description : "# `char_error_internals`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "llvm_asm" , description : "# `llvm_asm`\n\nThe tracking issue for this feature is: [#70173]\n\n[#70173]: https://github.com/rust-lang/rust/issues/70173\n\n------------------------\n\nFor extremely low-level manipulations and performance reasons, one\nmight wish to control the CPU directly. Rust supports using inline\nassembly to do this via the `llvm_asm!` macro.\n\n```rust,ignore\nllvm_asm!(assembly template\n : output operands\n : input operands\n : clobbers\n : options\n );\n```\n\nAny use of `llvm_asm` is feature gated (requires `#![feature(llvm_asm)]` on the\ncrate to allow) and of course requires an `unsafe` block.\n\n> **Note**: the examples here are given in x86/x86-64 assembly, but\n> all platforms are supported.\n\n## Assembly template\n\nThe `assembly template` is the only required parameter and must be a\nliteral string (i.e. `\"\"`)\n\n```rust\n#![feature(llvm_asm)]\n\n#[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\nfn foo() {\n unsafe {\n llvm_asm!(\"NOP\");\n }\n}\n\n// Other platforms:\n#[cfg(not(any(target_arch = \"x86\", target_arch = \"x86_64\")))]\nfn foo() { /* ... */ }\n\nfn main() {\n // ...\n foo();\n // ...\n}\n```\n\n(The `feature(llvm_asm)` and `#[cfg]`s are omitted from now on.)\n\nOutput operands, input operands, clobbers and options are all optional\nbut you must add the right number of `:` if you skip them:\n\n```rust\n# #![feature(llvm_asm)]\n# #[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\n# fn main() { unsafe {\nllvm_asm!(\"xor %eax, %eax\"\n :\n :\n : \"eax\"\n );\n# } }\n# #[cfg(not(any(target_arch = \"x86\", target_arch = \"x86_64\")))]\n# fn main() {}\n```\n\nWhitespace also doesn't matter:\n\n```rust\n# #![feature(llvm_asm)]\n# #[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\n# fn main() { unsafe {\nllvm_asm!(\"xor %eax, %eax\" ::: \"eax\");\n# } }\n# #[cfg(not(any(target_arch = \"x86\", target_arch = \"x86_64\")))]\n# fn main() {}\n```\n\n## Operands\n\nInput and output operands follow the same format: `:\n\"constraints1\"(expr1), \"constraints2\"(expr2), ...\"`. Output operand\nexpressions must be mutable place, or not yet assigned:\n\n```rust\n# #![feature(llvm_asm)]\n# #[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\nfn add(a: i32, b: i32) -> i32 {\n let c: i32;\n unsafe {\n llvm_asm!(\"add $2, $0\"\n : \"=r\"(c)\n : \"0\"(a), \"r\"(b)\n );\n }\n c\n}\n# #[cfg(not(any(target_arch = \"x86\", target_arch = \"x86_64\")))]\n# fn add(a: i32, b: i32) -> i32 { a + b }\n\nfn main() {\n assert_eq!(add(3, 14159), 14162)\n}\n```\n\nIf you would like to use real operands in this position, however,\nyou are required to put curly braces `{}` around the register that\nyou want, and you are required to put the specific size of the\noperand. This is useful for very low level programming, where\nwhich register you use is important:\n\n```rust\n# #![feature(llvm_asm)]\n# #[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\n# unsafe fn read_byte_in(port: u16) -> u8 {\nlet result: u8;\nllvm_asm!(\"in %dx, %al\" : \"={al}\"(result) : \"{dx}\"(port));\nresult\n# }\n```\n\n## Clobbers\n\nSome instructions modify registers which might otherwise have held\ndifferent values so we use the clobbers list to indicate to the\ncompiler not to assume any values loaded into those registers will\nstay valid.\n\n```rust\n# #![feature(llvm_asm)]\n# #[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\n# fn main() { unsafe {\n// Put the value 0x200 in eax:\nllvm_asm!(\"mov $$0x200, %eax\" : /* no outputs */ : /* no inputs */ : \"eax\");\n# } }\n# #[cfg(not(any(target_arch = \"x86\", target_arch = \"x86_64\")))]\n# fn main() {}\n```\n\nInput and output registers need not be listed since that information\nis already communicated by the given constraints. Otherwise, any other\nregisters used either implicitly or explicitly should be listed.\n\nIf the assembly changes the condition code register `cc` should be\nspecified as one of the clobbers. Similarly, if the assembly modifies\nmemory, `memory` should also be specified.\n\n## Options\n\nThe last section, `options` is specific to Rust. The format is comma\nseparated literal strings (i.e. `:\"foo\", \"bar\", \"baz\"`). It's used to\nspecify some extra info about the inline assembly:\n\nCurrent valid options are:\n\n1. *volatile* - specifying this is analogous to\n `__asm__ __volatile__ (...)` in gcc/clang.\n2. *alignstack* - certain instructions expect the stack to be\n aligned a certain way (i.e. SSE) and specifying this indicates to\n the compiler to insert its usual stack alignment code\n3. *intel* - use intel syntax instead of the default AT&T.\n\n```rust\n# #![feature(llvm_asm)]\n# #[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\n# fn main() {\nlet result: i32;\nunsafe {\n llvm_asm!(\"mov eax, 2\" : \"={eax}\"(result) : : : \"intel\")\n}\nprintln!(\"eax is currently {}\", result);\n# }\n# #[cfg(not(any(target_arch = \"x86\", target_arch = \"x86_64\")))]\n# fn main() {}\n```\n\n## More Information\n\nThe current implementation of the `llvm_asm!` macro is a direct binding to [LLVM's\ninline assembler expressions][llvm-docs], so be sure to check out [their\ndocumentation as well][llvm-docs] for more information about clobbers,\nconstraints, etc.\n\n[llvm-docs]: http://llvm.org/docs/LangRef.html#inline-assembler-expressions\n\nIf you need more power and don't mind losing some of the niceties of\n`llvm_asm!`, check out [global_asm](global-asm.md).\n" } ] ; +pub const UNSTABLE_FEATURE_DESCRIPTOR : & [ LintCompletion ] = & [ LintCompletion { label : "crate_visibility_modifier" , description : "# `crate_visibility_modifier`\n\nThe tracking issue for this feature is: [#53120]\n\n[#53120]: https://github.com/rust-lang/rust/issues/53120\n\n-----\n\nThe `crate_visibility_modifier` feature allows the `crate` keyword to be used\nas a visibility modifier synonymous to `pub(crate)`, indicating that a type\n(function, _&c._) is to be visible to the entire enclosing crate, but not to\nother crates.\n\n```rust\n#![feature(crate_visibility_modifier)]\n\ncrate struct Foo {\n bar: usize,\n}\n```\n" } , LintCompletion { label : "abi_thiscall" , description : "# `abi_thiscall`\n\nThe tracking issue for this feature is: [#42202]\n\n[#42202]: https://github.com/rust-lang/rust/issues/42202\n\n------------------------\n\nThe MSVC ABI on x86 Windows uses the `thiscall` calling convention for C++\ninstance methods by default; it is identical to the usual (C) calling\nconvention on x86 Windows except that the first parameter of the method,\nthe `this` pointer, is passed in the ECX register.\n" } , LintCompletion { label : "infer_static_outlives_requirements" , description : "# `infer_static_outlives_requirements`\n\nThe tracking issue for this feature is: [#54185]\n\n[#54185]: https://github.com/rust-lang/rust/issues/54185\n\n------------------------\nThe `infer_static_outlives_requirements` feature indicates that certain\n`'static` outlives requirements can be inferred by the compiler rather than\nstating them explicitly.\n\nNote: It is an accompanying feature to `infer_outlives_requirements`,\nwhich must be enabled to infer outlives requirements.\n\nFor example, currently generic struct definitions that contain\nreferences, require where-clauses of the form T: 'static. By using\nthis feature the outlives predicates will be inferred, although\nthey may still be written explicitly.\n\n```rust,ignore (pseudo-Rust)\nstruct Foo where U: 'static { // <-- currently required\n bar: Bar\n}\nstruct Bar {\n x: T,\n}\n```\n\n\n## Examples:\n\n```rust,ignore (pseudo-Rust)\n#![feature(infer_outlives_requirements)]\n#![feature(infer_static_outlives_requirements)]\n\n#[rustc_outlives]\n// Implicitly infer U: 'static\nstruct Foo {\n bar: Bar\n}\nstruct Bar {\n x: T,\n}\n```\n\n" } , LintCompletion { label : "repr128" , description : "# `repr128`\n\nThe tracking issue for this feature is: [#56071]\n\n[#56071]: https://github.com/rust-lang/rust/issues/56071\n\n------------------------\n\nThe `repr128` feature adds support for `#[repr(u128)]` on `enum`s.\n\n```rust\n#![feature(repr128)]\n\n#[repr(u128)]\nenum Foo {\n Bar(u64),\n}\n```\n" } , LintCompletion { label : "doc_masked" , description : "# `doc_masked`\n\nThe tracking issue for this feature is: [#44027]\n\n-----\n\nThe `doc_masked` feature allows a crate to exclude types from a given crate from appearing in lists\nof trait implementations. The specifics of the feature are as follows:\n\n1. When rustdoc encounters an `extern crate` statement annotated with a `#[doc(masked)]` attribute,\n it marks the crate as being masked.\n\n2. When listing traits a given type implements, rustdoc ensures that traits from masked crates are\n not emitted into the documentation.\n\n3. When listing types that implement a given trait, rustdoc ensures that types from masked crates\n are not emitted into the documentation.\n\nThis feature was introduced in PR [#44026] to ensure that compiler-internal and\nimplementation-specific types and traits were not included in the standard library's documentation.\nSuch types would introduce broken links into the documentation.\n\n[#44026]: https://github.com/rust-lang/rust/pull/44026\n[#44027]: https://github.com/rust-lang/rust/pull/44027\n" } , LintCompletion { label : "link_args" , description : "# `link_args`\n\nThe tracking issue for this feature is: [#29596]\n\n[#29596]: https://github.com/rust-lang/rust/issues/29596\n\n------------------------\n\nYou can tell `rustc` how to customize linking, and that is via the `link_args`\nattribute. This attribute is applied to `extern` blocks and specifies raw flags\nwhich need to get passed to the linker when producing an artifact. An example\nusage would be:\n\n```rust,no_run\n#![feature(link_args)]\n\n#[link_args = \"-foo -bar -baz\"]\nextern {}\n# fn main() {}\n```\n\nNote that this feature is currently hidden behind the `feature(link_args)` gate\nbecause this is not a sanctioned way of performing linking. Right now `rustc`\nshells out to the system linker (`gcc` on most systems, `link.exe` on MSVC), so\nit makes sense to provide extra command line arguments, but this will not\nalways be the case. In the future `rustc` may use LLVM directly to link native\nlibraries, in which case `link_args` will have no meaning. You can achieve the\nsame effect as the `link_args` attribute with the `-C link-args` argument to\n`rustc`.\n\nIt is highly recommended to *not* use this attribute, and rather use the more\nformal `#[link(...)]` attribute on `extern` blocks instead.\n" } , LintCompletion { label : "cfg_version" , description : "# `cfg_version`\n\nThe tracking issue for this feature is: [#64796]\n\n[#64796]: https://github.com/rust-lang/rust/issues/64796\n\n------------------------\n\nThe `cfg_version` feature makes it possible to execute different code\ndepending on the compiler version.\n\n## Examples\n\n```rust\n#![feature(cfg_version)]\n\n#[cfg(version(\"1.42\"))]\nfn a() {\n // ...\n}\n\n#[cfg(not(version(\"1.42\")))]\nfn a() {\n // ...\n}\n\nfn b() {\n if cfg!(version(\"1.42\")) {\n // ...\n } else {\n // ...\n }\n}\n```\n" } , LintCompletion { label : "ffi_const" , description : "# `ffi_const`\n\nThe `#[ffi_const]` attribute applies clang's `const` attribute to foreign\nfunctions declarations.\n\nThat is, `#[ffi_const]` functions shall have no effects except for its return\nvalue, which can only depend on the values of the function parameters, and is\nnot affected by changes to the observable state of the program.\n\nApplying the `#[ffi_const]` attribute to a function that violates these\nrequirements is undefined behaviour.\n\nThis attribute enables Rust to perform common optimizations, like sub-expression\nelimination, and it can avoid emitting some calls in repeated invocations of the\nfunction with the same argument values regardless of other operations being\nperformed in between these functions calls (as opposed to `#[ffi_pure]`\nfunctions).\n\n## Pitfalls\n\nA `#[ffi_const]` function can only read global memory that would not affect\nits return value for the whole execution of the program (e.g. immutable global\nmemory). `#[ffi_const]` functions are referentially-transparent and therefore\nmore strict than `#[ffi_pure]` functions.\n\nA common pitfall involves applying the `#[ffi_const]` attribute to a\nfunction that reads memory through pointer arguments which do not necessarily\npoint to immutable global memory.\n\nA `#[ffi_const]` function that returns unit has no effect on the abstract\nmachine's state, and a `#[ffi_const]` function cannot be `#[ffi_pure]`.\n\nA `#[ffi_const]` function must not diverge, neither via a side effect (e.g. a\ncall to `abort`) nor by infinite loops.\n\nWhen translating C headers to Rust FFI, it is worth verifying for which targets\nthe `const` attribute is enabled in those headers, and using the appropriate\n`cfg` macros in the Rust side to match those definitions. While the semantics of\n`const` are implemented identically by many C and C++ compilers, e.g., clang,\n[GCC], [ARM C/C++ compiler], [IBM ILE C/C++], etc. they are not necessarily\nimplemented in this way on all of them. It is therefore also worth verifying\nthat the semantics of the C toolchain used to compile the binary being linked\nagainst are compatible with those of the `#[ffi_const]`.\n\n[ARM C/C++ compiler]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/Cacgigch.html\n[GCC]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-const-function-attribute\n[IBM ILE C/C++]: https://www.ibm.com/support/knowledgecenter/fr/ssw_ibm_i_71/rzarg/fn_attrib_const.htm\n" } , LintCompletion { label : "doc_cfg" , description : "# `doc_cfg`\n\nThe tracking issue for this feature is: [#43781]\n\n------\n\nThe `doc_cfg` feature allows an API be documented as only available in some specific platforms.\nThis attribute has two effects:\n\n1. In the annotated item's documentation, there will be a message saying \"This is supported on\n (platform) only\".\n\n2. The item's doc-tests will only run on the specific platform.\n\nIn addition to allowing the use of the `#[doc(cfg)]` attribute, this feature enables the use of a\nspecial conditional compilation flag, `#[cfg(doc)]`, set whenever building documentation on your\ncrate.\n\nThis feature was introduced as part of PR [#43348] to allow the platform-specific parts of the\nstandard library be documented.\n\n```rust\n#![feature(doc_cfg)]\n\n#[cfg(any(windows, doc))]\n#[doc(cfg(windows))]\n/// The application's icon in the notification area (a.k.a. system tray).\n///\n/// # Examples\n///\n/// ```no_run\n/// extern crate my_awesome_ui_library;\n/// use my_awesome_ui_library::current_app;\n/// use my_awesome_ui_library::windows::notification;\n///\n/// let icon = current_app().get::();\n/// icon.show();\n/// icon.show_message(\"Hello\");\n/// ```\npub struct Icon {\n // ...\n}\n```\n\n[#43781]: https://github.com/rust-lang/rust/issues/43781\n[#43348]: https://github.com/rust-lang/rust/issues/43348\n" } , LintCompletion { label : "unsized_tuple_coercion" , description : "# `unsized_tuple_coercion`\n\nThe tracking issue for this feature is: [#42877]\n\n[#42877]: https://github.com/rust-lang/rust/issues/42877\n\n------------------------\n\nThis is a part of [RFC0401]. According to the RFC, there should be an implementation like this:\n\n```rust,ignore\nimpl<..., T, U: ?Sized> Unsized<(..., U)> for (..., T) where T: Unsized {}\n```\n\nThis implementation is currently gated behind `#[feature(unsized_tuple_coercion)]` to avoid insta-stability. Therefore you can use it like this:\n\n```rust\n#![feature(unsized_tuple_coercion)]\n\nfn main() {\n let x : ([i32; 3], [i32; 3]) = ([1, 2, 3], [4, 5, 6]);\n let y : &([i32; 3], [i32]) = &x;\n assert_eq!(y.1[0], 4);\n}\n```\n\n[RFC0401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md\n" } , LintCompletion { label : "abi_msp430_interrupt" , description : "# `abi_msp430_interrupt`\n\nThe tracking issue for this feature is: [#38487]\n\n[#38487]: https://github.com/rust-lang/rust/issues/38487\n\n------------------------\n\nIn the MSP430 architecture, interrupt handlers have a special calling\nconvention. You can use the `\"msp430-interrupt\"` ABI to make the compiler apply\nthe right calling convention to the interrupt handlers you define.\n\n\n\n``` rust,ignore\n#![feature(abi_msp430_interrupt)]\n#![no_std]\n\n// Place the interrupt handler at the appropriate memory address\n// (Alternatively, you can use `#[used]` and remove `pub` and `#[no_mangle]`)\n#[link_section = \"__interrupt_vector_10\"]\n#[no_mangle]\npub static TIM0_VECTOR: extern \"msp430-interrupt\" fn() = tim0;\n\n// The interrupt handler\nextern \"msp430-interrupt\" fn tim0() {\n // ..\n}\n```\n\n``` text\n$ msp430-elf-objdump -CD ./target/msp430/release/app\nDisassembly of section __interrupt_vector_10:\n\n0000fff2 :\n fff2: 00 c0 interrupt service routine at 0xc000\n\nDisassembly of section .text:\n\n0000c000 :\n c000: 00 13 reti\n```\n" } , LintCompletion { label : "generators" , description : "# `generators`\n\nThe tracking issue for this feature is: [#43122]\n\n[#43122]: https://github.com/rust-lang/rust/issues/43122\n\n------------------------\n\nThe `generators` feature gate in Rust allows you to define generator or\ncoroutine literals. A generator is a \"resumable function\" that syntactically\nresembles a closure but compiles to much different semantics in the compiler\nitself. The primary feature of a generator is that it can be suspended during\nexecution to be resumed at a later date. Generators use the `yield` keyword to\n\"return\", and then the caller can `resume` a generator to resume execution just\nafter the `yield` keyword.\n\nGenerators are an extra-unstable feature in the compiler right now. Added in\n[RFC 2033] they're mostly intended right now as a information/constraint\ngathering phase. The intent is that experimentation can happen on the nightly\ncompiler before actual stabilization. A further RFC will be required to\nstabilize generators/coroutines and will likely contain at least a few small\ntweaks to the overall design.\n\n[RFC 2033]: https://github.com/rust-lang/rfcs/pull/2033\n\nA syntactical example of a generator is:\n\n```rust\n#![feature(generators, generator_trait)]\n\nuse std::ops::{Generator, GeneratorState};\nuse std::pin::Pin;\n\nfn main() {\n let mut generator = || {\n yield 1;\n return \"foo\"\n };\n\n match Pin::new(&mut generator).resume(()) {\n GeneratorState::Yielded(1) => {}\n _ => panic!(\"unexpected value from resume\"),\n }\n match Pin::new(&mut generator).resume(()) {\n GeneratorState::Complete(\"foo\") => {}\n _ => panic!(\"unexpected value from resume\"),\n }\n}\n```\n\nGenerators are closure-like literals which can contain a `yield` statement. The\n`yield` statement takes an optional expression of a value to yield out of the\ngenerator. All generator literals implement the `Generator` trait in the\n`std::ops` module. The `Generator` trait has one main method, `resume`, which\nresumes execution of the generator at the previous suspension point.\n\nAn example of the control flow of generators is that the following example\nprints all numbers in order:\n\n```rust\n#![feature(generators, generator_trait)]\n\nuse std::ops::Generator;\nuse std::pin::Pin;\n\nfn main() {\n let mut generator = || {\n println!(\"2\");\n yield;\n println!(\"4\");\n };\n\n println!(\"1\");\n Pin::new(&mut generator).resume(());\n println!(\"3\");\n Pin::new(&mut generator).resume(());\n println!(\"5\");\n}\n```\n\nAt this time the main intended use case of generators is an implementation\nprimitive for async/await syntax, but generators will likely be extended to\nergonomic implementations of iterators and other primitives in the future.\nFeedback on the design and usage is always appreciated!\n\n### The `Generator` trait\n\nThe `Generator` trait in `std::ops` currently looks like:\n\n```rust\n# #![feature(arbitrary_self_types, generator_trait)]\n# use std::ops::GeneratorState;\n# use std::pin::Pin;\n\npub trait Generator {\n type Yield;\n type Return;\n fn resume(self: Pin<&mut Self>, resume: R) -> GeneratorState;\n}\n```\n\nThe `Generator::Yield` type is the type of values that can be yielded with the\n`yield` statement. The `Generator::Return` type is the returned type of the\ngenerator. This is typically the last expression in a generator's definition or\nany value passed to `return` in a generator. The `resume` function is the entry\npoint for executing the `Generator` itself.\n\nThe return value of `resume`, `GeneratorState`, looks like:\n\n```rust\npub enum GeneratorState {\n Yielded(Y),\n Complete(R),\n}\n```\n\nThe `Yielded` variant indicates that the generator can later be resumed. This\ncorresponds to a `yield` point in a generator. The `Complete` variant indicates\nthat the generator is complete and cannot be resumed again. Calling `resume`\nafter a generator has returned `Complete` will likely result in a panic of the\nprogram.\n\n### Closure-like semantics\n\nThe closure-like syntax for generators alludes to the fact that they also have\nclosure-like semantics. Namely:\n\n* When created, a generator executes no code. A closure literal does not\n actually execute any of the closure's code on construction, and similarly a\n generator literal does not execute any code inside the generator when\n constructed.\n\n* Generators can capture outer variables by reference or by move, and this can\n be tweaked with the `move` keyword at the beginning of the closure. Like\n closures all generators will have an implicit environment which is inferred by\n the compiler. Outer variables can be moved into a generator for use as the\n generator progresses.\n\n* Generator literals produce a value with a unique type which implements the\n `std::ops::Generator` trait. This allows actual execution of the generator\n through the `Generator::resume` method as well as also naming it in return\n types and such.\n\n* Traits like `Send` and `Sync` are automatically implemented for a `Generator`\n depending on the captured variables of the environment. Unlike closures,\n generators also depend on variables live across suspension points. This means\n that although the ambient environment may be `Send` or `Sync`, the generator\n itself may not be due to internal variables live across `yield` points being\n not-`Send` or not-`Sync`. Note that generators do\n not implement traits like `Copy` or `Clone` automatically.\n\n* Whenever a generator is dropped it will drop all captured environment\n variables.\n\n### Generators as state machines\n\nIn the compiler, generators are currently compiled as state machines. Each\n`yield` expression will correspond to a different state that stores all live\nvariables over that suspension point. Resumption of a generator will dispatch on\nthe current state and then execute internally until a `yield` is reached, at\nwhich point all state is saved off in the generator and a value is returned.\n\nLet's take a look at an example to see what's going on here:\n\n```rust\n#![feature(generators, generator_trait)]\n\nuse std::ops::Generator;\nuse std::pin::Pin;\n\nfn main() {\n let ret = \"foo\";\n let mut generator = move || {\n yield 1;\n return ret\n };\n\n Pin::new(&mut generator).resume(());\n Pin::new(&mut generator).resume(());\n}\n```\n\nThis generator literal will compile down to something similar to:\n\n```rust\n#![feature(arbitrary_self_types, generators, generator_trait)]\n\nuse std::ops::{Generator, GeneratorState};\nuse std::pin::Pin;\n\nfn main() {\n let ret = \"foo\";\n let mut generator = {\n enum __Generator {\n Start(&'static str),\n Yield1(&'static str),\n Done,\n }\n\n impl Generator for __Generator {\n type Yield = i32;\n type Return = &'static str;\n\n fn resume(mut self: Pin<&mut Self>, resume: ()) -> GeneratorState {\n use std::mem;\n match mem::replace(&mut *self, __Generator::Done) {\n __Generator::Start(s) => {\n *self = __Generator::Yield1(s);\n GeneratorState::Yielded(1)\n }\n\n __Generator::Yield1(s) => {\n *self = __Generator::Done;\n GeneratorState::Complete(s)\n }\n\n __Generator::Done => {\n panic!(\"generator resumed after completion\")\n }\n }\n }\n }\n\n __Generator::Start(ret)\n };\n\n Pin::new(&mut generator).resume(());\n Pin::new(&mut generator).resume(());\n}\n```\n\nNotably here we can see that the compiler is generating a fresh type,\n`__Generator` in this case. This type has a number of states (represented here\nas an `enum`) corresponding to each of the conceptual states of the generator.\nAt the beginning we're closing over our outer variable `foo` and then that\nvariable is also live over the `yield` point, so it's stored in both states.\n\nWhen the generator starts it'll immediately yield 1, but it saves off its state\njust before it does so indicating that it has reached the yield point. Upon\nresuming again we'll execute the `return ret` which returns the `Complete`\nstate.\n\nHere we can also note that the `Done` state, if resumed, panics immediately as\nit's invalid to resume a completed generator. It's also worth noting that this\nis just a rough desugaring, not a normative specification for what the compiler\ndoes.\n" } , LintCompletion { label : "marker_trait_attr" , description : "# `marker_trait_attr`\n\nThe tracking issue for this feature is: [#29864]\n\n[#29864]: https://github.com/rust-lang/rust/issues/29864\n\n------------------------\n\nNormally, Rust keeps you from adding trait implementations that could\noverlap with each other, as it would be ambiguous which to use. This\nfeature, however, carves out an exception to that rule: a trait can\nopt-in to having overlapping implementations, at the cost that those\nimplementations are not allowed to override anything (and thus the\ntrait itself cannot have any associated items, as they're pointless\nwhen they'd need to do the same thing for every type anyway).\n\n```rust\n#![feature(marker_trait_attr)]\n\n#[marker] trait CheapToClone: Clone {}\n\nimpl CheapToClone for T {}\n\n// These could potentially overlap with the blanket implementation above,\n// so are only allowed because CheapToClone is a marker trait.\nimpl CheapToClone for (T, U) {}\nimpl CheapToClone for std::ops::Range {}\n\nfn cheap_clone(t: T) -> T {\n t.clone()\n}\n```\n\nThis is expected to replace the unstable `overlapping_marker_traits`\nfeature, which applied to all empty traits (without needing an opt-in).\n" } , LintCompletion { label : "const_in_array_repeat_expressions" , description : "# `const_in_array_repeat_expressions`\n\nThe tracking issue for this feature is: [#49147]\n\n[#49147]: https://github.com/rust-lang/rust/issues/49147\n\n------------------------\n\nRelaxes the rules for repeat expressions, `[x; N]` such that `x` may also be `const` (strictly\nspeaking rvalue promotable), in addition to `typeof(x): Copy`. The result of `[x; N]` where `x` is\n`const` is itself also `const`.\n" } , LintCompletion { label : "external_doc" , description : "# `external_doc`\n\nThe tracking issue for this feature is: [#44732]\n\nThe `external_doc` feature allows the use of the `include` parameter to the `#[doc]` attribute, to\ninclude external files in documentation. Use the attribute in place of, or in addition to, regular\ndoc comments and `#[doc]` attributes, and `rustdoc` will load the given file when it renders\ndocumentation for your crate.\n\nWith the following files in the same directory:\n\n`external-doc.md`:\n\n```markdown\n# My Awesome Type\n\nThis is the documentation for this spectacular type.\n```\n\n`lib.rs`:\n\n```no_run (needs-external-files)\n#![feature(external_doc)]\n\n#[doc(include = \"external-doc.md\")]\npub struct MyAwesomeType;\n```\n\n`rustdoc` will load the file `external-doc.md` and use it as the documentation for the `MyAwesomeType`\nstruct.\n\nWhen locating files, `rustdoc` will base paths in the `src/` directory, as if they were alongside the\n`lib.rs` for your crate. So if you want a `docs/` folder to live alongside the `src/` directory,\nstart your paths with `../docs/` for `rustdoc` to properly find the file.\n\nThis feature was proposed in [RFC #1990] and initially implemented in PR [#44781].\n\n[#44732]: https://github.com/rust-lang/rust/issues/44732\n[RFC #1990]: https://github.com/rust-lang/rfcs/pull/1990\n[#44781]: https://github.com/rust-lang/rust/pull/44781\n" } , LintCompletion { label : "unsized_locals" , description : "# `unsized_locals`\n\nThe tracking issue for this feature is: [#48055]\n\n[#48055]: https://github.com/rust-lang/rust/issues/48055\n\n------------------------\n\nThis implements [RFC1909]. When turned on, you can have unsized arguments and locals:\n\n[RFC1909]: https://github.com/rust-lang/rfcs/blob/master/text/1909-unsized-rvalues.md\n\n```rust\n#![feature(unsized_locals)]\n\nuse std::any::Any;\n\nfn main() {\n let x: Box = Box::new(42);\n let x: dyn Any = *x;\n // ^ unsized local variable\n // ^^ unsized temporary\n foo(x);\n}\n\nfn foo(_: dyn Any) {}\n// ^^^^^^ unsized argument\n```\n\nThe RFC still forbids the following unsized expressions:\n\n```rust,ignore\n#![feature(unsized_locals)]\n\nuse std::any::Any;\n\nstruct MyStruct {\n content: T,\n}\n\nstruct MyTupleStruct(T);\n\nfn answer() -> Box {\n Box::new(42)\n}\n\nfn main() {\n // You CANNOT have unsized statics.\n static X: dyn Any = *answer(); // ERROR\n const Y: dyn Any = *answer(); // ERROR\n\n // You CANNOT have struct initialized unsized.\n MyStruct { content: *answer() }; // ERROR\n MyTupleStruct(*answer()); // ERROR\n (42, *answer()); // ERROR\n\n // You CANNOT have unsized return types.\n fn my_function() -> dyn Any { *answer() } // ERROR\n\n // You CAN have unsized local variables...\n let mut x: dyn Any = *answer(); // OK\n // ...but you CANNOT reassign to them.\n x = *answer(); // ERROR\n\n // You CANNOT even initialize them separately.\n let y: dyn Any; // OK\n y = *answer(); // ERROR\n\n // Not mentioned in the RFC, but by-move captured variables are also Sized.\n let x: dyn Any = *answer();\n (move || { // ERROR\n let y = x;\n })();\n\n // You CAN create a closure with unsized arguments,\n // but you CANNOT call it.\n // This is an implementation detail and may be changed in the future.\n let f = |x: dyn Any| {};\n f(*answer()); // ERROR\n}\n```\n\n## By-value trait objects\n\nWith this feature, you can have by-value `self` arguments without `Self: Sized` bounds.\n\n```rust\n#![feature(unsized_locals)]\n\ntrait Foo {\n fn foo(self) {}\n}\n\nimpl Foo for T {}\n\nfn main() {\n let slice: Box<[i32]> = Box::new([1, 2, 3]);\n <[i32] as Foo>::foo(*slice);\n}\n```\n\nAnd `Foo` will also be object-safe.\n\n```rust\n#![feature(unsized_locals)]\n\ntrait Foo {\n fn foo(self) {}\n}\n\nimpl Foo for T {}\n\nfn main () {\n let slice: Box = Box::new([1, 2, 3]);\n // doesn't compile yet\n ::foo(*slice);\n}\n```\n\nOne of the objectives of this feature is to allow `Box`.\n\n## Variable length arrays\n\nThe RFC also describes an extension to the array literal syntax: `[e; dyn n]`. In the syntax, `n` isn't necessarily a constant expression. The array is dynamically allocated on the stack and has the type of `[T]`, instead of `[T; n]`.\n\n```rust,ignore\n#![feature(unsized_locals)]\n\nfn mergesort(a: &mut [T]) {\n let mut tmp = [T; dyn a.len()];\n // ...\n}\n\nfn main() {\n let mut a = [3, 1, 5, 6];\n mergesort(&mut a);\n assert_eq!(a, [1, 3, 5, 6]);\n}\n```\n\nVLAs are not implemented yet. The syntax isn't final, either. We may need an alternative syntax for Rust 2015 because, in Rust 2015, expressions like `[e; dyn(1)]` would be ambiguous. One possible alternative proposed in the RFC is `[e; n]`: if `n` captures one or more local variables, then it is considered as `[e; dyn n]`.\n\n## Advisory on stack usage\n\nIt's advised not to casually use the `#![feature(unsized_locals)]` feature. Typical use-cases are:\n\n- When you need a by-value trait objects.\n- When you really need a fast allocation of small temporary arrays.\n\nAnother pitfall is repetitive allocation and temporaries. Currently the compiler simply extends the stack frame every time it encounters an unsized assignment. So for example, the code\n\n```rust\n#![feature(unsized_locals)]\n\nfn main() {\n let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]);\n let _x = {{{{{{{{{{*x}}}}}}}}}};\n}\n```\n\nand the code\n\n```rust\n#![feature(unsized_locals)]\n\nfn main() {\n for _ in 0..10 {\n let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]);\n let _x = *x;\n }\n}\n```\n\nwill unnecessarily extend the stack frame.\n" } , LintCompletion { label : "or_patterns" , description : "# `or_patterns`\n\nThe tracking issue for this feature is: [#54883]\n\n[#54883]: https://github.com/rust-lang/rust/issues/54883\n\n------------------------\n\nThe `or_pattern` language feature allows `|` to be arbitrarily nested within\na pattern, for example, `Some(A(0) | B(1 | 2))` becomes a valid pattern.\n\n## Examples\n\n```rust,ignore\n#![feature(or_patterns)]\n\npub enum Foo {\n Bar,\n Baz,\n Quux,\n}\n\npub fn example(maybe_foo: Option) {\n match maybe_foo {\n Some(Foo::Bar | Foo::Baz) => {\n println!(\"The value contained `Bar` or `Baz`\");\n }\n Some(_) => {\n println!(\"The value did not contain `Bar` or `Baz`\");\n }\n None => {\n println!(\"The value was `None`\");\n }\n }\n}\n```\n" } , LintCompletion { label : "member_constraints" , description : "# `member_constraints`\n\nThe tracking issue for this feature is: [#61997]\n\n[#61997]: https://github.com/rust-lang/rust/issues/61997\n\n------------------------\n\nThe `member_constraints` feature gate lets you use `impl Trait` syntax with\nmultiple unrelated lifetime parameters.\n\nA simple example is:\n\n```rust\n#![feature(member_constraints)]\n\ntrait Trait<'a, 'b> { }\nimpl Trait<'_, '_> for T {}\n\nfn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {\n (x, y)\n}\n\nfn main() { }\n```\n\nWithout the `member_constraints` feature gate, the above example is an\nerror because both `'a` and `'b` appear in the impl Trait bounds, but\nneither outlives the other.\n" } , LintCompletion { label : "optin_builtin_traits" , description : "# `optin_builtin_traits`\n\nThe tracking issue for this feature is [#13231] \n\n[#13231]: https://github.com/rust-lang/rust/issues/13231\n\n----\n\nThe `optin_builtin_traits` feature gate allows you to define auto traits.\n\nAuto traits, like [`Send`] or [`Sync`] in the standard library, are marker traits\nthat are automatically implemented for every type, unless the type, or a type it contains, \nhas explicitly opted out via a negative impl. (Negative impls are separately controlled\nby the `negative_impls` feature.)\n\n[`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html\n[`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html\n\n```rust,ignore\nimpl !Trait for Type\n```\n\nExample:\n\n```rust\n#![feature(negative_impls)]\n#![feature(optin_builtin_traits)]\n\nauto trait Valid {}\n\nstruct True;\nstruct False;\n\nimpl !Valid for False {}\n\nstruct MaybeValid(T);\n\nfn must_be_valid(_t: T) { }\n\nfn main() {\n // works\n must_be_valid( MaybeValid(True) );\n \n // compiler error - trait bound not satisfied\n // must_be_valid( MaybeValid(False) );\n}\n```\n\n## Automatic trait implementations\n\nWhen a type is declared as an `auto trait`, we will automatically\ncreate impls for every struct/enum/union, unless an explicit impl is\nprovided. These automatic impls contain a where clause for each field\nof the form `T: AutoTrait`, where `T` is the type of the field and\n`AutoTrait` is the auto trait in question. As an example, consider the\nstruct `List` and the auto trait `Send`:\n\n```rust\nstruct List {\n data: T,\n next: Option>>,\n}\n```\n\nPresuming that there is no explicit impl of `Send` for `List`, the\ncompiler will supply an automatic impl of the form:\n\n```rust\nstruct List {\n data: T,\n next: Option>>,\n}\n\nunsafe impl Send for List\nwhere\n T: Send, // from the field `data`\n Option>>: Send, // from the field `next`\n{ }\n```\n\nExplicit impls may be either positive or negative. They take the form:\n\n```rust,ignore\nimpl<...> AutoTrait for StructName<..> { }\nimpl<...> !AutoTrait for StructName<..> { }\n```\n\n## Coinduction: Auto traits permit cyclic matching\n\nUnlike ordinary trait matching, auto traits are **coinductive**. This\nmeans, in short, that cycles which occur in trait matching are\nconsidered ok. As an example, consider the recursive struct `List`\nintroduced in the previous section. In attempting to determine whether\n`List: Send`, we would wind up in a cycle: to apply the impl, we must\nshow that `Option>: Send`, which will in turn require\n`Box: Send` and then finally `List: Send` again. Under ordinary\ntrait matching, this cycle would be an error, but for an auto trait it\nis considered a successful match.\n\n## Items\n\nAuto traits cannot have any trait items, such as methods or associated types. This ensures that we can generate default implementations.\n\n## Supertraits\n\nAuto traits cannot have supertraits. This is for soundness reasons, as the interaction of coinduction with implied bounds is difficult to reconcile.\n\n" } , LintCompletion { label : "rustc_attrs" , description : "# `rustc_attrs`\n\nThis feature has no tracking issue, and is therefore internal to\nthe compiler, not being intended for general use.\n\nNote: `rustc_attrs` enables many rustc-internal attributes and this page\nonly discuss a few of them.\n\n------------------------\n\nThe `rustc_attrs` feature allows debugging rustc type layouts by using\n`#[rustc_layout(...)]` to debug layout at compile time (it even works\nwith `cargo check`) as an alternative to `rustc -Z print-type-sizes`\nthat is way more verbose.\n\nOptions provided by `#[rustc_layout(...)]` are `debug`, `size`, `abi`.\nNote that it only work best with sized type without generics.\n\n## Examples\n\n```rust,ignore\n#![feature(rustc_attrs)]\n\n#[rustc_layout(abi, size)]\npub enum X {\n Y(u8, u8, u8),\n Z(isize),\n}\n```\n\nWhen that is compiled, the compiler will error with something like\n\n```text\nerror: abi: Aggregate { sized: true }\n --> src/lib.rs:4:1\n |\n4 | / pub enum T {\n5 | | Y(u8, u8, u8),\n6 | | Z(isize),\n7 | | }\n | |_^\n\nerror: size: Size { raw: 16 }\n --> src/lib.rs:4:1\n |\n4 | / pub enum T {\n5 | | Y(u8, u8, u8),\n6 | | Z(isize),\n7 | | }\n | |_^\n\nerror: aborting due to 2 previous errors\n```\n" } , LintCompletion { label : "non_ascii_idents" , description : "# `non_ascii_idents`\n\nThe tracking issue for this feature is: [#55467]\n\n[#55467]: https://github.com/rust-lang/rust/issues/55467\n\n------------------------\n\nThe `non_ascii_idents` feature adds support for non-ASCII identifiers.\n\n## Examples\n\n```rust\n#![feature(non_ascii_idents)]\n\nconst ε: f64 = 0.00001f64;\nconst Π: f64 = 3.14f64;\n```\n\n## Changes to the language reference\n\n> **Lexer:** \n> IDENTIFIER : \n>       XID_start XID_continue\\* \n>    | `_` XID_continue+ \n\nAn identifier is any nonempty Unicode string of the following form:\n\nEither\n\n * The first character has property [`XID_start`]\n * The remaining characters have property [`XID_continue`]\n\nOr\n\n * The first character is `_`\n * The identifier is more than one character, `_` alone is not an identifier\n * The remaining characters have property [`XID_continue`]\n\nthat does _not_ occur in the set of [strict keywords].\n\n> **Note**: [`XID_start`] and [`XID_continue`] as character properties cover the\n> character ranges used to form the more familiar C and Java language-family\n> identifiers.\n\n[`XID_start`]: http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AXID_Start%3A%5D&abb=on&g=&i=\n[`XID_continue`]: http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AXID_Continue%3A%5D&abb=on&g=&i=\n[strict keywords]: ../../reference/keywords.md#strict-keywords\n" } , LintCompletion { label : "box_syntax" , description : "# `box_syntax`\n\nThe tracking issue for this feature is: [#49733]\n\n[#49733]: https://github.com/rust-lang/rust/issues/49733\n\nSee also [`box_patterns`](box-patterns.md)\n\n------------------------\n\nCurrently the only stable way to create a `Box` is via the `Box::new` method.\nAlso it is not possible in stable Rust to destructure a `Box` in a match\npattern. The unstable `box` keyword can be used to create a `Box`. An example\nusage would be:\n\n```rust\n#![feature(box_syntax)]\n\nfn main() {\n let b = box 5;\n}\n```\n" } , LintCompletion { label : "no_sanitize" , description : "# `no_sanitize`\n\nThe tracking issue for this feature is: [#39699]\n\n[#39699]: https://github.com/rust-lang/rust/issues/39699\n\n------------------------\n\nThe `no_sanitize` attribute can be used to selectively disable sanitizer\ninstrumentation in an annotated function. This might be useful to: avoid\ninstrumentation overhead in a performance critical function, or avoid\ninstrumenting code that contains constructs unsupported by given sanitizer.\n\nThe precise effect of this annotation depends on particular sanitizer in use.\nFor example, with `no_sanitize(thread)`, the thread sanitizer will no longer\ninstrument non-atomic store / load operations, but it will instrument atomic\noperations to avoid reporting false positives and provide meaning full stack\ntraces.\n\n## Examples\n\n``` rust\n#![feature(no_sanitize)]\n\n#[no_sanitize(address)]\nfn foo() {\n // ...\n}\n```\n" } , LintCompletion { label : "trait_alias" , description : "# `trait_alias`\n\nThe tracking issue for this feature is: [#41517]\n\n[#41517]: https://github.com/rust-lang/rust/issues/41517\n\n------------------------\n\nThe `trait_alias` feature adds support for trait aliases. These allow aliases\nto be created for one or more traits (currently just a single regular trait plus\nany number of auto-traits), and used wherever traits would normally be used as\neither bounds or trait objects.\n\n```rust\n#![feature(trait_alias)]\n\ntrait Foo = std::fmt::Debug + Send;\ntrait Bar = Foo + Sync;\n\n// Use trait alias as bound on type parameter.\nfn foo(v: &T) {\n println!(\"{:?}\", v);\n}\n\npub fn main() {\n foo(&1);\n\n // Use trait alias for trait objects.\n let a: &Bar = &123;\n println!(\"{:?}\", a);\n let b = Box::new(456) as Box;\n println!(\"{:?}\", b);\n}\n```\n" } , LintCompletion { label : "unboxed_closures" , description : "# `unboxed_closures`\n\nThe tracking issue for this feature is [#29625]\n\nSee Also: [`fn_traits`](../library-features/fn-traits.md)\n\n[#29625]: https://github.com/rust-lang/rust/issues/29625\n\n----\n\nThe `unboxed_closures` feature allows you to write functions using the `\"rust-call\"` ABI,\nrequired for implementing the [`Fn*`] family of traits. `\"rust-call\"` functions must have \nexactly one (non self) argument, a tuple representing the argument list.\n\n[`Fn*`]: https://doc.rust-lang.org/std/ops/trait.Fn.html\n\n```rust\n#![feature(unboxed_closures)]\n\nextern \"rust-call\" fn add_args(args: (u32, u32)) -> u32 {\n args.0 + args.1\n}\n\nfn main() {}\n```\n" } , LintCompletion { label : "lang_items" , description : "# `lang_items`\n\nThe tracking issue for this feature is: None.\n\n------------------------\n\nThe `rustc` compiler has certain pluggable operations, that is,\nfunctionality that isn't hard-coded into the language, but is\nimplemented in libraries, with a special marker to tell the compiler\nit exists. The marker is the attribute `#[lang = \"...\"]` and there are\nvarious different values of `...`, i.e. various different 'lang\nitems'.\n\nFor example, `Box` pointers require two lang items, one for allocation\nand one for deallocation. A freestanding program that uses the `Box`\nsugar for dynamic allocations via `malloc` and `free`:\n\n```rust,ignore\n#![feature(lang_items, box_syntax, start, libc, core_intrinsics)]\n#![no_std]\nuse core::intrinsics;\nuse core::panic::PanicInfo;\n\nextern crate libc;\n\n#[lang = \"owned_box\"]\npub struct Box(*mut T);\n\n#[lang = \"exchange_malloc\"]\nunsafe fn allocate(size: usize, _align: usize) -> *mut u8 {\n let p = libc::malloc(size as libc::size_t) as *mut u8;\n\n // Check if `malloc` failed:\n if p as usize == 0 {\n intrinsics::abort();\n }\n\n p\n}\n\n#[lang = \"box_free\"]\nunsafe fn box_free(ptr: *mut T) {\n libc::free(ptr as *mut libc::c_void)\n}\n\n#[start]\nfn main(_argc: isize, _argv: *const *const u8) -> isize {\n let _x = box 1;\n\n 0\n}\n\n#[lang = \"eh_personality\"] extern fn rust_eh_personality() {}\n#[lang = \"panic_impl\"] extern fn rust_begin_panic(info: &PanicInfo) -> ! { unsafe { intrinsics::abort() } }\n#[no_mangle] pub extern fn rust_eh_register_frames () {}\n#[no_mangle] pub extern fn rust_eh_unregister_frames () {}\n```\n\nNote the use of `abort`: the `exchange_malloc` lang item is assumed to\nreturn a valid pointer, and so needs to do the check internally.\n\nOther features provided by lang items include:\n\n- overloadable operators via traits: the traits corresponding to the\n `==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all\n marked with lang items; those specific four are `eq`, `ord`,\n `deref`, and `add` respectively.\n- stack unwinding and general failure; the `eh_personality`,\n `panic` and `panic_bounds_checks` lang items.\n- the traits in `std::marker` used to indicate types of\n various kinds; lang items `send`, `sync` and `copy`.\n- the marker types and variance indicators found in\n `std::marker`; lang items `covariant_type`,\n `contravariant_lifetime`, etc.\n\nLang items are loaded lazily by the compiler; e.g. if one never uses\n`Box` then there is no need to define functions for `exchange_malloc`\nand `box_free`. `rustc` will emit an error when an item is needed\nbut not found in the current crate or any that it depends on.\n\nMost lang items are defined by `libcore`, but if you're trying to build\nan executable without the standard library, you'll run into the need\nfor lang items. The rest of this page focuses on this use-case, even though\nlang items are a bit broader than that.\n\n### Using libc\n\nIn order to build a `#[no_std]` executable we will need libc as a dependency.\nWe can specify this using our `Cargo.toml` file:\n\n```toml\n[dependencies]\nlibc = { version = \"0.2.14\", default-features = false }\n```\n\nNote that the default features have been disabled. This is a critical step -\n**the default features of libc include the standard library and so must be\ndisabled.**\n\n### Writing an executable without stdlib\n\nControlling the entry point is possible in two ways: the `#[start]` attribute,\nor overriding the default shim for the C `main` function with your own.\n\nThe function marked `#[start]` is passed the command line parameters\nin the same format as C:\n\n```rust,ignore\n#![feature(lang_items, core_intrinsics)]\n#![feature(start)]\n#![no_std]\nuse core::intrinsics;\nuse core::panic::PanicInfo;\n\n// Pull in the system libc library for what crt0.o likely requires.\nextern crate libc;\n\n// Entry point for this program.\n#[start]\nfn start(_argc: isize, _argv: *const *const u8) -> isize {\n 0\n}\n\n// These functions are used by the compiler, but not\n// for a bare-bones hello world. These are normally\n// provided by libstd.\n#[lang = \"eh_personality\"]\n#[no_mangle]\npub extern fn rust_eh_personality() {\n}\n\n#[lang = \"panic_impl\"]\n#[no_mangle]\npub extern fn rust_begin_panic(info: &PanicInfo) -> ! {\n unsafe { intrinsics::abort() }\n}\n```\n\nTo override the compiler-inserted `main` shim, one has to disable it\nwith `#![no_main]` and then create the appropriate symbol with the\ncorrect ABI and the correct name, which requires overriding the\ncompiler's name mangling too:\n\n```rust,ignore\n#![feature(lang_items, core_intrinsics)]\n#![feature(start)]\n#![no_std]\n#![no_main]\nuse core::intrinsics;\nuse core::panic::PanicInfo;\n\n// Pull in the system libc library for what crt0.o likely requires.\nextern crate libc;\n\n// Entry point for this program.\n#[no_mangle] // ensure that this symbol is called `main` in the output\npub extern fn main(_argc: i32, _argv: *const *const u8) -> i32 {\n 0\n}\n\n// These functions are used by the compiler, but not\n// for a bare-bones hello world. These are normally\n// provided by libstd.\n#[lang = \"eh_personality\"]\n#[no_mangle]\npub extern fn rust_eh_personality() {\n}\n\n#[lang = \"panic_impl\"]\n#[no_mangle]\npub extern fn rust_begin_panic(info: &PanicInfo) -> ! {\n unsafe { intrinsics::abort() }\n}\n```\n\nIn many cases, you may need to manually link to the `compiler_builtins` crate\nwhen building a `no_std` binary. You may observe this via linker error messages\nsuch as \"```undefined reference to `__rust_probestack'```\".\n\n## More about the language items\n\nThe compiler currently makes a few assumptions about symbols which are\navailable in the executable to call. Normally these functions are provided by\nthe standard library, but without it you must define your own. These symbols\nare called \"language items\", and they each have an internal name, and then a\nsignature that an implementation must conform to.\n\nThe first of these functions, `rust_eh_personality`, is used by the failure\nmechanisms of the compiler. This is often mapped to GCC's personality function\n(see the [libstd implementation][unwind] for more information), but crates\nwhich do not trigger a panic can be assured that this function is never\ncalled. The language item's name is `eh_personality`.\n\n[unwind]: https://github.com/rust-lang/rust/blob/master/src/libpanic_unwind/gcc.rs\n\nThe second function, `rust_begin_panic`, is also used by the failure mechanisms of the\ncompiler. When a panic happens, this controls the message that's displayed on\nthe screen. While the language item's name is `panic_impl`, the symbol name is\n`rust_begin_panic`.\n\nFinally, a `eh_catch_typeinfo` static is needed for certain targets which\nimplement Rust panics on top of C++ exceptions.\n\n## List of all language items\n\nThis is a list of all language items in Rust along with where they are located in\nthe source code.\n\n- Primitives\n - `i8`: `libcore/num/mod.rs`\n - `i16`: `libcore/num/mod.rs`\n - `i32`: `libcore/num/mod.rs`\n - `i64`: `libcore/num/mod.rs`\n - `i128`: `libcore/num/mod.rs`\n - `isize`: `libcore/num/mod.rs`\n - `u8`: `libcore/num/mod.rs`\n - `u16`: `libcore/num/mod.rs`\n - `u32`: `libcore/num/mod.rs`\n - `u64`: `libcore/num/mod.rs`\n - `u128`: `libcore/num/mod.rs`\n - `usize`: `libcore/num/mod.rs`\n - `f32`: `libstd/f32.rs`\n - `f64`: `libstd/f64.rs`\n - `char`: `libcore/char.rs`\n - `slice`: `liballoc/slice.rs`\n - `str`: `liballoc/str.rs`\n - `const_ptr`: `libcore/ptr.rs`\n - `mut_ptr`: `libcore/ptr.rs`\n - `unsafe_cell`: `libcore/cell.rs`\n- Runtime\n - `start`: `libstd/rt.rs`\n - `eh_personality`: `libpanic_unwind/emcc.rs` (EMCC)\n - `eh_personality`: `libpanic_unwind/gcc.rs` (GNU)\n - `eh_personality`: `libpanic_unwind/seh.rs` (SEH)\n - `eh_catch_typeinfo`: `libpanic_unwind/emcc.rs` (EMCC)\n - `panic`: `libcore/panicking.rs`\n - `panic_bounds_check`: `libcore/panicking.rs`\n - `panic_impl`: `libcore/panicking.rs`\n - `panic_impl`: `libstd/panicking.rs`\n- Allocations\n - `owned_box`: `liballoc/boxed.rs`\n - `exchange_malloc`: `liballoc/heap.rs`\n - `box_free`: `liballoc/heap.rs`\n- Operands\n - `not`: `libcore/ops/bit.rs`\n - `bitand`: `libcore/ops/bit.rs`\n - `bitor`: `libcore/ops/bit.rs`\n - `bitxor`: `libcore/ops/bit.rs`\n - `shl`: `libcore/ops/bit.rs`\n - `shr`: `libcore/ops/bit.rs`\n - `bitand_assign`: `libcore/ops/bit.rs`\n - `bitor_assign`: `libcore/ops/bit.rs`\n - `bitxor_assign`: `libcore/ops/bit.rs`\n - `shl_assign`: `libcore/ops/bit.rs`\n - `shr_assign`: `libcore/ops/bit.rs`\n - `deref`: `libcore/ops/deref.rs`\n - `deref_mut`: `libcore/ops/deref.rs`\n - `index`: `libcore/ops/index.rs`\n - `index_mut`: `libcore/ops/index.rs`\n - `add`: `libcore/ops/arith.rs`\n - `sub`: `libcore/ops/arith.rs`\n - `mul`: `libcore/ops/arith.rs`\n - `div`: `libcore/ops/arith.rs`\n - `rem`: `libcore/ops/arith.rs`\n - `neg`: `libcore/ops/arith.rs`\n - `add_assign`: `libcore/ops/arith.rs`\n - `sub_assign`: `libcore/ops/arith.rs`\n - `mul_assign`: `libcore/ops/arith.rs`\n - `div_assign`: `libcore/ops/arith.rs`\n - `rem_assign`: `libcore/ops/arith.rs`\n - `eq`: `libcore/cmp.rs`\n - `ord`: `libcore/cmp.rs`\n- Functions\n - `fn`: `libcore/ops/function.rs`\n - `fn_mut`: `libcore/ops/function.rs`\n - `fn_once`: `libcore/ops/function.rs`\n - `generator_state`: `libcore/ops/generator.rs`\n - `generator`: `libcore/ops/generator.rs`\n- Other\n - `coerce_unsized`: `libcore/ops/unsize.rs`\n - `drop`: `libcore/ops/drop.rs`\n - `drop_in_place`: `libcore/ptr.rs`\n - `clone`: `libcore/clone.rs`\n - `copy`: `libcore/marker.rs`\n - `send`: `libcore/marker.rs`\n - `sized`: `libcore/marker.rs`\n - `unsize`: `libcore/marker.rs`\n - `sync`: `libcore/marker.rs`\n - `phantom_data`: `libcore/marker.rs`\n - `discriminant_kind`: `libcore/marker.rs`\n - `freeze`: `libcore/marker.rs`\n - `debug_trait`: `libcore/fmt/mod.rs`\n - `non_zero`: `libcore/nonzero.rs`\n - `arc`: `liballoc/sync.rs`\n - `rc`: `liballoc/rc.rs`\n" } , LintCompletion { label : "negative_impls" , description : "# `negative_impls`\n\nThe tracking issue for this feature is [#68318].\n\n[#68318]: https://github.com/rust-lang/rust/issues/68318\n\n----\n\nWith the feature gate `negative_impls`, you can write negative impls as well as positive ones:\n\n```rust\n#![feature(negative_impls)]\ntrait DerefMut { }\nimpl !DerefMut for &T { }\n```\n\nNegative impls indicate a semver guarantee that the given trait will not be implemented for the given types. Negative impls play an additional purpose for auto traits, described below.\n\nNegative impls have the following characteristics:\n\n* They do not have any items.\n* They must obey the orphan rules as if they were a positive impl.\n* They cannot \"overlap\" with any positive impls.\n\n## Semver interaction\n\nIt is a breaking change to remove a negative impl. Negative impls are a commitment not to implement the given trait for the named types.\n\n## Orphan and overlap rules\n\nNegative impls must obey the same orphan rules as a positive impl. This implies you cannot add a negative impl for types defined in upstream crates and so forth.\n\nSimilarly, negative impls cannot overlap with positive impls, again using the same \"overlap\" check that we ordinarily use to determine if two impls overlap. (Note that positive impls typically cannot overlap with one another either, except as permitted by specialization.)\n\n## Interaction with auto traits\n\nDeclaring a negative impl `impl !SomeAutoTrait for SomeType` for an\nauto-trait serves two purposes:\n\n* as with any trait, it declares that `SomeType` will never implement `SomeAutoTrait`;\n* it disables the automatic `SomeType: SomeAutoTrait` impl that would otherwise have been generated.\n\nNote that, at present, there is no way to indicate that a given type\ndoes not implement an auto trait *but that it may do so in the\nfuture*. For ordinary types, this is done by simply not declaring any\nimpl at all, but that is not an option for auto traits. A workaround\nis that one could embed a marker type as one of the fields, where the\nmarker type is `!AutoTrait`.\n\n## Immediate uses\n\nNegative impls are used to declare that `&T: !DerefMut` and `&mut T: !Clone`, as required to fix the soundness of `Pin` described in [#66544](https://github.com/rust-lang/rust/issues/66544).\n\nThis serves two purposes:\n\n* For proving the correctness of unsafe code, we can use that impl as evidence that no `DerefMut` or `Clone` impl exists.\n* It prevents downstream crates from creating such impls.\n" } , LintCompletion { label : "abi_ptx" , description : "# `abi_ptx`\n\nThe tracking issue for this feature is: [#38788]\n\n[#38788]: https://github.com/rust-lang/rust/issues/38788\n\n------------------------\n\nWhen emitting PTX code, all vanilla Rust functions (`fn`) get translated to\n\"device\" functions. These functions are *not* callable from the host via the\nCUDA API so a crate with only device functions is not too useful!\n\nOTOH, \"global\" functions *can* be called by the host; you can think of them\nas the real public API of your crate. To produce a global function use the\n`\"ptx-kernel\"` ABI.\n\n\n\n``` rust,ignore\n#![feature(abi_ptx)]\n#![no_std]\n\npub unsafe extern \"ptx-kernel\" fn global_function() {\n device_function();\n}\n\npub fn device_function() {\n // ..\n}\n```\n\n``` text\n$ xargo rustc --target nvptx64-nvidia-cuda --release -- --emit=asm\n\n$ cat $(find -name '*.s')\n//\n// Generated by LLVM NVPTX Back-End\n//\n\n.version 3.2\n.target sm_20\n.address_size 64\n\n // .globl _ZN6kernel15global_function17h46111ebe6516b382E\n\n.visible .entry _ZN6kernel15global_function17h46111ebe6516b382E()\n{\n\n\n ret;\n}\n\n // .globl _ZN6kernel15device_function17hd6a0e4993bbf3f78E\n.visible .func _ZN6kernel15device_function17hd6a0e4993bbf3f78E()\n{\n\n\n ret;\n}\n```\n" } , LintCompletion { label : "try_blocks" , description : "# `try_blocks`\n\nThe tracking issue for this feature is: [#31436]\n\n[#31436]: https://github.com/rust-lang/rust/issues/31436\n\n------------------------\n\nThe `try_blocks` feature adds support for `try` blocks. A `try`\nblock creates a new scope one can use the `?` operator in.\n\n```rust,edition2018\n#![feature(try_blocks)]\n\nuse std::num::ParseIntError;\n\nlet result: Result = try {\n \"1\".parse::()?\n + \"2\".parse::()?\n + \"3\".parse::()?\n};\nassert_eq!(result, Ok(6));\n\nlet result: Result = try {\n \"1\".parse::()?\n + \"foo\".parse::()?\n + \"3\".parse::()?\n};\nassert!(result.is_err());\n```\n" } , LintCompletion { label : "profiler_runtime" , description : "# `profiler_runtime`\n\nThe tracking issue for this feature is: [#42524](https://github.com/rust-lang/rust/issues/42524).\n\n------------------------\n" } , LintCompletion { label : "compiler_builtins" , description : "# `compiler_builtins`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "doc_spotlight" , description : "# `doc_spotlight`\n\nThe tracking issue for this feature is: [#45040]\n\nThe `doc_spotlight` feature allows the use of the `spotlight` parameter to the `#[doc]` attribute,\nto \"spotlight\" a specific trait on the return values of functions. Adding a `#[doc(spotlight)]`\nattribute to a trait definition will make rustdoc print extra information for functions which return\na type that implements that trait. This attribute is applied to the `Iterator`, `io::Read`, and\n`io::Write` traits in the standard library.\n\nYou can do this on your own traits, like this:\n\n```\n#![feature(doc_spotlight)]\n\n#[doc(spotlight)]\npub trait MyTrait {}\n\npub struct MyStruct;\nimpl MyTrait for MyStruct {}\n\n/// The docs for this function will have an extra line about `MyStruct` implementing `MyTrait`,\n/// without having to write that yourself!\npub fn my_fn() -> MyStruct { MyStruct }\n```\n\nThis feature was originally implemented in PR [#45039].\n\n[#45040]: https://github.com/rust-lang/rust/issues/45040\n[#45039]: https://github.com/rust-lang/rust/pull/45039\n" } , LintCompletion { label : "box_patterns" , description : "# `box_patterns`\n\nThe tracking issue for this feature is: [#29641]\n\n[#29641]: https://github.com/rust-lang/rust/issues/29641\n\nSee also [`box_syntax`](box-syntax.md)\n\n------------------------\n\nBox patterns let you match on `Box`s:\n\n\n```rust\n#![feature(box_patterns)]\n\nfn main() {\n let b = Some(Box::new(5));\n match b {\n Some(box n) if n < 0 => {\n println!(\"Box contains negative number {}\", n);\n },\n Some(box n) if n >= 0 => {\n println!(\"Box contains non-negative number {}\", n);\n },\n None => {\n println!(\"No box\");\n },\n _ => unreachable!()\n }\n}\n```\n" } , LintCompletion { label : "const_eval_limit" , description : "# `const_eval_limit`\n\nThe tracking issue for this feature is: [#67217]\n\n[#67217]: https://github.com/rust-lang/rust/issues/67217\n\nThe `const_eval_limit` allows someone to limit the evaluation steps the CTFE undertakes to evaluate a `const fn`.\n" } , LintCompletion { label : "arbitrary_enum_discriminant" , description : "# `arbitrary_enum_discriminant`\n\nThe tracking issue for this feature is: [#60553]\n\n[#60553]: https://github.com/rust-lang/rust/issues/60553\n\n------------------------\n\nThe `arbitrary_enum_discriminant` feature permits tuple-like and\nstruct-like enum variants with `#[repr()]` to have explicit discriminants.\n\n## Examples\n\n```rust\n#![feature(arbitrary_enum_discriminant)]\n\n#[allow(dead_code)]\n#[repr(u8)]\nenum Enum {\n Unit = 3,\n Tuple(u16) = 2,\n Struct {\n a: u8,\n b: u16,\n } = 1,\n}\n\nimpl Enum {\n fn tag(&self) -> u8 {\n unsafe { *(self as *const Self as *const u8) }\n }\n}\n\nassert_eq!(3, Enum::Unit.tag());\nassert_eq!(2, Enum::Tuple(5).tag());\nassert_eq!(1, Enum::Struct{a: 7, b: 11}.tag());\n```\n" } , LintCompletion { label : "custom_test_frameworks" , description : "# `custom_test_frameworks`\n\nThe tracking issue for this feature is: [#50297]\n\n[#50297]: https://github.com/rust-lang/rust/issues/50297\n\n------------------------\n\nThe `custom_test_frameworks` feature allows the use of `#[test_case]` and `#![test_runner]`.\nAny function, const, or static can be annotated with `#[test_case]` causing it to be aggregated (like `#[test]`)\nand be passed to the test runner determined by the `#![test_runner]` crate attribute.\n\n```rust\n#![feature(custom_test_frameworks)]\n#![test_runner(my_runner)]\n\nfn my_runner(tests: &[&i32]) {\n for t in tests {\n if **t == 0 {\n println!(\"PASSED\");\n } else {\n println!(\"FAILED\");\n }\n }\n}\n\n#[test_case]\nconst WILL_PASS: i32 = 0;\n\n#[test_case]\nconst WILL_FAIL: i32 = 4;\n```\n\n" } , LintCompletion { label : "plugin_registrar" , description : "# `plugin_registrar`\n\nThe tracking issue for this feature is: [#29597]\n\n[#29597]: https://github.com/rust-lang/rust/issues/29597\n\nThis feature is part of \"compiler plugins.\" It will often be used with the\n[`plugin`] and `rustc_private` features as well. For more details, see\ntheir docs.\n\n[`plugin`]: plugin.md\n\n------------------------\n" } , LintCompletion { label : "impl_trait_in_bindings" , description : "# `impl_trait_in_bindings`\n\nThe tracking issue for this feature is: [#63065]\n\n[#63065]: https://github.com/rust-lang/rust/issues/63065\n\n------------------------\n\nThe `impl_trait_in_bindings` feature gate lets you use `impl Trait` syntax in\n`let`, `static`, and `const` bindings.\n\nA simple example is:\n\n```rust\n#![feature(impl_trait_in_bindings)]\n\nuse std::fmt::Debug;\n\nfn main() {\n let a: impl Debug + Clone = 42;\n let b = a.clone();\n println!(\"{:?}\", b); // prints `42`\n}\n```\n\nNote however that because the types of `a` and `b` are opaque in the above\nexample, calling inherent methods or methods outside of the specified traits\n(e.g., `a.abs()` or `b.abs()`) is not allowed, and yields an error.\n" } , LintCompletion { label : "ffi_pure" , description : "# `ffi_pure`\n\nThe `#[ffi_pure]` attribute applies clang's `pure` attribute to foreign\nfunctions declarations.\n\nThat is, `#[ffi_pure]` functions shall have no effects except for its return\nvalue, which shall not change across two consecutive function calls with\nthe same parameters.\n\nApplying the `#[ffi_pure]` attribute to a function that violates these\nrequirements is undefined behavior.\n\nThis attribute enables Rust to perform common optimizations, like sub-expression\nelimination and loop optimizations. Some common examples of pure functions are\n`strlen` or `memcmp`.\n\nThese optimizations are only applicable when the compiler can prove that no\nprogram state observable by the `#[ffi_pure]` function has changed between calls\nof the function, which could alter the result. See also the `#[ffi_const]`\nattribute, which provides stronger guarantees regarding the allowable behavior\nof a function, enabling further optimization.\n\n## Pitfalls\n\nA `#[ffi_pure]` function can read global memory through the function\nparameters (e.g. pointers), globals, etc. `#[ffi_pure]` functions are not\nreferentially-transparent, and are therefore more relaxed than `#[ffi_const]`\nfunctions.\n\nHowever, accesing global memory through volatile or atomic reads can violate the\nrequirement that two consecutive function calls shall return the same value.\n\nA `pure` function that returns unit has no effect on the abstract machine's\nstate.\n\nA `#[ffi_pure]` function must not diverge, neither via a side effect (e.g. a\ncall to `abort`) nor by infinite loops.\n\nWhen translating C headers to Rust FFI, it is worth verifying for which targets\nthe `pure` attribute is enabled in those headers, and using the appropriate\n`cfg` macros in the Rust side to match those definitions. While the semantics of\n`pure` are implemented identically by many C and C++ compilers, e.g., clang,\n[GCC], [ARM C/C++ compiler], [IBM ILE C/C++], etc. they are not necessarily\nimplemented in this way on all of them. It is therefore also worth verifying\nthat the semantics of the C toolchain used to compile the binary being linked\nagainst are compatible with those of the `#[ffi_pure]`.\n\n\n[ARM C/C++ compiler]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/Cacigdac.html\n[GCC]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-pure-function-attribute\n[IBM ILE C/C++]: https://www.ibm.com/support/knowledgecenter/fr/ssw_ibm_i_71/rzarg/fn_attrib_pure.htm\n" } , LintCompletion { label : "const_fn" , description : "# `const_fn`\n\nThe tracking issue for this feature is: [#57563]\n\n[#57563]: https://github.com/rust-lang/rust/issues/57563\n\n------------------------\n\nThe `const_fn` feature allows marking free functions and inherent methods as\n`const`, enabling them to be called in constants contexts, with constant\narguments.\n\n## Examples\n\n```rust\n#![feature(const_fn)]\n\nconst fn double(x: i32) -> i32 {\n x * 2\n}\n\nconst FIVE: i32 = 5;\nconst TEN: i32 = double(FIVE);\n\nfn main() {\n assert_eq!(5, FIVE);\n assert_eq!(10, TEN);\n}\n```\n" } , LintCompletion { label : "intrinsics" , description : "# `intrinsics`\n\nThe tracking issue for this feature is: None.\n\nIntrinsics are never intended to be stable directly, but intrinsics are often\nexported in some sort of stable manner. Prefer using the stable interfaces to\nthe intrinsic directly when you can.\n\n------------------------\n\n\nThese are imported as if they were FFI functions, with the special\n`rust-intrinsic` ABI. For example, if one was in a freestanding\ncontext, but wished to be able to `transmute` between types, and\nperform efficient pointer arithmetic, one would import those functions\nvia a declaration like\n\n```rust\n#![feature(intrinsics)]\n# fn main() {}\n\nextern \"rust-intrinsic\" {\n fn transmute(x: T) -> U;\n\n fn offset(dst: *const T, offset: isize) -> *const T;\n}\n```\n\nAs with any other FFI functions, these are always `unsafe` to call.\n\n" } , LintCompletion { label : "c_variadic" , description : "# `c_variadic`\n\nThe tracking issue for this feature is: [#44930]\n\n[#44930]: https://github.com/rust-lang/rust/issues/44930\n\n------------------------\n\nThe `c_variadic` language feature enables C-variadic functions to be\ndefined in Rust. The may be called both from within Rust and via FFI.\n\n## Examples\n\n```rust\n#![feature(c_variadic)]\n\npub unsafe extern \"C\" fn add(n: usize, mut args: ...) -> usize {\n let mut sum = 0;\n for _ in 0..n {\n sum += args.arg::();\n }\n sum\n}\n```\n" } , LintCompletion { label : "cfg_sanitize" , description : "# `cfg_sanitize`\n\nThe tracking issue for this feature is: [#39699]\n\n[#39699]: https://github.com/rust-lang/rust/issues/39699\n\n------------------------\n\nThe `cfg_sanitize` feature makes it possible to execute different code\ndepending on whether a particular sanitizer is enabled or not.\n\n## Examples\n\n```rust\n#![feature(cfg_sanitize)]\n\n#[cfg(sanitize = \"thread\")]\nfn a() {\n // ...\n}\n\n#[cfg(not(sanitize = \"thread\"))]\nfn a() {\n // ...\n}\n\nfn b() {\n if cfg!(sanitize = \"leak\") {\n // ...\n } else {\n // ...\n }\n}\n```\n" } , LintCompletion { label : "allocator_internals" , description : "# `allocator_internals`\n\nThis feature does not have a tracking issue, it is an unstable implementation\ndetail of the `global_allocator` feature not intended for use outside the\ncompiler.\n\n------------------------\n" } , LintCompletion { label : "doc_alias" , description : "# `doc_alias`\n\nThe tracking issue for this feature is: [#50146]\n\n[#50146]: https://github.com/rust-lang/rust/issues/50146\n\n------------------------\n\nYou can add alias(es) to an item when using the `rustdoc` search through the\n`doc(alias)` attribute. Example:\n\n```rust,no_run\n#![feature(doc_alias)]\n\n#[doc(alias = \"x\")]\n#[doc(alias = \"big\")]\npub struct BigX;\n```\n\nThen, when looking for it through the `rustdoc` search, if you enter \"x\" or\n\"big\", search will show the `BigX` struct first.\n\nNote that this feature is currently hidden behind the `feature(doc_alias)` gate.\n" } , LintCompletion { label : "link_cfg" , description : "# `link_cfg`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "transparent_unions" , description : "# `transparent_unions`\n\nThe tracking issue for this feature is [#60405]\n\n[#60405]: https://github.com/rust-lang/rust/issues/60405\n\n----\n\nThe `transparent_unions` feature allows you mark `union`s as\n`#[repr(transparent)]`. A `union` may be `#[repr(transparent)]` in exactly the\nsame conditions in which a `struct` may be `#[repr(transparent)]` (generally,\nthis means the `union` must have exactly one non-zero-sized field). Some\nconcrete illustrations follow.\n\n```rust\n#![feature(transparent_unions)]\n\n// This union has the same representation as `f32`.\n#[repr(transparent)]\nunion SingleFieldUnion {\n field: f32,\n}\n\n// This union has the same representation as `usize`.\n#[repr(transparent)]\nunion MultiFieldUnion {\n field: usize,\n nothing: (),\n}\n```\n\nFor consistency with transparent `struct`s, `union`s must have exactly one\nnon-zero-sized field. If all fields are zero-sized, the `union` must not be\n`#[repr(transparent)]`:\n\n```rust\n#![feature(transparent_unions)]\n\n// This (non-transparent) union is already valid in stable Rust:\npub union GoodUnion {\n pub nothing: (),\n}\n\n// Error: transparent union needs exactly one non-zero-sized field, but has 0\n// #[repr(transparent)]\n// pub union BadUnion {\n// pub nothing: (),\n// }\n```\n\nThe one exception is if the `union` is generic over `T` and has a field of type\n`T`, it may be `#[repr(transparent)]` even if `T` is a zero-sized type:\n\n```rust\n#![feature(transparent_unions)]\n\n// This union has the same representation as `T`.\n#[repr(transparent)]\npub union GenericUnion { // Unions with non-`Copy` fields are unstable.\n pub field: T,\n pub nothing: (),\n}\n\n// This is okay even though `()` is a zero-sized type.\npub const THIS_IS_OKAY: GenericUnion<()> = GenericUnion { field: () };\n```\n\nLike transarent `struct`s, a transparent `union` of type `U` has the same\nlayout, size, and ABI as its single non-ZST field. If it is generic over a type\n`T`, and all its fields are ZSTs except for exactly one field of type `T`, then\nit has the same layout and ABI as `T` (even if `T` is a ZST when monomorphized).\n\nLike transparent `struct`s, transparent `union`s are FFI-safe if and only if\ntheir underlying representation type is also FFI-safe.\n\nA `union` may not be eligible for the same nonnull-style optimizations that a\n`struct` or `enum` (with the same fields) are eligible for. Adding\n`#[repr(transparent)]` to `union` does not change this. To give a more concrete\nexample, it is unspecified whether `size_of::()` is equal to\n`size_of::>()`, where `T` is a `union` (regardless of whether or not\nit is transparent). The Rust compiler is free to perform this optimization if\npossible, but is not required to, and different compiler versions may differ in\ntheir application of these optimizations.\n" } , LintCompletion { label : "plugin" , description : "# `plugin`\n\nThe tracking issue for this feature is: [#29597]\n\n[#29597]: https://github.com/rust-lang/rust/issues/29597\n\n\nThis feature is part of \"compiler plugins.\" It will often be used with the\n[`plugin_registrar`] and `rustc_private` features.\n\n[`plugin_registrar`]: plugin-registrar.md\n\n------------------------\n\n`rustc` can load compiler plugins, which are user-provided libraries that\nextend the compiler's behavior with new lint checks, etc.\n\nA plugin is a dynamic library crate with a designated *registrar* function that\nregisters extensions with `rustc`. Other crates can load these extensions using\nthe crate attribute `#![plugin(...)]`. See the\n`rustc_driver::plugin` documentation for more about the\nmechanics of defining and loading a plugin.\n\nIn the vast majority of cases, a plugin should *only* be used through\n`#![plugin]` and not through an `extern crate` item. Linking a plugin would\npull in all of librustc_ast and librustc as dependencies of your crate. This is\ngenerally unwanted unless you are building another plugin.\n\nThe usual practice is to put compiler plugins in their own crate, separate from\nany `macro_rules!` macros or ordinary Rust code meant to be used by consumers\nof a library.\n\n# Lint plugins\n\nPlugins can extend [Rust's lint\ninfrastructure](../../reference/attributes/diagnostics.md#lint-check-attributes) with\nadditional checks for code style, safety, etc. Now let's write a plugin\n[`lint-plugin-test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs)\nthat warns about any item named `lintme`.\n\n```rust,ignore\n#![feature(plugin_registrar)]\n#![feature(box_syntax, rustc_private)]\n\nextern crate rustc_ast;\n\n// Load rustc as a plugin to get macros\nextern crate rustc_driver;\n#[macro_use]\nextern crate rustc_lint;\n#[macro_use]\nextern crate rustc_session;\n\nuse rustc_driver::plugin::Registry;\nuse rustc_lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};\nuse rustc_ast::ast;\ndeclare_lint!(TEST_LINT, Warn, \"Warn about items named 'lintme'\");\n\ndeclare_lint_pass!(Pass => [TEST_LINT]);\n\nimpl EarlyLintPass for Pass {\n fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) {\n if it.ident.name.as_str() == \"lintme\" {\n cx.lint(TEST_LINT, |lint| {\n lint.build(\"item is named 'lintme'\").set_span(it.span).emit()\n });\n }\n }\n}\n\n#[plugin_registrar]\npub fn plugin_registrar(reg: &mut Registry) {\n reg.lint_store.register_lints(&[&TEST_LINT]);\n reg.lint_store.register_early_pass(|| box Pass);\n}\n```\n\nThen code like\n\n```rust,ignore\n#![feature(plugin)]\n#![plugin(lint_plugin_test)]\n\nfn lintme() { }\n```\n\nwill produce a compiler warning:\n\n```txt\nfoo.rs:4:1: 4:16 warning: item is named 'lintme', #[warn(test_lint)] on by default\nfoo.rs:4 fn lintme() { }\n ^~~~~~~~~~~~~~~\n```\n\nThe components of a lint plugin are:\n\n* one or more `declare_lint!` invocations, which define static `Lint` structs;\n\n* a struct holding any state needed by the lint pass (here, none);\n\n* a `LintPass`\n implementation defining how to check each syntax element. A single\n `LintPass` may call `span_lint` for several different `Lint`s, but should\n register them all through the `get_lints` method.\n\nLint passes are syntax traversals, but they run at a late stage of compilation\nwhere type information is available. `rustc`'s [built-in\nlints](https://github.com/rust-lang/rust/blob/master/src/librustc_session/lint/builtin.rs)\nmostly use the same infrastructure as lint plugins, and provide examples of how\nto access type information.\n\nLints defined by plugins are controlled by the usual [attributes and compiler\nflags](../../reference/attributes/diagnostics.md#lint-check-attributes), e.g.\n`#[allow(test_lint)]` or `-A test-lint`. These identifiers are derived from the\nfirst argument to `declare_lint!`, with appropriate case and punctuation\nconversion.\n\nYou can run `rustc -W help foo.rs` to see a list of lints known to `rustc`,\nincluding those provided by plugins loaded by `foo.rs`.\n" } , LintCompletion { label : "concat_idents" , description : "# `concat_idents`\n\nThe tracking issue for this feature is: [#29599]\n\n[#29599]: https://github.com/rust-lang/rust/issues/29599\n\n------------------------\n\nThe `concat_idents` feature adds a macro for concatenating multiple identifiers\ninto one identifier.\n\n## Examples\n\n```rust\n#![feature(concat_idents)]\n\nfn main() {\n fn foobar() -> u32 { 23 }\n let f = concat_idents!(foo, bar);\n assert_eq!(f(), 23);\n}\n```" } , LintCompletion { label : "update_panic_count" , description : "# `update_panic_count`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "fn_traits" , description : "# `fn_traits`\n\nThe tracking issue for this feature is [#29625]\n\nSee Also: [`unboxed_closures`](../language-features/unboxed-closures.md)\n\n[#29625]: https://github.com/rust-lang/rust/issues/29625\n\n----\n\nThe `fn_traits` feature allows for implementation of the [`Fn*`] traits\nfor creating custom closure-like types.\n\n[`Fn*`]: https://doc.rust-lang.org/std/ops/trait.Fn.html\n\n```rust\n#![feature(unboxed_closures)]\n#![feature(fn_traits)]\n\nstruct Adder {\n a: u32\n}\n\nimpl FnOnce<(u32, )> for Adder {\n type Output = u32;\n extern \"rust-call\" fn call_once(self, b: (u32, )) -> Self::Output {\n self.a + b.0\n }\n}\n\nfn main() {\n let adder = Adder { a: 3 };\n assert_eq!(adder(2), 5);\n}\n```\n" } , LintCompletion { label : "try_trait" , description : "# `try_trait`\n\nThe tracking issue for this feature is: [#42327]\n\n[#42327]: https://github.com/rust-lang/rust/issues/42327\n\n------------------------\n\nThis introduces a new trait `Try` for extending the `?` operator to types\nother than `Result` (a part of [RFC 1859]). The trait provides the canonical\nway to _view_ a type in terms of a success/failure dichotomy. This will\nallow `?` to supplant the `try_opt!` macro on `Option` and the `try_ready!`\nmacro on `Poll`, among other things.\n\n[RFC 1859]: https://github.com/rust-lang/rfcs/pull/1859\n\nHere's an example implementation of the trait:\n\n```rust,ignore\n/// A distinct type to represent the `None` value of an `Option`.\n///\n/// This enables using the `?` operator on `Option`; it's rarely useful alone.\n#[derive(Debug)]\n#[unstable(feature = \"try_trait\", issue = \"42327\")]\npub struct None { _priv: () }\n\n#[unstable(feature = \"try_trait\", issue = \"42327\")]\nimpl ops::Try for Option {\n type Ok = T;\n type Error = None;\n\n fn into_result(self) -> Result {\n self.ok_or(None { _priv: () })\n }\n\n fn from_ok(v: T) -> Self {\n Some(v)\n }\n\n fn from_error(_: None) -> Self {\n None\n }\n}\n```\n\nNote the `Error` associated type here is a new marker. The `?` operator\nallows interconversion between different `Try` implementers only when\nthe error type can be converted `Into` the error type of the enclosing\nfunction (or catch block). Having a distinct error type (as opposed to\njust `()`, or similar) restricts this to where it's semantically meaningful.\n" } , LintCompletion { label : "rt" , description : "# `rt`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "default_free_fn" , description : "# `default_free_fn`\n\nThe tracking issue for this feature is: [#73014]\n\n[#73014]: https://github.com/rust-lang/rust/issues/73014\n\n------------------------\n\nAdds a free `default()` function to the `std::default` module. This function\njust forwards to [`Default::default()`], but may remove repetition of the word\n\"default\" from the call site.\n\nHere is an example:\n\n```rust\n#![feature(default_free_fn)]\nuse std::default::default;\n\n#[derive(Default)]\nstruct AppConfig {\n foo: FooConfig,\n bar: BarConfig,\n}\n\n#[derive(Default)]\nstruct FooConfig {\n foo: i32,\n}\n\n#[derive(Default)]\nstruct BarConfig {\n bar: f32,\n baz: u8,\n}\n\nfn main() {\n let options = AppConfig {\n foo: default(),\n bar: BarConfig {\n bar: 10.1,\n ..default()\n },\n };\n}\n```\n" } , LintCompletion { label : "libstd_sys_internals" , description : "# `libstd_sys_internals`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "fd" , description : "# `fd`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "dec2flt" , description : "# `dec2flt`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "fmt_internals" , description : "# `fmt_internals`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "int_error_internals" , description : "# `int_error_internals`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "libstd_thread_internals" , description : "# `libstd_thread_internals`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "windows_net" , description : "# `windows_net`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "core_intrinsics" , description : "# `core_intrinsics`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "global_asm" , description : "# `global_asm`\n\nThe tracking issue for this feature is: [#35119]\n\n[#35119]: https://github.com/rust-lang/rust/issues/35119\n\n------------------------\n\nThe `global_asm!` macro allows the programmer to write arbitrary\nassembly outside the scope of a function body, passing it through\n`rustc` and `llvm` to the assembler. The macro is a no-frills\ninterface to LLVM's concept of [module-level inline assembly]. That is,\nall caveats applicable to LLVM's module-level inline assembly apply\nto `global_asm!`.\n\n[module-level inline assembly]: http://llvm.org/docs/LangRef.html#module-level-inline-assembly\n\n`global_asm!` fills a role not currently satisfied by either `asm!`\nor `#[naked]` functions. The programmer has _all_ features of the\nassembler at their disposal. The linker will expect to resolve any\nsymbols defined in the inline assembly, modulo any symbols marked as\nexternal. It also means syntax for directives and assembly follow the\nconventions of the assembler in your toolchain.\n\nA simple usage looks like this:\n\n```rust,ignore\n# #![feature(global_asm)]\n# you also need relevant target_arch cfgs\nglobal_asm!(include_str!(\"something_neato.s\"));\n```\n\nAnd a more complicated usage looks like this:\n\n```rust,ignore\n# #![feature(global_asm)]\n# #![cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\n\npub mod sally {\n global_asm!(r#\"\n .global foo\n foo:\n jmp baz\n \"#);\n\n #[no_mangle]\n pub unsafe extern \"C\" fn baz() {}\n}\n\n// the symbols `foo` and `bar` are global, no matter where\n// `global_asm!` was used.\nextern \"C\" {\n fn foo();\n fn bar();\n}\n\npub mod harry {\n global_asm!(r#\"\n .global bar\n bar:\n jmp quux\n \"#);\n\n #[no_mangle]\n pub unsafe extern \"C\" fn quux() {}\n}\n```\n\nYou may use `global_asm!` multiple times, anywhere in your crate, in\nwhatever way suits you. The effect is as if you concatenated all\nusages and placed the larger, single usage in the crate root.\n\n------------------------\n\nIf you don't need quite as much power and flexibility as\n`global_asm!` provides, and you don't mind restricting your inline\nassembly to `fn` bodies only, you might try the\n[asm](asm.md) feature instead.\n" } , LintCompletion { label : "sort_internals" , description : "# `sort_internals`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "test" , description : "# `test`\n\nThe tracking issue for this feature is: None.\n\n------------------------\n\nThe internals of the `test` crate are unstable, behind the `test` flag. The\nmost widely used part of the `test` crate are benchmark tests, which can test\nthe performance of your code. Let's make our `src/lib.rs` look like this\n(comments elided):\n\n```rust,ignore\n#![feature(test)]\n\nextern crate test;\n\npub fn add_two(a: i32) -> i32 {\n a + 2\n}\n\n#[cfg(test)]\nmod tests {\n use super::*;\n use test::Bencher;\n\n #[test]\n fn it_works() {\n assert_eq!(4, add_two(2));\n }\n\n #[bench]\n fn bench_add_two(b: &mut Bencher) {\n b.iter(|| add_two(2));\n }\n}\n```\n\nNote the `test` feature gate, which enables this unstable feature.\n\nWe've imported the `test` crate, which contains our benchmarking support.\nWe have a new function as well, with the `bench` attribute. Unlike regular\ntests, which take no arguments, benchmark tests take a `&mut Bencher`. This\n`Bencher` provides an `iter` method, which takes a closure. This closure\ncontains the code we'd like to benchmark.\n\nWe can run benchmark tests with `cargo bench`:\n\n```bash\n$ cargo bench\n Compiling adder v0.0.1 (file:///home/steve/tmp/adder)\n Running target/release/adder-91b3e234d4ed382a\n\nrunning 2 tests\ntest tests::it_works ... ignored\ntest tests::bench_add_two ... bench: 1 ns/iter (+/- 0)\n\ntest result: ok. 0 passed; 0 failed; 1 ignored; 1 measured\n```\n\nOur non-benchmark test was ignored. You may have noticed that `cargo bench`\ntakes a bit longer than `cargo test`. This is because Rust runs our benchmark\na number of times, and then takes the average. Because we're doing so little\nwork in this example, we have a `1 ns/iter (+/- 0)`, but this would show\nthe variance if there was one.\n\nAdvice on writing benchmarks:\n\n\n* Move setup code outside the `iter` loop; only put the part you want to measure inside\n* Make the code do \"the same thing\" on each iteration; do not accumulate or change state\n* Make the outer function idempotent too; the benchmark runner is likely to run\n it many times\n* Make the inner `iter` loop short and fast so benchmark runs are fast and the\n calibrator can adjust the run-length at fine resolution\n* Make the code in the `iter` loop do something simple, to assist in pinpointing\n performance improvements (or regressions)\n\n## Gotcha: optimizations\n\nThere's another tricky part to writing benchmarks: benchmarks compiled with\noptimizations activated can be dramatically changed by the optimizer so that\nthe benchmark is no longer benchmarking what one expects. For example, the\ncompiler might recognize that some calculation has no external effects and\nremove it entirely.\n\n```rust,ignore\n#![feature(test)]\n\nextern crate test;\nuse test::Bencher;\n\n#[bench]\nfn bench_xor_1000_ints(b: &mut Bencher) {\n b.iter(|| {\n (0..1000).fold(0, |old, new| old ^ new);\n });\n}\n```\n\ngives the following results\n\n```text\nrunning 1 test\ntest bench_xor_1000_ints ... bench: 0 ns/iter (+/- 0)\n\ntest result: ok. 0 passed; 0 failed; 0 ignored; 1 measured\n```\n\nThe benchmarking runner offers two ways to avoid this. Either, the closure that\nthe `iter` method receives can return an arbitrary value which forces the\noptimizer to consider the result used and ensures it cannot remove the\ncomputation entirely. This could be done for the example above by adjusting the\n`b.iter` call to\n\n```rust\n# struct X;\n# impl X { fn iter(&self, _: F) where F: FnMut() -> T {} } let b = X;\nb.iter(|| {\n // Note lack of `;` (could also use an explicit `return`).\n (0..1000).fold(0, |old, new| old ^ new)\n});\n```\n\nOr, the other option is to call the generic `test::black_box` function, which\nis an opaque \"black box\" to the optimizer and so forces it to consider any\nargument as used.\n\n```rust\n#![feature(test)]\n\nextern crate test;\n\n# fn main() {\n# struct X;\n# impl X { fn iter(&self, _: F) where F: FnMut() -> T {} } let b = X;\nb.iter(|| {\n let n = test::black_box(1000);\n\n (0..n).fold(0, |a, b| a ^ b)\n})\n# }\n```\n\nNeither of these read or modify the value, and are very cheap for small values.\nLarger values can be passed indirectly to reduce overhead (e.g.\n`black_box(&huge_struct)`).\n\nPerforming either of the above changes gives the following benchmarking results\n\n```text\nrunning 1 test\ntest bench_xor_1000_ints ... bench: 131 ns/iter (+/- 3)\n\ntest result: ok. 0 passed; 0 failed; 0 ignored; 1 measured\n```\n\nHowever, the optimizer can still modify a testcase in an undesirable manner\neven when using either of the above.\n" } , LintCompletion { label : "windows_stdio" , description : "# `windows_stdio`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "allocator_api" , description : "# `allocator_api`\n\nThe tracking issue for this feature is [#32838]\n\n[#32838]: https://github.com/rust-lang/rust/issues/32838\n\n------------------------\n\nSometimes you want the memory for one collection to use a different\nallocator than the memory for another collection. In this case,\nreplacing the global allocator is not a workable option. Instead,\nyou need to pass in an instance of an `AllocRef` to each collection\nfor which you want a custom allocator.\n\nTBD\n" } , LintCompletion { label : "asm" , description : "# `asm`\n\nThe tracking issue for this feature is: [#72016]\n\n[#72016]: https://github.com/rust-lang/rust/issues/72016\n\n------------------------\n\nFor extremely low-level manipulations and performance reasons, one\nmight wish to control the CPU directly. Rust supports using inline\nassembly to do this via the `asm!` macro.\n\n# Guide-level explanation\n[guide-level-explanation]: #guide-level-explanation\n\nRust provides support for inline assembly via the `asm!` macro.\nIt can be used to embed handwritten assembly in the assembly output generated by the compiler.\nGenerally this should not be necessary, but might be where the required performance or timing\ncannot be otherwise achieved. Accessing low level hardware primitives, e.g. in kernel code, may also demand this functionality.\n\n> **Note**: the examples here are given in x86/x86-64 assembly, but ARM, AArch64 and RISC-V are also supported.\n\n## Basic usage\n\nLet us start with the simplest possible example:\n\n```rust,allow_fail\n# #![feature(asm)]\nunsafe {\n asm!(\"nop\");\n}\n```\n\nThis will insert a NOP (no operation) instruction into the assembly generated by the compiler.\nNote that all `asm!` invocations have to be inside an `unsafe` block, as they could insert\narbitrary instructions and break various invariants. The instructions to be inserted are listed\nin the first argument of the `asm!` macro as a string literal.\n\n## Inputs and outputs\n\nNow inserting an instruction that does nothing is rather boring. Let us do something that\nactually acts on data:\n\n```rust,allow_fail\n# #![feature(asm)]\nlet x: u64;\nunsafe {\n asm!(\"mov {}, 5\", out(reg) x);\n}\nassert_eq!(x, 5);\n```\n\nThis will write the value `5` into the `u64` variable `x`.\nYou can see that the string literal we use to specify instructions is actually a template string.\nIt is governed by the same rules as Rust [format strings][format-syntax].\nThe arguments that are inserted into the template however look a bit different then you may\nbe familiar with. First we need to specify if the variable is an input or an output of the\ninline assembly. In this case it is an output. We declared this by writing `out`.\nWe also need to specify in what kind of register the assembly expects the variable.\nIn this case we put it in an arbitrary general purpose register by specifying `reg`.\nThe compiler will choose an appropriate register to insert into\nthe template and will read the variable from there after the inline assembly finishes executing.\n\nLet us see another example that also uses an input:\n\n```rust,allow_fail\n# #![feature(asm)]\nlet i: u64 = 3;\nlet o: u64;\nunsafe {\n asm!(\n \"mov {0}, {1}\",\n \"add {0}, {number}\",\n out(reg) o,\n in(reg) i,\n number = const 5,\n );\n}\nassert_eq!(o, 8);\n```\n\nThis will add `5` to the input in variable `i` and write the result to variable `o`.\nThe particular way this assembly does this is first copying the value from `i` to the output,\nand then adding `5` to it.\n\nThe example shows a few things:\n\nFirst, we can see that `asm!` allows multiple template string arguments; each\none is treated as a separate line of assembly code, as if they were all joined\ntogether with newlines between them. This makes it easy to format assembly\ncode.\n\nSecond, we can see that inputs are declared by writing `in` instead of `out`.\n\nThird, one of our operands has a type we haven't seen yet, `const`.\nThis tells the compiler to expand this argument to value directly inside the assembly template.\nThis is only possible for constants and literals.\n\nFourth, we can see that we can specify an argument number, or name as in any format string.\nFor inline assembly templates this is particularly useful as arguments are often used more than once.\nFor more complex inline assembly using this facility is generally recommended, as it improves\nreadability, and allows reordering instructions without changing the argument order.\n\nWe can further refine the above example to avoid the `mov` instruction:\n\n```rust,allow_fail\n# #![feature(asm)]\nlet mut x: u64 = 3;\nunsafe {\n asm!(\"add {0}, {number}\", inout(reg) x, number = const 5);\n}\nassert_eq!(x, 8);\n```\n\nWe can see that `inout` is used to specify an argument that is both input and output.\nThis is different from specifying an input and output separately in that it is guaranteed to assign both to the same register.\n\nIt is also possible to specify different variables for the input and output parts of an `inout` operand:\n\n```rust,allow_fail\n# #![feature(asm)]\nlet x: u64 = 3;\nlet y: u64;\nunsafe {\n asm!(\"add {0}, {number}\", inout(reg) x => y, number = const 5);\n}\nassert_eq!(y, 8);\n```\n\n## Late output operands\n\nThe Rust compiler is conservative with its allocation of operands. It is assumed that an `out`\ncan be written at any time, and can therefore not share its location with any other argument.\nHowever, to guarantee optimal performance it is important to use as few registers as possible,\nso they won't have to be saved and reloaded around the inline assembly block.\nTo achieve this Rust provides a `lateout` specifier. This can be used on any output that is\nwritten only after all inputs have been consumed.\nThere is also a `inlateout` variant of this specifier.\n\nHere is an example where `inlateout` *cannot* be used:\n\n```rust,allow_fail\n# #![feature(asm)]\nlet mut a: u64 = 4;\nlet b: u64 = 4;\nlet c: u64 = 4;\nunsafe {\n asm!(\n \"add {0}, {1}\",\n \"add {0}, {2}\",\n inout(reg) a,\n in(reg) b,\n in(reg) c,\n );\n}\nassert_eq!(a, 12);\n```\n\nHere the compiler is free to allocate the same register for inputs `b` and `c` since it knows they have the same value. However it must allocate a separate register for `a` since it uses `inout` and not `inlateout`. If `inlateout` was used, then `a` and `c` could be allocated to the same register, in which case the first instruction to overwrite the value of `c` and cause the assembly code to produce the wrong result.\n\nHowever the following example can use `inlateout` since the output is only modified after all input registers have been read:\n\n```rust,allow_fail\n# #![feature(asm)]\nlet mut a: u64 = 4;\nlet b: u64 = 4;\nunsafe {\n asm!(\"add {0}, {1}\", inlateout(reg) a, in(reg) b);\n}\nassert_eq!(a, 8);\n```\n\nAs you can see, this assembly fragment will still work correctly if `a` and `b` are assigned to the same register.\n\n## Explicit register operands\n\nSome instructions require that the operands be in a specific register.\nTherefore, Rust inline assembly provides some more specific constraint specifiers.\nWhile `reg` is generally available on any architecture, these are highly architecture specific. E.g. for x86 the general purpose registers `eax`, `ebx`, `ecx`, `edx`, `ebp`, `esi`, and `edi`\namong others can be addressed by their name.\n\n```rust,allow_fail,no_run\n# #![feature(asm)]\nlet cmd = 0xd1;\nunsafe {\n asm!(\"out 0x64, eax\", in(\"eax\") cmd);\n}\n```\n\nIn this example we call the `out` instruction to output the content of the `cmd` variable\nto port `0x64`. Since the `out` instruction only accepts `eax` (and its sub registers) as operand\nwe had to use the `eax` constraint specifier.\n\nNote that unlike other operand types, explicit register operands cannot be used in the template string: you can't use `{}` and should write the register name directly instead. Also, they must appear at the end of the operand list after all other operand types.\n\nConsider this example which uses the x86 `mul` instruction:\n\n```rust,allow_fail\n# #![feature(asm)]\nfn mul(a: u64, b: u64) -> u128 {\n let lo: u64;\n let hi: u64;\n\n unsafe {\n asm!(\n // The x86 mul instruction takes rax as an implicit input and writes\n // the 128-bit result of the multiplication to rax:rdx.\n \"mul {}\",\n in(reg) a,\n inlateout(\"rax\") b => lo,\n lateout(\"rdx\") hi\n );\n }\n\n ((hi as u128) << 64) + lo as u128\n}\n```\n\nThis uses the `mul` instruction to multiply two 64-bit inputs with a 128-bit result.\nThe only explicit operand is a register, that we fill from the variable `a`.\nThe second operand is implicit, and must be the `rax` register, which we fill from the variable `b`.\nThe lower 64 bits of the result are stored in `rax` from which we fill the variable `lo`.\nThe higher 64 bits are stored in `rdx` from which we fill the variable `hi`.\n\n## Clobbered registers\n\nIn many cases inline assembly will modify state that is not needed as an output.\nUsually this is either because we have to use a scratch register in the assembly,\nor instructions modify state that we don't need to further examine.\nThis state is generally referred to as being \"clobbered\".\nWe need to tell the compiler about this since it may need to save and restore this state\naround the inline assembly block.\n\n```rust,allow_fail\n# #![feature(asm)]\nlet ebx: u32;\nlet ecx: u32;\n\nunsafe {\n asm!(\n \"cpuid\",\n // EAX 4 selects the \"Deterministic Cache Parameters\" CPUID leaf\n inout(\"eax\") 4 => _,\n // ECX 0 selects the L0 cache information.\n inout(\"ecx\") 0 => ecx,\n lateout(\"ebx\") ebx,\n lateout(\"edx\") _,\n );\n}\n\nprintln!(\n \"L1 Cache: {}\",\n ((ebx >> 22) + 1) * (((ebx >> 12) & 0x3ff) + 1) * ((ebx & 0xfff) + 1) * (ecx + 1)\n);\n```\n\nIn the example above we use the `cpuid` instruction to get the L1 cache size.\nThis instruction writes to `eax`, `ebx`, `ecx`, and `edx`, but for the cache size we only care about the contents of `ebx` and `ecx`.\n\nHowever we still need to tell the compiler that `eax` and `edx` have been modified so that it can save any values that were in these registers before the asm. This is done by declaring these as outputs but with `_` instead of a variable name, which indicates that the output value is to be discarded.\n\nThis can also be used with a general register class (e.g. `reg`) to obtain a scratch register for use inside the asm code:\n\n```rust,allow_fail\n# #![feature(asm)]\n// Multiply x by 6 using shifts and adds\nlet mut x: u64 = 4;\nunsafe {\n asm!(\n \"mov {tmp}, {x}\",\n \"shl {tmp}, 1\",\n \"shl {x}, 2\",\n \"add {x}, {tmp}\",\n x = inout(reg) x,\n tmp = out(reg) _,\n );\n}\nassert_eq!(x, 4 * 6);\n```\n\n## Symbol operands\n\nA special operand type, `sym`, allows you to use the symbol name of a `fn` or `static` in inline assembly code.\nThis allows you to call a function or access a global variable without needing to keep its address in a register.\n\n```rust,allow_fail\n# #![feature(asm)]\nextern \"C\" fn foo(arg: i32) {\n println!(\"arg = {}\", arg);\n}\n\nfn call_foo(arg: i32) {\n unsafe {\n asm!(\n \"call {}\",\n sym foo,\n // 1st argument in rdi, which is caller-saved\n inout(\"rdi\") arg => _,\n // All caller-saved registers must be marked as clobberred\n out(\"rax\") _, out(\"rcx\") _, out(\"rdx\") _, out(\"rsi\") _,\n out(\"r8\") _, out(\"r9\") _, out(\"r10\") _, out(\"r11\") _,\n out(\"xmm0\") _, out(\"xmm1\") _, out(\"xmm2\") _, out(\"xmm3\") _,\n out(\"xmm4\") _, out(\"xmm5\") _, out(\"xmm6\") _, out(\"xmm7\") _,\n out(\"xmm8\") _, out(\"xmm9\") _, out(\"xmm10\") _, out(\"xmm11\") _,\n out(\"xmm12\") _, out(\"xmm13\") _, out(\"xmm14\") _, out(\"xmm15\") _,\n )\n }\n}\n```\n\nNote that the `fn` or `static` item does not need to be public or `#[no_mangle]`:\nthe compiler will automatically insert the appropriate mangled symbol name into the assembly code.\n\n## Register template modifiers\n\nIn some cases, fine control is needed over the way a register name is formatted when inserted into the template string. This is needed when an architecture's assembly language has several names for the same register, each typically being a \"view\" over a subset of the register (e.g. the low 32 bits of a 64-bit register).\n\nBy default the compiler will always choose the name that refers to the full register size (e.g. `rax` on x86-64, `eax` on x86, etc).\n\nThis default can be overriden by using modifiers on the template string operands, just like you would with format strings:\n\n```rust,allow_fail\n# #![feature(asm)]\nlet mut x: u16 = 0xab;\n\nunsafe {\n asm!(\"mov {0:h}, {0:l}\", inout(reg_abcd) x);\n}\n\nassert_eq!(x, 0xabab);\n```\n\nIn this example, we use the `reg_abcd` register class to restrict the register allocator to the 4 legacy x86 register (`ax`, `bx`, `cx`, `dx`) of which the first two bytes can be addressed independently.\n\nLet us assume that the register allocator has chosen to allocate `x` in the `ax` register.\nThe `h` modifier will emit the register name for the high byte of that register and the `l` modifier will emit the register name for the low byte. The asm code will therefore be expanded as `mov ah, al` which copies the low byte of the value into the high byte.\n\nIf you use a smaller data type (e.g. `u16`) with an operand and forget the use template modifiers, the compiler will emit a warning and suggest the correct modifier to use.\n\n## Options\n\nBy default, an inline assembly block is treated the same way as an external FFI function call with a custom calling convention: it may read/write memory, have observable side effects, etc. However in many cases, it is desirable to give the compiler more information about what the assembly code is actually doing so that it can optimize better.\n\nLet's take our previous example of an `add` instruction:\n\n```rust,allow_fail\n# #![feature(asm)]\nlet mut a: u64 = 4;\nlet b: u64 = 4;\nunsafe {\n asm!(\n \"add {0}, {1}\",\n inlateout(reg) a, in(reg) b,\n options(pure, nomem, nostack),\n );\n}\nassert_eq!(a, 8);\n```\n\nOptions can be provided as an optional final argument to the `asm!` macro. We specified three options here:\n- `pure` means that the asm code has no observable side effects and that its output depends only on its inputs. This allows the compiler optimizer to call the inline asm fewer times or even eliminate it entirely.\n- `nomem` means that the asm code does not read or write to memory. By default the compiler will assume that inline assembly can read or write any memory address that is accessible to it (e.g. through a pointer passed as an operand, or a global).\n- `nostack` means that the asm code does not push any data onto the stack. This allows the compiler to use optimizations such as the stack red zone on x86-64 to avoid stack pointer adjustments.\n\nThese allow the compiler to better optimize code using `asm!`, for example by eliminating pure `asm!` blocks whose outputs are not needed.\n\nSee the reference for the full list of available options and their effects.\n\n# Reference-level explanation\n[reference-level-explanation]: #reference-level-explanation\n\nInline assembler is implemented as an unsafe macro `asm!()`.\nThe first argument to this macro is a template string literal used to build the final assembly.\nThe following arguments specify input and output operands.\nWhen required, options are specified as the final argument.\n\nThe following ABNF specifies the general syntax:\n\n```ignore\ndir_spec := \"in\" / \"out\" / \"lateout\" / \"inout\" / \"inlateout\"\nreg_spec := / \"\"\noperand_expr := expr / \"_\" / expr \"=>\" expr / expr \"=>\" \"_\"\nreg_operand := dir_spec \"(\" reg_spec \")\" operand_expr\noperand := reg_operand / \"const\" const_expr / \"sym\" path\noption := \"pure\" / \"nomem\" / \"readonly\" / \"preserves_flags\" / \"noreturn\" / \"att_syntax\"\noptions := \"options(\" option *[\",\" option] [\",\"] \")\"\nasm := \"asm!(\" format_string *(\",\" format_string) *(\",\" [ident \"=\"] operand) [\",\" options] [\",\"] \")\"\n```\n\nThe macro will initially be supported only on ARM, AArch64, Hexagon, x86, x86-64 and RISC-V targets. Support for more targets may be added in the future. The compiler will emit an error if `asm!` is used on an unsupported target.\n\n[format-syntax]: https://doc.rust-lang.org/std/fmt/#syntax\n\n## Template string arguments\n\nThe assembler template uses the same syntax as [format strings][format-syntax] (i.e. placeholders are specified by curly braces). The corresponding arguments are accessed in order, by index, or by name. However, implicit named arguments (introduced by [RFC #2795][rfc-2795]) are not supported.\n\nAn `asm!` invocation may have one or more template string arguments; an `asm!` with multiple template string arguments is treated as if all the strings were concatenated with a `\\n` between them. The expected usage is for each template string argument to correspond to a line of assembly code. All template string arguments must appear before any other arguments.\n\nAs with format strings, named arguments must appear after positional arguments. Explicit register operands must appear at the end of the operand list, after named arguments if any.\n\nExplicit register operands cannot be used by placeholders in the template string. All other named and positional operands must appear at least once in the template string, otherwise a compiler error is generated.\n\nThe exact assembly code syntax is target-specific and opaque to the compiler except for the way operands are substituted into the template string to form the code passed to the assembler.\n\nThe 5 targets specified in this RFC (x86, ARM, AArch64, RISC-V, Hexagon) all use the assembly code syntax of the GNU assembler (GAS). On x86, the `.intel_syntax noprefix` mode of GAS is used by default. On ARM, the `.syntax unified` mode is used. These targets impose an additional restriction on the assembly code: any assembler state (e.g. the current section which can be changed with `.section`) must be restored to its original value at the end of the asm string. Assembly code that does not conform to the GAS syntax will result in assembler-specific behavior.\n\n[rfc-2795]: https://github.com/rust-lang/rfcs/pull/2795\n\n## Operand type\n\nSeveral types of operands are supported:\n\n* `in() `\n - `` can refer to a register class or an explicit register. The allocated register name is substituted into the asm template string.\n - The allocated register will contain the value of `` at the start of the asm code.\n - The allocated register must contain the same value at the end of the asm code (except if a `lateout` is allocated to the same register).\n* `out() `\n - `` can refer to a register class or an explicit register. The allocated register name is substituted into the asm template string.\n - The allocated register will contain an undefined value at the start of the asm code.\n - `` must be a (possibly uninitialized) place expression, to which the contents of the allocated register is written to at the end of the asm code.\n - An underscore (`_`) may be specified instead of an expression, which will cause the contents of the register to be discarded at the end of the asm code (effectively acting as a clobber).\n* `lateout() `\n - Identical to `out` except that the register allocator can reuse a register allocated to an `in`.\n - You should only write to the register after all inputs are read, otherwise you may clobber an input.\n* `inout() `\n - `` can refer to a register class or an explicit register. The allocated register name is substituted into the asm template string.\n - The allocated register will contain the value of `` at the start of the asm code.\n - `` must be a mutable initialized place expression, to which the contents of the allocated register is written to at the end of the asm code.\n* `inout() => `\n - Same as `inout` except that the initial value of the register is taken from the value of ``.\n - `` must be a (possibly uninitialized) place expression, to which the contents of the allocated register is written to at the end of the asm code.\n - An underscore (`_`) may be specified instead of an expression for ``, which will cause the contents of the register to be discarded at the end of the asm code (effectively acting as a clobber).\n - `` and `` may have different types.\n* `inlateout() ` / `inlateout() => `\n - Identical to `inout` except that the register allocator can reuse a register allocated to an `in` (this can happen if the compiler knows the `in` has the same initial value as the `inlateout`).\n - You should only write to the register after all inputs are read, otherwise you may clobber an input.\n* `const `\n - `` must be an integer or floating-point constant expression.\n - The value of the expression is formatted as a string and substituted directly into the asm template string.\n* `sym `\n - `` must refer to a `fn` or `static`.\n - A mangled symbol name referring to the item is substituted into the asm template string.\n - The substituted string does not include any modifiers (e.g. GOT, PLT, relocations, etc).\n - `` is allowed to point to a `#[thread_local]` static, in which case the asm code can combine the symbol with relocations (e.g. `@plt`, `@TPOFF`) to read from thread-local data.\n\nOperand expressions are evaluated from left to right, just like function call arguments. After the `asm!` has executed, outputs are written to in left to right order. This is significant if two outputs point to the same place: that place will contain the value of the rightmost output.\n\n## Register operands\n\nInput and output operands can be specified either as an explicit register or as a register class from which the register allocator can select a register. Explicit registers are specified as string literals (e.g. `\"eax\"`) while register classes are specified as identifiers (e.g. `reg`). Using string literals for register names enables support for architectures that use special characters in register names, such as MIPS (`$0`, `$1`, etc).\n\nNote that explicit registers treat register aliases (e.g. `r14` vs `lr` on ARM) and smaller views of a register (e.g. `eax` vs `rax`) as equivalent to the base register. It is a compile-time error to use the same explicit register for two input operands or two output operands. Additionally, it is also a compile-time error to use overlapping registers (e.g. ARM VFP) in input operands or in output operands.\n\nOnly the following types are allowed as operands for inline assembly:\n- Integers (signed and unsigned)\n- Floating-point numbers\n- Pointers (thin only)\n- Function pointers\n- SIMD vectors (structs defined with `#[repr(simd)]` and which implement `Copy`). This includes architecture-specific vector types defined in `std::arch` such as `__m128` (x86) or `int8x16_t` (ARM).\n\nHere is the list of currently supported register classes:\n\n| Architecture | Register class | Registers | LLVM constraint code |\n| ------------ | -------------- | --------- | -------------------- |\n| x86 | `reg` | `ax`, `bx`, `cx`, `dx`, `si`, `di`, `r[8-15]` (x86-64 only) | `r` |\n| x86 | `reg_abcd` | `ax`, `bx`, `cx`, `dx` | `Q` |\n| x86-32 | `reg_byte` | `al`, `bl`, `cl`, `dl`, `ah`, `bh`, `ch`, `dh` | `q` |\n| x86-64 | `reg_byte` | `al`, `bl`, `cl`, `dl`, `sil`, `dil`, `r[8-15]b`, `ah`\\*, `bh`\\*, `ch`\\*, `dh`\\* | `q` |\n| x86 | `xmm_reg` | `xmm[0-7]` (x86) `xmm[0-15]` (x86-64) | `x` |\n| x86 | `ymm_reg` | `ymm[0-7]` (x86) `ymm[0-15]` (x86-64) | `x` |\n| x86 | `zmm_reg` | `zmm[0-7]` (x86) `zmm[0-31]` (x86-64) | `v` |\n| x86 | `kreg` | `k[1-7]` | `Yk` |\n| AArch64 | `reg` | `x[0-28]`, `x30` | `r` |\n| AArch64 | `vreg` | `v[0-31]` | `w` |\n| AArch64 | `vreg_low16` | `v[0-15]` | `x` |\n| ARM | `reg` | `r[0-5]` `r7`\\*, `r[8-10]`, `r11`\\*, `r12`, `r14` | `r` |\n| ARM (Thumb) | `reg_thumb` | `r[0-r7]` | `l` |\n| ARM (ARM) | `reg_thumb` | `r[0-r10]`, `r12`, `r14` | `l` |\n| ARM | `sreg` | `s[0-31]` | `t` |\n| ARM | `sreg_low16` | `s[0-15]` | `x` |\n| ARM | `dreg` | `d[0-31]` | `w` |\n| ARM | `dreg_low16` | `d[0-15]` | `t` |\n| ARM | `dreg_low8` | `d[0-8]` | `x` |\n| ARM | `qreg` | `q[0-15]` | `w` |\n| ARM | `qreg_low8` | `q[0-7]` | `t` |\n| ARM | `qreg_low4` | `q[0-3]` | `x` |\n| NVPTX | `reg16` | None\\* | `h` |\n| NVPTX | `reg32` | None\\* | `r` |\n| NVPTX | `reg64` | None\\* | `l` |\n| RISC-V | `reg` | `x1`, `x[5-7]`, `x[9-15]`, `x[16-31]` (non-RV32E) | `r` |\n| RISC-V | `freg` | `f[0-31]` | `f` |\n| Hexagon | `reg` | `r[0-28]` | `r` |\n\n> **Note**: On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register.\n>\n> Note #2: On x86-64 the high byte registers (e.g. `ah`) are only available when used as an explicit register. Specifying the `reg_byte` register class for an operand will always allocate a low byte register.\n>\n> Note #3: NVPTX doesn't have a fixed register set, so named registers are not supported.\n>\n> Note #4: On ARM the frame pointer is either `r7` or `r11` depending on the platform.\n\nAdditional register classes may be added in the future based on demand (e.g. MMX, x87, etc).\n\nEach register class has constraints on which value types they can be used with. This is necessary because the way a value is loaded into a register depends on its type. For example, on big-endian systems, loading a `i32x4` and a `i8x16` into a SIMD register may result in different register contents even if the byte-wise memory representation of both values is identical. The availability of supported types for a particular register class may depend on what target features are currently enabled.\n\n| Architecture | Register class | Target feature | Allowed types |\n| ------------ | -------------- | -------------- | ------------- |\n| x86-32 | `reg` | None | `i16`, `i32`, `f32` |\n| x86-64 | `reg` | None | `i16`, `i32`, `f32`, `i64`, `f64` |\n| x86 | `reg_byte` | None | `i8` |\n| x86 | `xmm_reg` | `sse` | `i32`, `f32`, `i64`, `f64`,
`i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` |\n| x86 | `ymm_reg` | `avx` | `i32`, `f32`, `i64`, `f64`,
`i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2`
`i8x32`, `i16x16`, `i32x8`, `i64x4`, `f32x8`, `f64x4` |\n| x86 | `zmm_reg` | `avx512f` | `i32`, `f32`, `i64`, `f64`,
`i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2`
`i8x32`, `i16x16`, `i32x8`, `i64x4`, `f32x8`, `f64x4`
`i8x64`, `i16x32`, `i32x16`, `i64x8`, `f32x16`, `f64x8` |\n| x86 | `kreg` | `axv512f` | `i8`, `i16` |\n| x86 | `kreg` | `axv512bw` | `i32`, `i64` |\n| AArch64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |\n| AArch64 | `vreg` | `fp` | `i8`, `i16`, `i32`, `f32`, `i64`, `f64`,
`i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2`, `f64x1`,
`i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` |\n| ARM | `reg` | None | `i8`, `i16`, `i32`, `f32` |\n| ARM | `sreg` | `vfp2` | `i32`, `f32` |\n| ARM | `dreg` | `vfp2` | `i64`, `f64`, `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2` |\n| ARM | `qreg` | `neon` | `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4` |\n| NVPTX | `reg16` | None | `i8`, `i16` |\n| NVPTX | `reg32` | None | `i8`, `i16`, `i32`, `f32` |\n| NVPTX | `reg64` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |\n| RISC-V32 | `reg` | None | `i8`, `i16`, `i32`, `f32` |\n| RISC-V64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |\n| RISC-V | `freg` | `f` | `f32` |\n| RISC-V | `freg` | `d` | `f64` |\n| Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` |\n\n> **Note**: For the purposes of the above table pointers, function pointers and `isize`/`usize` are treated as the equivalent integer type (`i16`/`i32`/`i64` depending on the target).\n\nIf a value is of a smaller size than the register it is allocated in then the upper bits of that register will have an undefined value for inputs and will be ignored for outputs. The only exception is the `freg` register class on RISC-V where `f32` values are NaN-boxed in a `f64` as required by the RISC-V architecture.\n\nWhen separate input and output expressions are specified for an `inout` operand, both expressions must have the same type. The only exception is if both operands are pointers or integers, in which case they are only required to have the same size. This restriction exists because the register allocators in LLVM and GCC sometimes cannot handle tied operands with different types.\n\n## Register names\n\nSome registers have multiple names. These are all treated by the compiler as identical to the base register name. Here is the list of all supported register aliases:\n\n| Architecture | Base register | Aliases |\n| ------------ | ------------- | ------- |\n| x86 | `ax` | `eax`, `rax` |\n| x86 | `bx` | `ebx`, `rbx` |\n| x86 | `cx` | `ecx`, `rcx` |\n| x86 | `dx` | `edx`, `rdx` |\n| x86 | `si` | `esi`, `rsi` |\n| x86 | `di` | `edi`, `rdi` |\n| x86 | `bp` | `bpl`, `ebp`, `rbp` |\n| x86 | `sp` | `spl`, `esp`, `rsp` |\n| x86 | `ip` | `eip`, `rip` |\n| x86 | `st(0)` | `st` |\n| x86 | `r[8-15]` | `r[8-15]b`, `r[8-15]w`, `r[8-15]d` |\n| x86 | `xmm[0-31]` | `ymm[0-31]`, `zmm[0-31]` |\n| AArch64 | `x[0-30]` | `w[0-30]` |\n| AArch64 | `x29` | `fp` |\n| AArch64 | `x30` | `lr` |\n| AArch64 | `sp` | `wsp` |\n| AArch64 | `xzr` | `wzr` |\n| AArch64 | `v[0-31]` | `b[0-31]`, `h[0-31]`, `s[0-31]`, `d[0-31]`, `q[0-31]` |\n| ARM | `r[0-3]` | `a[1-4]` |\n| ARM | `r[4-9]` | `v[1-6]` |\n| ARM | `r9` | `rfp` |\n| ARM | `r10` | `sl` |\n| ARM | `r11` | `fp` |\n| ARM | `r12` | `ip` |\n| ARM | `r13` | `sp` |\n| ARM | `r14` | `lr` |\n| ARM | `r15` | `pc` |\n| RISC-V | `x0` | `zero` |\n| RISC-V | `x1` | `ra` |\n| RISC-V | `x2` | `sp` |\n| RISC-V | `x3` | `gp` |\n| RISC-V | `x4` | `tp` |\n| RISC-V | `x[5-7]` | `t[0-2]` |\n| RISC-V | `x8` | `fp`, `s0` |\n| RISC-V | `x9` | `s1` |\n| RISC-V | `x[10-17]` | `a[0-7]` |\n| RISC-V | `x[18-27]` | `s[2-11]` |\n| RISC-V | `x[28-31]` | `t[3-6]` |\n| RISC-V | `f[0-7]` | `ft[0-7]` |\n| RISC-V | `f[8-9]` | `fs[0-1]` |\n| RISC-V | `f[10-17]` | `fa[0-7]` |\n| RISC-V | `f[18-27]` | `fs[2-11]` |\n| RISC-V | `f[28-31]` | `ft[8-11]` |\n| Hexagon | `r29` | `sp` |\n| Hexagon | `r30` | `fr` |\n| Hexagon | `r31` | `lr` |\n\nSome registers cannot be used for input or output operands:\n\n| Architecture | Unsupported register | Reason |\n| ------------ | -------------------- | ------ |\n| All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. |\n| All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon) | The frame pointer cannot be used as an input or output. |\n| ARM | `r7` or `r11` | On ARM the frame pointer can be either `r7` or `r11` depending on the target. The frame pointer cannot be used as an input or output. |\n| ARM | `r6` | `r6` is used internally by LLVM as a base pointer and therefore cannot be used as an input or output. |\n| x86 | `k0` | This is a constant zero register which can't be modified. |\n| x86 | `ip` | This is the program counter, not a real register. |\n| x86 | `mm[0-7]` | MMX registers are not currently supported (but may be in the future). |\n| x86 | `st([0-7])` | x87 registers are not currently supported (but may be in the future). |\n| AArch64 | `xzr` | This is a constant zero register which can't be modified. |\n| ARM | `pc` | This is the program counter, not a real register. |\n| RISC-V | `x0` | This is a constant zero register which can't be modified. |\n| RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. |\n| Hexagon | `lr` | This is the link register which cannot be used as an input or output. |\n\n## Template modifiers\n\nThe placeholders can be augmented by modifiers which are specified after the `:` in the curly braces. These modifiers do not affect register allocation, but change the way operands are formatted when inserted into the template string. Only one modifier is allowed per template placeholder.\n\nThe supported modifiers are a subset of LLVM's (and GCC's) [asm template argument modifiers][llvm-argmod], but do not use the same letter codes.\n\n| Architecture | Register class | Modifier | Example output | LLVM modifier |\n| ------------ | -------------- | -------- | -------------- | ------------- |\n| x86-32 | `reg` | None | `eax` | `k` |\n| x86-64 | `reg` | None | `rax` | `q` |\n| x86-32 | `reg_abcd` | `l` | `al` | `b` |\n| x86-64 | `reg` | `l` | `al` | `b` |\n| x86 | `reg_abcd` | `h` | `ah` | `h` |\n| x86 | `reg` | `x` | `ax` | `w` |\n| x86 | `reg` | `e` | `eax` | `k` |\n| x86-64 | `reg` | `r` | `rax` | `q` |\n| x86 | `reg_byte` | None | `al` / `ah` | None |\n| x86 | `xmm_reg` | None | `xmm0` | `x` |\n| x86 | `ymm_reg` | None | `ymm0` | `t` |\n| x86 | `zmm_reg` | None | `zmm0` | `g` |\n| x86 | `*mm_reg` | `x` | `xmm0` | `x` |\n| x86 | `*mm_reg` | `y` | `ymm0` | `t` |\n| x86 | `*mm_reg` | `z` | `zmm0` | `g` |\n| x86 | `kreg` | None | `k1` | None |\n| AArch64 | `reg` | None | `x0` | `x` |\n| AArch64 | `reg` | `w` | `w0` | `w` |\n| AArch64 | `reg` | `x` | `x0` | `x` |\n| AArch64 | `vreg` | None | `v0` | None |\n| AArch64 | `vreg` | `v` | `v0` | None |\n| AArch64 | `vreg` | `b` | `b0` | `b` |\n| AArch64 | `vreg` | `h` | `h0` | `h` |\n| AArch64 | `vreg` | `s` | `s0` | `s` |\n| AArch64 | `vreg` | `d` | `d0` | `d` |\n| AArch64 | `vreg` | `q` | `q0` | `q` |\n| ARM | `reg` | None | `r0` | None |\n| ARM | `sreg` | None | `s0` | None |\n| ARM | `dreg` | None | `d0` | `P` |\n| ARM | `qreg` | None | `q0` | `q` |\n| ARM | `qreg` | `e` / `f` | `d0` / `d1` | `e` / `f` |\n| NVPTX | `reg16` | None | `rs0` | None |\n| NVPTX | `reg32` | None | `r0` | None |\n| NVPTX | `reg64` | None | `rd0` | None |\n| RISC-V | `reg` | None | `x1` | None |\n| RISC-V | `freg` | None | `f0` | None |\n| Hexagon | `reg` | None | `r0` | None |\n\n> Notes:\n> - on ARM `e` / `f`: this prints the low or high doubleword register name of a NEON quad (128-bit) register.\n> - on x86: our behavior for `reg` with no modifiers differs from what GCC does. GCC will infer the modifier based on the operand value type, while we default to the full register size.\n> - on x86 `xmm_reg`: the `x`, `t` and `g` LLVM modifiers are not yet implemented in LLVM (they are supported by GCC only), but this should be a simple change.\n\nAs stated in the previous section, passing an input value smaller than the register width will result in the upper bits of the register containing undefined values. This is not a problem if the inline asm only accesses the lower bits of the register, which can be done by using a template modifier to use a subregister name in the asm code (e.g. `ax` instead of `rax`). Since this an easy pitfall, the compiler will suggest a template modifier to use where appropriate given the input type. If all references to an operand already have modifiers then the warning is suppressed for that operand.\n\n[llvm-argmod]: http://llvm.org/docs/LangRef.html#asm-template-argument-modifiers\n\n## Options\n\nFlags are used to further influence the behavior of the inline assembly block.\nCurrently the following options are defined:\n- `pure`: The `asm` block has no side effects, and its outputs depend only on its direct inputs (i.e. the values themselves, not what they point to) or values read from memory (unless the `nomem` options is also set). This allows the compiler to execute the `asm` block fewer times than specified in the program (e.g. by hoisting it out of a loop) or even eliminate it entirely if the outputs are not used.\n- `nomem`: The `asm` blocks does not read or write to any memory. This allows the compiler to cache the values of modified global variables in registers across the `asm` block since it knows that they are not read or written to by the `asm`.\n- `readonly`: The `asm` block does not write to any memory. This allows the compiler to cache the values of unmodified global variables in registers across the `asm` block since it knows that they are not written to by the `asm`.\n- `preserves_flags`: The `asm` block does not modify the flags register (defined in the rules below). This allows the compiler to avoid recomputing the condition flags after the `asm` block.\n- `noreturn`: The `asm` block never returns, and its return type is defined as `!` (never). Behavior is undefined if execution falls through past the end of the asm code. A `noreturn` asm block behaves just like a function which doesn't return; notably, local variables in scope are not dropped before it is invoked.\n- `nostack`: The `asm` block does not push data to the stack, or write to the stack red-zone (if supported by the target). If this option is *not* used then the stack pointer is guaranteed to be suitably aligned (according to the target ABI) for a function call.\n- `att_syntax`: This option is only valid on x86, and causes the assembler to use the `.att_syntax prefix` mode of the GNU assembler. Register operands are substituted in with a leading `%`.\n\nThe compiler performs some additional checks on options:\n- The `nomem` and `readonly` options are mutually exclusive: it is a compile-time error to specify both.\n- The `pure` option must be combined with either the `nomem` or `readonly` options, otherwise a compile-time error is emitted.\n- It is a compile-time error to specify `pure` on an asm block with no outputs or only discarded outputs (`_`).\n- It is a compile-time error to specify `noreturn` on an asm block with outputs.\n\n## Rules for inline assembly\n\n- Any registers not specified as inputs will contain an undefined value on entry to the asm block.\n - An \"undefined value\" in the context of inline assembly means that the register can (non-deterministically) have any one of the possible values allowed by the architecture. Notably it is not the same as an LLVM `undef` which can have a different value every time you read it (since such a concept does not exist in assembly code).\n- Any registers not specified as outputs must have the same value upon exiting the asm block as they had on entry, otherwise behavior is undefined.\n - This only applies to registers which can be specified as an input or output. Other registers follow target-specific rules.\n - Note that a `lateout` may be allocated to the same register as an `in`, in which case this rule does not apply. Code should not rely on this however since it depends on the results of register allocation.\n- Behavior is undefined if execution unwinds out of an asm block.\n - This also applies if the assembly code calls a function which then unwinds.\n- The set of memory locations that assembly code is allowed the read and write are the same as those allowed for an FFI function.\n - Refer to the unsafe code guidelines for the exact rules.\n - If the `readonly` option is set, then only memory reads are allowed.\n - If the `nomem` option is set then no reads or writes to memory are allowed.\n - These rules do not apply to memory which is private to the asm code, such as stack space allocated within the asm block.\n- The compiler cannot assume that the instructions in the asm are the ones that will actually end up executed.\n - This effectively means that the compiler must treat the `asm!` as a black box and only take the interface specification into account, not the instructions themselves.\n - Runtime code patching is allowed, via target-specific mechanisms (outside the scope of this RFC).\n- Unless the `nostack` option is set, asm code is allowed to use stack space below the stack pointer.\n - On entry to the asm block the stack pointer is guaranteed to be suitably aligned (according to the target ABI) for a function call.\n - You are responsible for making sure you don't overflow the stack (e.g. use stack probing to ensure you hit a guard page).\n - You should adjust the stack pointer when allocating stack memory as required by the target ABI.\n - The stack pointer must be restored to its original value before leaving the asm block.\n- If the `noreturn` option is set then behavior is undefined if execution falls through to the end of the asm block.\n- If the `pure` option is set then behavior is undefined if the `asm` has side-effects other than its direct outputs. Behavior is also undefined if two executions of the `asm` code with the same inputs result in different outputs.\n - When used with the `nomem` option, \"inputs\" are just the direct inputs of the `asm!`.\n - When used with the `readonly` option, \"inputs\" comprise the direct inputs of the `asm!` and any memory that the `asm!` block is allowed to read.\n- These flags registers must be restored upon exiting the asm block if the `preserves_flags` option is set:\n - x86\n - Status flags in `EFLAGS` (CF, PF, AF, ZF, SF, OF).\n - Floating-point status word (all).\n - Floating-point exception flags in `MXCSR` (PE, UE, OE, ZE, DE, IE).\n - ARM\n - Condition flags in `CPSR` (N, Z, C, V)\n - Saturation flag in `CPSR` (Q)\n - Greater than or equal flags in `CPSR` (GE).\n - Condition flags in `FPSCR` (N, Z, C, V)\n - Saturation flag in `FPSCR` (QC)\n - Floating-point exception flags in `FPSCR` (IDC, IXC, UFC, OFC, DZC, IOC).\n - AArch64\n - Condition flags (`NZCV` register).\n - Floating-point status (`FPSR` register).\n - RISC-V\n - Floating-point exception flags in `fcsr` (`fflags`).\n- On x86, the direction flag (DF in `EFLAGS`) is clear on entry to an asm block and must be clear on exit.\n - Behavior is undefined if the direction flag is set on exiting an asm block.\n- The requirement of restoring the stack pointer and non-output registers to their original value only applies when exiting an `asm!` block.\n - This means that `asm!` blocks that never return (even if not marked `noreturn`) don't need to preserve these registers.\n - When returning to a different `asm!` block than you entered (e.g. for context switching), these registers must contain the value they had upon entering the `asm!` block that you are *exiting*.\n - You cannot exit an `asm!` block that has not been entered. Neither can you exit an `asm!` block that has already been exited.\n - You are responsible for switching any target-specific state (e.g. thread-local storage, stack bounds).\n - The set of memory locations that you may access is the intersection of those allowed by the `asm!` blocks you entered and exited.\n- You cannot assume that an `asm!` block will appear exactly once in the output binary. The compiler is allowed to instantiate multiple copies of the `asm!` block, for example when the function containing it is inlined in multiple places.\n - As a consequence, you should only use [local labels] inside inline assembly code. Defining symbols in assembly code may lead to assembler and/or linker errors due to duplicate symbol definitions.\n\n> **Note**: As a general rule, the flags covered by `preserves_flags` are those which are *not* preserved when performing a function call.\n\n[local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels\n" } , LintCompletion { label : "is_sorted" , description : "# `is_sorted`\n\nThe tracking issue for this feature is: [#53485]\n\n[#53485]: https://github.com/rust-lang/rust/issues/53485\n\n------------------------\n\nAdd the methods `is_sorted`, `is_sorted_by` and `is_sorted_by_key` to `[T]`;\nadd the methods `is_sorted`, `is_sorted_by` and `is_sorted_by_key` to\n`Iterator`.\n" } , LintCompletion { label : "derive_clone_copy" , description : "# `derive_clone_copy`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "print_internals" , description : "# `print_internals`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "set_stdio" , description : "# `set_stdio`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "windows_handle" , description : "# `windows_handle`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "thread_local_internals" , description : "# `thread_local_internals`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "profiler_runtime_lib" , description : "# `profiler_runtime_lib`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "windows_c" , description : "# `windows_c`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "fd_read" , description : "# `fd_read`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "c_void_variant" , description : "# `c_void_variant`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "flt2dec" , description : "# `flt2dec`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "core_private_bignum" , description : "# `core_private_bignum`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "format_args_capture" , description : "# `format_args_capture`\n\nThe tracking issue for this feature is: [#67984]\n\n[#67984]: https://github.com/rust-lang/rust/issues/67984\n\n------------------------\n\nEnables `format_args!` (and macros which use `format_args!` in their implementation, such\nas `format!`, `print!` and `panic!`) to capture variables from the surrounding scope.\nThis avoids the need to pass named parameters when the binding in question\nalready exists in scope.\n\n```rust\n#![feature(format_args_capture)]\n\nlet (person, species, name) = (\"Charlie Brown\", \"dog\", \"Snoopy\");\n\n// captures named argument `person`\nprint!(\"Hello {person}\");\n\n// captures named arguments `species` and `name`\nformat!(\"The {species}'s name is {name}.\");\n```\n\nThis also works for formatting parameters such as width and precision:\n\n```rust\n#![feature(format_args_capture)]\n\nlet precision = 2;\nlet s = format!(\"{:.precision$}\", 1.324223);\n\nassert_eq!(&s, \"1.32\");\n```\n\nA non-exhaustive list of macros which benefit from this functionality include:\n- `format!`\n- `print!` and `println!`\n- `eprint!` and `eprintln!`\n- `write!` and `writeln!`\n- `panic!`\n- `unreachable!`\n- `unimplemented!`\n- `todo!`\n- `assert!` and similar\n- macros in many thirdparty crates, such as `log`\n" } , LintCompletion { label : "libstd_io_internals" , description : "# `libstd_io_internals`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "derive_eq" , description : "# `derive_eq`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "c_variadic" , description : "# `c_variadic`\n\nThe tracking issue for this feature is: [#44930]\n\n[#44930]: https://github.com/rust-lang/rust/issues/44930\n\n------------------------\n\nThe `c_variadic` library feature exposes the `VaList` structure,\nRust's analogue of C's `va_list` type.\n\n## Examples\n\n```rust\n#![feature(c_variadic)]\n\nuse std::ffi::VaList;\n\npub unsafe extern \"C\" fn vadd(n: usize, mut args: VaList) -> usize {\n let mut sum = 0;\n for _ in 0..n {\n sum += args.arg::();\n }\n sum\n}\n```\n" } , LintCompletion { label : "trace_macros" , description : "# `trace_macros`\n\nThe tracking issue for this feature is [#29598].\n\n[#29598]: https://github.com/rust-lang/rust/issues/29598\n\n------------------------\n\nWith `trace_macros` you can trace the expansion of macros in your code.\n\n## Examples\n\n```rust\n#![feature(trace_macros)]\n\nfn main() {\n trace_macros!(true);\n println!(\"Hello, Rust!\");\n trace_macros!(false);\n}\n```\n\nThe `cargo build` output:\n\n```txt\nnote: trace_macro\n --> src/main.rs:5:5\n |\n5 | println!(\"Hello, Rust!\");\n | ^^^^^^^^^^^^^^^^^^^^^^^^^\n |\n = note: expanding `println! { \"Hello, Rust!\" }`\n = note: to `print ! ( concat ! ( \"Hello, Rust!\" , \"\\n\" ) )`\n = note: expanding `print! { concat ! ( \"Hello, Rust!\" , \"\\n\" ) }`\n = note: to `$crate :: io :: _print ( format_args ! ( concat ! ( \"Hello, Rust!\" , \"\\n\" ) )\n )`\n\n Finished dev [unoptimized + debuginfo] target(s) in 0.60 secs\n```\n" } , LintCompletion { label : "core_private_diy_float" , description : "# `core_private_diy_float`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "core_panic" , description : "# `core_panic`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "str_internals" , description : "# `str_internals`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "char_error_internals" , description : "# `char_error_internals`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\n" } , LintCompletion { label : "llvm_asm" , description : "# `llvm_asm`\n\nThe tracking issue for this feature is: [#70173]\n\n[#70173]: https://github.com/rust-lang/rust/issues/70173\n\n------------------------\n\nFor extremely low-level manipulations and performance reasons, one\nmight wish to control the CPU directly. Rust supports using inline\nassembly to do this via the `llvm_asm!` macro.\n\n```rust,ignore\nllvm_asm!(assembly template\n : output operands\n : input operands\n : clobbers\n : options\n );\n```\n\nAny use of `llvm_asm` is feature gated (requires `#![feature(llvm_asm)]` on the\ncrate to allow) and of course requires an `unsafe` block.\n\n> **Note**: the examples here are given in x86/x86-64 assembly, but\n> all platforms are supported.\n\n## Assembly template\n\nThe `assembly template` is the only required parameter and must be a\nliteral string (i.e. `\"\"`)\n\n```rust\n#![feature(llvm_asm)]\n\n#[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\nfn foo() {\n unsafe {\n llvm_asm!(\"NOP\");\n }\n}\n\n// Other platforms:\n#[cfg(not(any(target_arch = \"x86\", target_arch = \"x86_64\")))]\nfn foo() { /* ... */ }\n\nfn main() {\n // ...\n foo();\n // ...\n}\n```\n\n(The `feature(llvm_asm)` and `#[cfg]`s are omitted from now on.)\n\nOutput operands, input operands, clobbers and options are all optional\nbut you must add the right number of `:` if you skip them:\n\n```rust\n# #![feature(llvm_asm)]\n# #[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\n# fn main() { unsafe {\nllvm_asm!(\"xor %eax, %eax\"\n :\n :\n : \"eax\"\n );\n# } }\n# #[cfg(not(any(target_arch = \"x86\", target_arch = \"x86_64\")))]\n# fn main() {}\n```\n\nWhitespace also doesn't matter:\n\n```rust\n# #![feature(llvm_asm)]\n# #[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\n# fn main() { unsafe {\nllvm_asm!(\"xor %eax, %eax\" ::: \"eax\");\n# } }\n# #[cfg(not(any(target_arch = \"x86\", target_arch = \"x86_64\")))]\n# fn main() {}\n```\n\n## Operands\n\nInput and output operands follow the same format: `:\n\"constraints1\"(expr1), \"constraints2\"(expr2), ...\"`. Output operand\nexpressions must be mutable place, or not yet assigned:\n\n```rust\n# #![feature(llvm_asm)]\n# #[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\nfn add(a: i32, b: i32) -> i32 {\n let c: i32;\n unsafe {\n llvm_asm!(\"add $2, $0\"\n : \"=r\"(c)\n : \"0\"(a), \"r\"(b)\n );\n }\n c\n}\n# #[cfg(not(any(target_arch = \"x86\", target_arch = \"x86_64\")))]\n# fn add(a: i32, b: i32) -> i32 { a + b }\n\nfn main() {\n assert_eq!(add(3, 14159), 14162)\n}\n```\n\nIf you would like to use real operands in this position, however,\nyou are required to put curly braces `{}` around the register that\nyou want, and you are required to put the specific size of the\noperand. This is useful for very low level programming, where\nwhich register you use is important:\n\n```rust\n# #![feature(llvm_asm)]\n# #[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\n# unsafe fn read_byte_in(port: u16) -> u8 {\nlet result: u8;\nllvm_asm!(\"in %dx, %al\" : \"={al}\"(result) : \"{dx}\"(port));\nresult\n# }\n```\n\n## Clobbers\n\nSome instructions modify registers which might otherwise have held\ndifferent values so we use the clobbers list to indicate to the\ncompiler not to assume any values loaded into those registers will\nstay valid.\n\n```rust\n# #![feature(llvm_asm)]\n# #[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\n# fn main() { unsafe {\n// Put the value 0x200 in eax:\nllvm_asm!(\"mov $$0x200, %eax\" : /* no outputs */ : /* no inputs */ : \"eax\");\n# } }\n# #[cfg(not(any(target_arch = \"x86\", target_arch = \"x86_64\")))]\n# fn main() {}\n```\n\nInput and output registers need not be listed since that information\nis already communicated by the given constraints. Otherwise, any other\nregisters used either implicitly or explicitly should be listed.\n\nIf the assembly changes the condition code register `cc` should be\nspecified as one of the clobbers. Similarly, if the assembly modifies\nmemory, `memory` should also be specified.\n\n## Options\n\nThe last section, `options` is specific to Rust. The format is comma\nseparated literal strings (i.e. `:\"foo\", \"bar\", \"baz\"`). It's used to\nspecify some extra info about the inline assembly:\n\nCurrent valid options are:\n\n1. *volatile* - specifying this is analogous to\n `__asm__ __volatile__ (...)` in gcc/clang.\n2. *alignstack* - certain instructions expect the stack to be\n aligned a certain way (i.e. SSE) and specifying this indicates to\n the compiler to insert its usual stack alignment code\n3. *intel* - use intel syntax instead of the default AT&T.\n\n```rust\n# #![feature(llvm_asm)]\n# #[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\n# fn main() {\nlet result: i32;\nunsafe {\n llvm_asm!(\"mov eax, 2\" : \"={eax}\"(result) : : : \"intel\")\n}\nprintln!(\"eax is currently {}\", result);\n# }\n# #[cfg(not(any(target_arch = \"x86\", target_arch = \"x86_64\")))]\n# fn main() {}\n```\n\n## More Information\n\nThe current implementation of the `llvm_asm!` macro is a direct binding to [LLVM's\ninline assembler expressions][llvm-docs], so be sure to check out [their\ndocumentation as well][llvm-docs] for more information about clobbers,\nconstraints, etc.\n\n[llvm-docs]: http://llvm.org/docs/LangRef.html#inline-assembler-expressions\n\nIf you need more power and don't mind losing some of the niceties of\n`llvm_asm!`, check out [global_asm](global-asm.md).\n" } ] ; diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs index 897177d05d..73c0b82754 100644 --- a/crates/ra_ide/src/diagnostics.rs +++ b/crates/ra_ide/src/diagnostics.rs @@ -78,8 +78,10 @@ pub(crate) fn diagnostics( } else { let mut field_list = d.ast(db); for f in d.missed_fields.iter() { - let field = - make::record_field(make::name_ref(&f.to_string()), Some(make::expr_unit())); + let field = make::record_expr_field( + make::name_ref(&f.to_string()), + Some(make::expr_unit()), + ); field_list = field_list.append_field(&field); } @@ -146,7 +148,7 @@ fn missing_struct_field_fix( ) -> Option { let record_expr = sema.ast(d); - let record_lit = ast::RecordLit::cast(record_expr.syntax().parent()?.parent()?)?; + let record_lit = ast::RecordExpr::cast(record_expr.syntax().parent()?.parent()?)?; let def_id = sema.resolve_variant(record_lit)?; let module; let def_file_id; @@ -155,21 +157,21 @@ fn missing_struct_field_fix( module = s.module(sema.db); let source = s.source(sema.db); def_file_id = source.file_id; - let fields = source.value.field_def_list()?; - record_field_def_list(fields)? + let fields = source.value.field_list()?; + record_field_list(fields)? } VariantDef::Union(u) => { module = u.module(sema.db); let source = u.source(sema.db); def_file_id = source.file_id; - source.value.record_field_def_list()? + source.value.record_field_list()? } VariantDef::EnumVariant(e) => { module = e.module(sema.db); let source = e.source(sema.db); def_file_id = source.file_id; - let fields = source.value.field_def_list()?; - record_field_def_list(fields)? + let fields = source.value.field_list()?; + record_field_list(fields)? } }; let def_file_id = def_file_id.original_file(sema.db); @@ -178,9 +180,9 @@ fn missing_struct_field_fix( if new_field_type.is_unknown() { return None; } - let new_field = make::record_field_def( + let new_field = make::record_field( record_expr.field_name()?, - make::type_ref(&new_field_type.display_source_code(sema.db, module.into()).ok()?), + make::ty(&new_field_type.display_source_code(sema.db, module.into()).ok()?), ); let last_field = record_fields.fields().last()?; @@ -205,10 +207,10 @@ fn missing_struct_field_fix( let fix = Fix::new("Create field", source_change.into()); return Some(fix); - fn record_field_def_list(field_def_list: ast::FieldDefList) -> Option { + fn record_field_list(field_def_list: ast::FieldList) -> Option { match field_def_list { - ast::FieldDefList::RecordFieldDefList(it) => Some(it), - ast::FieldDefList::TupleFieldDefList(_) => None, + ast::FieldList::RecordFieldList(it) => Some(it), + ast::FieldList::TupleFieldList(_) => None, } } } @@ -263,8 +265,8 @@ fn check_struct_shorthand_initialization( file_id: FileId, node: &SyntaxNode, ) -> Option<()> { - let record_lit = ast::RecordLit::cast(node.clone())?; - let record_field_list = record_lit.record_field_list()?; + let record_lit = ast::RecordExpr::cast(node.clone())?; + let record_field_list = record_lit.record_expr_field_list()?; for record_field in record_field_list.fields() { if let (Some(name_ref), Some(expr)) = (record_field.name_ref(), record_field.expr()) { let field_name = name_ref.syntax().text().to_string(); diff --git a/crates/ra_ide/src/display.rs b/crates/ra_ide/src/display.rs index 6d4151dd85..fd42aa4352 100644 --- a/crates/ra_ide/src/display.rs +++ b/crates/ra_ide/src/display.rs @@ -5,7 +5,7 @@ mod navigation_target; mod short_label; use ra_syntax::{ - ast::{self, AstNode, AttrsOwner, NameOwner, TypeParamsOwner}, + ast::{self, AstNode, AttrsOwner, GenericParamsOwner, NameOwner}, SyntaxKind::{ATTR, COMMENT}, }; @@ -16,7 +16,7 @@ pub use navigation_target::NavigationTarget; pub(crate) use navigation_target::{ToNav, TryToNav}; pub(crate) use short_label::ShortLabel; -pub(crate) fn function_declaration(node: &ast::FnDef) -> String { +pub(crate) fn function_declaration(node: &ast::Fn) -> String { let mut buf = String::new(); if let Some(vis) = node.visibility() { format_to!(buf, "{} ", vis); @@ -37,14 +37,14 @@ pub(crate) fn function_declaration(node: &ast::FnDef) -> String { if let Some(name) = node.name() { format_to!(buf, "fn {}", name) } - if let Some(type_params) = node.type_param_list() { + if let Some(type_params) = node.generic_param_list() { format_to!(buf, "{}", type_params); } if let Some(param_list) = node.param_list() { format_to!(buf, "{}", param_list); } if let Some(ret_type) = node.ret_type() { - if ret_type.type_ref().is_some() { + if ret_type.ty().is_some() { format_to!(buf, " {}", ret_type); } } @@ -54,7 +54,7 @@ pub(crate) fn function_declaration(node: &ast::FnDef) -> String { buf } -pub(crate) fn const_label(node: &ast::ConstDef) -> String { +pub(crate) fn const_label(node: &ast::Const) -> String { let label: String = node .syntax() .children_with_tokens() @@ -65,7 +65,7 @@ pub(crate) fn const_label(node: &ast::ConstDef) -> String { label.trim().to_owned() } -pub(crate) fn type_label(node: &ast::TypeAliasDef) -> String { +pub(crate) fn type_label(node: &ast::TypeAlias) -> String { let label: String = node .syntax() .children_with_tokens() diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs index fd245705c1..fdbf75abd9 100644 --- a/crates/ra_ide/src/display/navigation_target.rs +++ b/crates/ra_ide/src/display/navigation_target.rs @@ -7,7 +7,7 @@ use ra_ide_db::{defs::Definition, RootDatabase}; use ra_syntax::{ ast::{self, DocCommentsOwner, NameOwner}, match_ast, AstNode, SmolStr, - SyntaxKind::{self, BIND_PAT, TYPE_PARAM}, + SyntaxKind::{self, IDENT_PAT, TYPE_PARAM}, TextRange, }; @@ -253,7 +253,7 @@ impl ToNav for hir::ImplDef { let focus_range = if derive_attr.is_some() { None } else { - src.value.target_type().map(|ty| original_range(db, src.with_value(ty.syntax())).range) + src.value.self_ty().map(|ty| original_range(db, src.with_value(ty.syntax())).range) }; NavigationTarget::from_syntax( @@ -339,7 +339,7 @@ impl ToNav for hir::Local { NavigationTarget { file_id: full_range.file_id, name, - kind: BIND_PAT, + kind: IDENT_PAT, full_range: full_range.range, focus_range: None, container_name: None, @@ -379,16 +379,16 @@ pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option match_ast! { match node { - ast::FnDef(it) => it.doc_comment_text(), - ast::StructDef(it) => it.doc_comment_text(), - ast::EnumDef(it) => it.doc_comment_text(), - ast::TraitDef(it) => it.doc_comment_text(), + ast::Fn(it) => it.doc_comment_text(), + ast::Struct(it) => it.doc_comment_text(), + ast::Enum(it) => it.doc_comment_text(), + ast::Trait(it) => it.doc_comment_text(), ast::Module(it) => it.doc_comment_text(), - ast::TypeAliasDef(it) => it.doc_comment_text(), - ast::ConstDef(it) => it.doc_comment_text(), - ast::StaticDef(it) => it.doc_comment_text(), - ast::RecordFieldDef(it) => it.doc_comment_text(), - ast::EnumVariant(it) => it.doc_comment_text(), + ast::TypeAlias(it) => it.doc_comment_text(), + ast::Const(it) => it.doc_comment_text(), + ast::Static(it) => it.doc_comment_text(), + ast::RecordField(it) => it.doc_comment_text(), + ast::Variant(it) => it.doc_comment_text(), ast::MacroCall(it) => it.doc_comment_text(), _ => None, } @@ -404,16 +404,16 @@ pub(crate) fn description_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> match_ast! { match node { - ast::FnDef(it) => it.short_label(), - ast::StructDef(it) => it.short_label(), - ast::EnumDef(it) => it.short_label(), - ast::TraitDef(it) => it.short_label(), + ast::Fn(it) => it.short_label(), + ast::Struct(it) => it.short_label(), + ast::Enum(it) => it.short_label(), + ast::Trait(it) => it.short_label(), ast::Module(it) => it.short_label(), - ast::TypeAliasDef(it) => it.short_label(), - ast::ConstDef(it) => it.short_label(), - ast::StaticDef(it) => it.short_label(), - ast::RecordFieldDef(it) => it.short_label(), - ast::EnumVariant(it) => it.short_label(), + ast::TypeAlias(it) => it.short_label(), + ast::Const(it) => it.short_label(), + ast::Static(it) => it.short_label(), + ast::RecordField(it) => it.short_label(), + ast::Variant(it) => it.short_label(), _ => None, } } @@ -446,7 +446,7 @@ fn foo() { enum FooInner { } } 5..13, ), name: "FooInner", - kind: ENUM_DEF, + kind: ENUM, container_name: None, description: Some( "enum FooInner", @@ -462,7 +462,7 @@ fn foo() { enum FooInner { } } 34..42, ), name: "FooInner", - kind: ENUM_DEF, + kind: ENUM, container_name: Some( "foo", ), diff --git a/crates/ra_ide/src/display/short_label.rs b/crates/ra_ide/src/display/short_label.rs index 5588130a10..0fdf8e9a58 100644 --- a/crates/ra_ide/src/display/short_label.rs +++ b/crates/ra_ide/src/display/short_label.rs @@ -1,37 +1,37 @@ //! FIXME: write short doc here -use ra_syntax::ast::{self, AstNode, NameOwner, TypeAscriptionOwner, VisibilityOwner}; +use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner}; use stdx::format_to; pub(crate) trait ShortLabel { fn short_label(&self) -> Option; } -impl ShortLabel for ast::FnDef { +impl ShortLabel for ast::Fn { fn short_label(&self) -> Option { Some(crate::display::function_declaration(self)) } } -impl ShortLabel for ast::StructDef { +impl ShortLabel for ast::Struct { fn short_label(&self) -> Option { short_label_from_node(self, "struct ") } } -impl ShortLabel for ast::UnionDef { +impl ShortLabel for ast::Union { fn short_label(&self) -> Option { short_label_from_node(self, "union ") } } -impl ShortLabel for ast::EnumDef { +impl ShortLabel for ast::Enum { fn short_label(&self) -> Option { short_label_from_node(self, "enum ") } } -impl ShortLabel for ast::TraitDef { +impl ShortLabel for ast::Trait { fn short_label(&self) -> Option { if self.unsafe_token().is_some() { short_label_from_node(self, "unsafe trait ") @@ -47,43 +47,43 @@ impl ShortLabel for ast::Module { } } -impl ShortLabel for ast::TypeAliasDef { +impl ShortLabel for ast::TypeAlias { fn short_label(&self) -> Option { short_label_from_node(self, "type ") } } -impl ShortLabel for ast::ConstDef { +impl ShortLabel for ast::Const { fn short_label(&self) -> Option { - short_label_from_ascribed_node(self, "const ") + short_label_from_ty(self, self.ty(), "const ") } } -impl ShortLabel for ast::StaticDef { +impl ShortLabel for ast::Static { fn short_label(&self) -> Option { - short_label_from_ascribed_node(self, "static ") + short_label_from_ty(self, self.ty(), "static ") } } -impl ShortLabel for ast::RecordFieldDef { +impl ShortLabel for ast::RecordField { fn short_label(&self) -> Option { - short_label_from_ascribed_node(self, "") + short_label_from_ty(self, self.ty(), "") } } -impl ShortLabel for ast::EnumVariant { +impl ShortLabel for ast::Variant { fn short_label(&self) -> Option { Some(self.name()?.text().to_string()) } } -fn short_label_from_ascribed_node(node: &T, prefix: &str) -> Option +fn short_label_from_ty(node: &T, ty: Option, prefix: &str) -> Option where - T: NameOwner + VisibilityOwner + TypeAscriptionOwner, + T: NameOwner + VisibilityOwner, { let mut buf = short_label_from_node(node, prefix)?; - if let Some(type_ref) = node.ascribed_type() { + if let Some(type_ref) = ty { format_to!(buf, ": {}", type_ref.syntax()); } diff --git a/crates/ra_ide/src/extend_selection.rs b/crates/ra_ide/src/extend_selection.rs index 8a6b3ea990..7230a0ff9e 100644 --- a/crates/ra_ide/src/extend_selection.rs +++ b/crates/ra_ide/src/extend_selection.rs @@ -37,15 +37,15 @@ fn try_extend_selection( let string_kinds = [COMMENT, STRING, RAW_STRING, BYTE_STRING, RAW_BYTE_STRING]; let list_kinds = [ - RECORD_FIELD_PAT_LIST, + RECORD_PAT_FIELD_LIST, MATCH_ARM_LIST, - RECORD_FIELD_DEF_LIST, - TUPLE_FIELD_DEF_LIST, RECORD_FIELD_LIST, - ENUM_VARIANT_LIST, + TUPLE_FIELD_LIST, + RECORD_EXPR_FIELD_LIST, + VARIANT_LIST, USE_TREE_LIST, - TYPE_PARAM_LIST, - TYPE_ARG_LIST, + GENERIC_PARAM_LIST, + GENERIC_ARG_LIST, TYPE_BOUND_LIST, PARAM_LIST, ARG_LIST, diff --git a/crates/ra_ide/src/file_structure.rs b/crates/ra_ide/src/file_structure.rs index 1f6a3febf3..87cab45037 100644 --- a/crates/ra_ide/src/file_structure.rs +++ b/crates/ra_ide/src/file_structure.rs @@ -1,5 +1,5 @@ use ra_syntax::{ - ast::{self, AttrsOwner, NameOwner, TypeAscriptionOwner, TypeParamsOwner}, + ast::{self, AttrsOwner, GenericParamsOwner, NameOwner}, match_ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, TextRange, WalkEvent, }; @@ -52,19 +52,12 @@ pub fn file_structure(file: &SourceFile) -> Vec { fn structure_node(node: &SyntaxNode) -> Option { fn decl(node: N) -> Option { - decl_with_detail(node, None) - } - - fn decl_with_ascription( - node: N, - ) -> Option { - let ty = node.ascribed_type(); - decl_with_type_ref(node, ty) + decl_with_detail(&node, None) } fn decl_with_type_ref( - node: N, - type_ref: Option, + node: &N, + type_ref: Option, ) -> Option { let detail = type_ref.map(|type_ref| { let mut detail = String::new(); @@ -75,7 +68,7 @@ fn structure_node(node: &SyntaxNode) -> Option { } fn decl_with_detail( - node: N, + node: &N, detail: Option, ) -> Option { let name = node.name()?; @@ -111,9 +104,9 @@ fn structure_node(node: &SyntaxNode) -> Option { match_ast! { match node { - ast::FnDef(it) => { + ast::Fn(it) => { let mut detail = String::from("fn"); - if let Some(type_param_list) = it.type_param_list() { + if let Some(type_param_list) = it.generic_param_list() { collapse_ws(type_param_list.syntax(), &mut detail); } if let Some(param_list) = it.param_list() { @@ -124,24 +117,21 @@ fn structure_node(node: &SyntaxNode) -> Option { collapse_ws(ret_type.syntax(), &mut detail); } - decl_with_detail(it, Some(detail)) + decl_with_detail(&it, Some(detail)) }, - ast::StructDef(it) => decl(it), - ast::UnionDef(it) => decl(it), - ast::EnumDef(it) => decl(it), - ast::EnumVariant(it) => decl(it), - ast::TraitDef(it) => decl(it), + ast::Struct(it) => decl(it), + ast::Union(it) => decl(it), + ast::Enum(it) => decl(it), + ast::Variant(it) => decl(it), + ast::Trait(it) => decl(it), ast::Module(it) => decl(it), - ast::TypeAliasDef(it) => { - let ty = it.type_ref(); - decl_with_type_ref(it, ty) - }, - ast::RecordFieldDef(it) => decl_with_ascription(it), - ast::ConstDef(it) => decl_with_ascription(it), - ast::StaticDef(it) => decl_with_ascription(it), - ast::ImplDef(it) => { - let target_type = it.target_type()?; - let target_trait = it.target_trait(); + ast::TypeAlias(it) => decl_with_type_ref(&it, it.ty()), + ast::RecordField(it) => decl_with_type_ref(&it, it.ty()), + ast::Const(it) => decl_with_type_ref(&it, it.ty()), + ast::Static(it) => decl_with_type_ref(&it, it.ty()), + ast::Impl(it) => { + let target_type = it.self_ty()?; + let target_trait = it.trait_(); let label = match target_trait { None => format!("impl {}", target_type.syntax().text()), Some(t) => { @@ -238,7 +228,7 @@ fn very_obsolete() {} label: "Foo", navigation_range: 8..11, node_range: 1..26, - kind: STRUCT_DEF, + kind: STRUCT, detail: None, deprecated: false, }, @@ -249,7 +239,7 @@ fn very_obsolete() {} label: "x", navigation_range: 18..19, node_range: 18..24, - kind: RECORD_FIELD_DEF, + kind: RECORD_FIELD, detail: Some( "i32", ), @@ -271,7 +261,7 @@ fn very_obsolete() {} label: "bar1", navigation_range: 43..47, node_range: 40..52, - kind: FN_DEF, + kind: FN, detail: Some( "fn()", ), @@ -284,7 +274,7 @@ fn very_obsolete() {} label: "bar2", navigation_range: 60..64, node_range: 57..81, - kind: FN_DEF, + kind: FN, detail: Some( "fn(t: T) -> T", ), @@ -297,7 +287,7 @@ fn very_obsolete() {} label: "bar3", navigation_range: 89..93, node_range: 86..156, - kind: FN_DEF, + kind: FN, detail: Some( "fn(a: A, b: B) -> Vec< u32 >", ), @@ -308,7 +298,7 @@ fn very_obsolete() {} label: "E", navigation_range: 165..166, node_range: 160..180, - kind: ENUM_DEF, + kind: ENUM, detail: None, deprecated: false, }, @@ -319,7 +309,7 @@ fn very_obsolete() {} label: "X", navigation_range: 169..170, node_range: 169..170, - kind: ENUM_VARIANT, + kind: VARIANT, detail: None, deprecated: false, }, @@ -330,7 +320,7 @@ fn very_obsolete() {} label: "Y", navigation_range: 172..173, node_range: 172..178, - kind: ENUM_VARIANT, + kind: VARIANT, detail: None, deprecated: false, }, @@ -339,7 +329,7 @@ fn very_obsolete() {} label: "T", navigation_range: 186..187, node_range: 181..193, - kind: TYPE_ALIAS_DEF, + kind: TYPE_ALIAS, detail: Some( "()", ), @@ -350,7 +340,7 @@ fn very_obsolete() {} label: "S", navigation_range: 201..202, node_range: 194..213, - kind: STATIC_DEF, + kind: STATIC, detail: Some( "i32", ), @@ -361,7 +351,7 @@ fn very_obsolete() {} label: "C", navigation_range: 220..221, node_range: 214..232, - kind: CONST_DEF, + kind: CONST, detail: Some( "i32", ), @@ -372,7 +362,7 @@ fn very_obsolete() {} label: "impl E", navigation_range: 239..240, node_range: 234..243, - kind: IMPL_DEF, + kind: IMPL, detail: None, deprecated: false, }, @@ -381,7 +371,7 @@ fn very_obsolete() {} label: "impl fmt::Debug for E", navigation_range: 265..266, node_range: 245..269, - kind: IMPL_DEF, + kind: IMPL, detail: None, deprecated: false, }, @@ -417,7 +407,7 @@ fn very_obsolete() {} label: "obsolete", navigation_range: 428..436, node_range: 411..441, - kind: FN_DEF, + kind: FN, detail: Some( "fn()", ), @@ -428,7 +418,7 @@ fn very_obsolete() {} label: "very_obsolete", navigation_range: 481..494, node_range: 443..499, - kind: FN_DEF, + kind: FN, detail: Some( "fn()", ), diff --git a/crates/ra_ide/src/folding_ranges.rs b/crates/ra_ide/src/folding_ranges.rs index 315808890b..0fbc9babd5 100644 --- a/crates/ra_ide/src/folding_ranges.rs +++ b/crates/ra_ide/src/folding_ranges.rs @@ -58,7 +58,7 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec { } NodeOrToken::Node(node) => { // Fold groups of imports - if node.kind() == USE_ITEM && !visited_imports.contains(&node) { + if node.kind() == USE && !visited_imports.contains(&node) { if let Some(range) = contiguous_range_for_group(&node, &mut visited_imports) { res.push(Fold { range, kind: FoldKind::Imports }) } @@ -83,17 +83,18 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec { fn fold_kind(kind: SyntaxKind) -> Option { match kind { COMMENT => Some(FoldKind::Comment), - USE_ITEM => Some(FoldKind::Imports), + USE => Some(FoldKind::Imports), ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList), - RECORD_FIELD_DEF_LIST - | RECORD_FIELD_PAT_LIST + ASSOC_ITEM_LIST | RECORD_FIELD_LIST + | RECORD_PAT_FIELD_LIST + | RECORD_EXPR_FIELD_LIST | ITEM_LIST | EXTERN_ITEM_LIST | USE_TREE_LIST | BLOCK_EXPR | MATCH_ARM_LIST - | ENUM_VARIANT_LIST + | VARIANT_LIST | TOKEN_TREE => Some(FoldKind::Block), _ => None, } @@ -336,6 +337,26 @@ fn main() { ); } + #[test] + fn test_folds_structs() { + check( + r#" +struct Foo { +} +"#, + ); + } + + #[test] + fn test_folds_traits() { + check( + r#" +trait Foo { +} +"#, + ); + } + #[test] fn test_folds_macros() { check( diff --git a/crates/ra_ide/src/goto_implementation.rs b/crates/ra_ide/src/goto_implementation.rs index 3ee048f285..9912b71421 100644 --- a/crates/ra_ide/src/goto_implementation.rs +++ b/crates/ra_ide/src/goto_implementation.rs @@ -23,12 +23,12 @@ pub(crate) fn goto_implementation( let krate = sema.to_module_def(position.file_id)?.krate(); - if let Some(nominal_def) = find_node_at_offset::(&syntax, position.offset) { + if let Some(nominal_def) = find_node_at_offset::(&syntax, position.offset) { return Some(RangeInfo::new( nominal_def.syntax().text_range(), impls_for_def(&sema, &nominal_def, krate)?, )); - } else if let Some(trait_def) = find_node_at_offset::(&syntax, position.offset) { + } else if let Some(trait_def) = find_node_at_offset::(&syntax, position.offset) { return Some(RangeInfo::new( trait_def.syntax().text_range(), impls_for_trait(&sema, &trait_def, krate)?, @@ -40,13 +40,13 @@ pub(crate) fn goto_implementation( fn impls_for_def( sema: &Semantics, - node: &ast::NominalDef, + node: &ast::AdtDef, krate: Crate, ) -> Option> { let ty = match node { - ast::NominalDef::StructDef(def) => sema.to_def(def)?.ty(sema.db), - ast::NominalDef::EnumDef(def) => sema.to_def(def)?.ty(sema.db), - ast::NominalDef::UnionDef(def) => sema.to_def(def)?.ty(sema.db), + ast::AdtDef::Struct(def) => sema.to_def(def)?.ty(sema.db), + ast::AdtDef::Enum(def) => sema.to_def(def)?.ty(sema.db), + ast::AdtDef::Union(def) => sema.to_def(def)?.ty(sema.db), }; let impls = ImplDef::all_in_crate(sema.db, krate); @@ -62,7 +62,7 @@ fn impls_for_def( fn impls_for_trait( sema: &Semantics, - node: &ast::TraitDef, + node: &ast::Trait, krate: Crate, ) -> Option> { let tr = sema.to_def(node)?; diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index d067c339d3..aa48cb412f 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs @@ -1361,7 +1361,7 @@ fn foo_<|>test() {} 11..19, ), name: "foo_test", - kind: FN_DEF, + kind: FN, container_name: None, description: None, docs: None, @@ -1443,7 +1443,7 @@ fn main() { let s<|>t = S{ f1:0 }; } 7..8, ), name: "S", - kind: STRUCT_DEF, + kind: STRUCT, container_name: None, description: Some( "struct S", @@ -1482,7 +1482,7 @@ fn main() { let s<|>t = S{ f1:Arg(0) }; } 24..25, ), name: "S", - kind: STRUCT_DEF, + kind: STRUCT, container_name: None, description: Some( "struct S", @@ -1501,7 +1501,7 @@ fn main() { let s<|>t = S{ f1:Arg(0) }; } 7..10, ), name: "Arg", - kind: STRUCT_DEF, + kind: STRUCT, container_name: None, description: Some( "struct Arg", @@ -1540,7 +1540,7 @@ fn main() { let s<|>t = S{ f1: S{ f1: Arg(0) } }; } 24..25, ), name: "S", - kind: STRUCT_DEF, + kind: STRUCT, container_name: None, description: Some( "struct S", @@ -1559,7 +1559,7 @@ fn main() { let s<|>t = S{ f1: S{ f1: Arg(0) } }; } 7..10, ), name: "Arg", - kind: STRUCT_DEF, + kind: STRUCT, container_name: None, description: Some( "struct Arg", @@ -1601,7 +1601,7 @@ fn main() { let s<|>t = (A(1), B(2), M::C(3) ); } 7..8, ), name: "A", - kind: STRUCT_DEF, + kind: STRUCT, container_name: None, description: Some( "struct A", @@ -1620,7 +1620,7 @@ fn main() { let s<|>t = (A(1), B(2), M::C(3) ); } 22..23, ), name: "B", - kind: STRUCT_DEF, + kind: STRUCT, container_name: None, description: Some( "struct B", @@ -1639,7 +1639,7 @@ fn main() { let s<|>t = (A(1), B(2), M::C(3) ); } 53..54, ), name: "C", - kind: STRUCT_DEF, + kind: STRUCT, container_name: None, description: Some( "pub struct C", @@ -1678,7 +1678,7 @@ fn main() { let s<|>t = foo(); } 6..9, ), name: "Foo", - kind: TRAIT_DEF, + kind: TRAIT, container_name: None, description: Some( "trait Foo", @@ -1718,7 +1718,7 @@ fn main() { let s<|>t = foo(); } 6..9, ), name: "Foo", - kind: TRAIT_DEF, + kind: TRAIT, container_name: None, description: Some( "trait Foo", @@ -1737,7 +1737,7 @@ fn main() { let s<|>t = foo(); } 23..24, ), name: "S", - kind: STRUCT_DEF, + kind: STRUCT, container_name: None, description: Some( "struct S", @@ -1777,7 +1777,7 @@ fn main() { let s<|>t = foo(); } 6..9, ), name: "Foo", - kind: TRAIT_DEF, + kind: TRAIT, container_name: None, description: Some( "trait Foo", @@ -1796,7 +1796,7 @@ fn main() { let s<|>t = foo(); } 19..22, ), name: "Bar", - kind: TRAIT_DEF, + kind: TRAIT, container_name: None, description: Some( "trait Bar", @@ -1839,7 +1839,7 @@ fn main() { let s<|>t = foo(); } 6..9, ), name: "Foo", - kind: TRAIT_DEF, + kind: TRAIT, container_name: None, description: Some( "trait Foo", @@ -1858,7 +1858,7 @@ fn main() { let s<|>t = foo(); } 22..25, ), name: "Bar", - kind: TRAIT_DEF, + kind: TRAIT, container_name: None, description: Some( "trait Bar", @@ -1877,7 +1877,7 @@ fn main() { let s<|>t = foo(); } 39..41, ), name: "S1", - kind: STRUCT_DEF, + kind: STRUCT, container_name: None, description: Some( "struct S1", @@ -1896,7 +1896,7 @@ fn main() { let s<|>t = foo(); } 52..54, ), name: "S2", - kind: STRUCT_DEF, + kind: STRUCT, container_name: None, description: Some( "struct S2", @@ -1933,7 +1933,7 @@ fn foo(ar<|>g: &impl Foo) {} 6..9, ), name: "Foo", - kind: TRAIT_DEF, + kind: TRAIT, container_name: None, description: Some( "trait Foo", @@ -1973,7 +1973,7 @@ fn foo(ar<|>g: &impl Foo + Bar) {} 6..9, ), name: "Foo", - kind: TRAIT_DEF, + kind: TRAIT, container_name: None, description: Some( "trait Foo", @@ -1992,7 +1992,7 @@ fn foo(ar<|>g: &impl Foo + Bar) {} 19..22, ), name: "Bar", - kind: TRAIT_DEF, + kind: TRAIT, container_name: None, description: Some( "trait Bar", @@ -2011,7 +2011,7 @@ fn foo(ar<|>g: &impl Foo + Bar) {} 36..37, ), name: "S", - kind: STRUCT_DEF, + kind: STRUCT, container_name: None, description: Some( "struct S", @@ -2049,7 +2049,7 @@ fn foo(ar<|>g: &impl Foo) {} 6..9, ), name: "Foo", - kind: TRAIT_DEF, + kind: TRAIT, container_name: None, description: Some( "trait Foo", @@ -2068,7 +2068,7 @@ fn foo(ar<|>g: &impl Foo) {} 23..24, ), name: "S", - kind: STRUCT_DEF, + kind: STRUCT, container_name: None, description: Some( "struct S", @@ -2111,7 +2111,7 @@ fn main() { let s<|>t = foo(); } 49..50, ), name: "B", - kind: STRUCT_DEF, + kind: STRUCT, container_name: None, description: Some( "struct B", @@ -2130,7 +2130,7 @@ fn main() { let s<|>t = foo(); } 6..9, ), name: "Foo", - kind: TRAIT_DEF, + kind: TRAIT, container_name: None, description: Some( "trait Foo", @@ -2167,7 +2167,7 @@ fn foo(ar<|>g: &dyn Foo) {} 6..9, ), name: "Foo", - kind: TRAIT_DEF, + kind: TRAIT, container_name: None, description: Some( "trait Foo", @@ -2205,7 +2205,7 @@ fn foo(ar<|>g: &dyn Foo) {} 6..9, ), name: "Foo", - kind: TRAIT_DEF, + kind: TRAIT, container_name: None, description: Some( "trait Foo", @@ -2224,7 +2224,7 @@ fn foo(ar<|>g: &dyn Foo) {} 23..24, ), name: "S", - kind: STRUCT_DEF, + kind: STRUCT, container_name: None, description: Some( "struct S", @@ -2265,7 +2265,7 @@ fn foo(a<|>rg: &impl ImplTrait>>>) {} 6..15, ), name: "ImplTrait", - kind: TRAIT_DEF, + kind: TRAIT, container_name: None, description: Some( "trait ImplTrait", @@ -2284,7 +2284,7 @@ fn foo(a<|>rg: &impl ImplTrait>>>) {} 50..51, ), name: "B", - kind: STRUCT_DEF, + kind: STRUCT, container_name: None, description: Some( "struct B", @@ -2303,7 +2303,7 @@ fn foo(a<|>rg: &impl ImplTrait>>>) {} 28..36, ), name: "DynTrait", - kind: TRAIT_DEF, + kind: TRAIT, container_name: None, description: Some( "trait DynTrait", @@ -2322,7 +2322,7 @@ fn foo(a<|>rg: &impl ImplTrait>>>) {} 65..66, ), name: "S", - kind: STRUCT_DEF, + kind: STRUCT, container_name: None, description: Some( "struct S", @@ -2370,7 +2370,7 @@ fn main() { let s<|>t = test().get(); } 6..9, ), name: "Foo", - kind: TRAIT_DEF, + kind: TRAIT, container_name: None, description: Some( "trait Foo", diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs index f2e4f7ee54..1bacead63c 100644 --- a/crates/ra_ide/src/inlay_hints.rs +++ b/crates/ra_ide/src/inlay_hints.rs @@ -2,7 +2,7 @@ use hir::{Adt, Callable, HirDisplay, Semantics, Type}; use ra_ide_db::RootDatabase; use ra_prof::profile; use ra_syntax::{ - ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner}, + ast::{self, ArgListOwner, AstNode}, match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, TextRange, T, }; use stdx::to_lower_snake_case; @@ -78,7 +78,7 @@ pub(crate) fn inlay_hints( match node { ast::CallExpr(it) => { get_param_name_hints(&mut res, &sema, config, ast::Expr::from(it)); }, ast::MethodCallExpr(it) => { get_param_name_hints(&mut res, &sema, config, ast::Expr::from(it)); }, - ast::BindPat(it) => { get_bind_pat_hints(&mut res, &sema, config, it); }, + ast::IdentPat(it) => { get_bind_pat_hints(&mut res, &sema, config, it); }, _ => (), } } @@ -96,7 +96,7 @@ fn get_chaining_hints( return None; } - if matches!(expr, ast::Expr::RecordLit(_)) { + if matches!(expr, ast::Expr::RecordExpr(_)) { return None; } @@ -161,7 +161,7 @@ fn get_param_name_hints( Either::Left(self_param) => Some((self_param.to_string(), arg)), Either::Right(pat) => { let param_name = match pat { - ast::Pat::BindPat(it) => it.name()?.to_string(), + ast::Pat::IdentPat(it) => it.name()?.to_string(), it => it.to_string(), }; Some((param_name, arg)) @@ -182,7 +182,7 @@ fn get_bind_pat_hints( acc: &mut Vec, sema: &Semantics, config: &InlayHintsConfig, - pat: ast::BindPat, + pat: ast::IdentPat, ) -> Option<()> { if !config.type_hints { return None; @@ -202,7 +202,7 @@ fn get_bind_pat_hints( Some(()) } -fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::BindPat, pat_ty: &Type) -> bool { +fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &Type) -> bool { if let Some(Adt::Enum(enum_data)) = pat_ty.as_adt() { let pat_text = bind_pat.to_string(); enum_data @@ -215,7 +215,11 @@ fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::BindPat, pat_ty: &Type } } -fn should_not_display_type_hint(db: &RootDatabase, bind_pat: &ast::BindPat, pat_ty: &Type) -> bool { +fn should_not_display_type_hint( + db: &RootDatabase, + bind_pat: &ast::IdentPat, + pat_ty: &Type, +) -> bool { if pat_ty.is_unknown() { return true; } @@ -230,10 +234,10 @@ fn should_not_display_type_hint(db: &RootDatabase, bind_pat: &ast::BindPat, pat_ match_ast! { match node { ast::LetStmt(it) => { - return it.ascribed_type().is_some() + return it.ty().is_some() }, ast::Param(it) => { - return it.ascribed_type().is_some() + return it.ty().is_some() }, ast::MatchArm(_it) => { return pat_is_enum_variant(db, bind_pat, pat_ty); diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index 4c4d9f6fa9..0fede0d879 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs @@ -510,9 +510,10 @@ impl Analysis { query: &str, parse_only: bool, position: FilePosition, + selections: Vec, ) -> Cancelable> { self.with_db(|db| { - let edits = ssr::parse_search_replace(query, parse_only, db, position)?; + let edits = ssr::parse_search_replace(query, parse_only, db, position, selections)?; Ok(SourceChange::from(edits)) }) } diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs index fe1c074d12..cf456630a5 100644 --- a/crates/ra_ide/src/references.rs +++ b/crates/ra_ide/src/references.rs @@ -150,7 +150,7 @@ fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Optio let stmt = find_node_at_offset::(syntax, range.start())?; if stmt.initializer().is_some() { let pat = stmt.pat()?; - if let ast::Pat::BindPat(it) = pat { + if let ast::Pat::IdentPat(it) = pat { if it.mut_token().is_some() { return Some(ReferenceAccess::Write); } @@ -172,16 +172,16 @@ fn get_struct_def_name_for_struct_literal_search( if let Some(name) = sema.find_node_at_offset_with_descend::(&syntax, left.text_range().start()) { - return name.syntax().ancestors().find_map(ast::StructDef::cast).and_then(|l| l.name()); + return name.syntax().ancestors().find_map(ast::Struct::cast).and_then(|l| l.name()); } if sema - .find_node_at_offset_with_descend::( + .find_node_at_offset_with_descend::( &syntax, left.text_range().start(), ) .is_some() { - return left.ancestors().find_map(ast::StructDef::cast).and_then(|l| l.name()); + return left.ancestors().find_map(ast::Struct::cast).and_then(|l| l.name()); } } None @@ -212,7 +212,7 @@ fn main() { ); check_result( refs, - "Foo STRUCT_DEF FileId(1) 0..26 7..10 Other", + "Foo STRUCT FileId(1) 0..26 7..10 Other", &["FileId(1) 101..104 StructLiteral"], ); } @@ -230,7 +230,7 @@ struct Foo<|> {} ); check_result( refs, - "Foo STRUCT_DEF FileId(1) 0..13 7..10 Other", + "Foo STRUCT FileId(1) 0..13 7..10 Other", &["FileId(1) 41..44 Other", "FileId(1) 54..57 StructLiteral"], ); } @@ -248,7 +248,7 @@ struct Foo <|>{} ); check_result( refs, - "Foo STRUCT_DEF FileId(1) 0..16 7..10 Other", + "Foo STRUCT FileId(1) 0..16 7..10 Other", &["FileId(1) 64..67 StructLiteral"], ); } @@ -267,7 +267,7 @@ fn main() { ); check_result( refs, - "Foo STRUCT_DEF FileId(1) 0..16 7..10 Other", + "Foo STRUCT FileId(1) 0..16 7..10 Other", &["FileId(1) 54..57 StructLiteral"], ); } @@ -290,7 +290,7 @@ fn main() { ); check_result( refs, - "i BIND_PAT FileId(1) 24..25 Other Write", + "i IDENT_PAT FileId(1) 24..25 Other Write", &[ "FileId(1) 50..51 Other Write", "FileId(1) 54..55 Other Read", @@ -316,7 +316,7 @@ fn bar() { ); check_result( refs, - "spam BIND_PAT FileId(1) 19..23 Other", + "spam IDENT_PAT FileId(1) 19..23 Other", &["FileId(1) 34..38 Other Read", "FileId(1) 41..45 Other Read"], ); } @@ -330,7 +330,7 @@ fn foo(i : u32) -> u32 { } "#, ); - check_result(refs, "i BIND_PAT FileId(1) 7..8 Other", &["FileId(1) 29..30 Other Read"]); + check_result(refs, "i IDENT_PAT FileId(1) 7..8 Other", &["FileId(1) 29..30 Other Read"]); } #[test] @@ -342,7 +342,7 @@ fn foo(i<|> : u32) -> u32 { } "#, ); - check_result(refs, "i BIND_PAT FileId(1) 7..8 Other", &["FileId(1) 29..30 Other Read"]); + check_result(refs, "i IDENT_PAT FileId(1) 7..8 Other", &["FileId(1) 29..30 Other Read"]); } #[test] @@ -361,7 +361,7 @@ fn main(s: Foo) { ); check_result( refs, - "spam RECORD_FIELD_DEF FileId(1) 17..30 21..25 Other", + "spam RECORD_FIELD FileId(1) 17..30 21..25 Other", &["FileId(1) 67..71 Other Read"], ); } @@ -376,7 +376,7 @@ impl Foo { } "#, ); - check_result(refs, "f FN_DEF FileId(1) 27..43 30..31 Other", &[]); + check_result(refs, "f FN FileId(1) 27..43 30..31 Other", &[]); } #[test] @@ -390,7 +390,7 @@ enum Foo { } "#, ); - check_result(refs, "B ENUM_VARIANT FileId(1) 22..23 22..23 Other", &[]); + check_result(refs, "B VARIANT FileId(1) 22..23 22..23 Other", &[]); } #[test] @@ -431,7 +431,7 @@ fn f() { let refs = analysis.find_all_refs(pos, None).unwrap().unwrap(); check_result( refs, - "Foo STRUCT_DEF FileId(2) 17..51 28..31 Other", + "Foo STRUCT FileId(2) 17..51 28..31 Other", &["FileId(1) 53..56 StructLiteral", "FileId(3) 79..82 StructLiteral"], ); } @@ -486,7 +486,7 @@ pub(super) struct Foo<|> { let refs = analysis.find_all_refs(pos, None).unwrap().unwrap(); check_result( refs, - "Foo STRUCT_DEF FileId(3) 0..41 18..21 Other", + "Foo STRUCT FileId(3) 0..41 18..21 Other", &["FileId(2) 20..23 Other", "FileId(2) 47..50 StructLiteral"], ); } @@ -514,7 +514,7 @@ pub(super) struct Foo<|> { let refs = analysis.find_all_refs(pos, None).unwrap().unwrap(); check_result( refs, - "quux FN_DEF FileId(1) 19..35 26..30 Other", + "quux FN FileId(1) 19..35 26..30 Other", &["FileId(2) 16..20 StructLiteral", "FileId(3) 16..20 StructLiteral"], ); @@ -522,7 +522,7 @@ pub(super) struct Foo<|> { analysis.find_all_refs(pos, Some(SearchScope::single_file(bar))).unwrap().unwrap(); check_result( refs, - "quux FN_DEF FileId(1) 19..35 26..30 Other", + "quux FN FileId(1) 19..35 26..30 Other", &["FileId(3) 16..20 StructLiteral"], ); } @@ -559,7 +559,7 @@ fn foo() { ); check_result( refs, - "i BIND_PAT FileId(1) 23..24 Other Write", + "i IDENT_PAT FileId(1) 23..24 Other Write", &["FileId(1) 34..35 Other Write", "FileId(1) 38..39 Other Read"], ); } @@ -580,7 +580,7 @@ fn foo() { ); check_result( refs, - "f RECORD_FIELD_DEF FileId(1) 15..21 15..16 Other", + "f RECORD_FIELD FileId(1) 15..21 15..16 Other", &["FileId(1) 55..56 Other Read", "FileId(1) 68..69 Other Write"], ); } @@ -595,7 +595,7 @@ fn foo() { } "#, ); - check_result(refs, "i BIND_PAT FileId(1) 19..20 Other", &["FileId(1) 26..27 Other Write"]); + check_result(refs, "i IDENT_PAT FileId(1) 19..20 Other", &["FileId(1) 26..27 Other Write"]); } #[test] @@ -619,7 +619,7 @@ fn main() { ); check_result( refs, - "new FN_DEF FileId(1) 54..101 61..64 Other", + "new FN FileId(1) 54..101 61..64 Other", &["FileId(1) 146..149 StructLiteral"], ); } @@ -646,7 +646,7 @@ fn main() { let refs = analysis.find_all_refs(pos, None).unwrap().unwrap(); check_result( refs, - "f FN_DEF FileId(1) 26..35 29..30 Other", + "f FN FileId(1) 26..35 29..30 Other", &["FileId(2) 11..12 Other", "FileId(2) 28..29 StructLiteral"], ); } diff --git a/crates/ra_ide/src/references/rename.rs b/crates/ra_ide/src/references/rename.rs index 8735ec53cf..c8d80fcf7c 100644 --- a/crates/ra_ide/src/references/rename.rs +++ b/crates/ra_ide/src/references/rename.rs @@ -7,7 +7,8 @@ use ra_ide_db::{ RootDatabase, }; use ra_syntax::{ - algo::find_node_at_offset, ast, ast::NameOwner, ast::TypeAscriptionOwner, + algo::find_node_at_offset, + ast::{self, NameOwner}, lex_single_valid_syntax_kind, match_ast, AstNode, SyntaxKind, SyntaxNode, SyntaxToken, }; use ra_text_edit::TextEdit; @@ -149,14 +150,14 @@ fn rename_to_self( let source_file = sema.parse(position.file_id); let syn = source_file.syntax(); - let fn_def = find_node_at_offset::(syn, position.offset)?; + let fn_def = find_node_at_offset::(syn, position.offset)?; let params = fn_def.param_list()?; if params.self_param().is_some() { return None; // method already has self param } let first_param = params.params().next()?; - let mutable = match first_param.ascribed_type() { - Some(ast::TypeRef::ReferenceType(rt)) => rt.mut_token().is_some(), + let mutable = match first_param.ty() { + Some(ast::Type::RefType(rt)) => rt.mut_token().is_some(), _ => return None, // not renaming other types }; @@ -192,15 +193,14 @@ fn text_edit_from_self_param( self_param: &ast::SelfParam, new_name: &str, ) -> Option { - fn target_type_name(impl_def: &ast::ImplDef) -> Option { - if let Some(ast::TypeRef::PathType(p)) = impl_def.target_type() { + fn target_type_name(impl_def: &ast::Impl) -> Option { + if let Some(ast::Type::PathType(p)) = impl_def.self_ty() { return Some(p.path()?.segment()?.name_ref()?.text().to_string()); } None } - let impl_def = - find_node_at_offset::(syn, self_param.syntax().text_range().start())?; + let impl_def = find_node_at_offset::(syn, self_param.syntax().text_range().start())?; let type_name = target_type_name(&impl_def)?; let mut replacement_text = String::from(new_name); @@ -221,7 +221,7 @@ fn rename_self_to_param( let syn = source_file.syntax(); let text = sema.db.file_text(position.file_id); - let fn_def = find_node_at_offset::(syn, position.offset)?; + let fn_def = find_node_at_offset::(syn, position.offset)?; let search_range = fn_def.syntax().text_range(); let mut edits: Vec = vec![]; diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs index 95a35a28db..3b7162b841 100644 --- a/crates/ra_ide/src/runnables.rs +++ b/crates/ra_ide/src/runnables.rs @@ -102,7 +102,7 @@ pub(crate) fn runnable( ) -> Option { match_ast! { match item { - ast::FnDef(it) => runnable_fn(sema, it, file_id), + ast::Fn(it) => runnable_fn(sema, it, file_id), ast::Module(it) => runnable_mod(sema, it, file_id), _ => None, } @@ -111,7 +111,7 @@ pub(crate) fn runnable( fn runnable_fn( sema: &Semantics, - fn_def: ast::FnDef, + fn_def: ast::Fn, file_id: FileId, ) -> Option { let name_string = fn_def.name()?.text().to_string(); @@ -188,7 +188,7 @@ pub struct TestAttr { } impl TestAttr { - fn from_fn(fn_def: &ast::FnDef) -> TestAttr { + fn from_fn(fn_def: &ast::Fn) -> TestAttr { let ignore = fn_def .attrs() .filter_map(|attr| attr.simple_name()) @@ -203,7 +203,7 @@ impl TestAttr { /// /// It may produce false positives, for example, `#[wasm_bindgen_test]` requires a different command to run the test, /// but it's better than not to have the runnables for the tests at all. -fn has_test_related_attribute(fn_def: &ast::FnDef) -> bool { +fn has_test_related_attribute(fn_def: &ast::Fn) -> bool { fn_def .attrs() .filter_map(|attr| attr.path()) @@ -211,7 +211,7 @@ fn has_test_related_attribute(fn_def: &ast::FnDef) -> bool { .any(|attribute_text| attribute_text.contains("test")) } -fn has_doc_test(fn_def: &ast::FnDef) -> bool { +fn has_doc_test(fn_def: &ast::Fn) -> bool { fn_def.doc_comment_text().map_or(false, |comment| comment.contains("```")) } @@ -220,15 +220,7 @@ fn runnable_mod( module: ast::Module, file_id: FileId, ) -> Option { - let has_test_function = module - .item_list()? - .items() - .filter_map(|it| match it { - ast::ModuleItem::FnDef(it) => Some(it), - _ => None, - }) - .any(|f| has_test_related_attribute(&f)); - if !has_test_function { + if !has_test_function_or_multiple_test_submodules(&module) { return None; } let module_def = sema.to_def(&module)?; @@ -246,6 +238,34 @@ fn runnable_mod( Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg_exprs }) } +// We could create runnables for modules with number_of_test_submodules > 0, +// but that bloats the runnables for no real benefit, since all tests can be run by the submodule already +fn has_test_function_or_multiple_test_submodules(module: &ast::Module) -> bool { + if let Some(item_list) = module.item_list() { + let mut number_of_test_submodules = 0; + + for item in item_list.items() { + match item { + ast::Item::Fn(f) => { + if has_test_related_attribute(&f) { + return true; + } + } + ast::Item::Module(submodule) => { + if has_test_function_or_multiple_test_submodules(&submodule) { + number_of_test_submodules += 1; + } + } + _ => (), + } + } + + number_of_test_submodules > 1 + } else { + false + } +} + #[cfg(test)] mod tests { use expect::{expect, Expect}; @@ -300,7 +320,7 @@ fn bench() {} 4..8, ), name: "main", - kind: FN_DEF, + kind: FN, container_name: None, description: None, docs: None, @@ -318,7 +338,7 @@ fn bench() {} 26..34, ), name: "test_foo", - kind: FN_DEF, + kind: FN, container_name: None, description: None, docs: None, @@ -343,7 +363,7 @@ fn bench() {} 62..70, ), name: "test_foo", - kind: FN_DEF, + kind: FN, container_name: None, description: None, docs: None, @@ -368,7 +388,7 @@ fn bench() {} 89..94, ), name: "bench", - kind: FN_DEF, + kind: FN, container_name: None, description: None, docs: None, @@ -411,7 +431,7 @@ fn foo() {} 4..8, ), name: "main", - kind: FN_DEF, + kind: FN, container_name: None, description: None, docs: None, @@ -427,7 +447,7 @@ fn foo() {} full_range: 15..57, focus_range: None, name: "foo", - kind: FN_DEF, + kind: FN, container_name: None, description: None, docs: None, @@ -473,7 +493,7 @@ impl Data { 4..8, ), name: "main", - kind: FN_DEF, + kind: FN, container_name: None, description: None, docs: None, @@ -489,7 +509,7 @@ impl Data { full_range: 44..98, focus_range: None, name: "foo", - kind: FN_DEF, + kind: FN, container_name: None, description: None, docs: None, @@ -550,7 +570,7 @@ mod test_mod { 35..44, ), name: "test_foo1", - kind: FN_DEF, + kind: FN, container_name: None, description: None, docs: None, @@ -571,19 +591,33 @@ mod test_mod { } #[test] - fn test_runnables_one_depth_layer_module() { + fn only_modules_with_test_functions_or_more_than_one_test_submodule_have_runners() { check( r#" //- /lib.rs <|> -mod foo { - mod test_mod { - #[test] - fn test_foo1() {} +mod root_tests { + mod nested_tests_0 { + mod nested_tests_1 { + #[test] + fn nested_test_11() {} + + #[test] + fn nested_test_12() {} + } + + mod nested_tests_2 { + #[test] + fn nested_test_2() {} + } + + mod nested_tests_3 {} } + + mod nested_tests_4 {} } "#, - &[&TEST, &TEST], + &[&TEST, &TEST, &TEST, &TEST, &TEST, &TEST], expect![[r#" [ Runnable { @@ -591,18 +625,18 @@ mod foo { file_id: FileId( 1, ), - full_range: 15..77, + full_range: 22..323, focus_range: Some( - 19..27, + 26..40, ), - name: "test_mod", + name: "nested_tests_0", kind: MODULE, container_name: None, description: None, docs: None, }, kind: TestMod { - path: "foo::test_mod", + path: "root_tests::nested_tests_0", }, cfg_exprs: [], }, @@ -611,19 +645,39 @@ mod foo { file_id: FileId( 1, ), - full_range: 38..71, + full_range: 51..192, focus_range: Some( - 57..66, + 55..69, ), - name: "test_foo1", - kind: FN_DEF, + name: "nested_tests_1", + kind: MODULE, + container_name: None, + description: None, + docs: None, + }, + kind: TestMod { + path: "root_tests::nested_tests_0::nested_tests_1", + }, + cfg_exprs: [], + }, + Runnable { + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 84..126, + focus_range: Some( + 107..121, + ), + name: "nested_test_11", + kind: FN, container_name: None, description: None, docs: None, }, kind: Test { test_id: Path( - "foo::test_mod::test_foo1", + "root_tests::nested_tests_0::nested_tests_1::nested_test_11", ), attr: TestAttr { ignore: false, @@ -631,46 +685,28 @@ mod foo { }, cfg_exprs: [], }, - ] - "#]], - ); - } - - #[test] - fn test_runnables_multiple_depth_module() { - check( - r#" -//- /lib.rs -<|> -mod foo { - mod bar { - mod test_mod { - #[test] - fn test_foo1() {} - } - } -} -"#, - &[&TEST, &TEST], - expect![[r#" - [ Runnable { nav: NavigationTarget { file_id: FileId( 1, ), - full_range: 33..107, + full_range: 140..182, focus_range: Some( - 37..45, + 163..177, ), - name: "test_mod", - kind: MODULE, + name: "nested_test_12", + kind: FN, container_name: None, description: None, docs: None, }, - kind: TestMod { - path: "foo::bar::test_mod", + kind: Test { + test_id: Path( + "root_tests::nested_tests_0::nested_tests_1::nested_test_12", + ), + attr: TestAttr { + ignore: false, + }, }, cfg_exprs: [], }, @@ -679,19 +715,39 @@ mod foo { file_id: FileId( 1, ), - full_range: 60..97, + full_range: 202..286, focus_range: Some( - 83..92, + 206..220, ), - name: "test_foo1", - kind: FN_DEF, + name: "nested_tests_2", + kind: MODULE, + container_name: None, + description: None, + docs: None, + }, + kind: TestMod { + path: "root_tests::nested_tests_0::nested_tests_2", + }, + cfg_exprs: [], + }, + Runnable { + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 235..276, + focus_range: Some( + 258..271, + ), + name: "nested_test_2", + kind: FN, container_name: None, description: None, docs: None, }, kind: Test { test_id: Path( - "foo::bar::test_mod::test_foo1", + "root_tests::nested_tests_0::nested_tests_2::nested_test_2", ), attr: TestAttr { ignore: false, @@ -727,7 +783,7 @@ fn test_foo1() {} 36..45, ), name: "test_foo1", - kind: FN_DEF, + kind: FN, container_name: None, description: None, docs: None, @@ -775,7 +831,7 @@ fn test_foo1() {} 58..67, ), name: "test_foo1", - kind: FN_DEF, + kind: FN, container_name: None, description: None, docs: None, diff --git a/crates/ra_ide/src/ssr.rs b/crates/ra_ide/src/ssr.rs index 95d8f79b87..4348b43beb 100644 --- a/crates/ra_ide/src/ssr.rs +++ b/crates/ra_ide/src/ssr.rs @@ -1,4 +1,4 @@ -use ra_db::FilePosition; +use ra_db::{FilePosition, FileRange}; use ra_ide_db::RootDatabase; use crate::SourceFileEdit; @@ -24,6 +24,9 @@ use ra_ssr::{MatchFinder, SsrError, SsrRule}; // Method calls should generally be written in UFCS form. e.g. `foo::Bar::baz($s, $a)` will match // `$s.baz($a)`, provided the method call `baz` resolves to the method `foo::Bar::baz`. // +// The scope of the search / replace will be restricted to the current selection if any, otherwise +// it will apply to the whole workspace. +// // Placeholders may be given constraints by writing them as `${::...}`. // // Supported constraints: @@ -56,10 +59,11 @@ pub fn parse_search_replace( rule: &str, parse_only: bool, db: &RootDatabase, - position: FilePosition, + resolve_context: FilePosition, + selections: Vec, ) -> Result, SsrError> { let rule: SsrRule = rule.parse()?; - let mut match_finder = MatchFinder::in_context(db, position); + let mut match_finder = MatchFinder::in_context(db, resolve_context, selections); match_finder.add_rule(rule)?; if parse_only { return Ok(Vec::new()); diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index d456d5d362..f71b804fe9 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs @@ -4,7 +4,7 @@ mod injection; #[cfg(test)] mod tests; -use hir::{Name, Semantics}; +use hir::{Name, Semantics, VariantDef}; use ra_ide_db::{ defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass}, RootDatabase, @@ -455,6 +455,18 @@ fn macro_call_range(macro_call: &ast::MacroCall) -> Option { Some(TextRange::new(range_start, range_end)) } +fn is_possibly_unsafe(name_ref: &ast::NameRef) -> bool { + name_ref + .syntax() + .parent() + .and_then(|parent| { + ast::FieldExpr::cast(parent.clone()) + .map(|_| true) + .or_else(|| ast::RecordPatField::cast(parent).map(|_| true)) + }) + .unwrap_or(false) +} + fn highlight_element( sema: &Semantics, bindings_shadow_count: &mut FxHashMap, @@ -464,7 +476,7 @@ fn highlight_element( let db = sema.db; let mut binding_hash = None; let highlight: Highlight = match element.kind() { - FN_DEF => { + FN => { bindings_shadow_count.clear(); return None; } @@ -484,10 +496,19 @@ fn highlight_element( match name_kind { Some(NameClass::Definition(def)) => { - highlight_name(db, def) | HighlightModifier::Definition + highlight_name(db, def, false) | HighlightModifier::Definition + } + Some(NameClass::ConstReference(def)) => highlight_name(db, def, false), + Some(NameClass::FieldShorthand { field, .. }) => { + let mut h = HighlightTag::Field.into(); + if let Definition::Field(field) = field { + if let VariantDef::Union(_) = field.parent_def(db) { + h |= HighlightModifier::Unsafe; + } + } + + h } - Some(NameClass::ConstReference(def)) => highlight_name(db, def), - Some(NameClass::FieldShorthand { .. }) => HighlightTag::Field.into(), None => highlight_name_by_syntax(name) | HighlightModifier::Definition, } } @@ -498,6 +519,7 @@ fn highlight_element( } NAME_REF => { let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap(); + let possibly_unsafe = is_possibly_unsafe(&name_ref); match classify_name_ref(sema, &name_ref) { Some(name_kind) => match name_kind { NameRefClass::Definition(def) => { @@ -508,11 +530,13 @@ fn highlight_element( binding_hash = Some(calc_binding_hash(&name, *shadow_count)) } }; - highlight_name(db, def) + highlight_name(db, def, possibly_unsafe) } NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(), }, - None if syntactic_name_ref_highlighting => highlight_name_ref_by_syntax(name_ref), + None if syntactic_name_ref_highlighting => { + highlight_name_ref_by_syntax(name_ref, sema) + } None => HighlightTag::UnresolvedReference.into(), } } @@ -546,7 +570,7 @@ fn highlight_element( T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => { HighlightTag::Macro.into() } - T![*] if element.parent().and_then(ast::PointerType::cast).is_some() => { + T![*] if element.parent().and_then(ast::PtrType::cast).is_some() => { HighlightTag::Keyword.into() } T![*] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => { @@ -577,7 +601,7 @@ fn highlight_element( _ if element.parent().and_then(ast::RangePat::cast).is_some() => { HighlightTag::Operator.into() } - _ if element.parent().and_then(ast::DotDotPat::cast).is_some() => { + _ if element.parent().and_then(ast::RestPat::cast).is_some() => { HighlightTag::Operator.into() } _ if element.parent().and_then(ast::Attr::cast).is_some() => { @@ -647,15 +671,24 @@ fn highlight_element( fn is_child_of_impl(element: &SyntaxElement) -> bool { match element.parent() { - Some(e) => e.kind() == IMPL_DEF, + Some(e) => e.kind() == IMPL, _ => false, } } -fn highlight_name(db: &RootDatabase, def: Definition) -> Highlight { +fn highlight_name(db: &RootDatabase, def: Definition, possibly_unsafe: bool) -> Highlight { match def { Definition::Macro(_) => HighlightTag::Macro, - Definition::Field(_) => HighlightTag::Field, + Definition::Field(field) => { + let mut h = HighlightTag::Field.into(); + if possibly_unsafe { + if let VariantDef::Union(_) = field.parent_def(db) { + h |= HighlightModifier::Unsafe; + } + } + + return h; + } Definition::ModuleDef(def) => match def { hir::ModuleDef::Module(_) => HighlightTag::Module, hir::ModuleDef::Function(func) => { @@ -677,6 +710,7 @@ fn highlight_name(db: &RootDatabase, def: Definition) -> Highlight { let mut h = Highlight::new(HighlightTag::Static); if s.is_mut(db) { h |= HighlightModifier::Mutable; + h |= HighlightModifier::Unsafe; } return h; } @@ -705,26 +739,26 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight { }; let tag = match parent.kind() { - STRUCT_DEF => HighlightTag::Struct, - ENUM_DEF => HighlightTag::Enum, - UNION_DEF => HighlightTag::Union, - TRAIT_DEF => HighlightTag::Trait, - TYPE_ALIAS_DEF => HighlightTag::TypeAlias, + STRUCT => HighlightTag::Struct, + ENUM => HighlightTag::Enum, + UNION => HighlightTag::Union, + TRAIT => HighlightTag::Trait, + TYPE_ALIAS => HighlightTag::TypeAlias, TYPE_PARAM => HighlightTag::TypeParam, - RECORD_FIELD_DEF => HighlightTag::Field, + RECORD_FIELD => HighlightTag::Field, MODULE => HighlightTag::Module, - FN_DEF => HighlightTag::Function, - CONST_DEF => HighlightTag::Constant, - STATIC_DEF => HighlightTag::Static, - ENUM_VARIANT => HighlightTag::EnumVariant, - BIND_PAT => HighlightTag::Local, + FN => HighlightTag::Function, + CONST => HighlightTag::Constant, + STATIC => HighlightTag::Static, + VARIANT => HighlightTag::EnumVariant, + IDENT_PAT => HighlightTag::Local, _ => default, }; tag.into() } -fn highlight_name_ref_by_syntax(name: ast::NameRef) -> Highlight { +fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics) -> Highlight { let default = HighlightTag::UnresolvedReference; let parent = match name.syntax().parent() { @@ -734,7 +768,20 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef) -> Highlight { let tag = match parent.kind() { METHOD_CALL_EXPR => HighlightTag::Function, - FIELD_EXPR => HighlightTag::Field, + FIELD_EXPR => { + let h = HighlightTag::Field; + let is_union = ast::FieldExpr::cast(parent) + .and_then(|field_expr| { + let field = sema.resolve_field(&field_expr)?; + Some(if let VariantDef::Union(_) = field.parent_def(sema.db) { + true + } else { + false + }) + }) + .unwrap_or(false); + return if is_union { h | HighlightModifier::Unsafe } else { h.into() }; + } PATH_SEGMENT => { let path = match parent.parent().and_then(ast::Path::cast) { Some(it) => it, diff --git a/crates/ra_ide/src/syntax_highlighting/html.rs b/crates/ra_ide/src/syntax_highlighting/html.rs index 0be55bca98..a5e7d28676 100644 --- a/crates/ra_ide/src/syntax_highlighting/html.rs +++ b/crates/ra_ide/src/syntax_highlighting/html.rs @@ -1,5 +1,6 @@ //! Renders a bit of code as HTML. +use oorandom::Rand32; use ra_db::SourceDatabase; use ra_syntax::{AstNode, TextRange, TextSize}; @@ -9,13 +10,12 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo let parse = db.parse(file_id); fn rainbowify(seed: u64) -> String { - use rand::prelude::*; - let mut rng = SmallRng::seed_from_u64(seed); + let mut rng = Rand32::new(seed); format!( "hsl({h},{s}%,{l}%)", - h = rng.gen_range::(0, 361), - s = rng.gen_range::(42, 99), - l = rng.gen_range::(40, 91), + h = rng.rand_range(0..361), + s = rng.rand_range(42..99), + l = rng.rand_range(40..91), ) } diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs index 87a6e2523b..730efff0de 100644 --- a/crates/ra_ide/src/syntax_highlighting/tests.rs +++ b/crates/ra_ide/src/syntax_highlighting/tests.rs @@ -9,6 +9,9 @@ use crate::{mock_analysis::single_file, FileRange, TextRange}; fn test_highlighting() { check_highlighting( r#" +use inner::{self as inner_mod}; +mod inner {} + #[derive(Clone, Debug)] struct Foo { pub x: i32, @@ -272,19 +275,37 @@ fn test_unsafe_highlighting() { r#" unsafe fn unsafe_fn() {} +union Union { + a: u32, + b: f32, +} + struct HasUnsafeFn; impl HasUnsafeFn { unsafe fn unsafe_method(&self) {} } +struct TypeForStaticMut { + a: u8 +} + +static mut global_mut: TypeForStaticMut = TypeForStaticMut { a: 0 }; + fn main() { let x = &5 as *const usize; + let u = Union { b: 0 }; unsafe { unsafe_fn(); + let b = u.b; + match u { + Union { b: 0 } => (), + Union { a } => (), + } HasUnsafeFn.unsafe_method(); let y = *(x); let z = -x; + let a = global_mut.a; } } "# diff --git a/crates/ra_ide/src/syntax_tree.rs b/crates/ra_ide/src/syntax_tree.rs index f716a38616..07217e8087 100644 --- a/crates/ra_ide/src/syntax_tree.rs +++ b/crates/ra_ide/src/syntax_tree.rs @@ -116,7 +116,7 @@ mod tests { syn.trim(), r#" SOURCE_FILE@0..11 - FN_DEF@0..11 + FN@0..11 FN_KW@0..2 "fn" WHITESPACE@2..3 " " NAME@3..6 @@ -148,7 +148,7 @@ fn test() { syn.trim(), r#" SOURCE_FILE@0..60 - FN_DEF@0..60 + FN@0..60 FN_KW@0..2 "fn" WHITESPACE@2..3 " " NAME@3..7 @@ -190,7 +190,7 @@ SOURCE_FILE@0..60 assert_eq_text!( syn.trim(), r#" -FN_DEF@0..11 +FN@0..11 FN_KW@0..2 "fn" WHITESPACE@2..3 " " NAME@3..6 @@ -258,7 +258,7 @@ fn bar() { syn.trim(), r#" SOURCE_FILE@0..12 - FN_DEF@0..12 + FN@0..12 FN_KW@0..2 "fn" WHITESPACE@2..3 " " NAME@3..6 @@ -292,7 +292,7 @@ fn bar() { syn.trim(), r#" SOURCE_FILE@0..12 - FN_DEF@0..12 + FN@0..12 FN_KW@0..2 "fn" WHITESPACE@2..3 " " NAME@3..6 @@ -325,7 +325,7 @@ fn bar() { syn.trim(), r#" SOURCE_FILE@0..25 - FN_DEF@0..12 + FN@0..12 FN_KW@0..2 "fn" WHITESPACE@2..3 " " NAME@3..6 @@ -339,7 +339,7 @@ SOURCE_FILE@0..25 WHITESPACE@10..11 "\n" R_CURLY@11..12 "}" WHITESPACE@12..13 "\n" - FN_DEF@13..25 + FN@13..25 FN_KW@13..15 "fn" WHITESPACE@15..16 " " NAME@16..19 diff --git a/crates/ra_ide/test_data/highlight_unsafe.html b/crates/ra_ide/test_data/highlight_unsafe.html index b81b6f1c3b..79409fe816 100644 --- a/crates/ra_ide/test_data/highlight_unsafe.html +++ b/crates/ra_ide/test_data/highlight_unsafe.html @@ -37,18 +37,36 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
unsafe fn unsafe_fn() {}
 
+union Union {
+    a: u32,
+    b: f32,
+}
+
 struct HasUnsafeFn;
 
 impl HasUnsafeFn {
     unsafe fn unsafe_method(&self) {}
 }
 
+struct TypeForStaticMut {
+    a: u8
+}
+
+static mut global_mut: TypeForStaticMut = TypeForStaticMut { a: 0 };
+
 fn main() {
     let x = &5 as *const usize;
+    let u = Union { b: 0 };
     unsafe {
         unsafe_fn();
+        let b = u.b;
+        match u {
+            Union { b: 0 } => (),
+            Union { a } => (),
+        }
         HasUnsafeFn.unsafe_method();
         let y = *(x);
         let z = -x;
+        let a = global_mut.a;
     }
 }
\ No newline at end of file diff --git a/crates/ra_ide/test_data/highlighting.html b/crates/ra_ide/test_data/highlighting.html index 345a2f0231..8e0160eee5 100644 --- a/crates/ra_ide/test_data/highlighting.html +++ b/crates/ra_ide/test_data/highlighting.html @@ -35,7 +35,10 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } -
#[derive(Clone, Debug)]
+
use inner::{self as inner_mod};
+mod inner {}
+
+#[derive(Clone, Debug)]
 struct Foo {
     pub x: i32,
     pub y: i32,
@@ -61,7 +64,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     }
 }
 
-static mut STATIC_MUT: i32 = 0;
+static mut STATIC_MUT: i32 = 0;
 
 fn foo<'a, T>() -> T {
     foo::<'a, i32>()
@@ -94,7 +97,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     }
     unsafe {
         vec.set_len(0);
-        STATIC_MUT = 1;
+        STATIC_MUT = 1;
     }
 
     for e in vec {
diff --git a/crates/ra_ide/test_data/rainbow_highlighting.html b/crates/ra_ide/test_data/rainbow_highlighting.html
index 08d83302ce..401e87a73d 100644
--- a/crates/ra_ide/test_data/rainbow_highlighting.html
+++ b/crates/ra_ide/test_data/rainbow_highlighting.html
@@ -36,14 +36,14 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
 
 
fn main() {
-    let hello = "hello";
-    let x = hello.to_string();
-    let y = hello.to_string();
+    let hello = "hello";
+    let x = hello.to_string();
+    let y = hello.to_string();
 
-    let x = "other color please!";
-    let y = x.to_string();
+    let x = "other color please!";
+    let y = x.to_string();
 }
 
 fn bar() {
-    let mut hello = "hello";
+    let mut hello = "hello";
 }
\ No newline at end of file diff --git a/crates/ra_ide_db/src/change.rs b/crates/ra_ide_db/src/change.rs index 32d9a8d1ff..b13df8b855 100644 --- a/crates/ra_ide_db/src/change.rs +++ b/crates/ra_ide_db/src/change.rs @@ -190,11 +190,24 @@ impl RootDatabase { let q: $q = Default::default(); let name = format!("{:?} (deps)", q); acc.push((name, before - after)); + + let before = memory_usage().allocated; + $q.in_db(self).purge(); + let after = memory_usage().allocated; + let q: $q = Default::default(); + let name = format!("{:?} (purge)", q); + acc.push((name, before - after)); )*} } sweep_each_query![ // SourceDatabase ra_db::ParseQuery + ra_db::CrateGraphQuery + + // SourceDatabaseExt + ra_db::FileTextQuery + ra_db::FileSourceRootQuery + ra_db::SourceRootQuery ra_db::SourceRootCratesQuery // AstDatabase @@ -242,15 +255,24 @@ impl RootDatabase { hir::db::TraitImplsInCrateQuery hir::db::TraitImplsInDepsQuery hir::db::AssociatedTyDataQuery + hir::db::AssociatedTyDataQuery hir::db::TraitDatumQuery hir::db::StructDatumQuery hir::db::ImplDatumQuery + hir::db::FnDefDatumQuery + hir::db::ReturnTypeImplTraitsQuery + hir::db::InternCallableDefQuery + hir::db::InternTypeParamIdQuery + hir::db::InternImplTraitIdQuery + hir::db::InternClosureQuery hir::db::AssociatedTyValueQuery hir::db::TraitSolveQuery - hir::db::ReturnTypeImplTraitsQuery // SymbolsDatabase crate::symbol_index::FileSymbolsQuery + crate::symbol_index::LibrarySymbolsQuery + crate::symbol_index::LocalRootsQuery + crate::symbol_index::LibraryRootsQuery // LineIndexDatabase crate::LineIndexQuery diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs index f391a8e432..b51000b03f 100644 --- a/crates/ra_ide_db/src/defs.rs +++ b/crates/ra_ide_db/src/defs.rs @@ -12,7 +12,7 @@ use hir::{ use ra_prof::profile; use ra_syntax::{ ast::{self, AstNode}, - match_ast, + match_ast, SyntaxNode, }; use crate::RootDatabase; @@ -111,7 +111,7 @@ pub fn classify_name(sema: &Semantics, name: &ast::Name) -> Option let parent = name.syntax().parent()?; - if let Some(bind_pat) = ast::BindPat::cast(parent.clone()) { + if let Some(bind_pat) = ast::IdentPat::cast(parent.clone()) { if let Some(def) = sema.resolve_bind_pat_to_const(&bind_pat) { return Some(NameClass::ConstReference(Definition::ModuleDef(def))); } @@ -119,19 +119,38 @@ pub fn classify_name(sema: &Semantics, name: &ast::Name) -> Option match_ast! { match parent { - ast::Alias(it) => { + ast::Rename(it) => { let use_tree = it.syntax().parent().and_then(ast::UseTree::cast)?; let path = use_tree.path()?; let path_segment = path.segment()?; - let name_ref = path_segment.name_ref()?; - let name_ref_class = classify_name_ref(sema, &name_ref)?; + let name_ref_class = path_segment + .name_ref() + // The rename might be from a `self` token, so fallback to the name higher + // in the use tree. + .or_else(||{ + if path_segment.self_token().is_none() { + return None; + } + + let use_tree = use_tree + .syntax() + .parent() + .as_ref() + // Skip over UseTreeList + .and_then(SyntaxNode::parent) + .and_then(ast::UseTree::cast)?; + let path = use_tree.path()?; + let path_segment = path.segment()?; + path_segment.name_ref() + }) + .and_then(|name_ref| classify_name_ref(sema, &name_ref))?; Some(NameClass::Definition(name_ref_class.definition())) }, - ast::BindPat(it) => { + ast::IdentPat(it) => { let local = sema.to_def(&it)?; - if let Some(record_field_pat) = it.syntax().parent().and_then(ast::RecordFieldPat::cast) { + if let Some(record_field_pat) = it.syntax().parent().and_then(ast::RecordPatField::cast) { if record_field_pat.name_ref().is_none() { if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) { let field = Definition::Field(field); @@ -142,7 +161,7 @@ pub fn classify_name(sema: &Semantics, name: &ast::Name) -> Option Some(NameClass::Definition(Definition::Local(local))) }, - ast::RecordFieldDef(it) => { + ast::RecordField(it) => { let field: hir::Field = sema.to_def(&it)?; Some(NameClass::Definition(Definition::Field(field))) }, @@ -150,39 +169,39 @@ pub fn classify_name(sema: &Semantics, name: &ast::Name) -> Option let def = sema.to_def(&it)?; Some(NameClass::Definition(Definition::ModuleDef(def.into()))) }, - ast::StructDef(it) => { + ast::Struct(it) => { let def: hir::Struct = sema.to_def(&it)?; Some(NameClass::Definition(Definition::ModuleDef(def.into()))) }, - ast::UnionDef(it) => { + ast::Union(it) => { let def: hir::Union = sema.to_def(&it)?; Some(NameClass::Definition(Definition::ModuleDef(def.into()))) }, - ast::EnumDef(it) => { + ast::Enum(it) => { let def: hir::Enum = sema.to_def(&it)?; Some(NameClass::Definition(Definition::ModuleDef(def.into()))) }, - ast::TraitDef(it) => { + ast::Trait(it) => { let def: hir::Trait = sema.to_def(&it)?; Some(NameClass::Definition(Definition::ModuleDef(def.into()))) }, - ast::StaticDef(it) => { + ast::Static(it) => { let def: hir::Static = sema.to_def(&it)?; Some(NameClass::Definition(Definition::ModuleDef(def.into()))) }, - ast::EnumVariant(it) => { + ast::Variant(it) => { let def: hir::EnumVariant = sema.to_def(&it)?; Some(NameClass::Definition(Definition::ModuleDef(def.into()))) }, - ast::FnDef(it) => { + ast::Fn(it) => { let def: hir::Function = sema.to_def(&it)?; Some(NameClass::Definition(Definition::ModuleDef(def.into()))) }, - ast::ConstDef(it) => { + ast::Const(it) => { let def: hir::Const = sema.to_def(&it)?; Some(NameClass::Definition(Definition::ModuleDef(def.into()))) }, - ast::TypeAliasDef(it) => { + ast::TypeAlias(it) => { let def: hir::TypeAlias = sema.to_def(&it)?; Some(NameClass::Definition(Definition::ModuleDef(def.into()))) }, @@ -236,7 +255,7 @@ pub fn classify_name_ref( } } - if let Some(record_field) = ast::RecordField::for_field_name(name_ref) { + if let Some(record_field) = ast::RecordExprField::for_field_name(name_ref) { if let Some((field, local)) = sema.resolve_record_field(&record_field) { let field = Definition::Field(field); let res = match local { @@ -247,7 +266,7 @@ pub fn classify_name_ref( } } - if let Some(record_field_pat) = ast::RecordFieldPat::cast(parent.clone()) { + if let Some(record_field_pat) = ast::RecordPatField::cast(parent.clone()) { if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) { let field = Definition::Field(field); return Some(NameRefClass::Definition(field)); diff --git a/crates/ra_ide_db/src/search.rs b/crates/ra_ide_db/src/search.rs index a7cae37b0c..0b862b449f 100644 --- a/crates/ra_ide_db/src/search.rs +++ b/crates/ra_ide_db/src/search.rs @@ -315,7 +315,7 @@ fn is_record_lit_name_ref(name_ref: &ast::NameRef) -> bool { name_ref .syntax() .ancestors() - .find_map(ast::RecordLit::cast) + .find_map(ast::RecordExpr::cast) .and_then(|l| l.path()) .and_then(|p| p.segment()) .map(|p| p.name_ref().as_ref() == Some(name_ref)) diff --git a/crates/ra_ide_db/src/symbol_index.rs b/crates/ra_ide_db/src/symbol_index.rs index 131e2a128d..35a2c5be3b 100644 --- a/crates/ra_ide_db/src/symbol_index.rs +++ b/crates/ra_ide_db/src/symbol_index.rs @@ -344,7 +344,7 @@ impl Query { } fn is_type(kind: SyntaxKind) -> bool { - matches!(kind, STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF) + matches!(kind, STRUCT | ENUM | TRAIT | TYPE_ALIAS) } /// The actual data that is stored in the index. It should be as compact as @@ -397,14 +397,14 @@ fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr, TextRange)> { } match_ast! { match node { - ast::FnDef(it) => decl(it), - ast::StructDef(it) => decl(it), - ast::EnumDef(it) => decl(it), - ast::TraitDef(it) => decl(it), + ast::Fn(it) => decl(it), + ast::Struct(it) => decl(it), + ast::Enum(it) => decl(it), + ast::Trait(it) => decl(it), ast::Module(it) => decl(it), - ast::TypeAliasDef(it) => decl(it), - ast::ConstDef(it) => decl(it), - ast::StaticDef(it) => decl(it), + ast::TypeAlias(it) => decl(it), + ast::Const(it) => decl(it), + ast::Static(it) => decl(it), ast::MacroCall(it) => { if it.is_macro_rules().is_some() { decl(it) diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs index fc4133a675..5fc48507ff 100644 --- a/crates/ra_mbe/src/syntax_bridge.rs +++ b/crates/ra_mbe/src/syntax_bridge.rs @@ -825,7 +825,7 @@ mod tests { #[test] fn test_token_tree_multi_char_punct() { let source_file = ast::SourceFile::parse("struct Foo { a: x::Y }").ok().unwrap(); - let struct_def = source_file.syntax().descendants().find_map(ast::StructDef::cast).unwrap(); + let struct_def = source_file.syntax().descendants().find_map(ast::Struct::cast).unwrap(); let tt = ast_to_token_tree(&struct_def).unwrap().0; token_tree_to_syntax_node(&tt, FragmentKind::Item).unwrap(); } diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs index c43003fd63..286983d60b 100644 --- a/crates/ra_mbe/src/tests.rs +++ b/crates/ra_mbe/src/tests.rs @@ -258,7 +258,7 @@ fn test_expr_order() { assert_eq_text!( dump.trim(), r#"MACRO_ITEMS@0..15 - FN_DEF@0..15 + FN@0..15 FN_KW@0..2 "fn" NAME@2..5 IDENT@2..5 "bar" @@ -490,13 +490,13 @@ fn test_expand_to_item_list() { format!("{:#?}", tree).trim(), r#" MACRO_ITEMS@0..40 - STRUCT_DEF@0..20 + STRUCT@0..20 STRUCT_KW@0..6 "struct" NAME@6..9 IDENT@6..9 "Foo" - RECORD_FIELD_DEF_LIST@9..20 + RECORD_FIELD_LIST@9..20 L_CURLY@9..10 "{" - RECORD_FIELD_DEF@10..19 + RECORD_FIELD@10..19 NAME@10..15 IDENT@10..15 "field" COLON@15..16 ":" @@ -506,13 +506,13 @@ MACRO_ITEMS@0..40 NAME_REF@16..19 IDENT@16..19 "u32" R_CURLY@19..20 "}" - STRUCT_DEF@20..40 + STRUCT@20..40 STRUCT_KW@20..26 "struct" NAME@26..29 IDENT@26..29 "Bar" - RECORD_FIELD_DEF_LIST@29..40 + RECORD_FIELD_LIST@29..40 L_CURLY@29..30 "{" - RECORD_FIELD_DEF@30..39 + RECORD_FIELD@30..39 NAME@30..35 IDENT@30..35 "field" COLON@35..36 ":" @@ -625,7 +625,7 @@ fn test_tt_to_stmts() { r#"MACRO_STMTS@0..15 LET_STMT@0..7 LET_KW@0..3 "let" - BIND_PAT@3..4 + IDENT_PAT@3..4 NAME@3..4 IDENT@3..4 "a" EQ@4..5 "=" @@ -1116,7 +1116,7 @@ fn test_vec() { L_CURLY@0..1 "{" LET_STMT@1..20 LET_KW@1..4 "let" - BIND_PAT@4..8 + IDENT_PAT@4..8 MUT_KW@4..7 "mut" NAME@7..8 IDENT@7..8 "v" @@ -1467,7 +1467,7 @@ macro_rules! quick_error { buf [ ] queue [ ] ) => { - quick_error!(ENUM_DEFINITION [enum $name $( #[$meta] )*] + quick_error!(ENUMINITION [enum $name $( #[$meta] )*] body [] queue [$( $( #[$imeta] )* @@ -1489,7 +1489,7 @@ quick_error ! (SORT [enum Wrapped # [derive (Debug)]] items [ "#, ); - assert_eq!(expanded.to_string(), "quick_error ! (ENUM_DEFINITION [enum Wrapped # [derive (Debug)]] body [] queue [=> One : UNIT [] => Two : TUPLE [s : String]]) ;"); + assert_eq!(expanded.to_string(), "quick_error ! (ENUMINITION [enum Wrapped # [derive (Debug)]] body [] queue [=> One : UNIT [] => Two : TUPLE [s : String]]) ;"); } #[test] diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs index caedeead08..c2e1d701e2 100644 --- a/crates/ra_parser/src/grammar.rs +++ b/crates/ra_parser/src/grammar.rs @@ -142,19 +142,19 @@ pub(crate) fn reparser( ) -> Option { let res = match node { BLOCK_EXPR => expressions::block_expr, - RECORD_FIELD_DEF_LIST => items::record_field_def_list, - RECORD_FIELD_LIST => items::record_field_list, - ENUM_VARIANT_LIST => items::enum_variant_list, + RECORD_FIELD_LIST => items::record_field_def_list, + RECORD_EXPR_FIELD_LIST => items::record_field_list, + VARIANT_LIST => items::enum_variant_list, MATCH_ARM_LIST => items::match_arm_list, USE_TREE_LIST => items::use_tree_list, EXTERN_ITEM_LIST => items::extern_item_list, TOKEN_TREE if first_child? == T!['{'] => items::token_tree, - ITEM_LIST => match parent? { - IMPL_DEF => items::impl_item_list, - TRAIT_DEF => items::trait_item_list, - MODULE => items::mod_item_list, + ASSOC_ITEM_LIST => match parent? { + IMPL => items::impl_item_list, + TRAIT => items::trait_item_list, _ => return None, }, + ITEM_LIST => items::mod_item_list, _ => return None, }; Some(res) @@ -224,7 +224,7 @@ fn opt_alias(p: &mut Parser) { if !p.eat(T![_]) { name(p); } - m.complete(p, ALIAS); + m.complete(p, RENAME); } } @@ -270,10 +270,6 @@ fn name_ref(p: &mut Parser) { let m = p.start(); p.bump(IDENT); m.complete(p, NAME_REF); - } else if p.at(T![self]) { - let m = p.start(); - p.bump(T![self]); - m.complete(p, T![self]); } else { p.err_and_bump("expected identifier"); } diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs index 6e72eea664..e1c25a838f 100644 --- a/crates/ra_parser/src/grammar/expressions.rs +++ b/crates/ra_parser/src/grammar/expressions.rs @@ -587,7 +587,7 @@ fn path_expr(p: &mut Parser, r: Restrictions) -> (CompletedMarker, BlockLike) { match p.current() { T!['{'] if !r.forbid_structs => { record_field_list(p); - (m.complete(p, RECORD_LIT), BlockLike::NotBlock) + (m.complete(p, RECORD_EXPR), BlockLike::NotBlock) } T![!] if !p.at(T![!=]) => { let block_like = items::macro_call_after_excl(p); @@ -627,7 +627,7 @@ pub(crate) fn record_field_list(p: &mut Parser) { p.expect(T![:]); } expr(p); - m.complete(p, RECORD_FIELD); + m.complete(p, RECORD_EXPR_FIELD); } T![.] if p.at(T![..]) => { m.abandon(p); @@ -648,5 +648,5 @@ pub(crate) fn record_field_list(p: &mut Parser) { } } p.expect(T!['}']); - m.complete(p, RECORD_FIELD_LIST); + m.complete(p, RECORD_EXPR_FIELD_LIST); } diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs index 706a2f796b..0b01d3bc64 100644 --- a/crates/ra_parser/src/grammar/expressions/atom.rs +++ b/crates/ra_parser/src/grammar/expressions/atom.rs @@ -250,7 +250,7 @@ fn lambda_expr(p: &mut Parser) -> CompletedMarker { p.error("expected expression"); } } - m.complete(p, LAMBDA_EXPR) + m.complete(p, CLOSURE_EXPR) } // test if_expr diff --git a/crates/ra_parser/src/grammar/items.rs b/crates/ra_parser/src/grammar/items.rs index 97642bc244..cca524ceaa 100644 --- a/crates/ra_parser/src/grammar/items.rs +++ b/crates/ra_parser/src/grammar/items.rs @@ -180,7 +180,7 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul // unsafe const fn bar() {} T![fn] => { fn_def(p); - m.complete(p, FN_DEF); + m.complete(p, FN); } // test unsafe_trait @@ -193,7 +193,7 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul // unsafe auto trait T {} T![trait] => { traits::trait_def(p); - m.complete(p, TRAIT_DEF); + m.complete(p, TRAIT); } // test unsafe_impl @@ -221,7 +221,7 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul // unsafe default impl Foo {} T![impl] => { traits::impl_def(p); - m.complete(p, IMPL_DEF); + m.complete(p, IMPL); } // test existential_type @@ -304,10 +304,16 @@ fn extern_crate_item(p: &mut Parser, m: Marker) { p.bump(T![extern]); assert!(p.at(T![crate])); p.bump(T![crate]); - name_ref(p); + + if p.at(T![self]) { + p.bump(T![self]); + } else { + name_ref(p); + } + opt_alias(p); p.expect(T![;]); - m.complete(p, EXTERN_CRATE_ITEM); + m.complete(p, EXTERN_CRATE); } pub(crate) fn extern_item_list(p: &mut Parser) { @@ -374,7 +380,7 @@ fn type_def(p: &mut Parser, m: Marker) { types::type_(p); } p.expect(T![;]); - m.complete(p, TYPE_ALIAS_DEF); + m.complete(p, TYPE_ALIAS); } pub(crate) fn mod_item(p: &mut Parser, m: Marker) { diff --git a/crates/ra_parser/src/grammar/items/adt.rs b/crates/ra_parser/src/grammar/items/adt.rs index 74b9f514bd..addfb59d4b 100644 --- a/crates/ra_parser/src/grammar/items/adt.rs +++ b/crates/ra_parser/src/grammar/items/adt.rs @@ -5,13 +5,13 @@ use super::*; pub(super) fn struct_def(p: &mut Parser, m: Marker) { assert!(p.at(T![struct])); p.bump(T![struct]); - struct_or_union(p, m, T![struct], STRUCT_DEF); + struct_or_union(p, m, T![struct], STRUCT); } pub(super) fn union_def(p: &mut Parser, m: Marker) { assert!(p.at_contextual_kw("union")); p.bump_remap(T![union]); - struct_or_union(p, m, T![union], UNION_DEF); + struct_or_union(p, m, T![union], UNION); } fn struct_or_union(p: &mut Parser, m: Marker, kw: SyntaxKind, def: SyntaxKind) { @@ -64,7 +64,7 @@ pub(super) fn enum_def(p: &mut Parser, m: Marker) { } else { p.error("expected `{`") } - m.complete(p, ENUM_DEF); + m.complete(p, ENUM); } pub(crate) fn enum_variant_list(p: &mut Parser) { @@ -91,7 +91,7 @@ pub(crate) fn enum_variant_list(p: &mut Parser) { if p.eat(T![=]) { expressions::expr(p); } - var.complete(p, ENUM_VARIANT); + var.complete(p, VARIANT); } else { var.abandon(p); p.err_and_bump("expected enum variant"); @@ -101,7 +101,7 @@ pub(crate) fn enum_variant_list(p: &mut Parser) { } } p.expect(T!['}']); - m.complete(p, ENUM_VARIANT_LIST); + m.complete(p, VARIANT_LIST); } pub(crate) fn record_field_def_list(p: &mut Parser) { @@ -119,7 +119,7 @@ pub(crate) fn record_field_def_list(p: &mut Parser) { } } p.expect(T!['}']); - m.complete(p, RECORD_FIELD_DEF_LIST); + m.complete(p, RECORD_FIELD_LIST); fn record_field_def(p: &mut Parser) { let m = p.start(); @@ -134,7 +134,7 @@ pub(crate) fn record_field_def_list(p: &mut Parser) { name(p); p.expect(T![:]); types::type_(p); - m.complete(p, RECORD_FIELD_DEF); + m.complete(p, RECORD_FIELD); } else { m.abandon(p); p.err_and_bump("expected field declaration"); @@ -167,12 +167,12 @@ fn tuple_field_def_list(p: &mut Parser) { break; } types::type_(p); - m.complete(p, TUPLE_FIELD_DEF); + m.complete(p, TUPLE_FIELD); if !p.at(T![')']) { p.expect(T![,]); } } p.expect(T![')']); - m.complete(p, TUPLE_FIELD_DEF_LIST); + m.complete(p, TUPLE_FIELD_LIST); } diff --git a/crates/ra_parser/src/grammar/items/consts.rs b/crates/ra_parser/src/grammar/items/consts.rs index 742a7e0562..35ad766dce 100644 --- a/crates/ra_parser/src/grammar/items/consts.rs +++ b/crates/ra_parser/src/grammar/items/consts.rs @@ -3,11 +3,11 @@ use super::*; pub(super) fn static_def(p: &mut Parser, m: Marker) { - const_or_static(p, m, T![static], STATIC_DEF) + const_or_static(p, m, T![static], STATIC) } pub(super) fn const_def(p: &mut Parser, m: Marker) { - const_or_static(p, m, T![const], CONST_DEF) + const_or_static(p, m, T![const], CONST) } fn const_or_static(p: &mut Parser, m: Marker, kw: SyntaxKind, def: SyntaxKind) { diff --git a/crates/ra_parser/src/grammar/items/traits.rs b/crates/ra_parser/src/grammar/items/traits.rs index c819e33be9..ef9c8ff5b0 100644 --- a/crates/ra_parser/src/grammar/items/traits.rs +++ b/crates/ra_parser/src/grammar/items/traits.rs @@ -50,7 +50,7 @@ pub(crate) fn trait_item_list(p: &mut Parser) { item_or_macro(p, true, ItemFlavor::Trait); } p.expect(T!['}']); - m.complete(p, ITEM_LIST); + m.complete(p, ASSOC_ITEM_LIST); } // test impl_def @@ -107,7 +107,7 @@ pub(crate) fn impl_item_list(p: &mut Parser) { item_or_macro(p, true, ItemFlavor::Mod); } p.expect(T!['}']); - m.complete(p, ITEM_LIST); + m.complete(p, ASSOC_ITEM_LIST); } // test impl_type_params diff --git a/crates/ra_parser/src/grammar/items/use_item.rs b/crates/ra_parser/src/grammar/items/use_item.rs index 3a0c7a31a8..8e836a77e1 100644 --- a/crates/ra_parser/src/grammar/items/use_item.rs +++ b/crates/ra_parser/src/grammar/items/use_item.rs @@ -7,7 +7,7 @@ pub(super) fn use_item(p: &mut Parser, m: Marker) { p.bump(T![use]); use_tree(p, true); p.expect(T![;]); - m.complete(p, USE_ITEM); + m.complete(p, USE); } /// Parse a use 'tree', such as `some::path` in `use some::path;` diff --git a/crates/ra_parser/src/grammar/patterns.rs b/crates/ra_parser/src/grammar/patterns.rs index 427c0eb49c..716bdc9784 100644 --- a/crates/ra_parser/src/grammar/patterns.rs +++ b/crates/ra_parser/src/grammar/patterns.rs @@ -192,7 +192,7 @@ fn record_field_pat_list(p: &mut Parser) { p.bump(T!['{']); while !p.at(EOF) && !p.at(T!['}']) { match p.current() { - // A trailing `..` is *not* treated as a DOT_DOT_PAT. + // A trailing `..` is *not* treated as a REST_PAT. T![.] if p.at(T![..]) => p.bump(T![..]), T!['{'] => error_block(p, "expected ident"), @@ -217,7 +217,7 @@ fn record_field_pat_list(p: &mut Parser) { bind_pat(p, false); } } - m.complete(p, RECORD_FIELD_PAT); + m.complete(p, RECORD_PAT_FIELD); } } if !p.at(T!['}']) { @@ -225,7 +225,7 @@ fn record_field_pat_list(p: &mut Parser) { } } p.expect(T!['}']); - m.complete(p, RECORD_FIELD_PAT_LIST); + m.complete(p, RECORD_PAT_FIELD_LIST); } // test placeholder_pat @@ -234,7 +234,7 @@ fn placeholder_pat(p: &mut Parser) -> CompletedMarker { assert!(p.at(T![_])); let m = p.start(); p.bump(T![_]); - m.complete(p, PLACEHOLDER_PAT) + m.complete(p, WILDCARD_PAT) } // test dot_dot_pat @@ -267,7 +267,7 @@ fn dot_dot_pat(p: &mut Parser) -> CompletedMarker { assert!(p.at(T![..])); let m = p.start(); p.bump(T![..]); - m.complete(p, DOT_DOT_PAT) + m.complete(p, REST_PAT) } // test ref_pat @@ -361,7 +361,7 @@ fn bind_pat(p: &mut Parser, with_at: bool) -> CompletedMarker { if with_at && p.eat(T![@]) { pattern_single(p); } - m.complete(p, BIND_PAT) + m.complete(p, IDENT_PAT) } // test box_pat diff --git a/crates/ra_parser/src/grammar/type_args.rs b/crates/ra_parser/src/grammar/type_args.rs index 2d61f9d808..aef7cd6fbb 100644 --- a/crates/ra_parser/src/grammar/type_args.rs +++ b/crates/ra_parser/src/grammar/type_args.rs @@ -22,7 +22,7 @@ pub(super) fn opt_type_arg_list(p: &mut Parser, colon_colon_required: bool) { } } p.expect(T![>]); - m.complete(p, TYPE_ARG_LIST); + m.complete(p, GENERIC_ARG_LIST); } // test type_arg @@ -52,7 +52,7 @@ fn type_arg(p: &mut Parser) { m.complete(p, CONST_ARG); } k if k.is_literal() => { - p.bump(k); + expressions::literal(p); m.complete(p, CONST_ARG); } _ => { diff --git a/crates/ra_parser/src/grammar/type_params.rs b/crates/ra_parser/src/grammar/type_params.rs index d1330d4b95..90dabb4c0f 100644 --- a/crates/ra_parser/src/grammar/type_params.rs +++ b/crates/ra_parser/src/grammar/type_params.rs @@ -36,7 +36,7 @@ fn type_param_list(p: &mut Parser) { } } p.expect(T![>]); - m.complete(p, TYPE_PARAM_LIST); + m.complete(p, GENERIC_PARAM_LIST); } fn lifetime_param(p: &mut Parser, m: Marker) { diff --git a/crates/ra_parser/src/grammar/types.rs b/crates/ra_parser/src/grammar/types.rs index 9e8e3bd97f..0aa173a52b 100644 --- a/crates/ra_parser/src/grammar/types.rs +++ b/crates/ra_parser/src/grammar/types.rs @@ -117,7 +117,7 @@ fn pointer_type(p: &mut Parser) { }; type_no_bounds(p); - m.complete(p, POINTER_TYPE); + m.complete(p, PTR_TYPE); } fn array_or_slice_type(p: &mut Parser) { @@ -163,7 +163,7 @@ fn reference_type(p: &mut Parser) { p.eat(LIFETIME); p.eat(T![mut]); type_no_bounds(p); - m.complete(p, REFERENCE_TYPE); + m.complete(p, REF_TYPE); } // test placeholder_type @@ -172,7 +172,7 @@ fn placeholder_type(p: &mut Parser) { assert!(p.at(T![_])); let m = p.start(); p.bump(T![_]); - m.complete(p, PLACEHOLDER_TYPE); + m.complete(p, INFER_TYPE); } // test fn_pointer_type @@ -201,7 +201,7 @@ fn fn_pointer_type(p: &mut Parser) { // test fn_pointer_type_with_ret // type F = fn() -> (); opt_fn_ret_type(p); - m.complete(p, FN_POINTER_TYPE); + m.complete(p, FN_PTR_TYPE); } pub(super) fn for_binder(p: &mut Parser) { diff --git a/crates/ra_parser/src/syntax_kind/generated.rs b/crates/ra_parser/src/syntax_kind/generated.rs index e7404492a8..192ecd864e 100644 --- a/crates/ra_parser/src/syntax_kind/generated.rs +++ b/crates/ra_parser/src/syntax_kind/generated.rs @@ -1,7 +1,7 @@ //! Generated file, do not edit by hand, see `xtask/src/codegen` #![allow(bad_style, missing_docs, unreachable_pub)] -#[doc = r" The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT_DEF`."] +#[doc = r" The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT`."] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[repr(u16)] pub enum SyntaxKind { @@ -123,19 +123,19 @@ pub enum SyntaxKind { L_DOLLAR, R_DOLLAR, SOURCE_FILE, - STRUCT_DEF, - UNION_DEF, - ENUM_DEF, - FN_DEF, + STRUCT, + UNION, + ENUM, + FN, RET_TYPE, - EXTERN_CRATE_ITEM, + EXTERN_CRATE, MODULE, - USE_ITEM, - STATIC_DEF, - CONST_DEF, - TRAIT_DEF, - IMPL_DEF, - TYPE_ALIAS_DEF, + USE, + STATIC, + CONST, + TRAIT, + IMPL, + TYPE_ALIAS, MACRO_CALL, TOKEN_TREE, MACRO_DEF, @@ -143,12 +143,12 @@ pub enum SyntaxKind { TUPLE_TYPE, NEVER_TYPE, PATH_TYPE, - POINTER_TYPE, + PTR_TYPE, ARRAY_TYPE, SLICE_TYPE, - REFERENCE_TYPE, - PLACEHOLDER_TYPE, - FN_POINTER_TYPE, + REF_TYPE, + INFER_TYPE, + FN_PTR_TYPE, FOR_TYPE, IMPL_TRAIT_TYPE, DYN_TRAIT_TYPE, @@ -156,13 +156,13 @@ pub enum SyntaxKind { PAREN_PAT, REF_PAT, BOX_PAT, - BIND_PAT, - PLACEHOLDER_PAT, - DOT_DOT_PAT, + IDENT_PAT, + WILDCARD_PAT, + REST_PAT, PATH_PAT, RECORD_PAT, - RECORD_FIELD_PAT_LIST, - RECORD_FIELD_PAT, + RECORD_PAT_FIELD_LIST, + RECORD_PAT_FIELD, TUPLE_STRUCT_PAT, TUPLE_PAT, SLICE_PAT, @@ -173,7 +173,7 @@ pub enum SyntaxKind { ARRAY_EXPR, PAREN_EXPR, PATH_EXPR, - LAMBDA_EXPR, + CLOSURE_EXPR, IF_EXPR, WHILE_EXPR, CONDITION, @@ -188,9 +188,9 @@ pub enum SyntaxKind { MATCH_ARM_LIST, MATCH_ARM, MATCH_GUARD, - RECORD_LIT, - RECORD_FIELD_LIST, - RECORD_FIELD, + RECORD_EXPR, + RECORD_EXPR_FIELD_LIST, + RECORD_EXPR_FIELD, EFFECT_EXPR, BOX_EXPR, CALL_EXPR, @@ -206,13 +206,14 @@ pub enum SyntaxKind { BIN_EXPR, EXTERN_BLOCK, EXTERN_ITEM_LIST, - ENUM_VARIANT, - RECORD_FIELD_DEF_LIST, - RECORD_FIELD_DEF, - TUPLE_FIELD_DEF_LIST, - TUPLE_FIELD_DEF, - ENUM_VARIANT_LIST, + VARIANT, + RECORD_FIELD_LIST, + RECORD_FIELD, + TUPLE_FIELD_LIST, + TUPLE_FIELD, + VARIANT_LIST, ITEM_LIST, + ASSOC_ITEM_LIST, ATTR, META_ITEM, USE_TREE, @@ -220,7 +221,7 @@ pub enum SyntaxKind { PATH, PATH_SEGMENT, LITERAL, - ALIAS, + RENAME, VISIBILITY, WHERE_CLAUSE, WHERE_PRED, @@ -229,11 +230,12 @@ pub enum SyntaxKind { NAME_REF, LET_STMT, EXPR_STMT, - TYPE_PARAM_LIST, + GENERIC_PARAM_LIST, + GENERIC_PARAM, LIFETIME_PARAM, TYPE_PARAM, CONST_PARAM, - TYPE_ARG_LIST, + GENERIC_ARG_LIST, LIFETIME_ARG, TYPE_ARG, ASSOC_TYPE_ARG, @@ -362,4 +364,4 @@ impl SyntaxKind { } } #[macro_export] -macro_rules ! T { [ ; ] => { $ crate :: SyntaxKind :: SEMICOLON } ; [ , ] => { $ crate :: SyntaxKind :: COMMA } ; [ '(' ] => { $ crate :: SyntaxKind :: L_PAREN } ; [ ')' ] => { $ crate :: SyntaxKind :: R_PAREN } ; [ '{' ] => { $ crate :: SyntaxKind :: L_CURLY } ; [ '}' ] => { $ crate :: SyntaxKind :: R_CURLY } ; [ '[' ] => { $ crate :: SyntaxKind :: L_BRACK } ; [ ']' ] => { $ crate :: SyntaxKind :: R_BRACK } ; [ < ] => { $ crate :: SyntaxKind :: L_ANGLE } ; [ > ] => { $ crate :: SyntaxKind :: R_ANGLE } ; [ @ ] => { $ crate :: SyntaxKind :: AT } ; [ # ] => { $ crate :: SyntaxKind :: POUND } ; [ ~ ] => { $ crate :: SyntaxKind :: TILDE } ; [ ? ] => { $ crate :: SyntaxKind :: QUESTION } ; [ $ ] => { $ crate :: SyntaxKind :: DOLLAR } ; [ & ] => { $ crate :: SyntaxKind :: AMP } ; [ | ] => { $ crate :: SyntaxKind :: PIPE } ; [ + ] => { $ crate :: SyntaxKind :: PLUS } ; [ * ] => { $ crate :: SyntaxKind :: STAR } ; [ / ] => { $ crate :: SyntaxKind :: SLASH } ; [ ^ ] => { $ crate :: SyntaxKind :: CARET } ; [ % ] => { $ crate :: SyntaxKind :: PERCENT } ; [ _ ] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [ . ] => { $ crate :: SyntaxKind :: DOT } ; [ .. ] => { $ crate :: SyntaxKind :: DOT2 } ; [ ... ] => { $ crate :: SyntaxKind :: DOT3 } ; [ ..= ] => { $ crate :: SyntaxKind :: DOT2EQ } ; [ : ] => { $ crate :: SyntaxKind :: COLON } ; [ :: ] => { $ crate :: SyntaxKind :: COLON2 } ; [ = ] => { $ crate :: SyntaxKind :: EQ } ; [ == ] => { $ crate :: SyntaxKind :: EQ2 } ; [ => ] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [ ! ] => { $ crate :: SyntaxKind :: BANG } ; [ != ] => { $ crate :: SyntaxKind :: NEQ } ; [ - ] => { $ crate :: SyntaxKind :: MINUS } ; [ -> ] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [ <= ] => { $ crate :: SyntaxKind :: LTEQ } ; [ >= ] => { $ crate :: SyntaxKind :: GTEQ } ; [ += ] => { $ crate :: SyntaxKind :: PLUSEQ } ; [ -= ] => { $ crate :: SyntaxKind :: MINUSEQ } ; [ |= ] => { $ crate :: SyntaxKind :: PIPEEQ } ; [ &= ] => { $ crate :: SyntaxKind :: AMPEQ } ; [ ^= ] => { $ crate :: SyntaxKind :: CARETEQ } ; [ /= ] => { $ crate :: SyntaxKind :: SLASHEQ } ; [ *= ] => { $ crate :: SyntaxKind :: STAREQ } ; [ %= ] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [ && ] => { $ crate :: SyntaxKind :: AMP2 } ; [ || ] => { $ crate :: SyntaxKind :: PIPE2 } ; [ << ] => { $ crate :: SyntaxKind :: SHL } ; [ >> ] => { $ crate :: SyntaxKind :: SHR } ; [ <<= ] => { $ crate :: SyntaxKind :: SHLEQ } ; [ >>= ] => { $ crate :: SyntaxKind :: SHREQ } ; [ as ] => { $ crate :: SyntaxKind :: AS_KW } ; [ async ] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [ await ] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [ box ] => { $ crate :: SyntaxKind :: BOX_KW } ; [ break ] => { $ crate :: SyntaxKind :: BREAK_KW } ; [ const ] => { $ crate :: SyntaxKind :: CONST_KW } ; [ continue ] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [ crate ] => { $ crate :: SyntaxKind :: CRATE_KW } ; [ dyn ] => { $ crate :: SyntaxKind :: DYN_KW } ; [ else ] => { $ crate :: SyntaxKind :: ELSE_KW } ; [ enum ] => { $ crate :: SyntaxKind :: ENUM_KW } ; [ extern ] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [ false ] => { $ crate :: SyntaxKind :: FALSE_KW } ; [ fn ] => { $ crate :: SyntaxKind :: FN_KW } ; [ for ] => { $ crate :: SyntaxKind :: FOR_KW } ; [ if ] => { $ crate :: SyntaxKind :: IF_KW } ; [ impl ] => { $ crate :: SyntaxKind :: IMPL_KW } ; [ in ] => { $ crate :: SyntaxKind :: IN_KW } ; [ let ] => { $ crate :: SyntaxKind :: LET_KW } ; [ loop ] => { $ crate :: SyntaxKind :: LOOP_KW } ; [ macro ] => { $ crate :: SyntaxKind :: MACRO_KW } ; [ match ] => { $ crate :: SyntaxKind :: MATCH_KW } ; [ mod ] => { $ crate :: SyntaxKind :: MOD_KW } ; [ move ] => { $ crate :: SyntaxKind :: MOVE_KW } ; [ mut ] => { $ crate :: SyntaxKind :: MUT_KW } ; [ pub ] => { $ crate :: SyntaxKind :: PUB_KW } ; [ ref ] => { $ crate :: SyntaxKind :: REF_KW } ; [ return ] => { $ crate :: SyntaxKind :: RETURN_KW } ; [ self ] => { $ crate :: SyntaxKind :: SELF_KW } ; [ static ] => { $ crate :: SyntaxKind :: STATIC_KW } ; [ struct ] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [ super ] => { $ crate :: SyntaxKind :: SUPER_KW } ; [ trait ] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [ true ] => { $ crate :: SyntaxKind :: TRUE_KW } ; [ try ] => { $ crate :: SyntaxKind :: TRY_KW } ; [ type ] => { $ crate :: SyntaxKind :: TYPE_KW } ; [ unsafe ] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [ use ] => { $ crate :: SyntaxKind :: USE_KW } ; [ where ] => { $ crate :: SyntaxKind :: WHERE_KW } ; [ while ] => { $ crate :: SyntaxKind :: WHILE_KW } ; [ auto ] => { $ crate :: SyntaxKind :: AUTO_KW } ; [ default ] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [ existential ] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [ union ] => { $ crate :: SyntaxKind :: UNION_KW } ; [ raw ] => { $ crate :: SyntaxKind :: RAW_KW } ; [ lifetime ] => { $ crate :: SyntaxKind :: LIFETIME } ; [ ident ] => { $ crate :: SyntaxKind :: IDENT } ; } +macro_rules ! T { [ ; ] => { $ crate :: SyntaxKind :: SEMICOLON } ; [ , ] => { $ crate :: SyntaxKind :: COMMA } ; [ '(' ] => { $ crate :: SyntaxKind :: L_PAREN } ; [ ')' ] => { $ crate :: SyntaxKind :: R_PAREN } ; [ '{' ] => { $ crate :: SyntaxKind :: L_CURLY } ; [ '}' ] => { $ crate :: SyntaxKind :: R_CURLY } ; [ '[' ] => { $ crate :: SyntaxKind :: L_BRACK } ; [ ']' ] => { $ crate :: SyntaxKind :: R_BRACK } ; [ < ] => { $ crate :: SyntaxKind :: L_ANGLE } ; [ > ] => { $ crate :: SyntaxKind :: R_ANGLE } ; [ @ ] => { $ crate :: SyntaxKind :: AT } ; [ # ] => { $ crate :: SyntaxKind :: POUND } ; [ ~ ] => { $ crate :: SyntaxKind :: TILDE } ; [ ? ] => { $ crate :: SyntaxKind :: QUESTION } ; [ $ ] => { $ crate :: SyntaxKind :: DOLLAR } ; [ & ] => { $ crate :: SyntaxKind :: AMP } ; [ | ] => { $ crate :: SyntaxKind :: PIPE } ; [ + ] => { $ crate :: SyntaxKind :: PLUS } ; [ * ] => { $ crate :: SyntaxKind :: STAR } ; [ / ] => { $ crate :: SyntaxKind :: SLASH } ; [ ^ ] => { $ crate :: SyntaxKind :: CARET } ; [ % ] => { $ crate :: SyntaxKind :: PERCENT } ; [ _ ] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [ . ] => { $ crate :: SyntaxKind :: DOT } ; [ .. ] => { $ crate :: SyntaxKind :: DOT2 } ; [ ... ] => { $ crate :: SyntaxKind :: DOT3 } ; [ ..= ] => { $ crate :: SyntaxKind :: DOT2EQ } ; [ : ] => { $ crate :: SyntaxKind :: COLON } ; [ :: ] => { $ crate :: SyntaxKind :: COLON2 } ; [ = ] => { $ crate :: SyntaxKind :: EQ } ; [ == ] => { $ crate :: SyntaxKind :: EQ2 } ; [ => ] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [ ! ] => { $ crate :: SyntaxKind :: BANG } ; [ != ] => { $ crate :: SyntaxKind :: NEQ } ; [ - ] => { $ crate :: SyntaxKind :: MINUS } ; [ -> ] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [ <= ] => { $ crate :: SyntaxKind :: LTEQ } ; [ >= ] => { $ crate :: SyntaxKind :: GTEQ } ; [ += ] => { $ crate :: SyntaxKind :: PLUSEQ } ; [ -= ] => { $ crate :: SyntaxKind :: MINUSEQ } ; [ |= ] => { $ crate :: SyntaxKind :: PIPEEQ } ; [ &= ] => { $ crate :: SyntaxKind :: AMPEQ } ; [ ^= ] => { $ crate :: SyntaxKind :: CARETEQ } ; [ /= ] => { $ crate :: SyntaxKind :: SLASHEQ } ; [ *= ] => { $ crate :: SyntaxKind :: STAREQ } ; [ %= ] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [ && ] => { $ crate :: SyntaxKind :: AMP2 } ; [ || ] => { $ crate :: SyntaxKind :: PIPE2 } ; [ << ] => { $ crate :: SyntaxKind :: SHL } ; [ >> ] => { $ crate :: SyntaxKind :: SHR } ; [ <<= ] => { $ crate :: SyntaxKind :: SHLEQ } ; [ >>= ] => { $ crate :: SyntaxKind :: SHREQ } ; [ as ] => { $ crate :: SyntaxKind :: AS_KW } ; [ async ] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [ await ] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [ box ] => { $ crate :: SyntaxKind :: BOX_KW } ; [ break ] => { $ crate :: SyntaxKind :: BREAK_KW } ; [ const ] => { $ crate :: SyntaxKind :: CONST_KW } ; [ continue ] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [ crate ] => { $ crate :: SyntaxKind :: CRATE_KW } ; [ dyn ] => { $ crate :: SyntaxKind :: DYN_KW } ; [ else ] => { $ crate :: SyntaxKind :: ELSE_KW } ; [ enum ] => { $ crate :: SyntaxKind :: ENUM_KW } ; [ extern ] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [ false ] => { $ crate :: SyntaxKind :: FALSE_KW } ; [ fn ] => { $ crate :: SyntaxKind :: FN_KW } ; [ for ] => { $ crate :: SyntaxKind :: FOR_KW } ; [ if ] => { $ crate :: SyntaxKind :: IF_KW } ; [ impl ] => { $ crate :: SyntaxKind :: IMPL_KW } ; [ in ] => { $ crate :: SyntaxKind :: IN_KW } ; [ let ] => { $ crate :: SyntaxKind :: LET_KW } ; [ loop ] => { $ crate :: SyntaxKind :: LOOP_KW } ; [ macro ] => { $ crate :: SyntaxKind :: MACRO_KW } ; [ match ] => { $ crate :: SyntaxKind :: MATCH_KW } ; [ mod ] => { $ crate :: SyntaxKind :: MOD_KW } ; [ move ] => { $ crate :: SyntaxKind :: MOVE_KW } ; [ mut ] => { $ crate :: SyntaxKind :: MUT_KW } ; [ pub ] => { $ crate :: SyntaxKind :: PUB_KW } ; [ ref ] => { $ crate :: SyntaxKind :: REF_KW } ; [ return ] => { $ crate :: SyntaxKind :: RETURN_KW } ; [ self ] => { $ crate :: SyntaxKind :: SELF_KW } ; [ static ] => { $ crate :: SyntaxKind :: STATIC_KW } ; [ struct ] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [ super ] => { $ crate :: SyntaxKind :: SUPER_KW } ; [ trait ] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [ true ] => { $ crate :: SyntaxKind :: TRUE_KW } ; [ try ] => { $ crate :: SyntaxKind :: TRY_KW } ; [ type ] => { $ crate :: SyntaxKind :: TYPE_KW } ; [ unsafe ] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [ use ] => { $ crate :: SyntaxKind :: USE_KW } ; [ where ] => { $ crate :: SyntaxKind :: WHERE_KW } ; [ while ] => { $ crate :: SyntaxKind :: WHILE_KW } ; [ auto ] => { $ crate :: SyntaxKind :: AUTO_KW } ; [ default ] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [ existential ] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [ union ] => { $ crate :: SyntaxKind :: UNION_KW } ; [ raw ] => { $ crate :: SyntaxKind :: RAW_KW } ; [ lifetime ] => { $ crate :: SyntaxKind :: LIFETIME } ; [ ident ] => { $ crate :: SyntaxKind :: IDENT } ; [ shebang ] => { $ crate :: SyntaxKind :: SHEBANG } ; } diff --git a/crates/ra_proc_macro_srv/Cargo.toml b/crates/ra_proc_macro_srv/Cargo.toml index 12ce497f87..bc119a6c71 100644 --- a/crates/ra_proc_macro_srv/Cargo.toml +++ b/crates/ra_proc_macro_srv/Cargo.toml @@ -19,7 +19,7 @@ memmap = "0.7" test_utils = { path = "../test_utils" } [dev-dependencies] -cargo_metadata = "0.10.0" +cargo_metadata = "0.11.1" difference = "2.0.0" # used as proc macro test target serde_derive = "1.0.106" diff --git a/crates/ra_prof/Cargo.toml b/crates/ra_prof/Cargo.toml index 6c214501e4..c82b9f76d4 100644 --- a/crates/ra_prof/Cargo.toml +++ b/crates/ra_prof/Cargo.toml @@ -16,6 +16,9 @@ backtrace = { version = "0.3.44", optional = true } cfg-if = "0.1.10" libc = "0.2.73" +[target.'cfg(target_os = "linux")'.dependencies] +perf-event = "0.4" + [features] cpu_profiler = [] diff --git a/crates/ra_prof/src/lib.rs b/crates/ra_prof/src/lib.rs index ba5609703a..eb50965ae6 100644 --- a/crates/ra_prof/src/lib.rs +++ b/crates/ra_prof/src/lib.rs @@ -1,5 +1,6 @@ //! A collection of tools for profiling rust-analyzer. +mod stop_watch; mod memory_usage; #[cfg(feature = "cpu_profiler")] mod google_cpu_profiler; @@ -11,6 +12,7 @@ use std::cell::RefCell; pub use crate::{ hprof::{init, init_from, profile}, memory_usage::{Bytes, MemoryUsage}, + stop_watch::{StopWatch, StopWatchSpan}, }; /// Prints backtrace to stderr, useful for debugging. diff --git a/crates/ra_prof/src/memory_usage.rs b/crates/ra_prof/src/memory_usage.rs index 745345fac0..c2ecbd33cf 100644 --- a/crates/ra_prof/src/memory_usage.rs +++ b/crates/ra_prof/src/memory_usage.rs @@ -3,9 +3,22 @@ use std::fmt; use cfg_if::cfg_if; +#[derive(Copy, Clone)] pub struct MemoryUsage { pub allocated: Bytes, - pub resident: Bytes, +} + +impl fmt::Display for MemoryUsage { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{}", self.allocated) + } +} + +impl std::ops::Sub for MemoryUsage { + type Output = MemoryUsage; + fn sub(self, rhs: MemoryUsage) -> MemoryUsage { + MemoryUsage { allocated: self.allocated - rhs.allocated } + } } impl MemoryUsage { @@ -13,26 +26,20 @@ impl MemoryUsage { cfg_if! { if #[cfg(target_os = "linux")] { // Note: This is incredibly slow. - let alloc = unsafe { libc::mallinfo() }.uordblks as u32 as usize; - MemoryUsage { allocated: Bytes(alloc), resident: Bytes(0) } + let alloc = unsafe { libc::mallinfo() }.uordblks as isize; + MemoryUsage { allocated: Bytes(alloc) } } else { - MemoryUsage { allocated: Bytes(0), resident: Bytes(0) } + MemoryUsage { allocated: Bytes(0) } } } } } -impl fmt::Display for MemoryUsage { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{} allocated {} resident", self.allocated, self.resident,) - } -} - #[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] -pub struct Bytes(usize); +pub struct Bytes(isize); impl Bytes { - pub fn megabytes(self) -> usize { + pub fn megabytes(self) -> isize { self.0 / 1024 / 1024 } } @@ -42,10 +49,10 @@ impl fmt::Display for Bytes { let bytes = self.0; let mut value = bytes; let mut suffix = "b"; - if value > 4096 { + if value.abs() > 4096 { value /= 1024; suffix = "kb"; - if value > 4096 { + if value.abs() > 4096 { value /= 1024; suffix = "mb"; } @@ -56,7 +63,7 @@ impl fmt::Display for Bytes { impl std::ops::AddAssign for Bytes { fn add_assign(&mut self, x: usize) { - self.0 += x; + self.0 += x as isize; } } diff --git a/crates/ra_prof/src/stop_watch.rs b/crates/ra_prof/src/stop_watch.rs new file mode 100644 index 0000000000..5e276190e5 --- /dev/null +++ b/crates/ra_prof/src/stop_watch.rs @@ -0,0 +1,86 @@ +//! Like `std::time::Instant`, but also measures memory & CPU cycles. +use std::{ + fmt, + time::{Duration, Instant}, +}; + +use crate::MemoryUsage; + +pub struct StopWatch { + time: Instant, + #[cfg(target_os = "linux")] + counter: Option, + memory: Option, +} + +pub struct StopWatchSpan { + pub time: Duration, + pub instructions: Option, + pub memory: Option, +} + +impl StopWatch { + pub fn start() -> StopWatch { + #[cfg(target_os = "linux")] + let counter = { + let mut counter = perf_event::Builder::new() + .build() + .map_err(|err| eprintln!("Failed to create perf counter: {}", err)) + .ok(); + if let Some(counter) = &mut counter { + if let Err(err) = counter.enable() { + eprintln!("Failed to start perf counter: {}", err) + } + } + counter + }; + let time = Instant::now(); + StopWatch { + time, + #[cfg(target_os = "linux")] + counter, + memory: None, + } + } + pub fn memory(mut self, yes: bool) -> StopWatch { + if yes { + self.memory = Some(MemoryUsage::current()); + } + self + } + pub fn elapsed(&mut self) -> StopWatchSpan { + let time = self.time.elapsed(); + + #[cfg(target_os = "linux")] + let instructions = self.counter.as_mut().and_then(|it| { + it.read().map_err(|err| eprintln!("Failed to read perf counter: {}", err)).ok() + }); + #[cfg(not(target_os = "linux"))] + let instructions = None; + + let memory = self.memory.map(|it| MemoryUsage::current() - it); + StopWatchSpan { time, instructions, memory } + } +} + +impl fmt::Display for StopWatchSpan { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:.2?}", self.time)?; + if let Some(mut instructions) = self.instructions { + let mut prefix = ""; + if instructions > 10000 { + instructions /= 1000; + prefix = "k" + } + if instructions > 10000 { + instructions /= 1000; + prefix = "m" + } + write!(f, ", {}{}i", instructions, prefix)?; + } + if let Some(memory) = self.memory { + write!(f, ", {}", memory)?; + } + Ok(()) + } +} diff --git a/crates/ra_project_model/Cargo.toml b/crates/ra_project_model/Cargo.toml index 827eb7e28e..99adea8e44 100644 --- a/crates/ra_project_model/Cargo.toml +++ b/crates/ra_project_model/Cargo.toml @@ -12,7 +12,7 @@ doctest = false log = "0.4.8" rustc-hash = "1.1.0" -cargo_metadata = "0.10.0" +cargo_metadata = "0.11.1" ra_arena = { path = "../ra_arena" } ra_cfg = { path = "../ra_cfg" } diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index fb88e0f066..10513542e2 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs @@ -144,12 +144,15 @@ impl CargoWorkspace { meta.manifest_path(cargo_toml.to_path_buf()); if cargo_features.all_features { meta.features(CargoOpt::AllFeatures); - } else if cargo_features.no_default_features { - // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` - // https://github.com/oli-obk/cargo_metadata/issues/79 - meta.features(CargoOpt::NoDefaultFeatures); - } else if !cargo_features.features.is_empty() { - meta.features(CargoOpt::SomeFeatures(cargo_features.features.clone())); + } else { + if cargo_features.no_default_features { + // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` + // https://github.com/oli-obk/cargo_metadata/issues/79 + meta.features(CargoOpt::NoDefaultFeatures); + } + if !cargo_features.features.is_empty() { + meta.features(CargoOpt::SomeFeatures(cargo_features.features.clone())); + } } if let Some(parent) = cargo_toml.parent() { meta.current_dir(parent.to_path_buf()); @@ -289,12 +292,16 @@ pub fn load_extern_resources( cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml); if cargo_features.all_features { cmd.arg("--all-features"); - } else if cargo_features.no_default_features { - // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` - // https://github.com/oli-obk/cargo_metadata/issues/79 - cmd.arg("--no-default-features"); } else { - cmd.args(&cargo_features.features); + if cargo_features.no_default_features { + // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` + // https://github.com/oli-obk/cargo_metadata/issues/79 + cmd.arg("--no-default-features"); + } + if !cargo_features.features.is_empty() { + cmd.arg("--features"); + cmd.arg(cargo_features.features.join(" ")); + } } let output = cmd.output()?; diff --git a/crates/ra_project_model/src/cfg_flag.rs b/crates/ra_project_model/src/cfg_flag.rs index 1bc5d4832d..bd50056c68 100644 --- a/crates/ra_project_model/src/cfg_flag.rs +++ b/crates/ra_project_model/src/cfg_flag.rs @@ -4,7 +4,7 @@ use std::str::FromStr; use ra_cfg::CfgOptions; -use stdx::split_delim; +use stdx::split_once; #[derive(Clone, Eq, PartialEq, Debug)] pub enum CfgFlag { @@ -15,7 +15,7 @@ pub enum CfgFlag { impl FromStr for CfgFlag { type Err = String; fn from_str(s: &str) -> Result { - let res = match split_delim(s, '=') { + let res = match split_once(s, '=') { Some((key, value)) => { if !(value.starts_with('"') && value.ends_with('"')) { return Err(format!("Invalid cfg ({:?}), value should be in quotes", s)); diff --git a/crates/ra_project_model/src/sysroot.rs b/crates/ra_project_model/src/sysroot.rs index 8a92acea54..a10ade3757 100644 --- a/crates/ra_project_model/src/sysroot.rs +++ b/crates/ra_project_model/src/sysroot.rs @@ -54,6 +54,8 @@ impl Sysroot { let src = get_or_install_rust_src(cargo_toml)?; let mut sysroot = Sysroot { crates: Arena::default() }; for name in SYSROOT_CRATES.trim().lines() { + // FIXME: remove this path when 1.47 comes out + // https://github.com/rust-lang/rust/pull/73265 let root = src.join(format!("lib{}", name)).join("lib.rs"); if root.exists() { sysroot.crates.alloc(SysrootCrateData { @@ -61,6 +63,15 @@ impl Sysroot { root, deps: Vec::new(), }); + } else { + let root = src.join(name).join("src/lib.rs"); + if root.exists() { + sysroot.crates.alloc(SysrootCrateData { + name: name.into(), + root, + deps: Vec::new(), + }); + } } } if let Some(std) = sysroot.std() { @@ -94,23 +105,38 @@ fn get_or_install_rust_src(cargo_toml: &AbsPath) -> Result { rustc.current_dir(current_dir).args(&["--print", "sysroot"]); let stdout = utf8_stdout(rustc)?; let sysroot_path = AbsPath::assert(Path::new(stdout.trim())); - let src_path = sysroot_path.join("lib/rustlib/src/rust/src"); - - if !src_path.exists() { + let mut src = get_rust_src(sysroot_path); + if src.is_none() { let mut rustup = Command::new(ra_toolchain::rustup()); rustup.current_dir(current_dir).args(&["component", "add", "rust-src"]); utf8_stdout(rustup)?; + src = get_rust_src(sysroot_path); } - if !src_path.exists() { - bail!( + match src { + Some(r) => Ok(r), + None => bail!( "can't load standard library from sysroot\n\ {}\n\ (discovered via `rustc --print sysroot`)\n\ try running `rustup component add rust-src` or set `RUST_SRC_PATH`", - src_path.display(), - ) + sysroot_path.display(), + ), + } +} + +fn get_rust_src(sysroot_path: &AbsPath) -> Option { + // try the new path first since the old one still exists + let mut src_path = sysroot_path.join("lib/rustlib/src/rust/library"); + if !src_path.exists() { + // FIXME: remove this path when 1.47 comes out + // https://github.com/rust-lang/rust/pull/73265 + src_path = sysroot_path.join("lib/rustlib/src/rust/src"); + } + if src_path.exists() { + Some(src_path) + } else { + None } - Ok(src_path) } impl SysrootCrateData { @@ -120,42 +146,28 @@ impl SysrootCrateData { } const SYSROOT_CRATES: &str = " -std -core alloc -collections -libc -proc_macro -rustc_unicode -std_unicode -test -alloc_jemalloc -alloc_system -compiler_builtins -getopts -panic_unwind +core panic_abort -rand +panic_unwind +proc_macro +profiler_builtins +rtstartup +std +stdarch term -unwind -build_helper -rustc_asan -rustc_lsan -rustc_msan -rustc_tsan -syntax"; +test +unwind"; const STD_DEPS: &str = " alloc -alloc_jemalloc -alloc_system core panic_abort -rand -compiler_builtins -unwind -rustc_asan -rustc_lsan -rustc_msan -rustc_tsan -build_helper"; +panic_unwind +profiler_builtins +rtstartup +proc_macro +stdarch +term +test +unwind"; diff --git a/crates/ra_ssr/src/lib.rs b/crates/ra_ssr/src/lib.rs index 7014a6ac66..c780b460a7 100644 --- a/crates/ra_ssr/src/lib.rs +++ b/crates/ra_ssr/src/lib.rs @@ -52,6 +52,7 @@ pub struct MatchFinder<'db> { sema: Semantics<'db, ra_ide_db::RootDatabase>, rules: Vec, resolution_scope: resolving::ResolutionScope<'db>, + restrict_ranges: Vec, } impl<'db> MatchFinder<'db> { @@ -60,10 +61,12 @@ impl<'db> MatchFinder<'db> { pub fn in_context( db: &'db ra_ide_db::RootDatabase, lookup_context: FilePosition, + mut restrict_ranges: Vec, ) -> MatchFinder<'db> { + restrict_ranges.retain(|range| !range.range.is_empty()); let sema = Semantics::new(db); let resolution_scope = resolving::ResolutionScope::new(&sema, lookup_context); - MatchFinder { sema: Semantics::new(db), rules: Vec::new(), resolution_scope } + MatchFinder { sema, rules: Vec::new(), resolution_scope, restrict_ranges } } /// Constructs an instance using the start of the first file in `db` as the lookup context. @@ -79,6 +82,7 @@ impl<'db> MatchFinder<'db> { Ok(MatchFinder::in_context( db, FilePosition { file_id: first_file_id, offset: 0.into() }, + vec![], )) } else { bail!("No files to search"); diff --git a/crates/ra_ssr/src/matching.rs b/crates/ra_ssr/src/matching.rs index 4862622bde..0f72fea691 100644 --- a/crates/ra_ssr/src/matching.rs +++ b/crates/ra_ssr/src/matching.rs @@ -209,7 +209,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> { // Some kinds of nodes have special handling. For everything else, we fall back to default // matching. match code.kind() { - SyntaxKind::RECORD_FIELD_LIST => { + SyntaxKind::RECORD_EXPR_FIELD_LIST => { self.attempt_match_record_field_list(phase, pattern, code) } SyntaxKind::TOKEN_TREE => self.attempt_match_token_tree(phase, pattern, code), @@ -348,8 +348,8 @@ impl<'db, 'sema> Matcher<'db, 'sema> { // separately via comparing what the path resolves to below. self.attempt_match_opt( phase, - pattern_segment.type_arg_list(), - code_segment.type_arg_list(), + pattern_segment.generic_arg_list(), + code_segment.generic_arg_list(), )?; self.attempt_match_opt( phase, @@ -399,7 +399,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> { // Build a map keyed by field name. let mut fields_by_name = FxHashMap::default(); for child in code.children() { - if let Some(record) = ast::RecordField::cast(child.clone()) { + if let Some(record) = ast::RecordExprField::cast(child.clone()) { if let Some(name) = record.field_name() { fields_by_name.insert(name.text().clone(), child.clone()); } @@ -706,8 +706,8 @@ mod tests { let rule: SsrRule = "foo($x) ==>> bar($x)".parse().unwrap(); let input = "fn foo() {} fn bar() {} fn main() { foo(1+2); }"; - let (db, position) = crate::tests::single_file(input); - let mut match_finder = MatchFinder::in_context(&db, position); + let (db, position, selections) = crate::tests::single_file(input); + let mut match_finder = MatchFinder::in_context(&db, position, selections); match_finder.add_rule(rule).unwrap(); let matches = match_finder.matches(); assert_eq!(matches.matches.len(), 1); diff --git a/crates/ra_ssr/src/parsing.rs b/crates/ra_ssr/src/parsing.rs index 2d6f4e514f..f455eb5b7e 100644 --- a/crates/ra_ssr/src/parsing.rs +++ b/crates/ra_ssr/src/parsing.rs @@ -10,6 +10,7 @@ use crate::{SsrError, SsrPattern, SsrRule}; use ra_syntax::{ast, AstNode, SmolStr, SyntaxKind, SyntaxNode, T}; use rustc_hash::{FxHashMap, FxHashSet}; use std::str::FromStr; +use test_utils::mark; #[derive(Debug)] pub(crate) struct ParsedRule { @@ -69,11 +70,8 @@ impl ParsedRule { rules: Vec::new(), }; builder.try_add(ast::Expr::parse(&raw_pattern), raw_template.map(ast::Expr::parse)); - builder.try_add(ast::TypeRef::parse(&raw_pattern), raw_template.map(ast::TypeRef::parse)); - builder.try_add( - ast::ModuleItem::parse(&raw_pattern), - raw_template.map(ast::ModuleItem::parse), - ); + builder.try_add(ast::Type::parse(&raw_pattern), raw_template.map(ast::Type::parse)); + builder.try_add(ast::Item::parse(&raw_pattern), raw_template.map(ast::Item::parse)); builder.try_add(ast::Path::parse(&raw_pattern), raw_template.map(ast::Path::parse)); builder.try_add(ast::Pat::parse(&raw_pattern), raw_template.map(ast::Pat::parse)); builder.build() @@ -102,14 +100,35 @@ impl RuleBuilder { } } - fn build(self) -> Result, SsrError> { + fn build(mut self) -> Result, SsrError> { if self.rules.is_empty() { bail!("Not a valid Rust expression, type, item, path or pattern"); } + // If any rules contain paths, then we reject any rules that don't contain paths. Allowing a + // mix leads to strange semantics, since the path-based rules only match things where the + // path refers to semantically the same thing, whereas the non-path-based rules could match + // anything. Specifically, if we have a rule like `foo ==>> bar` we only want to match the + // `foo` that is in the current scope, not any `foo`. However "foo" can be parsed as a + // pattern (IDENT_PAT -> NAME -> IDENT). Allowing such a rule through would result in + // renaming everything called `foo` to `bar`. It'd also be slow, since without a path, we'd + // have to use the slow-scan search mechanism. + if self.rules.iter().any(|rule| contains_path(&rule.pattern)) { + let old_len = self.rules.len(); + self.rules.retain(|rule| contains_path(&rule.pattern)); + if self.rules.len() < old_len { + mark::hit!(pattern_is_a_single_segment_path); + } + } Ok(self.rules) } } +/// Returns whether there are any paths in `node`. +fn contains_path(node: &SyntaxNode) -> bool { + node.kind() == SyntaxKind::PATH + || node.descendants().any(|node| node.kind() == SyntaxKind::PATH) +} + impl FromStr for SsrRule { type Err = SsrError; diff --git a/crates/ra_ssr/src/replacing.rs b/crates/ra_ssr/src/replacing.rs index 4b3f5509c3..0943244ff9 100644 --- a/crates/ra_ssr/src/replacing.rs +++ b/crates/ra_ssr/src/replacing.rs @@ -3,8 +3,9 @@ use crate::matching::Var; use crate::{resolving::ResolvedRule, Match, SsrMatches}; use ra_syntax::ast::{self, AstToken}; -use ra_syntax::{SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextSize}; +use ra_syntax::{SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize}; use ra_text_edit::TextEdit; +use rustc_hash::{FxHashMap, FxHashSet}; /// Returns a text edit that will replace each match in `matches` with its corresponding replacement /// template. Placeholders in the template will have been substituted with whatever they matched to @@ -38,62 +39,79 @@ struct ReplacementRenderer<'a> { file_src: &'a str, rules: &'a [ResolvedRule], rule: &'a ResolvedRule, + out: String, + // Map from a range within `out` to a token in `template` that represents a placeholder. This is + // used to validate that the generated source code doesn't split any placeholder expansions (see + // below). + placeholder_tokens_by_range: FxHashMap, + // Which placeholder tokens need to be wrapped in parenthesis in order to ensure that when `out` + // is parsed, placeholders don't get split. e.g. if a template of `$a.to_string()` results in `1 + // + 2.to_string()` then the placeholder value `1 + 2` was split and needs parenthesis. + placeholder_tokens_requiring_parenthesis: FxHashSet, } fn render_replace(match_info: &Match, file_src: &str, rules: &[ResolvedRule]) -> String { - let mut out = String::new(); let rule = &rules[match_info.rule_index]; let template = rule .template .as_ref() .expect("You called MatchFinder::edits after calling MatchFinder::add_search_pattern"); - let renderer = ReplacementRenderer { match_info, file_src, rules, rule }; - renderer.render_node(&template.node, &mut out); + let mut renderer = ReplacementRenderer { + match_info, + file_src, + rules, + rule, + out: String::new(), + placeholder_tokens_requiring_parenthesis: FxHashSet::default(), + placeholder_tokens_by_range: FxHashMap::default(), + }; + renderer.render_node(&template.node); + renderer.maybe_rerender_with_extra_parenthesis(&template.node); for comment in &match_info.ignored_comments { - out.push_str(&comment.syntax().to_string()); + renderer.out.push_str(&comment.syntax().to_string()); } - out + renderer.out } impl ReplacementRenderer<'_> { - fn render_node_children(&self, node: &SyntaxNode, out: &mut String) { + fn render_node_children(&mut self, node: &SyntaxNode) { for node_or_token in node.children_with_tokens() { - self.render_node_or_token(&node_or_token, out); + self.render_node_or_token(&node_or_token); } } - fn render_node_or_token(&self, node_or_token: &SyntaxElement, out: &mut String) { + fn render_node_or_token(&mut self, node_or_token: &SyntaxElement) { match node_or_token { SyntaxElement::Token(token) => { - self.render_token(&token, out); + self.render_token(&token); } SyntaxElement::Node(child_node) => { - self.render_node(&child_node, out); + self.render_node(&child_node); } } } - fn render_node(&self, node: &SyntaxNode, out: &mut String) { + fn render_node(&mut self, node: &SyntaxNode) { use ra_syntax::ast::AstNode; if let Some(mod_path) = self.match_info.rendered_template_paths.get(&node) { - out.push_str(&mod_path.to_string()); + self.out.push_str(&mod_path.to_string()); // Emit everything except for the segment's name-ref, since we already effectively // emitted that as part of `mod_path`. if let Some(path) = ast::Path::cast(node.clone()) { if let Some(segment) = path.segment() { for node_or_token in segment.syntax().children_with_tokens() { if node_or_token.kind() != SyntaxKind::NAME_REF { - self.render_node_or_token(&node_or_token, out); + self.render_node_or_token(&node_or_token); } } } } } else { - self.render_node_children(&node, out); + self.render_node_children(&node); } } - fn render_token(&self, token: &SyntaxToken, out: &mut String) { + fn render_token(&mut self, token: &SyntaxToken) { if let Some(placeholder) = self.rule.get_placeholder(&token) { if let Some(placeholder_value) = self.match_info.placeholder_values.get(&Var(placeholder.ident.to_string())) @@ -107,8 +125,23 @@ impl ReplacementRenderer<'_> { range.start(), self.rules, ); + let needs_parenthesis = + self.placeholder_tokens_requiring_parenthesis.contains(token); edit.apply(&mut matched_text); - out.push_str(&matched_text); + if needs_parenthesis { + self.out.push('('); + } + self.placeholder_tokens_by_range.insert( + TextRange::new( + TextSize::of(&self.out), + TextSize::of(&self.out) + TextSize::of(&matched_text), + ), + token.clone(), + ); + self.out.push_str(&matched_text); + if needs_parenthesis { + self.out.push(')'); + } } else { // We validated that all placeholder references were valid before we // started, so this shouldn't happen. @@ -118,7 +151,44 @@ impl ReplacementRenderer<'_> { ); } } else { - out.push_str(token.text().as_str()); + self.out.push_str(token.text().as_str()); + } + } + + // Checks if the resulting code, when parsed doesn't split any placeholders due to different + // order of operations between the search pattern and the replacement template. If any do, then + // we rerender the template and wrap the problematic placeholders with parenthesis. + fn maybe_rerender_with_extra_parenthesis(&mut self, template: &SyntaxNode) { + if let Some(node) = parse_as_kind(&self.out, template.kind()) { + self.remove_node_ranges(node); + if self.placeholder_tokens_by_range.is_empty() { + return; + } + self.placeholder_tokens_requiring_parenthesis = + self.placeholder_tokens_by_range.values().cloned().collect(); + self.out.clear(); + self.render_node(template); + } + } + + fn remove_node_ranges(&mut self, node: SyntaxNode) { + self.placeholder_tokens_by_range.remove(&node.text_range()); + for child in node.children() { + self.remove_node_ranges(child); } } } + +fn parse_as_kind(code: &str, kind: SyntaxKind) -> Option { + use ra_syntax::ast::AstNode; + if ast::Expr::can_cast(kind) { + if let Ok(expr) = ast::Expr::parse(code) { + return Some(expr.syntax().clone()); + } + } else if ast::Item::can_cast(kind) { + if let Ok(item) = ast::Item::parse(code) { + return Some(item.syntax().clone()); + } + } + None +} diff --git a/crates/ra_ssr/src/resolving.rs b/crates/ra_ssr/src/resolving.rs index 123bd2bb24..df60048eb2 100644 --- a/crates/ra_ssr/src/resolving.rs +++ b/crates/ra_ssr/src/resolving.rs @@ -11,6 +11,7 @@ use test_utils::mark; pub(crate) struct ResolutionScope<'db> { scope: hir::SemanticsScope<'db>, hygiene: hir::Hygiene, + node: SyntaxNode, } pub(crate) struct ResolvedRule { @@ -25,6 +26,7 @@ pub(crate) struct ResolvedPattern { // Paths in `node` that we've resolved. pub(crate) resolved_paths: FxHashMap, pub(crate) ufcs_function_calls: FxHashMap, + pub(crate) contains_self: bool, } pub(crate) struct ResolvedPath { @@ -68,6 +70,7 @@ struct Resolver<'a, 'db> { impl Resolver<'_, '_> { fn resolve_pattern_tree(&self, pattern: SyntaxNode) -> Result { + use ra_syntax::{SyntaxElement, T}; let mut resolved_paths = FxHashMap::default(); self.resolve(pattern.clone(), 0, &mut resolved_paths)?; let ufcs_function_calls = resolved_paths @@ -85,11 +88,17 @@ impl Resolver<'_, '_> { None }) .collect(); + let contains_self = + pattern.descendants_with_tokens().any(|node_or_token| match node_or_token { + SyntaxElement::Token(t) => t.kind() == T![self], + _ => false, + }); Ok(ResolvedPattern { node: pattern, resolved_paths, placeholders_by_stand_in: self.placeholders_by_stand_in.clone(), ufcs_function_calls, + contains_self, }) } @@ -101,6 +110,10 @@ impl Resolver<'_, '_> { ) -> Result<(), SsrError> { use ra_syntax::ast::AstNode; if let Some(path) = ast::Path::cast(node.clone()) { + if is_self(&path) { + // Self cannot be resolved like other paths. + return Ok(()); + } // Check if this is an appropriate place in the path to resolve. If the path is // something like `a::B::::c` then we want to resolve `a::B`. If the path contains // a placeholder. e.g. `a::$b::c` then we want to resolve `a`. @@ -141,14 +154,14 @@ impl Resolver<'_, '_> { impl<'db> ResolutionScope<'db> { pub(crate) fn new( sema: &hir::Semantics<'db, ra_ide_db::RootDatabase>, - lookup_context: FilePosition, + resolve_context: FilePosition, ) -> ResolutionScope<'db> { use ra_syntax::ast::AstNode; - let file = sema.parse(lookup_context.file_id); + let file = sema.parse(resolve_context.file_id); // Find a node at the requested position, falling back to the whole file. let node = file .syntax() - .token_at_offset(lookup_context.offset) + .token_at_offset(resolve_context.offset) .left_biased() .map(|token| token.parent()) .unwrap_or_else(|| file.syntax().clone()); @@ -156,10 +169,16 @@ impl<'db> ResolutionScope<'db> { let scope = sema.scope(&node); ResolutionScope { scope, - hygiene: hir::Hygiene::new(sema.db, lookup_context.file_id.into()), + hygiene: hir::Hygiene::new(sema.db, resolve_context.file_id.into()), + node, } } + /// Returns the function in which SSR was invoked, if any. + pub(crate) fn current_function(&self) -> Option { + self.node.ancestors().find(|node| node.kind() == SyntaxKind::FN).map(|node| node.clone()) + } + fn resolve_path(&self, path: &ast::Path) -> Option { let hir_path = hir::Path::from_src(path.clone(), &self.hygiene)?; // First try resolving the whole path. This will work for things like @@ -186,6 +205,10 @@ impl<'db> ResolutionScope<'db> { } } +fn is_self(path: &ast::Path) -> bool { + path.segment().map(|segment| segment.self_token().is_some()).unwrap_or(false) +} + /// Returns a suitable node for resolving paths in the current scope. If we create a scope based on /// a statement node, then we can't resolve local variables that were defined in the current scope /// (only in parent scopes). So we find another node, ideally a child of the statement where local @@ -198,7 +221,7 @@ fn pick_node_for_resolution(node: SyntaxNode) -> SyntaxNode { return n; } } - SyntaxKind::LET_STMT | SyntaxKind::BIND_PAT => { + SyntaxKind::LET_STMT | SyntaxKind::IDENT_PAT => { if let Some(next) = node.next_sibling() { return pick_node_for_resolution(next); } @@ -217,7 +240,7 @@ fn pick_node_for_resolution(node: SyntaxNode) -> SyntaxNode { fn path_contains_type_arguments(path: Option) -> bool { if let Some(path) = path { if let Some(segment) = path.segment() { - if segment.type_arg_list().is_some() { + if segment.generic_arg_list().is_some() { mark::hit!(type_arguments_within_path); return true; } diff --git a/crates/ra_ssr/src/search.rs b/crates/ra_ssr/src/search.rs index bcf0f04689..85ffa2ac23 100644 --- a/crates/ra_ssr/src/search.rs +++ b/crates/ra_ssr/src/search.rs @@ -5,12 +5,13 @@ use crate::{ resolving::{ResolvedPath, ResolvedPattern, ResolvedRule}, Match, MatchFinder, }; -use ra_db::FileRange; +use ra_db::{FileId, FileRange}; use ra_ide_db::{ defs::Definition, search::{Reference, SearchScope}, }; use ra_syntax::{ast, AstNode, SyntaxKind, SyntaxNode}; +use rustc_hash::FxHashSet; use test_utils::mark; /// A cache for the results of find_usages. This is for when we have multiple patterns that have the @@ -32,6 +33,15 @@ impl<'db> MatchFinder<'db> { usage_cache: &mut UsageCache, matches_out: &mut Vec, ) { + if rule.pattern.contains_self { + // If the pattern contains `self` we restrict the scope of the search to just the + // current method. No other method can reference the same `self`. This makes the + // behavior of `self` consistent with other variables. + if let Some(current_function) = self.resolution_scope.current_function() { + self.slow_scan_node(¤t_function, rule, &None, matches_out); + } + return; + } if pick_path_for_usages(&rule.pattern).is_none() { self.slow_scan(rule, matches_out); return; @@ -54,11 +64,7 @@ impl<'db> MatchFinder<'db> { mark::hit!(use_declaration_with_braces); continue; } - if let Ok(m) = - matching::get_match(false, rule, &node_to_match, &None, &self.sema) - { - matches_out.push(m); - } + self.try_add_match(rule, &node_to_match, &None, matches_out); } } } @@ -121,25 +127,39 @@ impl<'db> MatchFinder<'db> { // FIXME: We should ideally have a test that checks that we edit local roots and not library // roots. This probably would require some changes to fixtures, since currently everything // seems to get put into a single source root. - use ra_db::SourceDatabaseExt; - use ra_ide_db::symbol_index::SymbolsDatabase; let mut files = Vec::new(); - for &root in self.sema.db.local_roots().iter() { - let sr = self.sema.db.source_root(root); - files.extend(sr.iter()); - } + self.search_files_do(|file_id| { + files.push(file_id); + }); SearchScope::files(&files) } fn slow_scan(&self, rule: &ResolvedRule, matches_out: &mut Vec) { - use ra_db::SourceDatabaseExt; - use ra_ide_db::symbol_index::SymbolsDatabase; - for &root in self.sema.db.local_roots().iter() { - let sr = self.sema.db.source_root(root); - for file_id in sr.iter() { - let file = self.sema.parse(file_id); - let code = file.syntax(); - self.slow_scan_node(code, rule, &None, matches_out); + self.search_files_do(|file_id| { + let file = self.sema.parse(file_id); + let code = file.syntax(); + self.slow_scan_node(code, rule, &None, matches_out); + }) + } + + fn search_files_do(&self, mut callback: impl FnMut(FileId)) { + if self.restrict_ranges.is_empty() { + // Unrestricted search. + use ra_db::SourceDatabaseExt; + use ra_ide_db::symbol_index::SymbolsDatabase; + for &root in self.sema.db.local_roots().iter() { + let sr = self.sema.db.source_root(root); + for file_id in sr.iter() { + callback(file_id); + } + } + } else { + // Search is restricted, deduplicate file IDs (generally only one). + let mut files = FxHashSet::default(); + for range in &self.restrict_ranges { + if files.insert(range.file_id) { + callback(range.file_id); + } } } } @@ -154,9 +174,7 @@ impl<'db> MatchFinder<'db> { if !is_search_permitted(code) { return; } - if let Ok(m) = matching::get_match(false, rule, &code, restrict_range, &self.sema) { - matches_out.push(m); - } + self.try_add_match(rule, &code, restrict_range, matches_out); // If we've got a macro call, we already tried matching it pre-expansion, which is the only // way to match the whole macro, now try expanding it and matching the expansion. if let Some(macro_call) = ast::MacroCall::cast(code.clone()) { @@ -178,6 +196,38 @@ impl<'db> MatchFinder<'db> { self.slow_scan_node(&child, rule, restrict_range, matches_out); } } + + fn try_add_match( + &self, + rule: &ResolvedRule, + code: &SyntaxNode, + restrict_range: &Option, + matches_out: &mut Vec, + ) { + if !self.within_range_restrictions(code) { + mark::hit!(replace_nonpath_within_selection); + return; + } + if let Ok(m) = matching::get_match(false, rule, code, restrict_range, &self.sema) { + matches_out.push(m); + } + } + + /// Returns whether `code` is within one of our range restrictions if we have any. No range + /// restrictions is considered unrestricted and always returns true. + fn within_range_restrictions(&self, code: &SyntaxNode) -> bool { + if self.restrict_ranges.is_empty() { + // There is no range restriction. + return true; + } + let node_range = self.sema.original_range(code); + for range in &self.restrict_ranges { + if range.file_id == node_range.file_id && range.range.contains_range(node_range.range) { + return true; + } + } + false + } } /// Returns whether we support matching within `node` and all of its ancestors. @@ -196,7 +246,7 @@ fn is_search_permitted(node: &SyntaxNode) -> bool { // and the code is `use foo::{baz, bar}`, we'll match `bar`, since it resolves to `foo::bar`. // However we'll then replace just the part we matched `bar`. We probably need to instead remove // `bar` and insert a new use declaration. - node.kind() != SyntaxKind::USE_ITEM + node.kind() != SyntaxKind::USE } impl UsageCache { diff --git a/crates/ra_ssr/src/tests.rs b/crates/ra_ssr/src/tests.rs index 18ef2506af..d483640df1 100644 --- a/crates/ra_ssr/src/tests.rs +++ b/crates/ra_ssr/src/tests.rs @@ -1,9 +1,9 @@ use crate::{MatchFinder, SsrRule}; use expect::{expect, Expect}; -use ra_db::{salsa::Durability, FileId, FilePosition, SourceDatabaseExt}; +use ra_db::{salsa::Durability, FileId, FilePosition, FileRange, SourceDatabaseExt}; use rustc_hash::FxHashSet; use std::sync::Arc; -use test_utils::mark; +use test_utils::{mark, RangeOrOffset}; fn parse_error_text(query: &str) -> String { format!("{}", query.parse::().unwrap_err()) @@ -60,20 +60,32 @@ fn parser_undefined_placeholder_in_replacement() { } /// `code` may optionally contain a cursor marker `<|>`. If it doesn't, then the position will be -/// the start of the file. -pub(crate) fn single_file(code: &str) -> (ra_ide_db::RootDatabase, FilePosition) { +/// the start of the file. If there's a second cursor marker, then we'll return a single range. +pub(crate) fn single_file(code: &str) -> (ra_ide_db::RootDatabase, FilePosition, Vec) { use ra_db::fixture::WithFixture; use ra_ide_db::symbol_index::SymbolsDatabase; - let (mut db, position) = if code.contains(test_utils::CURSOR_MARKER) { - ra_ide_db::RootDatabase::with_position(code) + let (mut db, file_id, range_or_offset) = if code.contains(test_utils::CURSOR_MARKER) { + ra_ide_db::RootDatabase::with_range_or_offset(code) } else { let (db, file_id) = ra_ide_db::RootDatabase::with_single_file(code); - (db, FilePosition { file_id, offset: 0.into() }) + (db, file_id, RangeOrOffset::Offset(0.into())) }; + let selections; + let position; + match range_or_offset { + RangeOrOffset::Range(range) => { + position = FilePosition { file_id, offset: range.start() }; + selections = vec![FileRange { file_id, range: range }]; + } + RangeOrOffset::Offset(offset) => { + position = FilePosition { file_id, offset }; + selections = vec![]; + } + } let mut local_roots = FxHashSet::default(); local_roots.insert(ra_db::fixture::WORKSPACE); db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH); - (db, position) + (db, position, selections) } fn assert_ssr_transform(rule: &str, input: &str, expected: Expect) { @@ -81,8 +93,8 @@ fn assert_ssr_transform(rule: &str, input: &str, expected: Expect) { } fn assert_ssr_transforms(rules: &[&str], input: &str, expected: Expect) { - let (db, position) = single_file(input); - let mut match_finder = MatchFinder::in_context(&db, position); + let (db, position, selections) = single_file(input); + let mut match_finder = MatchFinder::in_context(&db, position, selections); for rule in rules { let rule: SsrRule = rule.parse().unwrap(); match_finder.add_rule(rule).unwrap(); @@ -112,8 +124,8 @@ fn print_match_debug_info(match_finder: &MatchFinder, file_id: FileId, snippet: } fn assert_matches(pattern: &str, code: &str, expected: &[&str]) { - let (db, position) = single_file(code); - let mut match_finder = MatchFinder::in_context(&db, position); + let (db, position, selections) = single_file(code); + let mut match_finder = MatchFinder::in_context(&db, position, selections); match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap(); let matched_strings: Vec = match_finder.matches().flattened().matches.iter().map(|m| m.matched_text()).collect(); @@ -124,8 +136,8 @@ fn assert_matches(pattern: &str, code: &str, expected: &[&str]) { } fn assert_no_match(pattern: &str, code: &str) { - let (db, position) = single_file(code); - let mut match_finder = MatchFinder::in_context(&db, position); + let (db, position, selections) = single_file(code); + let mut match_finder = MatchFinder::in_context(&db, position, selections); match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap(); let matches = match_finder.matches().flattened().matches; if !matches.is_empty() { @@ -135,8 +147,8 @@ fn assert_no_match(pattern: &str, code: &str) { } fn assert_match_failure_reason(pattern: &str, code: &str, snippet: &str, expected_reason: &str) { - let (db, position) = single_file(code); - let mut match_finder = MatchFinder::in_context(&db, position); + let (db, position, selections) = single_file(code); + let mut match_finder = MatchFinder::in_context(&db, position, selections); match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap(); let mut reasons = Vec::new(); for d in match_finder.debug_where_text_equal(position.file_id, snippet) { @@ -490,9 +502,10 @@ fn no_match_split_expression() { #[test] fn replace_function_call() { + // This test also makes sure that we ignore empty-ranges. assert_ssr_transform( "foo() ==>> bar()", - "fn foo() {} fn bar() {} fn f1() {foo(); foo();}", + "fn foo() {<|><|>} fn bar() {} fn f1() {foo(); foo();}", expect![["fn foo() {} fn bar() {} fn f1() {bar(); bar();}"]], ); } @@ -651,7 +664,7 @@ fn replace_binary_op() { assert_ssr_transform( "$a + $b ==>> $b + $a", "fn f() {1 + 2 + 3 + 4}", - expect![["fn f() {4 + 3 + 2 + 1}"]], + expect![[r#"fn f() {4 + (3 + (2 + 1))}"#]], ); } @@ -760,11 +773,32 @@ fn preserves_whitespace_within_macro_expansion() { macro_rules! macro1 { ($a:expr) => {$a} } - fn f() {macro1!(4 - 3 - 1 * 2} + fn f() {macro1!(4 - (3 - 1 * 2)} "#]], ) } +#[test] +fn add_parenthesis_when_necessary() { + assert_ssr_transform( + "foo($a) ==>> $a.to_string()", + r#" + fn foo(_: i32) {} + fn bar3(v: i32) { + foo(1 + 2); + foo(-v); + } + "#, + expect![[r#" + fn foo(_: i32) {} + fn bar3(v: i32) { + (1 + 2).to_string(); + (-v).to_string(); + } + "#]], + ) +} + #[test] fn match_failure_reasons() { let code = r#" @@ -886,6 +920,45 @@ fn ufcs_matches_method_call() { ); } +#[test] +fn pattern_is_a_single_segment_path() { + mark::check!(pattern_is_a_single_segment_path); + // The first function should not be altered because the `foo` in scope at the cursor position is + // a different `foo`. This case is special because "foo" can be parsed as a pattern (IDENT_PAT -> + // NAME -> IDENT), which contains no path. If we're not careful we'll end up matching the `foo` + // in `let foo` from the first function. Whether we should match the `let foo` in the second + // function is less clear. At the moment, we don't. Doing so sounds like a rename operation, + // which isn't really what SSR is for, especially since the replacement `bar` must be able to be + // resolved, which means if we rename `foo` we'll get a name collision. + assert_ssr_transform( + "foo ==>> bar", + r#" + fn f1() -> i32 { + let foo = 1; + let bar = 2; + foo + } + fn f1() -> i32 { + let foo = 1; + let bar = 2; + foo<|> + } + "#, + expect![[r#" + fn f1() -> i32 { + let foo = 1; + let bar = 2; + foo + } + fn f1() -> i32 { + let foo = 1; + let bar = 2; + bar + } + "#]], + ); +} + #[test] fn replace_local_variable_reference() { // The pattern references a local variable `foo` in the block containing the cursor. We should @@ -922,3 +995,87 @@ fn replace_local_variable_reference() { "#]], ) } + +#[test] +fn replace_path_within_selection() { + assert_ssr_transform( + "foo ==>> bar", + r#" + fn main() { + let foo = 41; + let bar = 42; + do_stuff(foo); + do_stuff(foo);<|> + do_stuff(foo); + do_stuff(foo);<|> + do_stuff(foo); + }"#, + expect![[r#" + fn main() { + let foo = 41; + let bar = 42; + do_stuff(foo); + do_stuff(foo); + do_stuff(bar); + do_stuff(bar); + do_stuff(foo); + }"#]], + ); +} + +#[test] +fn replace_nonpath_within_selection() { + mark::check!(replace_nonpath_within_selection); + assert_ssr_transform( + "$a + $b ==>> $b * $a", + r#" + fn main() { + let v = 1 + 2;<|> + let v2 = 3 + 3; + let v3 = 4 + 5;<|> + let v4 = 6 + 7; + }"#, + expect![[r#" + fn main() { + let v = 1 + 2; + let v2 = 3 * 3; + let v3 = 5 * 4; + let v4 = 6 + 7; + }"#]], + ); +} + +#[test] +fn replace_self() { + // `foo(self)` occurs twice in the code, however only the first occurrence is the `self` that's + // in scope where the rule is invoked. + assert_ssr_transform( + "foo(self) ==>> bar(self)", + r#" + struct S1 {} + fn foo(_: &S1) {} + fn bar(_: &S1) {} + impl S1 { + fn f1(&self) { + foo(self)<|> + } + fn f2(&self) { + foo(self) + } + } + "#, + expect![[r#" + struct S1 {} + fn foo(_: &S1) {} + fn bar(_: &S1) {} + impl S1 { + fn f1(&self) { + bar(self) + } + fn f2(&self) { + foo(self) + } + } + "#]], + ); +} diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml index 670f04578a..fc4d7aa048 100644 --- a/crates/ra_syntax/Cargo.toml +++ b/crates/ra_syntax/Cargo.toml @@ -13,7 +13,7 @@ doctest = false [dependencies] itertools = "0.9.0" rowan = "0.10.0" -rustc_lexer = { version = "669.0.0", package = "rustc-ap-rustc_lexer" } +rustc_lexer = { version = "671.0.0", package = "rustc-ap-rustc_lexer" } rustc-hash = "1.1.0" arrayvec = "0.5.1" once_cell = "1.3.1" diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index c65c485cb9..d536bb1e7d 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs @@ -17,7 +17,7 @@ use crate::{ pub use self::{ expr_ext::{ArrayExprKind, BinOp, Effect, ElseBranch, LiteralKind, PrefixOp, RangeOp}, - generated::{nodes::*, tokens::*}, + generated::*, node_ext::{ AttrKind, FieldKind, NameOrNameRef, PathSegmentKind, SelfParamKind, SlicePatComponents, StructKind, TypeBoundKind, VisibilityKind, @@ -139,7 +139,7 @@ fn test_doc_comment_of_statics() { ) .ok() .unwrap(); - let st = file.syntax().descendants().find_map(StaticDef::cast).unwrap(); + let st = file.syntax().descendants().find_map(Static::cast).unwrap(); assert_eq!("Number of levels", st.doc_comment_text().unwrap()); } @@ -235,7 +235,7 @@ fn test_comments_preserve_trailing_whitespace() { ) .ok() .unwrap(); - let def = file.syntax().descendants().find_map(StructDef::cast).unwrap(); + let def = file.syntax().descendants().find_map(Struct::cast).unwrap(); assert_eq!( "Representation of a Realm. \nIn the specification these are called Realm Records.", def.doc_comment_text().unwrap() @@ -286,8 +286,8 @@ where let mut bounds = pred.type_bound_list().unwrap().bounds(); assert!(pred.for_token().is_none()); - assert!(pred.type_param_list().is_none()); - assert_eq!("T", pred.type_ref().unwrap().syntax().text().to_string()); + assert!(pred.generic_param_list().is_none()); + assert_eq!("T", pred.ty().unwrap().syntax().text().to_string()); assert_bound("Clone", bounds.next()); assert_bound("Copy", bounds.next()); assert_bound("Debug", bounds.next()); @@ -304,20 +304,20 @@ where let pred = predicates.next().unwrap(); let mut bounds = pred.type_bound_list().unwrap().bounds(); - assert_eq!("Iterator::Item", pred.type_ref().unwrap().syntax().text().to_string()); + assert_eq!("Iterator::Item", pred.ty().unwrap().syntax().text().to_string()); assert_bound("'a", bounds.next()); let pred = predicates.next().unwrap(); let mut bounds = pred.type_bound_list().unwrap().bounds(); - assert_eq!("Iterator::Item", pred.type_ref().unwrap().syntax().text().to_string()); + assert_eq!("Iterator::Item", pred.ty().unwrap().syntax().text().to_string()); assert_bound("Debug", bounds.next()); assert_bound("'a", bounds.next()); let pred = predicates.next().unwrap(); let mut bounds = pred.type_bound_list().unwrap().bounds(); - assert_eq!("::Item", pred.type_ref().unwrap().syntax().text().to_string()); + assert_eq!("::Item", pred.ty().unwrap().syntax().text().to_string()); assert_bound("Debug", bounds.next()); assert_bound("'a", bounds.next()); @@ -325,7 +325,7 @@ where let mut bounds = pred.type_bound_list().unwrap().bounds(); assert!(pred.for_token().is_some()); - assert_eq!("<'a>", pred.type_param_list().unwrap().syntax().text().to_string()); - assert_eq!("F", pred.type_ref().unwrap().syntax().text().to_string()); + assert_eq!("<'a>", pred.generic_param_list().unwrap().syntax().text().to_string()); + assert_eq!("F", pred.ty().unwrap().syntax().text().to_string()); assert_bound("Fn(&'a str)", bounds.next()); } diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs index abc7a646c2..5ed123f91f 100644 --- a/crates/ra_syntax/src/ast/edit.rs +++ b/crates/ra_syntax/src/ast/edit.rs @@ -29,9 +29,9 @@ impl ast::BinExpr { } } -impl ast::FnDef { +impl ast::Fn { #[must_use] - pub fn with_body(&self, body: ast::BlockExpr) -> ast::FnDef { + pub fn with_body(&self, body: ast::BlockExpr) -> ast::Fn { let mut to_insert: ArrayVec<[SyntaxElement; 2]> = ArrayVec::new(); let old_body_or_semi: SyntaxElement = if let Some(old_body) = self.body() { old_body.syntax().clone().into() @@ -80,9 +80,12 @@ where } } -impl ast::ItemList { +impl ast::AssocItemList { #[must_use] - pub fn append_items(&self, items: impl IntoIterator) -> ast::ItemList { + pub fn append_items( + &self, + items: impl IntoIterator, + ) -> ast::AssocItemList { let mut res = self.clone(); if !self.syntax().text().contains_char('\n') { res = make_multiline(res); @@ -92,7 +95,7 @@ impl ast::ItemList { } #[must_use] - pub fn append_item(&self, item: ast::AssocItem) -> ast::ItemList { + pub fn append_item(&self, item: ast::AssocItem) -> ast::AssocItemList { let (indent, position) = match self.assoc_items().last() { Some(it) => ( leading_indent(it.syntax()).unwrap_or_default().to_string(), @@ -113,18 +116,18 @@ impl ast::ItemList { } } -impl ast::RecordFieldList { +impl ast::RecordExprFieldList { #[must_use] - pub fn append_field(&self, field: &ast::RecordField) -> ast::RecordFieldList { + pub fn append_field(&self, field: &ast::RecordExprField) -> ast::RecordExprFieldList { self.insert_field(InsertPosition::Last, field) } #[must_use] pub fn insert_field( &self, - position: InsertPosition<&'_ ast::RecordField>, - field: &ast::RecordField, - ) -> ast::RecordFieldList { + position: InsertPosition<&'_ ast::RecordExprField>, + field: &ast::RecordExprField, + ) -> ast::RecordExprFieldList { let is_multiline = self.syntax().text().contains_char('\n'); let ws; let space = if is_multiline { @@ -189,9 +192,9 @@ impl ast::RecordFieldList { } } -impl ast::TypeAliasDef { +impl ast::TypeAlias { #[must_use] - pub fn remove_bounds(&self) -> ast::TypeAliasDef { + pub fn remove_bounds(&self) -> ast::TypeAlias { let colon = match self.colon_token() { Some(it) => it, None => return self.clone(), @@ -234,17 +237,17 @@ impl ast::Path { impl ast::PathSegment { #[must_use] - pub fn with_type_args(&self, type_args: ast::TypeArgList) -> ast::PathSegment { + pub fn with_type_args(&self, type_args: ast::GenericArgList) -> ast::PathSegment { self._with_type_args(type_args, false) } #[must_use] - pub fn with_turbo_fish(&self, type_args: ast::TypeArgList) -> ast::PathSegment { + pub fn with_turbo_fish(&self, type_args: ast::GenericArgList) -> ast::PathSegment { self._with_type_args(type_args, true) } - fn _with_type_args(&self, type_args: ast::TypeArgList, turbo: bool) -> ast::PathSegment { - if let Some(old) = self.type_arg_list() { + fn _with_type_args(&self, type_args: ast::GenericArgList, turbo: bool) -> ast::PathSegment { + if let Some(old) = self.generic_arg_list() { return self.replace_children( single_node(old.syntax().clone()), iter::once(type_args.syntax().clone().into()), @@ -259,9 +262,9 @@ impl ast::PathSegment { } } -impl ast::UseItem { +impl ast::Use { #[must_use] - pub fn with_use_tree(&self, use_tree: ast::UseTree) -> ast::UseItem { + pub fn with_use_tree(&self, use_tree: ast::UseTree) -> ast::Use { if let Some(old) = self.use_tree() { return self.replace_descendant(old, use_tree); } @@ -314,8 +317,12 @@ impl ast::UseTree { Some(it) => it, None => return self.clone(), }; - let use_tree = - make::use_tree(suffix, self.use_tree_list(), self.alias(), self.star_token().is_some()); + let use_tree = make::use_tree( + suffix, + self.use_tree_list(), + self.rename(), + self.star_token().is_some(), + ); let nested = make::use_tree_list(iter::once(use_tree)); return make::use_tree(prefix.clone(), Some(nested), None, false); @@ -383,7 +390,7 @@ impl ast::MatchArmList { #[must_use] pub fn remove_placeholder(&self) -> ast::MatchArmList { let placeholder = - self.arms().find(|arm| matches!(arm.pat(), Some(ast::Pat::PlaceholderPat(_)))); + self.arms().find(|arm| matches!(arm.pat(), Some(ast::Pat::WildcardPat(_)))); if let Some(placeholder) = placeholder { self.remove_arm(&placeholder) } else { @@ -614,7 +621,7 @@ fn single_node(element: impl Into) -> RangeInclusive bool { match self { @@ -331,13 +333,12 @@ impl ast::Literal { match token.kind() { INT_NUMBER => { - // FYI: there was a bug here previously, thus an if statement bellow is necessary. + // FYI: there was a bug here previously, thus the if statement below is necessary. // The lexer treats e.g. `1f64` as an integer literal. See // https://github.com/rust-analyzer/rust-analyzer/issues/1592 // and the comments on the linked PR. let text = token.text(); - if let suffix @ Some(_) = Self::find_suffix(&text, &FLOAT_SUFFIXES) { LiteralKind::FloatNumber { suffix } } else { @@ -399,7 +400,7 @@ impl ast::BlockExpr { Some(it) => it, None => return true, }; - !matches!(parent.kind(), FN_DEF | IF_EXPR | WHILE_EXPR | LOOP_EXPR | EFFECT_EXPR) + !matches!(parent.kind(), FN | IF_EXPR | WHILE_EXPR | LOOP_EXPR | EFFECT_EXPR) } } @@ -410,8 +411,8 @@ fn test_literal_with_attr() { assert_eq!(lit.token().text(), r#""Hello""#); } -impl ast::RecordField { - pub fn parent_record_lit(&self) -> ast::RecordLit { - self.syntax().ancestors().find_map(ast::RecordLit::cast).unwrap() +impl ast::RecordExprField { + pub fn parent_record_lit(&self) -> ast::RecordExpr { + self.syntax().ancestors().find_map(ast::RecordExpr::cast).unwrap() } } diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index f5199e09f2..4a6f41ee71 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs @@ -1,6 +1,41 @@ //! This file is actually hand-written, but the submodules are indeed generated. +#[rustfmt::skip] +mod nodes; +#[rustfmt::skip] +mod tokens; -#[rustfmt::skip] -pub(super) mod nodes; -#[rustfmt::skip] -pub(super) mod tokens; +use crate::{ + AstNode, + SyntaxKind::{self, *}, + SyntaxNode, +}; + +pub use {nodes::*, tokens::*}; + +// Stmt is the only nested enum, so it's easier to just hand-write it +impl AstNode for Stmt { + fn can_cast(kind: SyntaxKind) -> bool { + match kind { + LET_STMT | EXPR_STMT => true, + _ => Item::can_cast(kind), + } + } + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + LET_STMT => Stmt::LetStmt(LetStmt { syntax }), + EXPR_STMT => Stmt::ExprStmt(ExprStmt { syntax }), + _ => { + let item = Item::cast(syntax)?; + Stmt::Item(item) + } + }; + Some(res) + } + fn syntax(&self) -> &SyntaxNode { + match self { + Stmt::LetStmt(it) => &it.syntax, + Stmt::ExprStmt(it) => &it.syntax, + Stmt::Item(it) => it.syntax(), + } + } +} diff --git a/crates/ra_syntax/src/ast/generated/nodes.rs b/crates/ra_syntax/src/ast/generated/nodes.rs index 58141da114..3d49309d14 100644 --- a/crates/ra_syntax/src/ast/generated/nodes.rs +++ b/crates/ra_syntax/src/ast/generated/nodes.rs @@ -5,595 +5,76 @@ use crate::{ SyntaxKind::{self, *}, SyntaxNode, SyntaxToken, T, }; -/// The entire Rust source file. Includes all top-level inner attributes and module items. -/// -/// [Reference](https://doc.rust-lang.org/reference/crates-and-source-files.html) #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct SourceFile { +pub struct Name { pub(crate) syntax: SyntaxNode, } -impl ast::ModuleItemOwner for SourceFile {} -impl ast::AttrsOwner for SourceFile {} -impl ast::DocCommentsOwner for SourceFile {} -impl SourceFile { - pub fn modules(&self) -> AstChildren { support::children(&self.syntax) } +impl Name { + pub fn ident_token(&self) -> Option { support::token(&self.syntax, T![ident]) } } -/// Function definition either with body or not. -/// Includes all of its attributes and doc comments. -/// -/// ``` -/// ❰ -/// /// Docs -/// #[attr] -/// pub extern "C" fn foo(#[attr] Patern {p}: Pattern) -> u32 -/// where -/// T: Debug -/// { -/// 42 -/// } -/// ❱ -/// -/// extern "C" { -/// ❰ fn fn_decl(also_variadic_ffi: u32, ...) -> u32; ❱ -/// } -/// ``` -/// -/// - [Reference](https://doc.rust-lang.org/reference/items/functions.html) -/// - [Nomicon](https://doc.rust-lang.org/nomicon/ffi.html#variadic-functions) #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct FnDef { +pub struct NameRef { pub(crate) syntax: SyntaxNode, } -impl ast::VisibilityOwner for FnDef {} -impl ast::NameOwner for FnDef {} -impl ast::TypeParamsOwner for FnDef {} -impl ast::DocCommentsOwner for FnDef {} -impl ast::AttrsOwner for FnDef {} -impl FnDef { - pub fn abi(&self) -> Option { support::child(&self.syntax) } - pub fn const_token(&self) -> Option { support::token(&self.syntax, T![const]) } - pub fn default_token(&self) -> Option { support::token(&self.syntax, T![default]) } - pub fn async_token(&self) -> Option { support::token(&self.syntax, T![async]) } - pub fn unsafe_token(&self) -> Option { support::token(&self.syntax, T![unsafe]) } - pub fn fn_token(&self) -> Option { support::token(&self.syntax, T![fn]) } +impl NameRef { + pub fn ident_token(&self) -> Option { support::token(&self.syntax, T![ident]) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Path { + pub(crate) syntax: SyntaxNode, +} +impl Path { + pub fn qualifier(&self) -> Option { support::child(&self.syntax) } + pub fn coloncolon_token(&self) -> Option { support::token(&self.syntax, T![::]) } + pub fn segment(&self) -> Option { support::child(&self.syntax) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct PathSegment { + pub(crate) syntax: SyntaxNode, +} +impl PathSegment { + pub fn crate_token(&self) -> Option { support::token(&self.syntax, T![crate]) } + pub fn self_token(&self) -> Option { support::token(&self.syntax, T![self]) } + pub fn super_token(&self) -> Option { support::token(&self.syntax, T![super]) } + pub fn coloncolon_token(&self) -> Option { support::token(&self.syntax, T![::]) } + pub fn name_ref(&self) -> Option { support::child(&self.syntax) } + pub fn generic_arg_list(&self) -> Option { support::child(&self.syntax) } pub fn param_list(&self) -> Option { support::child(&self.syntax) } pub fn ret_type(&self) -> Option { support::child(&self.syntax) } - pub fn body(&self) -> Option { support::child(&self.syntax) } - pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } + pub fn l_angle_token(&self) -> Option { support::token(&self.syntax, T![<]) } + pub fn path_type(&self) -> Option { support::child(&self.syntax) } + pub fn as_token(&self) -> Option { support::token(&self.syntax, T![as]) } + pub fn r_angle_token(&self) -> Option { support::token(&self.syntax, T![>]) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct GenericArgList { + pub(crate) syntax: SyntaxNode, +} +impl GenericArgList { + pub fn coloncolon_token(&self) -> Option { support::token(&self.syntax, T![::]) } + pub fn l_angle_token(&self) -> Option { support::token(&self.syntax, T![<]) } + pub fn generic_args(&self) -> AstChildren { support::children(&self.syntax) } + pub fn r_angle_token(&self) -> Option { support::token(&self.syntax, T![>]) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ParamList { + pub(crate) syntax: SyntaxNode, +} +impl ParamList { + pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } + pub fn self_param(&self) -> Option { support::child(&self.syntax) } + pub fn comma_token(&self) -> Option { support::token(&self.syntax, T![,]) } + pub fn params(&self) -> AstChildren { support::children(&self.syntax) } + pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } } -/// Return type annotation. -/// -/// ``` -/// fn foo(a: u32) ❰ -> Option ❱ { Some(a) } -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/items/functions.html) #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct RetType { pub(crate) syntax: SyntaxNode, } impl RetType { pub fn thin_arrow_token(&self) -> Option { support::token(&self.syntax, T![->]) } - pub fn type_ref(&self) -> Option { support::child(&self.syntax) } + pub fn ty(&self) -> Option { support::child(&self.syntax) } } -/// Struct definition. -/// Includes all of its attributes and doc comments. -/// -/// ``` -/// ❰ -/// /// Docs -/// #[attr] -/// struct Foo where T: Debug { -/// /// Docs -/// #[attr] -/// pub a: u32, -/// b: T, -/// } -/// ❱ -/// -/// ❰ struct Foo; ❱ -/// ❰ struct Foo(#[attr] T) where T: Debug; ❱ -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/items/structs.html) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct StructDef { - pub(crate) syntax: SyntaxNode, -} -impl ast::VisibilityOwner for StructDef {} -impl ast::NameOwner for StructDef {} -impl ast::TypeParamsOwner for StructDef {} -impl ast::AttrsOwner for StructDef {} -impl ast::DocCommentsOwner for StructDef {} -impl StructDef { - pub fn struct_token(&self) -> Option { support::token(&self.syntax, T![struct]) } - pub fn field_def_list(&self) -> Option { support::child(&self.syntax) } - pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } -} -/// Union definition. -/// Includes all of its attributes and doc comments. -/// -/// ``` -/// ❰ -/// /// Docs -/// #[attr] -/// pub union Foo where T: Debug { -/// /// Docs -/// #[attr] -/// a: T, -/// b: u32, -/// } -/// ❱ -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/items/unions.html) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct UnionDef { - pub(crate) syntax: SyntaxNode, -} -impl ast::VisibilityOwner for UnionDef {} -impl ast::NameOwner for UnionDef {} -impl ast::TypeParamsOwner for UnionDef {} -impl ast::AttrsOwner for UnionDef {} -impl ast::DocCommentsOwner for UnionDef {} -impl UnionDef { - pub fn union_token(&self) -> Option { support::token(&self.syntax, T![union]) } - pub fn record_field_def_list(&self) -> Option { - support::child(&self.syntax) - } -} -/// Record field definition list including enclosing curly braces. -/// -/// ``` -/// struct Foo // same for union -/// ❰ -/// { -/// a: u32, -/// b: bool, -/// } -/// ❱ -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/items/structs.html) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct RecordFieldDefList { - pub(crate) syntax: SyntaxNode, -} -impl RecordFieldDefList { - pub fn l_curly_token(&self) -> Option { support::token(&self.syntax, T!['{']) } - pub fn fields(&self) -> AstChildren { support::children(&self.syntax) } - pub fn r_curly_token(&self) -> Option { support::token(&self.syntax, T!['}']) } -} -/// Record field definition including its attributes and doc comments. -/// -/// ` `` -/// same for union -/// struct Foo { -/// ❰ -/// /// Docs -/// #[attr] -/// pub a: u32 -/// ❱ -/// -/// ❰ b: bool ❱ -/// } -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/items/structs.html) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct RecordFieldDef { - pub(crate) syntax: SyntaxNode, -} -impl ast::VisibilityOwner for RecordFieldDef {} -impl ast::NameOwner for RecordFieldDef {} -impl ast::AttrsOwner for RecordFieldDef {} -impl ast::DocCommentsOwner for RecordFieldDef {} -impl ast::TypeAscriptionOwner for RecordFieldDef {} -impl RecordFieldDef {} -/// Tuple field definition list including enclosing parens. -/// -/// ``` -/// struct Foo ❰ (u32, String, Vec) ❱; -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/items/structs.html) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct TupleFieldDefList { - pub(crate) syntax: SyntaxNode, -} -impl TupleFieldDefList { - pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } - pub fn fields(&self) -> AstChildren { support::children(&self.syntax) } - pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } -} -/// Tuple field definition including its attributes. -/// -/// ``` -/// struct Foo(❰ #[attr] u32 ❱); -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/items/structs.html) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct TupleFieldDef { - pub(crate) syntax: SyntaxNode, -} -impl ast::VisibilityOwner for TupleFieldDef {} -impl ast::AttrsOwner for TupleFieldDef {} -impl TupleFieldDef { - pub fn type_ref(&self) -> Option { support::child(&self.syntax) } -} -/// Enum definition. -/// Includes all of its attributes and doc comments. -/// -/// ``` -/// ❰ -/// /// Docs -/// #[attr] -/// pub enum Foo where T: Debug { -/// /// Docs -/// #[attr] -/// Bar, -/// Baz(#[attr] u32), -/// Bruh { -/// a: u32, -/// /// Docs -/// #[attr] -/// b: T, -/// } -/// } -/// ❱ -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/items/enumerations.html) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct EnumDef { - pub(crate) syntax: SyntaxNode, -} -impl ast::VisibilityOwner for EnumDef {} -impl ast::NameOwner for EnumDef {} -impl ast::TypeParamsOwner for EnumDef {} -impl ast::AttrsOwner for EnumDef {} -impl ast::DocCommentsOwner for EnumDef {} -impl EnumDef { - pub fn enum_token(&self) -> Option { support::token(&self.syntax, T![enum]) } - pub fn variant_list(&self) -> Option { support::child(&self.syntax) } -} -/// Enum variant definition list including enclosing curly braces. -/// -/// ``` -/// enum Foo -/// ❰ -/// { -/// Bar, -/// Baz(u32), -/// Bruh { -/// a: u32 -/// } -/// } -/// ❱ -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/items/enumerations.html) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct EnumVariantList { - pub(crate) syntax: SyntaxNode, -} -impl EnumVariantList { - pub fn l_curly_token(&self) -> Option { support::token(&self.syntax, T!['{']) } - pub fn variants(&self) -> AstChildren { support::children(&self.syntax) } - pub fn r_curly_token(&self) -> Option { support::token(&self.syntax, T!['}']) } -} -/// Enum variant definition including its attributes and discriminant value definition. -/// -/// ``` -/// enum Foo { -/// ❰ -/// /// Docs -/// #[attr] -/// Bar -/// ❱ -/// -/// // same for tuple and record variants -/// } -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/items/enumerations.html) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct EnumVariant { - pub(crate) syntax: SyntaxNode, -} -impl ast::VisibilityOwner for EnumVariant {} -impl ast::NameOwner for EnumVariant {} -impl ast::DocCommentsOwner for EnumVariant {} -impl ast::AttrsOwner for EnumVariant {} -impl EnumVariant { - pub fn field_def_list(&self) -> Option { support::child(&self.syntax) } - pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } - pub fn expr(&self) -> Option { support::child(&self.syntax) } -} -/// Trait definition. -/// Includes all of its attributes and doc comments. -/// -/// ``` -/// ❰ -/// /// Docs -/// #[attr] -/// pub unsafe trait Foo: Debug where T: Debug { -/// // ... -/// } -/// ❱ -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/items/traits.html) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct TraitDef { - pub(crate) syntax: SyntaxNode, -} -impl ast::VisibilityOwner for TraitDef {} -impl ast::NameOwner for TraitDef {} -impl ast::AttrsOwner for TraitDef {} -impl ast::DocCommentsOwner for TraitDef {} -impl ast::TypeParamsOwner for TraitDef {} -impl ast::TypeBoundsOwner for TraitDef {} -impl TraitDef { - pub fn unsafe_token(&self) -> Option { support::token(&self.syntax, T![unsafe]) } - pub fn auto_token(&self) -> Option { support::token(&self.syntax, T![auto]) } - pub fn trait_token(&self) -> Option { support::token(&self.syntax, T![trait]) } - pub fn item_list(&self) -> Option { support::child(&self.syntax) } -} -/// Module definition either with body or not. -/// Includes all of its inner and outer attributes, module items, doc comments. -/// -/// ``` -/// ❰ -/// /// Docs -/// #[attr] -/// pub mod foo; -/// ❱ -/// -/// ❰ -/// /// Docs -/// #[attr] -/// pub mod bar { -/// //! Inner docs -/// #![inner_attr] -/// } -/// ❱ -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/items/modules.html) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Module { - pub(crate) syntax: SyntaxNode, -} -impl ast::VisibilityOwner for Module {} -impl ast::NameOwner for Module {} -impl ast::AttrsOwner for Module {} -impl ast::DocCommentsOwner for Module {} -impl Module { - pub fn mod_token(&self) -> Option { support::token(&self.syntax, T![mod]) } - pub fn item_list(&self) -> Option { support::child(&self.syntax) } - pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } -} -/// Item defintion list. -/// This is used for both top-level items and impl block items. -/// -/// ``` -/// ❰ -/// fn foo {} -/// struct Bar; -/// enum Baz; -/// trait Bruh; -/// const BRUUH: u32 = 42; -/// ❱ -/// -/// impl Foo -/// ❰ -/// { -/// fn bar() {} -/// const BAZ: u32 = 42; -/// } -/// ❱ -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/items.html) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ItemList { - pub(crate) syntax: SyntaxNode, -} -impl ast::ModuleItemOwner for ItemList {} -impl ItemList { - pub fn l_curly_token(&self) -> Option { support::token(&self.syntax, T!['{']) } - pub fn assoc_items(&self) -> AstChildren { support::children(&self.syntax) } - pub fn r_curly_token(&self) -> Option { support::token(&self.syntax, T!['}']) } -} -/// Constant variable definition. -/// Includes all of its attributes and doc comments. -/// -/// ``` -/// ❰ -/// /// Docs -/// #[attr] -/// pub const FOO: u32 = 42; -/// ❱ -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/items/constant-items.html) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ConstDef { - pub(crate) syntax: SyntaxNode, -} -impl ast::VisibilityOwner for ConstDef {} -impl ast::NameOwner for ConstDef {} -impl ast::TypeParamsOwner for ConstDef {} -impl ast::AttrsOwner for ConstDef {} -impl ast::DocCommentsOwner for ConstDef {} -impl ast::TypeAscriptionOwner for ConstDef {} -impl ConstDef { - pub fn default_token(&self) -> Option { support::token(&self.syntax, T![default]) } - pub fn const_token(&self) -> Option { support::token(&self.syntax, T![const]) } - pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } - pub fn body(&self) -> Option { support::child(&self.syntax) } - pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } -} -/// Static variable definition. -/// Includes all of its attributes and doc comments. -/// -/// ``` -/// ❰ -/// /// Docs -/// #[attr] -/// pub static mut FOO: u32 = 42; -/// ❱ -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/items/static-items.html) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct StaticDef { - pub(crate) syntax: SyntaxNode, -} -impl ast::VisibilityOwner for StaticDef {} -impl ast::NameOwner for StaticDef {} -impl ast::TypeParamsOwner for StaticDef {} -impl ast::AttrsOwner for StaticDef {} -impl ast::DocCommentsOwner for StaticDef {} -impl ast::TypeAscriptionOwner for StaticDef {} -impl StaticDef { - pub fn static_token(&self) -> Option { support::token(&self.syntax, T![static]) } - pub fn mut_token(&self) -> Option { support::token(&self.syntax, T![mut]) } - pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } - pub fn body(&self) -> Option { support::child(&self.syntax) } - pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } -} -/// Type alias definition. -/// Includes associated type clauses with type bounds. -/// -/// ``` -/// ❰ -/// /// Docs -/// #[attr] -/// pub type Foo where T: Debug = T; -/// ❱ -/// -/// trait Bar { -/// ❰ type Baz: Debug; ❱ -/// ❰ type Bruh = String; ❱ -/// ❰ type Bruuh: Debug = u32; ❱ -/// } -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/items/type-aliases.html) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct TypeAliasDef { - pub(crate) syntax: SyntaxNode, -} -impl ast::VisibilityOwner for TypeAliasDef {} -impl ast::NameOwner for TypeAliasDef {} -impl ast::TypeParamsOwner for TypeAliasDef {} -impl ast::AttrsOwner for TypeAliasDef {} -impl ast::DocCommentsOwner for TypeAliasDef {} -impl ast::TypeBoundsOwner for TypeAliasDef {} -impl TypeAliasDef { - pub fn default_token(&self) -> Option { support::token(&self.syntax, T![default]) } - pub fn type_token(&self) -> Option { support::token(&self.syntax, T![type]) } - pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } - pub fn type_ref(&self) -> Option { support::child(&self.syntax) } - pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } -} -/// Inherent and trait impl definition. -/// Includes all of its inner and outer attributes. -/// -/// ``` -/// ❰ -/// #[attr] -/// unsafe impl const !Foo for Bar where T: Debug { -/// #![inner_attr] -/// // ... -/// } -/// ❱ -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/items/implementations.html) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ImplDef { - pub(crate) syntax: SyntaxNode, -} -impl ast::TypeParamsOwner for ImplDef {} -impl ast::AttrsOwner for ImplDef {} -impl ast::DocCommentsOwner for ImplDef {} -impl ImplDef { - pub fn default_token(&self) -> Option { support::token(&self.syntax, T![default]) } - pub fn const_token(&self) -> Option { support::token(&self.syntax, T![const]) } - pub fn unsafe_token(&self) -> Option { support::token(&self.syntax, T![unsafe]) } - pub fn impl_token(&self) -> Option { support::token(&self.syntax, T![impl]) } - pub fn excl_token(&self) -> Option { support::token(&self.syntax, T![!]) } - pub fn for_token(&self) -> Option { support::token(&self.syntax, T![for]) } - pub fn item_list(&self) -> Option { support::child(&self.syntax) } -} -/// Parenthesized type reference. -/// Note: parens are only used for grouping, this is not a tuple type. -/// -/// ``` -/// // This is effectively just `u32`. -/// // Single-item tuple must be defined with a trailing comma: `(u32,)` -/// type Foo = ❰ (u32) ❱; -/// -/// let bar: &'static ❰ (dyn Debug) ❱ = "bruh"; -/// ``` -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ParenType { - pub(crate) syntax: SyntaxNode, -} -impl ParenType { - pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } - pub fn type_ref(&self) -> Option { support::child(&self.syntax) } - pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } -} -/// Unnamed tuple type. -/// -/// ``` -/// let foo: ❰ (u32, bool) ❱ = (42, true); -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/types/tuple.html) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct TupleType { - pub(crate) syntax: SyntaxNode, -} -impl TupleType { - pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } - pub fn fields(&self) -> AstChildren { support::children(&self.syntax) } - pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } -} -/// The never type (i.e. the exclamation point). -/// -/// ``` -/// type T = ❰ ! ❱; -/// -/// fn no_return() -> ❰ ! ❱ { -/// loop {} -/// } -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/types/never.html) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct NeverType { - pub(crate) syntax: SyntaxNode, -} -impl NeverType { - pub fn excl_token(&self) -> Option { support::token(&self.syntax, T![!]) } -} -/// Path to a type. -/// Includes single identifier type names and elaborate paths with -/// generic parameters. -/// -/// ``` -/// type Foo = ❰ String ❱; -/// type Bar = ❰ std::vec::Vec ❱; -/// type Baz = ❰ ::bruh::::Item ❱; -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/paths.html) #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct PathType { pub(crate) syntax: SyntaxNode, @@ -601,183 +82,560 @@ pub struct PathType { impl PathType { pub fn path(&self) -> Option { support::child(&self.syntax) } } -/// Raw pointer type. -/// -/// ``` -/// type Foo = ❰ *const u32 ❱; -/// type Bar = ❰ *mut u32 ❱; -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/types/pointer.html#raw-pointers-const-and-mut) #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct PointerType { +pub struct TypeArg { pub(crate) syntax: SyntaxNode, } -impl PointerType { - pub fn star_token(&self) -> Option { support::token(&self.syntax, T![*]) } - pub fn const_token(&self) -> Option { support::token(&self.syntax, T![const]) } - pub fn mut_token(&self) -> Option { support::token(&self.syntax, T![mut]) } - pub fn type_ref(&self) -> Option { support::child(&self.syntax) } +impl TypeArg { + pub fn ty(&self) -> Option { support::child(&self.syntax) } } -/// Array type. -/// -/// ``` -/// type Foo = ❰ [u32; 24 - 3] ❱; -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/types/array.html) #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ArrayType { +pub struct AssocTypeArg { pub(crate) syntax: SyntaxNode, } -impl ArrayType { - pub fn l_brack_token(&self) -> Option { support::token(&self.syntax, T!['[']) } - pub fn type_ref(&self) -> Option { support::child(&self.syntax) } - pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } +impl ast::TypeBoundsOwner for AssocTypeArg {} +impl AssocTypeArg { + pub fn name_ref(&self) -> Option { support::child(&self.syntax) } + pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } + pub fn ty(&self) -> Option { support::child(&self.syntax) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct LifetimeArg { + pub(crate) syntax: SyntaxNode, +} +impl LifetimeArg { + pub fn lifetime_token(&self) -> Option { + support::token(&self.syntax, T![lifetime]) + } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ConstArg { + pub(crate) syntax: SyntaxNode, +} +impl ConstArg { pub fn expr(&self) -> Option { support::child(&self.syntax) } - pub fn r_brack_token(&self) -> Option { support::token(&self.syntax, T![']']) } } -/// Slice type. -/// -/// ``` -/// type Foo = ❰ [u8] ❱; -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/types/slice.html) #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct SliceType { +pub struct TypeBoundList { pub(crate) syntax: SyntaxNode, } -impl SliceType { +impl TypeBoundList { + pub fn bounds(&self) -> AstChildren { support::children(&self.syntax) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct MacroCall { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for MacroCall {} +impl ast::NameOwner for MacroCall {} +impl MacroCall { + pub fn path(&self) -> Option { support::child(&self.syntax) } + pub fn excl_token(&self) -> Option { support::token(&self.syntax, T![!]) } + pub fn token_tree(&self) -> Option { support::child(&self.syntax) } + pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Attr { + pub(crate) syntax: SyntaxNode, +} +impl Attr { + pub fn pound_token(&self) -> Option { support::token(&self.syntax, T![#]) } + pub fn excl_token(&self) -> Option { support::token(&self.syntax, T![!]) } pub fn l_brack_token(&self) -> Option { support::token(&self.syntax, T!['[']) } - pub fn type_ref(&self) -> Option { support::child(&self.syntax) } + pub fn path(&self) -> Option { support::child(&self.syntax) } + pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } + pub fn literal(&self) -> Option { support::child(&self.syntax) } + pub fn token_tree(&self) -> Option { support::child(&self.syntax) } pub fn r_brack_token(&self) -> Option { support::token(&self.syntax, T![']']) } } -/// Reference type. -/// -/// ``` -/// type Foo = ❰ &'static str ❱; -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/types/pointer.html) #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ReferenceType { +pub struct TokenTree { pub(crate) syntax: SyntaxNode, } -impl ReferenceType { +impl TokenTree { + pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } + pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } + pub fn l_curly_token(&self) -> Option { support::token(&self.syntax, T!['{']) } + pub fn r_curly_token(&self) -> Option { support::token(&self.syntax, T!['}']) } + pub fn l_brack_token(&self) -> Option { support::token(&self.syntax, T!['[']) } + pub fn r_brack_token(&self) -> Option { support::token(&self.syntax, T![']']) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct MacroItems { + pub(crate) syntax: SyntaxNode, +} +impl ast::ModuleItemOwner for MacroItems {} +impl MacroItems {} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct MacroStmts { + pub(crate) syntax: SyntaxNode, +} +impl MacroStmts { + pub fn statements(&self) -> AstChildren { support::children(&self.syntax) } + pub fn expr(&self) -> Option { support::child(&self.syntax) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct SourceFile { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for SourceFile {} +impl ast::ModuleItemOwner for SourceFile {} +impl SourceFile { + pub fn shebang_token(&self) -> Option { support::token(&self.syntax, T![shebang]) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Const { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for Const {} +impl ast::NameOwner for Const {} +impl ast::VisibilityOwner for Const {} +impl Const { + pub fn default_token(&self) -> Option { support::token(&self.syntax, T![default]) } + pub fn const_token(&self) -> Option { support::token(&self.syntax, T![const]) } + pub fn underscore_token(&self) -> Option { support::token(&self.syntax, T![_]) } + pub fn colon_token(&self) -> Option { support::token(&self.syntax, T![:]) } + pub fn ty(&self) -> Option { support::child(&self.syntax) } + pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } + pub fn body(&self) -> Option { support::child(&self.syntax) } + pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Enum { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for Enum {} +impl ast::NameOwner for Enum {} +impl ast::VisibilityOwner for Enum {} +impl ast::GenericParamsOwner for Enum {} +impl Enum { + pub fn enum_token(&self) -> Option { support::token(&self.syntax, T![enum]) } + pub fn variant_list(&self) -> Option { support::child(&self.syntax) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ExternBlock { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for ExternBlock {} +impl ExternBlock { + pub fn abi(&self) -> Option { support::child(&self.syntax) } + pub fn extern_item_list(&self) -> Option { support::child(&self.syntax) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ExternCrate { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for ExternCrate {} +impl ast::VisibilityOwner for ExternCrate {} +impl ExternCrate { + pub fn extern_token(&self) -> Option { support::token(&self.syntax, T![extern]) } + pub fn crate_token(&self) -> Option { support::token(&self.syntax, T![crate]) } + pub fn name_ref(&self) -> Option { support::child(&self.syntax) } + pub fn self_token(&self) -> Option { support::token(&self.syntax, T![self]) } + pub fn rename(&self) -> Option { support::child(&self.syntax) } + pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Fn { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for Fn {} +impl ast::NameOwner for Fn {} +impl ast::VisibilityOwner for Fn {} +impl ast::GenericParamsOwner for Fn {} +impl Fn { + pub fn default_token(&self) -> Option { support::token(&self.syntax, T![default]) } + pub fn async_token(&self) -> Option { support::token(&self.syntax, T![async]) } + pub fn const_token(&self) -> Option { support::token(&self.syntax, T![const]) } + pub fn unsafe_token(&self) -> Option { support::token(&self.syntax, T![unsafe]) } + pub fn abi(&self) -> Option { support::child(&self.syntax) } + pub fn fn_token(&self) -> Option { support::token(&self.syntax, T![fn]) } + pub fn param_list(&self) -> Option { support::child(&self.syntax) } + pub fn ret_type(&self) -> Option { support::child(&self.syntax) } + pub fn body(&self) -> Option { support::child(&self.syntax) } + pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Impl { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for Impl {} +impl ast::VisibilityOwner for Impl {} +impl ast::GenericParamsOwner for Impl {} +impl Impl { + pub fn default_token(&self) -> Option { support::token(&self.syntax, T![default]) } + pub fn unsafe_token(&self) -> Option { support::token(&self.syntax, T![unsafe]) } + pub fn impl_token(&self) -> Option { support::token(&self.syntax, T![impl]) } + pub fn const_token(&self) -> Option { support::token(&self.syntax, T![const]) } + pub fn excl_token(&self) -> Option { support::token(&self.syntax, T![!]) } + pub fn for_token(&self) -> Option { support::token(&self.syntax, T![for]) } + pub fn assoc_item_list(&self) -> Option { support::child(&self.syntax) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Module { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for Module {} +impl ast::NameOwner for Module {} +impl ast::VisibilityOwner for Module {} +impl Module { + pub fn mod_token(&self) -> Option { support::token(&self.syntax, T![mod]) } + pub fn item_list(&self) -> Option { support::child(&self.syntax) } + pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Static { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for Static {} +impl ast::NameOwner for Static {} +impl ast::VisibilityOwner for Static {} +impl Static { + pub fn static_token(&self) -> Option { support::token(&self.syntax, T![static]) } + pub fn mut_token(&self) -> Option { support::token(&self.syntax, T![mut]) } + pub fn colon_token(&self) -> Option { support::token(&self.syntax, T![:]) } + pub fn ty(&self) -> Option { support::child(&self.syntax) } + pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } + pub fn body(&self) -> Option { support::child(&self.syntax) } + pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Struct { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for Struct {} +impl ast::NameOwner for Struct {} +impl ast::VisibilityOwner for Struct {} +impl ast::GenericParamsOwner for Struct {} +impl Struct { + pub fn struct_token(&self) -> Option { support::token(&self.syntax, T![struct]) } + pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } + pub fn field_list(&self) -> Option { support::child(&self.syntax) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Trait { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for Trait {} +impl ast::NameOwner for Trait {} +impl ast::VisibilityOwner for Trait {} +impl ast::GenericParamsOwner for Trait {} +impl ast::TypeBoundsOwner for Trait {} +impl Trait { + pub fn unsafe_token(&self) -> Option { support::token(&self.syntax, T![unsafe]) } + pub fn auto_token(&self) -> Option { support::token(&self.syntax, T![auto]) } + pub fn trait_token(&self) -> Option { support::token(&self.syntax, T![trait]) } + pub fn assoc_item_list(&self) -> Option { support::child(&self.syntax) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct TypeAlias { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for TypeAlias {} +impl ast::NameOwner for TypeAlias {} +impl ast::VisibilityOwner for TypeAlias {} +impl ast::GenericParamsOwner for TypeAlias {} +impl ast::TypeBoundsOwner for TypeAlias {} +impl TypeAlias { + pub fn default_token(&self) -> Option { support::token(&self.syntax, T![default]) } + pub fn type_token(&self) -> Option { support::token(&self.syntax, T![type]) } + pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } + pub fn ty(&self) -> Option { support::child(&self.syntax) } + pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Union { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for Union {} +impl ast::NameOwner for Union {} +impl ast::VisibilityOwner for Union {} +impl ast::GenericParamsOwner for Union {} +impl Union { + pub fn union_token(&self) -> Option { support::token(&self.syntax, T![union]) } + pub fn record_field_list(&self) -> Option { support::child(&self.syntax) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Use { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for Use {} +impl ast::VisibilityOwner for Use {} +impl Use { + pub fn use_token(&self) -> Option { support::token(&self.syntax, T![use]) } + pub fn use_tree(&self) -> Option { support::child(&self.syntax) } + pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Visibility { + pub(crate) syntax: SyntaxNode, +} +impl Visibility { + pub fn pub_token(&self) -> Option { support::token(&self.syntax, T![pub]) } + pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } + pub fn super_token(&self) -> Option { support::token(&self.syntax, T![super]) } + pub fn self_token(&self) -> Option { support::token(&self.syntax, T![self]) } + pub fn crate_token(&self) -> Option { support::token(&self.syntax, T![crate]) } + pub fn in_token(&self) -> Option { support::token(&self.syntax, T![in]) } + pub fn path(&self) -> Option { support::child(&self.syntax) } + pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ItemList { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for ItemList {} +impl ast::ModuleItemOwner for ItemList {} +impl ItemList { + pub fn l_curly_token(&self) -> Option { support::token(&self.syntax, T!['{']) } + pub fn r_curly_token(&self) -> Option { support::token(&self.syntax, T!['}']) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Rename { + pub(crate) syntax: SyntaxNode, +} +impl ast::NameOwner for Rename {} +impl Rename { + pub fn as_token(&self) -> Option { support::token(&self.syntax, T![as]) } + pub fn underscore_token(&self) -> Option { support::token(&self.syntax, T![_]) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct UseTree { + pub(crate) syntax: SyntaxNode, +} +impl UseTree { + pub fn path(&self) -> Option { support::child(&self.syntax) } + pub fn coloncolon_token(&self) -> Option { support::token(&self.syntax, T![::]) } + pub fn star_token(&self) -> Option { support::token(&self.syntax, T![*]) } + pub fn use_tree_list(&self) -> Option { support::child(&self.syntax) } + pub fn rename(&self) -> Option { support::child(&self.syntax) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct UseTreeList { + pub(crate) syntax: SyntaxNode, +} +impl UseTreeList { + pub fn l_curly_token(&self) -> Option { support::token(&self.syntax, T!['{']) } + pub fn use_trees(&self) -> AstChildren { support::children(&self.syntax) } + pub fn r_curly_token(&self) -> Option { support::token(&self.syntax, T!['}']) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Abi { + pub(crate) syntax: SyntaxNode, +} +impl Abi { + pub fn extern_token(&self) -> Option { support::token(&self.syntax, T![extern]) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct GenericParamList { + pub(crate) syntax: SyntaxNode, +} +impl GenericParamList { + pub fn l_angle_token(&self) -> Option { support::token(&self.syntax, T![<]) } + pub fn generic_params(&self) -> AstChildren { support::children(&self.syntax) } + pub fn r_angle_token(&self) -> Option { support::token(&self.syntax, T![>]) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct WhereClause { + pub(crate) syntax: SyntaxNode, +} +impl WhereClause { + pub fn where_token(&self) -> Option { support::token(&self.syntax, T![where]) } + pub fn predicates(&self) -> AstChildren { support::children(&self.syntax) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct BlockExpr { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for BlockExpr {} +impl BlockExpr { + pub fn l_curly_token(&self) -> Option { support::token(&self.syntax, T!['{']) } + pub fn statements(&self) -> AstChildren { support::children(&self.syntax) } + pub fn expr(&self) -> Option { support::child(&self.syntax) } + pub fn r_curly_token(&self) -> Option { support::token(&self.syntax, T!['}']) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct SelfParam { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for SelfParam {} +impl SelfParam { pub fn amp_token(&self) -> Option { support::token(&self.syntax, T![&]) } pub fn lifetime_token(&self) -> Option { support::token(&self.syntax, T![lifetime]) } pub fn mut_token(&self) -> Option { support::token(&self.syntax, T![mut]) } - pub fn type_ref(&self) -> Option { support::child(&self.syntax) } + pub fn self_token(&self) -> Option { support::token(&self.syntax, T![self]) } + pub fn colon_token(&self) -> Option { support::token(&self.syntax, T![:]) } + pub fn ty(&self) -> Option { support::child(&self.syntax) } } -/// Placeholder type (i.e. the underscore). -/// -/// ``` -/// let foo: ❰ _ ❱ = 42_u32; -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/types/inferred.html) #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct PlaceholderType { +pub struct Param { pub(crate) syntax: SyntaxNode, } -impl PlaceholderType { - pub fn underscore_token(&self) -> Option { support::token(&self.syntax, T![_]) } +impl ast::AttrsOwner for Param {} +impl Param { + pub fn pat(&self) -> Option { support::child(&self.syntax) } + pub fn colon_token(&self) -> Option { support::token(&self.syntax, T![:]) } + pub fn ty(&self) -> Option { support::child(&self.syntax) } + pub fn dotdotdot_token(&self) -> Option { support::token(&self.syntax, T![...]) } } -/// Function pointer type (not to be confused with `Fn*` family of traits). -/// -/// ``` -/// type Foo = ❰ async fn(#[attr] u32, named: bool) -> u32 ❱; -/// -/// type Bar = ❰ extern "C" fn(variadic: u32, #[attr] ...) ❱; -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/types/function-pointer.html) #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct FnPointerType { +pub struct RecordFieldList { pub(crate) syntax: SyntaxNode, } -impl FnPointerType { - pub fn abi(&self) -> Option { support::child(&self.syntax) } - pub fn unsafe_token(&self) -> Option { support::token(&self.syntax, T![unsafe]) } - pub fn fn_token(&self) -> Option { support::token(&self.syntax, T![fn]) } - pub fn param_list(&self) -> Option { support::child(&self.syntax) } - pub fn ret_type(&self) -> Option { support::child(&self.syntax) } +impl RecordFieldList { + pub fn l_curly_token(&self) -> Option { support::token(&self.syntax, T!['{']) } + pub fn fields(&self) -> AstChildren { support::children(&self.syntax) } + pub fn r_curly_token(&self) -> Option { support::token(&self.syntax, T!['}']) } } -/// Higher order type. -/// -/// ``` -/// type Foo = ❰ for<'a> fn(&'a str) ❱; -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/nomicon/hrtb.html) #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ForType { +pub struct TupleFieldList { pub(crate) syntax: SyntaxNode, } -impl ForType { - pub fn for_token(&self) -> Option { support::token(&self.syntax, T![for]) } - pub fn type_param_list(&self) -> Option { support::child(&self.syntax) } - pub fn type_ref(&self) -> Option { support::child(&self.syntax) } -} -/// Opaque `impl Trait` type. -/// -/// ``` -/// fn foo(bar: ❰ impl Debug + Eq ❱) {} -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/types/impl-trait.html) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ImplTraitType { - pub(crate) syntax: SyntaxNode, -} -impl ast::TypeBoundsOwner for ImplTraitType {} -impl ImplTraitType { - pub fn impl_token(&self) -> Option { support::token(&self.syntax, T![impl]) } -} -/// Trait object type. -/// -/// ``` -/// type Foo = ❰ dyn Debug ❱; -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/types/trait-object.html) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct DynTraitType { - pub(crate) syntax: SyntaxNode, -} -impl ast::TypeBoundsOwner for DynTraitType {} -impl DynTraitType { - pub fn dyn_token(&self) -> Option { support::token(&self.syntax, T![dyn]) } -} -/// Tuple literal. -/// -/// ``` -/// ❰ (42, true) ❱; -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/expressions/tuple-expr.html) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct TupleExpr { - pub(crate) syntax: SyntaxNode, -} -impl ast::AttrsOwner for TupleExpr {} -impl TupleExpr { +impl TupleFieldList { pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } - pub fn exprs(&self) -> AstChildren { support::children(&self.syntax) } + pub fn fields(&self) -> AstChildren { support::children(&self.syntax) } pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } } -/// Array literal. -/// -/// ``` -/// ❰ [#![inner_attr] true, false, true] ❱; -/// -/// ❰ ["baz"; 24] ❱; -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/expressions/array-expr.html) +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct RecordField { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for RecordField {} +impl ast::NameOwner for RecordField {} +impl ast::VisibilityOwner for RecordField {} +impl RecordField { + pub fn colon_token(&self) -> Option { support::token(&self.syntax, T![:]) } + pub fn ty(&self) -> Option { support::child(&self.syntax) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct TupleField { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for TupleField {} +impl ast::VisibilityOwner for TupleField {} +impl TupleField { + pub fn ty(&self) -> Option { support::child(&self.syntax) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct VariantList { + pub(crate) syntax: SyntaxNode, +} +impl VariantList { + pub fn l_curly_token(&self) -> Option { support::token(&self.syntax, T!['{']) } + pub fn variants(&self) -> AstChildren { support::children(&self.syntax) } + pub fn r_curly_token(&self) -> Option { support::token(&self.syntax, T!['}']) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Variant { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for Variant {} +impl ast::NameOwner for Variant {} +impl ast::VisibilityOwner for Variant {} +impl Variant { + pub fn field_list(&self) -> Option { support::child(&self.syntax) } + pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } + pub fn expr(&self) -> Option { support::child(&self.syntax) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct AssocItemList { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for AssocItemList {} +impl AssocItemList { + pub fn l_curly_token(&self) -> Option { support::token(&self.syntax, T!['{']) } + pub fn assoc_items(&self) -> AstChildren { support::children(&self.syntax) } + pub fn r_curly_token(&self) -> Option { support::token(&self.syntax, T!['}']) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ExternItemList { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for ExternItemList {} +impl ExternItemList { + pub fn l_curly_token(&self) -> Option { support::token(&self.syntax, T!['{']) } + pub fn extern_items(&self) -> AstChildren { support::children(&self.syntax) } + pub fn r_curly_token(&self) -> Option { support::token(&self.syntax, T!['}']) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ConstParam { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for ConstParam {} +impl ast::NameOwner for ConstParam {} +impl ConstParam { + pub fn const_token(&self) -> Option { support::token(&self.syntax, T![const]) } + pub fn colon_token(&self) -> Option { support::token(&self.syntax, T![:]) } + pub fn ty(&self) -> Option { support::child(&self.syntax) } + pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } + pub fn default_val(&self) -> Option { support::child(&self.syntax) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct LifetimeParam { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for LifetimeParam {} +impl ast::TypeBoundsOwner for LifetimeParam {} +impl LifetimeParam { + pub fn lifetime_token(&self) -> Option { + support::token(&self.syntax, T![lifetime]) + } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct TypeParam { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for TypeParam {} +impl ast::NameOwner for TypeParam {} +impl ast::TypeBoundsOwner for TypeParam {} +impl TypeParam { + pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } + pub fn default_type(&self) -> Option { support::child(&self.syntax) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct WherePred { + pub(crate) syntax: SyntaxNode, +} +impl ast::TypeBoundsOwner for WherePred {} +impl WherePred { + pub fn for_token(&self) -> Option { support::token(&self.syntax, T![for]) } + pub fn generic_param_list(&self) -> Option { support::child(&self.syntax) } + pub fn lifetime_token(&self) -> Option { + support::token(&self.syntax, T![lifetime]) + } + pub fn ty(&self) -> Option { support::child(&self.syntax) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Literal { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for Literal {} +impl Literal {} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ExprStmt { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for ExprStmt {} +impl ExprStmt { + pub fn expr(&self) -> Option { support::child(&self.syntax) } + pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct LetStmt { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for LetStmt {} +impl LetStmt { + pub fn let_token(&self) -> Option { support::token(&self.syntax, T![let]) } + pub fn pat(&self) -> Option { support::child(&self.syntax) } + pub fn colon_token(&self) -> Option { support::token(&self.syntax, T![:]) } + pub fn ty(&self) -> Option { support::child(&self.syntax) } + pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } + pub fn initializer(&self) -> Option { support::child(&self.syntax) } + pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } +} #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ArrayExpr { pub(crate) syntax: SyntaxNode, @@ -786,64 +644,72 @@ impl ast::AttrsOwner for ArrayExpr {} impl ArrayExpr { pub fn l_brack_token(&self) -> Option { support::token(&self.syntax, T!['[']) } pub fn exprs(&self) -> AstChildren { support::children(&self.syntax) } + pub fn expr(&self) -> Option { support::child(&self.syntax) } pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } pub fn r_brack_token(&self) -> Option { support::token(&self.syntax, T![']']) } } -/// Parenthesized expression. -/// Note: parens are only used for grouping, this is not a tuple literal. -/// -/// ``` -/// ❰ (#![inner_attr] 2 + 2) ❱ * 2; -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/expressions/grouped-expr.html) #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ParenExpr { +pub struct AwaitExpr { pub(crate) syntax: SyntaxNode, } -impl ast::AttrsOwner for ParenExpr {} -impl ParenExpr { - pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } +impl ast::AttrsOwner for AwaitExpr {} +impl AwaitExpr { pub fn expr(&self) -> Option { support::child(&self.syntax) } - pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } + pub fn dot_token(&self) -> Option { support::token(&self.syntax, T![.]) } + pub fn await_token(&self) -> Option { support::token(&self.syntax, T![await]) } } -/// Path to a symbol in expression context. -/// Includes single identifier variable names and elaborate paths with -/// generic parameters. -/// -/// ``` -/// ❰ Some:: ❱; -/// ❰ foo ❱ + 42; -/// ❰ Vec::::push ❱; -/// ❰ <[i32]>::reverse ❱; -/// ❰ >::borrow ❱; -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/expressions/path-expr.html) #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct PathExpr { +pub struct BinExpr { pub(crate) syntax: SyntaxNode, } -impl PathExpr { - pub fn path(&self) -> Option { support::child(&self.syntax) } -} -/// Anonymous callable object literal a.k.a. closure, lambda or functor. -/// -/// ``` -/// ❰ || 42 ❱; -/// ❰ |a: u32| val + 1 ❱; -/// ❰ async |#[attr] Pattern(_): Pattern| { bar } ❱; -/// ❰ move || baz ❱; -/// ❰ || -> u32 { closure_with_ret_type_annotation_requires_block_expr } ❱ -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/expressions/closure-expr.html) +impl ast::AttrsOwner for BinExpr {} +impl BinExpr {} #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct LambdaExpr { +pub struct BoxExpr { pub(crate) syntax: SyntaxNode, } -impl ast::AttrsOwner for LambdaExpr {} -impl LambdaExpr { +impl ast::AttrsOwner for BoxExpr {} +impl BoxExpr { + pub fn box_token(&self) -> Option { support::token(&self.syntax, T![box]) } + pub fn expr(&self) -> Option { support::child(&self.syntax) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct BreakExpr { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for BreakExpr {} +impl BreakExpr { + pub fn break_token(&self) -> Option { support::token(&self.syntax, T![break]) } + pub fn lifetime_token(&self) -> Option { + support::token(&self.syntax, T![lifetime]) + } + pub fn expr(&self) -> Option { support::child(&self.syntax) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct CallExpr { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for CallExpr {} +impl ast::ArgListOwner for CallExpr {} +impl CallExpr { + pub fn expr(&self) -> Option { support::child(&self.syntax) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct CastExpr { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for CastExpr {} +impl CastExpr { + pub fn expr(&self) -> Option { support::child(&self.syntax) } + pub fn as_token(&self) -> Option { support::token(&self.syntax, T![as]) } + pub fn ty(&self) -> Option { support::child(&self.syntax) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ClosureExpr { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for ClosureExpr {} +impl ClosureExpr { pub fn static_token(&self) -> Option { support::token(&self.syntax, T![static]) } pub fn async_token(&self) -> Option { support::token(&self.syntax, T![async]) } pub fn move_token(&self) -> Option { support::token(&self.syntax, T![move]) } @@ -851,147 +717,6 @@ impl LambdaExpr { pub fn ret_type(&self) -> Option { support::child(&self.syntax) } pub fn body(&self) -> Option { support::child(&self.syntax) } } -/// If expression. Includes both regular `if` and `if let` forms. -/// Beware that `else if` is a special case syntax sugar, because in general -/// there has to be block expression after `else`. -/// -/// ``` -/// ❰ if bool_cond { 42 } ❱ -/// ❰ if bool_cond { 42 } else { 24 } ❱ -/// ❰ if bool_cond { 42 } else if bool_cond2 { 42 } ❱ -/// -/// ❰ -/// if let Pattern(foo) = bar { -/// foo -/// } else { -/// panic!(); -/// } -/// ❱ -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/expressions/if-expr.html) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct IfExpr { - pub(crate) syntax: SyntaxNode, -} -impl ast::AttrsOwner for IfExpr {} -impl IfExpr { - pub fn if_token(&self) -> Option { support::token(&self.syntax, T![if]) } - pub fn condition(&self) -> Option { support::child(&self.syntax) } -} -/// Unconditional loop expression. -/// -/// ``` -/// ❰ -/// loop { -/// // yeah, it's that simple... -/// } -/// ❱ -/// ``` -/// -/// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct LoopExpr { - pub(crate) syntax: SyntaxNode, -} -impl ast::AttrsOwner for LoopExpr {} -impl ast::LoopBodyOwner for LoopExpr {} -impl LoopExpr { - pub fn loop_token(&self) -> Option { support::token(&self.syntax, T![loop]) } -} -/// Block expression with an optional prefix (label, try ketword, -/// unsafe keyword, async keyword...). -/// -/// ``` -/// ❰ -/// 'label: try { -/// None? -/// } -/// ❱ -/// ``` -/// -/// - [try block](https://doc.rust-lang.org/unstable-book/language-features/try-blocks.html) -/// - [unsafe block](https://doc.rust-lang.org/reference/expressions/block-expr.html#unsafe-blocks) -/// - [async block](https://doc.rust-lang.org/reference/expressions/block-expr.html#async-blocks) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct EffectExpr { - pub(crate) syntax: SyntaxNode, -} -impl ast::AttrsOwner for EffectExpr {} -impl EffectExpr { - pub fn label(&self) -> Option