aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/actions/github-release/main.js1
-rw-r--r--.github/workflows/release.yaml6
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock64
-rw-r--r--crates/assists/src/handlers/auto_import.rs4
-rw-r--r--crates/assists/src/handlers/change_visibility.rs18
-rw-r--r--crates/assists/src/handlers/fill_match_arms.rs2
-rw-r--r--crates/assists/src/handlers/fix_visibility.rs6
-rw-r--r--crates/assists/src/handlers/generate_from_impl_for_enum.rs2
-rw-r--r--crates/assists/src/handlers/qualify_path.rs1048
-rw-r--r--crates/assists/src/handlers/replace_string_with_char.rs141
-rw-r--r--crates/assists/src/lib.rs4
-rw-r--r--crates/assists/src/tests/generated.rs36
-rw-r--r--crates/assists/src/utils.rs25
-rw-r--r--crates/assists/src/utils/import_assets.rs40
-rw-r--r--crates/base_db/src/fixture.rs4
-rw-r--r--crates/base_db/src/input.rs76
-rw-r--r--crates/base_db/src/lib.rs4
-rw-r--r--crates/call_info/Cargo.toml26
-rw-r--r--crates/call_info/src/lib.rs (renamed from crates/ide/src/call_info.rs)47
-rw-r--r--crates/completion/Cargo.toml32
-rw-r--r--crates/completion/src/complete_attribute.rs (renamed from crates/ide/src/completion/complete_attribute.rs)135
-rw-r--r--crates/completion/src/complete_dot.rs (renamed from crates/ide/src/completion/complete_dot.rs)19
-rw-r--r--crates/completion/src/complete_fn_param.rs (renamed from crates/ide/src/completion/complete_fn_param.rs)4
-rw-r--r--crates/completion/src/complete_keyword.rs (renamed from crates/ide/src/completion/complete_keyword.rs)8
-rw-r--r--crates/completion/src/complete_macro_in_item_position.rs (renamed from crates/ide/src/completion/complete_macro_in_item_position.rs)6
-rw-r--r--crates/completion/src/complete_mod.rs (renamed from crates/ide/src/completion/complete_mod.rs)2
-rw-r--r--crates/completion/src/complete_pattern.rs (renamed from crates/ide/src/completion/complete_pattern.rs)6
-rw-r--r--crates/completion/src/complete_postfix.rs (renamed from crates/ide/src/completion/complete_postfix.rs)12
-rw-r--r--crates/completion/src/complete_postfix/format_like.rs (renamed from crates/ide/src/completion/complete_postfix/format_like.rs)2
-rw-r--r--crates/completion/src/complete_qualified_path.rs (renamed from crates/ide/src/completion/complete_qualified_path.rs)4
-rw-r--r--crates/completion/src/complete_record.rs (renamed from crates/ide/src/completion/complete_record.rs)4
-rw-r--r--crates/completion/src/complete_snippet.rs (renamed from crates/ide/src/completion/complete_snippet.rs)6
-rw-r--r--crates/completion/src/complete_trait_impl.rs (renamed from crates/ide/src/completion/complete_trait_impl.rs)13
-rw-r--r--crates/completion/src/complete_unqualified_path.rs (renamed from crates/ide/src/completion/complete_unqualified_path.rs)4
-rw-r--r--crates/completion/src/completion_config.rs (renamed from crates/ide/src/completion/completion_config.rs)0
-rw-r--r--crates/completion/src/completion_context.rs (renamed from crates/ide/src/completion/completion_context.rs)40
-rw-r--r--crates/completion/src/completion_item.rs (renamed from crates/ide/src/completion/completion_item.rs)10
-rw-r--r--crates/completion/src/generated_lint_completions.rs5
-rw-r--r--crates/completion/src/lib.rs (renamed from crates/ide/src/completion.rs)77
-rw-r--r--crates/completion/src/patterns.rs (renamed from crates/ide/src/completion/patterns.rs)48
-rw-r--r--crates/completion/src/presentation.rs (renamed from crates/ide/src/completion/presentation.rs)19
-rw-r--r--crates/completion/src/test_utils.rs (renamed from crates/ide/src/completion/test_utils.rs)55
-rw-r--r--crates/hir/src/code_model.rs6
-rw-r--r--crates/hir/src/diagnostics.rs2
-rw-r--r--crates/hir_def/src/body.rs6
-rw-r--r--crates/hir_def/src/diagnostics.rs34
-rw-r--r--crates/hir_def/src/import_map.rs6
-rw-r--r--crates/hir_def/src/item_tree.rs18
-rw-r--r--crates/hir_def/src/nameres.rs21
-rw-r--r--crates/hir_def/src/nameres/collector.rs13
-rw-r--r--crates/hir_expand/src/db.rs1
-rw-r--r--crates/hir_ty/src/diagnostics.rs55
-rw-r--r--crates/ide/Cargo.toml2
-rw-r--r--crates/ide/src/call_hierarchy.rs4
-rw-r--r--crates/ide/src/completion/generated_features.rs4
-rw-r--r--crates/ide/src/diagnostics.rs89
-rw-r--r--crates/ide/src/diagnostics/field_shorthand.rs32
-rw-r--r--crates/ide/src/display.rs81
-rw-r--r--crates/ide/src/doc_links.rs8
-rw-r--r--crates/ide/src/hover.rs2
-rw-r--r--crates/ide/src/inlay_hints.rs24
-rw-r--r--crates/ide/src/lib.rs10
-rw-r--r--crates/ide/src/prime_caches.rs3
-rw-r--r--crates/ide/src/status.rs2
-rw-r--r--crates/ide/src/syntax_highlighting/injection.rs6
-rw-r--r--crates/project_model/src/lib.rs16
-rw-r--r--crates/project_model/src/project_json.rs7
-rw-r--r--crates/rust-analyzer/Cargo.toml2
-rw-r--r--crates/rust-analyzer/src/cli/diagnostics.rs8
-rw-r--r--crates/rust-analyzer/src/handlers.rs14
-rw-r--r--crates/syntax/src/ast/make.rs3
-rw-r--r--crates/syntax/src/display.rs83
-rw-r--r--crates/syntax/src/lib.rs1
-rw-r--r--docs/user/generated_diagnostic.adoc105
-rw-r--r--docs/user/manual.adoc4
-rw-r--r--editors/code/rust.tmGrammar.json45
-rw-r--r--editors/code/src/run.ts4
-rw-r--r--xtask/src/codegen.rs9
-rw-r--r--xtask/src/codegen/gen_assists_docs.rs4
-rw-r--r--xtask/src/codegen/gen_diagnostic_docs.rs74
-rw-r--r--xtask/src/codegen/gen_feature_docs.rs4
-rw-r--r--xtask/src/codegen/gen_lint_completions.rs113
-rw-r--r--xtask/src/codegen/gen_parser_tests.rs2
-rw-r--r--xtask/src/release.rs9
-rw-r--r--xtask/tests/tidy.rs11
86 files changed, 2462 insertions, 551 deletions
diff --git a/.github/actions/github-release/main.js b/.github/actions/github-release/main.js
index b499cd0fd..a08e59a91 100644
--- a/.github/actions/github-release/main.js
+++ b/.github/actions/github-release/main.js
@@ -70,6 +70,7 @@ async function runOnce() {
70 repo, 70 repo,
71 name, 71 name,
72 tag_name: name, 72 tag_name: name,
73 target_commitish: sha,
73 prerelease: name === 'nightly', 74 prerelease: name === 'nightly',
74 }); 75 });
75 76
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 1ae8ed1b6..c1d56a8e0 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -79,16 +79,16 @@ jobs:
79 with: 79 with:
80 node-version: 12.x 80 node-version: 12.x
81 81
82 - run: echo "::set-env name=TAG::$(date --iso --utc)" 82 - run: echo "TAG=$(date --iso --utc)" >> $GITHUB_ENV
83 if: github.ref == 'refs/heads/release' 83 if: github.ref == 'refs/heads/release'
84 - run: echo "::set-env name=TAG::nightly" 84 - run: echo "TAG=nightly" >> $GITHUB_ENV
85 if: github.ref != 'refs/heads/release' 85 if: github.ref != 'refs/heads/release'
86 - run: 'echo "TAG: $TAG"' 86 - run: 'echo "TAG: $TAG"'
87 87
88 - name: Checkout repository 88 - name: Checkout repository
89 uses: actions/checkout@v2 89 uses: actions/checkout@v2
90 90
91 - run: echo "::set-env name=HEAD_SHA::$(git rev-parse HEAD)" 91 - run: echo "HEAD_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
92 - run: 'echo "HEAD_SHA: $HEAD_SHA"' 92 - run: 'echo "HEAD_SHA: $HEAD_SHA"'
93 93
94 - uses: actions/download-artifact@v1 94 - uses: actions/download-artifact@v1
diff --git a/.gitignore b/.gitignore
index 472fe1a13..b205bf3fb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,4 @@ crates/*/target
9.vscode/settings.json 9.vscode/settings.json
10generated_assists.adoc 10generated_assists.adoc
11generated_features.adoc 11generated_features.adoc
12generated_diagnostic.adoc
diff --git a/Cargo.lock b/Cargo.lock
index 7a77ed722..65c8de719 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -128,6 +128,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
128checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" 128checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
129 129
130[[package]] 130[[package]]
131name = "call_info"
132version = "0.0.0"
133dependencies = [
134 "base_db",
135 "either",
136 "expect-test",
137 "hir",
138 "ide_db",
139 "stdx",
140 "syntax",
141 "test_utils",
142]
143
144[[package]]
131name = "cargo_metadata" 145name = "cargo_metadata"
132version = "0.11.4" 146version = "0.11.4"
133source = "registry+https://github.com/rust-lang/crates.io-index" 147source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -250,6 +264,26 @@ dependencies = [
250] 264]
251 265
252[[package]] 266[[package]]
267name = "completion"
268version = "0.0.0"
269dependencies = [
270 "assists",
271 "base_db",
272 "call_info",
273 "expect-test",
274 "hir",
275 "ide_db",
276 "itertools",
277 "log",
278 "profile",
279 "rustc-hash",
280 "stdx",
281 "syntax",
282 "test_utils",
283 "text_edit",
284]
285
286[[package]]
253name = "const_fn" 287name = "const_fn"
254version = "0.4.2" 288version = "0.4.2"
255source = "registry+https://github.com/rust-lang/crates.io-index" 289source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -362,9 +396,9 @@ dependencies = [
362 396
363[[package]] 397[[package]]
364name = "env_logger" 398name = "env_logger"
365version = "0.7.1" 399version = "0.8.1"
366source = "registry+https://github.com/rust-lang/crates.io-index" 400source = "registry+https://github.com/rust-lang/crates.io-index"
367checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" 401checksum = "54532e3223c5af90a6a757c90b5c5521564b07e5e7a958681bcd2afad421cdcd"
368dependencies = [ 402dependencies = [
369 "log", 403 "log",
370] 404]
@@ -609,7 +643,9 @@ version = "0.0.0"
609dependencies = [ 643dependencies = [
610 "assists", 644 "assists",
611 "base_db", 645 "base_db",
646 "call_info",
612 "cfg", 647 "cfg",
648 "completion",
613 "either", 649 "either",
614 "expect-test", 650 "expect-test",
615 "hir", 651 "hir",
@@ -796,9 +832,9 @@ dependencies = [
796 832
797[[package]] 833[[package]]
798name = "lsp-server" 834name = "lsp-server"
799version = "0.4.0" 835version = "0.4.1"
800source = "registry+https://github.com/rust-lang/crates.io-index" 836source = "registry+https://github.com/rust-lang/crates.io-index"
801checksum = "ff7452ee21b8de64f10ceb4e9fee1212e1a9579cd717226613333e751676c86a" 837checksum = "9c85acaf36c53bf15da2b8b35afeea56747707261f59eb0b77229081dd72b04e"
802dependencies = [ 838dependencies = [
803 "crossbeam-channel 0.5.0", 839 "crossbeam-channel 0.5.0",
804 "log", 840 "log",
@@ -1441,18 +1477,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
1441 1477
1442[[package]] 1478[[package]]
1443name = "serde" 1479name = "serde"
1444version = "1.0.116" 1480version = "1.0.117"
1445source = "registry+https://github.com/rust-lang/crates.io-index" 1481source = "registry+https://github.com/rust-lang/crates.io-index"
1446checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5" 1482checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a"
1447dependencies = [ 1483dependencies = [
1448 "serde_derive", 1484 "serde_derive",
1449] 1485]
1450 1486
1451[[package]] 1487[[package]]
1452name = "serde_derive" 1488name = "serde_derive"
1453version = "1.0.116" 1489version = "1.0.117"
1454source = "registry+https://github.com/rust-lang/crates.io-index" 1490source = "registry+https://github.com/rust-lang/crates.io-index"
1455checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" 1491checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e"
1456dependencies = [ 1492dependencies = [
1457 "proc-macro2", 1493 "proc-macro2",
1458 "quote", 1494 "quote",
@@ -1532,9 +1568,9 @@ version = "0.0.0"
1532 1568
1533[[package]] 1569[[package]]
1534name = "syn" 1570name = "syn"
1535version = "1.0.44" 1571version = "1.0.45"
1536source = "registry+https://github.com/rust-lang/crates.io-index" 1572source = "registry+https://github.com/rust-lang/crates.io-index"
1537checksum = "e03e57e4fcbfe7749842d53e24ccb9aa12b7252dbe5e91d2acad31834c8b8fdd" 1573checksum = "ea9c5432ff16d6152371f808fb5a871cd67368171b09bb21b43df8e4a47a3556"
1538dependencies = [ 1574dependencies = [
1539 "proc-macro2", 1575 "proc-macro2",
1540 "quote", 1576 "quote",
@@ -1916,18 +1952,18 @@ dependencies = [
1916 1952
1917[[package]] 1953[[package]]
1918name = "xshell" 1954name = "xshell"
1919version = "0.1.0" 1955version = "0.1.6"
1920source = "registry+https://github.com/rust-lang/crates.io-index" 1956source = "registry+https://github.com/rust-lang/crates.io-index"
1921checksum = "1f7f756f2faab73adb00db44db716598ab2c9e4bce4a875c053022291bd3cab4" 1957checksum = "3e9bbfccbb2233e6b0473b7870d4b0811a402e9e249a5e8394e768e5a5c9c37d"
1922dependencies = [ 1958dependencies = [
1923 "xshell-macros", 1959 "xshell-macros",
1924] 1960]
1925 1961
1926[[package]] 1962[[package]]
1927name = "xshell-macros" 1963name = "xshell-macros"
1928version = "0.1.0" 1964version = "0.1.6"
1929source = "registry+https://github.com/rust-lang/crates.io-index" 1965source = "registry+https://github.com/rust-lang/crates.io-index"
1930checksum = "51b020c2f3132b34067e2f6ebc58f0f210624898713a8186b8cdb75d3b8c3001" 1966checksum = "b94f1c632d730a1704b21dc551a4c74fbed713cfa59593708f94943548206134"
1931 1967
1932[[package]] 1968[[package]]
1933name = "xtask" 1969name = "xtask"
diff --git a/crates/assists/src/handlers/auto_import.rs b/crates/assists/src/handlers/auto_import.rs
index 4a7059c83..e49e641b3 100644
--- a/crates/assists/src/handlers/auto_import.rs
+++ b/crates/assists/src/handlers/auto_import.rs
@@ -6,7 +6,7 @@ use crate::{
6 AssistContext, AssistId, AssistKind, Assists, GroupLabel, 6 AssistContext, AssistId, AssistKind, Assists, GroupLabel,
7}; 7};
8 8
9// Feature: Import Insertion 9// Feature: Auto Import
10// 10//
11// Using the `auto-import` assist it is possible to insert missing imports for unresolved items. 11// Using the `auto-import` assist it is possible to insert missing imports for unresolved items.
12// When inserting an import it will do so in a structured manner by keeping imports grouped, 12// When inserting an import it will do so in a structured manner by keeping imports grouped,
@@ -100,7 +100,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
100 let group = import_group_message(import_assets.import_candidate()); 100 let group = import_group_message(import_assets.import_candidate());
101 let scope = ImportScope::find_insert_use_container(import_assets.syntax_under_caret(), ctx)?; 101 let scope = ImportScope::find_insert_use_container(import_assets.syntax_under_caret(), ctx)?;
102 let syntax = scope.as_syntax_node(); 102 let syntax = scope.as_syntax_node();
103 for import in proposed_imports { 103 for (import, _) in proposed_imports {
104 acc.add_group( 104 acc.add_group(
105 &group, 105 &group,
106 AssistId("auto_import", AssistKind::QuickFix), 106 AssistId("auto_import", AssistKind::QuickFix),
diff --git a/crates/assists/src/handlers/change_visibility.rs b/crates/assists/src/handlers/change_visibility.rs
index 32dc05378..22d7c95d9 100644
--- a/crates/assists/src/handlers/change_visibility.rs
+++ b/crates/assists/src/handlers/change_visibility.rs
@@ -1,7 +1,7 @@
1use syntax::{ 1use syntax::{
2 ast::{self, NameOwner, VisibilityOwner}, 2 ast::{self, NameOwner, VisibilityOwner},
3 AstNode, 3 AstNode,
4 SyntaxKind::{CONST, ENUM, FN, MODULE, STATIC, STRUCT, TRAIT, VISIBILITY}, 4 SyntaxKind::{CONST, ENUM, FN, MODULE, STATIC, STRUCT, TRAIT, TYPE_ALIAS, VISIBILITY},
5 T, 5 T,
6}; 6};
7use test_utils::mark; 7use test_utils::mark;
@@ -30,13 +30,20 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
30 let item_keyword = ctx.token_at_offset().find(|leaf| { 30 let item_keyword = ctx.token_at_offset().find(|leaf| {
31 matches!( 31 matches!(
32 leaf.kind(), 32 leaf.kind(),
33 T![const] | T![static] | T![fn] | T![mod] | T![struct] | T![enum] | T![trait] 33 T![const]
34 | T![static]
35 | T![fn]
36 | T![mod]
37 | T![struct]
38 | T![enum]
39 | T![trait]
40 | T![type]
34 ) 41 )
35 }); 42 });
36 43
37 let (offset, target) = if let Some(keyword) = item_keyword { 44 let (offset, target) = if let Some(keyword) = item_keyword {
38 let parent = keyword.parent(); 45 let parent = keyword.parent();
39 let def_kws = vec![CONST, STATIC, FN, MODULE, STRUCT, ENUM, TRAIT]; 46 let def_kws = vec![CONST, STATIC, TYPE_ALIAS, FN, MODULE, STRUCT, ENUM, TRAIT];
40 // Parent is not a definition, can't add visibility 47 // Parent is not a definition, can't add visibility
41 if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) { 48 if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) {
42 return None; 49 return None;
@@ -160,6 +167,11 @@ mod tests {
160 } 167 }
161 168
162 #[test] 169 #[test]
170 fn change_visibility_type_alias() {
171 check_assist(change_visibility, "<|>type T = ();", "pub(crate) type T = ();");
172 }
173
174 #[test]
163 fn change_visibility_handles_comment_attrs() { 175 fn change_visibility_handles_comment_attrs() {
164 check_assist( 176 check_assist(
165 change_visibility, 177 change_visibility,
diff --git a/crates/assists/src/handlers/fill_match_arms.rs b/crates/assists/src/handlers/fill_match_arms.rs
index 676f5ad92..eda45f5b3 100644
--- a/crates/assists/src/handlers/fill_match_arms.rs
+++ b/crates/assists/src/handlers/fill_match_arms.rs
@@ -59,7 +59,7 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
59 .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat)) 59 .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat))
60 .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block())) 60 .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block()))
61 .collect::<Vec<_>>(); 61 .collect::<Vec<_>>();
62 if Some(enum_def) == FamousDefs(&ctx.sema, module.krate()).core_option_Option() { 62 if Some(enum_def) == FamousDefs(&ctx.sema, Some(module.krate())).core_option_Option() {
63 // Match `Some` variant first. 63 // Match `Some` variant first.
64 mark::hit!(option_order); 64 mark::hit!(option_order);
65 variants.reverse() 65 variants.reverse()
diff --git a/crates/assists/src/handlers/fix_visibility.rs b/crates/assists/src/handlers/fix_visibility.rs
index d505e9444..66f74150c 100644
--- a/crates/assists/src/handlers/fix_visibility.rs
+++ b/crates/assists/src/handlers/fix_visibility.rs
@@ -1,9 +1,11 @@
1use base_db::FileId; 1use base_db::FileId;
2use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution}; 2use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution};
3use syntax::{ast, AstNode, TextRange, TextSize}; 3use syntax::{
4 ast::{self, VisibilityOwner},
5 AstNode, TextRange, TextSize,
6};
4 7
5use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists}; 8use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists};
6use ast::VisibilityOwner;
7 9
8// FIXME: this really should be a fix for diagnostic, rather than an assist. 10// FIXME: this really should be a fix for diagnostic, rather than an assist.
9 11
diff --git a/crates/assists/src/handlers/generate_from_impl_for_enum.rs b/crates/assists/src/handlers/generate_from_impl_for_enum.rs
index 7f04b9572..674e5a175 100644
--- a/crates/assists/src/handlers/generate_from_impl_for_enum.rs
+++ b/crates/assists/src/handlers/generate_from_impl_for_enum.rs
@@ -75,7 +75,7 @@ fn existing_from_impl(
75 let enum_ = variant.parent_enum(sema.db); 75 let enum_ = variant.parent_enum(sema.db);
76 let krate = enum_.module(sema.db).krate(); 76 let krate = enum_.module(sema.db).krate();
77 77
78 let from_trait = FamousDefs(sema, krate).core_convert_From()?; 78 let from_trait = FamousDefs(sema, Some(krate)).core_convert_From()?;
79 79
80 let enum_type = enum_.ty(sema.db); 80 let enum_type = enum_.ty(sema.db);
81 81
diff --git a/crates/assists/src/handlers/qualify_path.rs b/crates/assists/src/handlers/qualify_path.rs
new file mode 100644
index 000000000..f436bdbbf
--- /dev/null
+++ b/crates/assists/src/handlers/qualify_path.rs
@@ -0,0 +1,1048 @@
1use std::iter;
2
3use hir::AsName;
4use ide_db::RootDatabase;
5use syntax::{
6 ast,
7 ast::{make, ArgListOwner},
8 AstNode,
9};
10use test_utils::mark;
11
12use crate::{
13 assist_context::{AssistContext, Assists},
14 utils::import_assets::{ImportAssets, ImportCandidate},
15 utils::mod_path_to_ast,
16 AssistId, AssistKind, GroupLabel,
17};
18
19// Assist: qualify_path
20//
21// If the name is unresolved, provides all possible qualified paths for it.
22//
23// ```
24// fn main() {
25// let map = HashMap<|>::new();
26// }
27// # pub mod std { pub mod collections { pub struct HashMap { } } }
28// ```
29// ->
30// ```
31// fn main() {
32// let map = std::collections::HashMap::new();
33// }
34// # pub mod std { pub mod collections { pub struct HashMap { } } }
35// ```
36pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
37 let import_assets =
38 if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() {
39 ImportAssets::for_regular_path(path_under_caret, &ctx.sema)
40 } else if let Some(method_under_caret) =
41 ctx.find_node_at_offset_with_descend::<ast::MethodCallExpr>()
42 {
43 ImportAssets::for_method_call(method_under_caret, &ctx.sema)
44 } else {
45 None
46 }?;
47 let proposed_imports = import_assets.search_for_relative_paths(&ctx.sema);
48 if proposed_imports.is_empty() {
49 return None;
50 }
51
52 let candidate = import_assets.import_candidate();
53 let range = ctx.sema.original_range(import_assets.syntax_under_caret()).range;
54
55 let qualify_candidate = match candidate {
56 ImportCandidate::QualifierStart(_) => {
57 mark::hit!(qualify_path_qualifier_start);
58 let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?;
59 let segment = path.segment()?;
60 QualifyCandidate::QualifierStart(segment)
61 }
62 ImportCandidate::UnqualifiedName(_) => {
63 mark::hit!(qualify_path_unqualified_name);
64 QualifyCandidate::UnqualifiedName
65 }
66 ImportCandidate::TraitAssocItem(_) => {
67 mark::hit!(qualify_path_trait_assoc_item);
68 let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?;
69 let (qualifier, segment) = (path.qualifier()?, path.segment()?);
70 QualifyCandidate::TraitAssocItem(qualifier, segment)
71 }
72 ImportCandidate::TraitMethod(_) => {
73 mark::hit!(qualify_path_trait_method);
74 let mcall_expr = ast::MethodCallExpr::cast(import_assets.syntax_under_caret().clone())?;
75 QualifyCandidate::TraitMethod(ctx.sema.db, mcall_expr)
76 }
77 };
78
79 let group_label = group_label(candidate);
80 for (import, item) in proposed_imports {
81 acc.add_group(
82 &group_label,
83 AssistId("qualify_path", AssistKind::QuickFix),
84 label(candidate, &import),
85 range,
86 |builder| {
87 qualify_candidate.qualify(
88 |replace_with: String| builder.replace(range, replace_with),
89 import,
90 item,
91 )
92 },
93 );
94 }
95 Some(())
96}
97
98enum QualifyCandidate<'db> {
99 QualifierStart(ast::PathSegment),
100 UnqualifiedName,
101 TraitAssocItem(ast::Path, ast::PathSegment),
102 TraitMethod(&'db RootDatabase, ast::MethodCallExpr),
103}
104
105impl QualifyCandidate<'_> {
106 fn qualify(&self, mut replacer: impl FnMut(String), import: hir::ModPath, item: hir::ItemInNs) {
107 match self {
108 QualifyCandidate::QualifierStart(segment) => {
109 let import = mod_path_to_ast(&import);
110 replacer(format!("{}::{}", import, segment));
111 }
112 QualifyCandidate::UnqualifiedName => replacer(mod_path_to_ast(&import).to_string()),
113 QualifyCandidate::TraitAssocItem(qualifier, segment) => {
114 let import = mod_path_to_ast(&import);
115 replacer(format!("<{} as {}>::{}", qualifier, import, segment));
116 }
117 &QualifyCandidate::TraitMethod(db, ref mcall_expr) => {
118 Self::qualify_trait_method(db, mcall_expr, replacer, import, item);
119 }
120 }
121 }
122
123 fn qualify_trait_method(
124 db: &RootDatabase,
125 mcall_expr: &ast::MethodCallExpr,
126 mut replacer: impl FnMut(String),
127 import: hir::ModPath,
128 item: hir::ItemInNs,
129 ) -> Option<()> {
130 let receiver = mcall_expr.receiver()?;
131 let trait_method_name = mcall_expr.name_ref()?;
132 let arg_list = mcall_expr.arg_list().map(|arg_list| arg_list.args());
133 let trait_ = item_as_trait(item)?;
134 let method = find_trait_method(db, trait_, &trait_method_name)?;
135 if let Some(self_access) = method.self_param(db).map(|sp| sp.access(db)) {
136 let import = mod_path_to_ast(&import);
137 let receiver = match self_access {
138 hir::Access::Shared => make::expr_ref(receiver, false),
139 hir::Access::Exclusive => make::expr_ref(receiver, true),
140 hir::Access::Owned => receiver,
141 };
142 replacer(format!(
143 "{}::{}{}",
144 import,
145 trait_method_name,
146 match arg_list.clone() {
147 Some(args) => make::arg_list(iter::once(receiver).chain(args)),
148 None => make::arg_list(iter::once(receiver)),
149 }
150 ));
151 }
152 Some(())
153 }
154}
155
156fn find_trait_method(
157 db: &RootDatabase,
158 trait_: hir::Trait,
159 trait_method_name: &ast::NameRef,
160) -> Option<hir::Function> {
161 if let Some(hir::AssocItem::Function(method)) =
162 trait_.items(db).into_iter().find(|item: &hir::AssocItem| {
163 item.name(db).map(|name| name == trait_method_name.as_name()).unwrap_or(false)
164 })
165 {
166 Some(method)
167 } else {
168 None
169 }
170}
171
172fn item_as_trait(item: hir::ItemInNs) -> Option<hir::Trait> {
173 if let hir::ModuleDef::Trait(trait_) = hir::ModuleDef::from(item.as_module_def_id()?) {
174 Some(trait_)
175 } else {
176 None
177 }
178}
179
180fn group_label(candidate: &ImportCandidate) -> GroupLabel {
181 let name = match candidate {
182 ImportCandidate::UnqualifiedName(it) | ImportCandidate::QualifierStart(it) => &it.name,
183 ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => &it.name,
184 };
185 GroupLabel(format!("Qualify {}", name))
186}
187
188fn label(candidate: &ImportCandidate, import: &hir::ModPath) -> String {
189 match candidate {
190 ImportCandidate::UnqualifiedName(_) => format!("Qualify as `{}`", &import),
191 ImportCandidate::QualifierStart(_) => format!("Qualify with `{}`", &import),
192 ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", &import),
193 ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", &import),
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
200
201 use super::*;
202
203 #[test]
204 fn applicable_when_found_an_import_partial() {
205 mark::check!(qualify_path_unqualified_name);
206 check_assist(
207 qualify_path,
208 r"
209 mod std {
210 pub mod fmt {
211 pub struct Formatter;
212 }
213 }
214
215 use std::fmt;
216
217 <|>Formatter
218 ",
219 r"
220 mod std {
221 pub mod fmt {
222 pub struct Formatter;
223 }
224 }
225
226 use std::fmt;
227
228 fmt::Formatter
229 ",
230 );
231 }
232
233 #[test]
234 fn applicable_when_found_an_import() {
235 check_assist(
236 qualify_path,
237 r"
238 <|>PubStruct
239
240 pub mod PubMod {
241 pub struct PubStruct;
242 }
243 ",
244 r"
245 PubMod::PubStruct
246
247 pub mod PubMod {
248 pub struct PubStruct;
249 }
250 ",
251 );
252 }
253
254 #[test]
255 fn applicable_in_macros() {
256 check_assist(
257 qualify_path,
258 r"
259 macro_rules! foo {
260 ($i:ident) => { fn foo(a: $i) {} }
261 }
262 foo!(Pub<|>Struct);
263
264 pub mod PubMod {
265 pub struct PubStruct;
266 }
267 ",
268 r"
269 macro_rules! foo {
270 ($i:ident) => { fn foo(a: $i) {} }
271 }
272 foo!(PubMod::PubStruct);
273
274 pub mod PubMod {
275 pub struct PubStruct;
276 }
277 ",
278 );
279 }
280
281 #[test]
282 fn applicable_when_found_multiple_imports() {
283 check_assist(
284 qualify_path,
285 r"
286 PubSt<|>ruct
287
288 pub mod PubMod1 {
289 pub struct PubStruct;
290 }
291 pub mod PubMod2 {
292 pub struct PubStruct;
293 }
294 pub mod PubMod3 {
295 pub struct PubStruct;
296 }
297 ",
298 r"
299 PubMod3::PubStruct
300
301 pub mod PubMod1 {
302 pub struct PubStruct;
303 }
304 pub mod PubMod2 {
305 pub struct PubStruct;
306 }
307 pub mod PubMod3 {
308 pub struct PubStruct;
309 }
310 ",
311 );
312 }
313
314 #[test]
315 fn not_applicable_for_already_imported_types() {
316 check_assist_not_applicable(
317 qualify_path,
318 r"
319 use PubMod::PubStruct;
320
321 PubStruct<|>
322
323 pub mod PubMod {
324 pub struct PubStruct;
325 }
326 ",
327 );
328 }
329
330 #[test]
331 fn not_applicable_for_types_with_private_paths() {
332 check_assist_not_applicable(
333 qualify_path,
334 r"
335 PrivateStruct<|>
336
337 pub mod PubMod {
338 struct PrivateStruct;
339 }
340 ",
341 );
342 }
343
344 #[test]
345 fn not_applicable_when_no_imports_found() {
346 check_assist_not_applicable(
347 qualify_path,
348 "
349 PubStruct<|>",
350 );
351 }
352
353 #[test]
354 fn not_applicable_in_import_statements() {
355 check_assist_not_applicable(
356 qualify_path,
357 r"
358 use PubStruct<|>;
359
360 pub mod PubMod {
361 pub struct PubStruct;
362 }",
363 );
364 }
365
366 #[test]
367 fn qualify_function() {
368 check_assist(
369 qualify_path,
370 r"
371 test_function<|>
372
373 pub mod PubMod {
374 pub fn test_function() {};
375 }
376 ",
377 r"
378 PubMod::test_function
379
380 pub mod PubMod {
381 pub fn test_function() {};
382 }
383 ",
384 );
385 }
386
387 #[test]
388 fn qualify_macro() {
389 check_assist(
390 qualify_path,
391 r"
392//- /lib.rs crate:crate_with_macro
393#[macro_export]
394macro_rules! foo {
395 () => ()
396}
397
398//- /main.rs crate:main deps:crate_with_macro
399fn main() {
400 foo<|>
401}
402",
403 r"
404fn main() {
405 crate_with_macro::foo
406}
407",
408 );
409 }
410
411 #[test]
412 fn qualify_path_target() {
413 check_assist_target(
414 qualify_path,
415 r"
416 struct AssistInfo {
417 group_label: Option<<|>GroupLabel>,
418 }
419
420 mod m { pub struct GroupLabel; }
421 ",
422 "GroupLabel",
423 )
424 }
425
426 #[test]
427 fn not_applicable_when_path_start_is_imported() {
428 check_assist_not_applicable(
429 qualify_path,
430 r"
431 pub mod mod1 {
432 pub mod mod2 {
433 pub mod mod3 {
434 pub struct TestStruct;
435 }
436 }
437 }
438
439 use mod1::mod2;
440 fn main() {
441 mod2::mod3::TestStruct<|>
442 }
443 ",
444 );
445 }
446
447 #[test]
448 fn not_applicable_for_imported_function() {
449 check_assist_not_applicable(
450 qualify_path,
451 r"
452 pub mod test_mod {
453 pub fn test_function() {}
454 }
455
456 use test_mod::test_function;
457 fn main() {
458 test_function<|>
459 }
460 ",
461 );
462 }
463
464 #[test]
465 fn associated_struct_function() {
466 check_assist(
467 qualify_path,
468 r"
469 mod test_mod {
470 pub struct TestStruct {}
471 impl TestStruct {
472 pub fn test_function() {}
473 }
474 }
475
476 fn main() {
477 TestStruct::test_function<|>
478 }
479 ",
480 r"
481 mod test_mod {
482 pub struct TestStruct {}
483 impl TestStruct {
484 pub fn test_function() {}
485 }
486 }
487
488 fn main() {
489 test_mod::TestStruct::test_function
490 }
491 ",
492 );
493 }
494
495 #[test]
496 fn associated_struct_const() {
497 mark::check!(qualify_path_qualifier_start);
498 check_assist(
499 qualify_path,
500 r"
501 mod test_mod {
502 pub struct TestStruct {}
503 impl TestStruct {
504 const TEST_CONST: u8 = 42;
505 }
506 }
507
508 fn main() {
509 TestStruct::TEST_CONST<|>
510 }
511 ",
512 r"
513 mod test_mod {
514 pub struct TestStruct {}
515 impl TestStruct {
516 const TEST_CONST: u8 = 42;
517 }
518 }
519
520 fn main() {
521 test_mod::TestStruct::TEST_CONST
522 }
523 ",
524 );
525 }
526
527 #[test]
528 fn associated_trait_function() {
529 check_assist(
530 qualify_path,
531 r"
532 mod test_mod {
533 pub trait TestTrait {
534 fn test_function();
535 }
536 pub struct TestStruct {}
537 impl TestTrait for TestStruct {
538 fn test_function() {}
539 }
540 }
541
542 fn main() {
543 test_mod::TestStruct::test_function<|>
544 }
545 ",
546 r"
547 mod test_mod {
548 pub trait TestTrait {
549 fn test_function();
550 }
551 pub struct TestStruct {}
552 impl TestTrait for TestStruct {
553 fn test_function() {}
554 }
555 }
556
557 fn main() {
558 <test_mod::TestStruct as test_mod::TestTrait>::test_function
559 }
560 ",
561 );
562 }
563
564 #[test]
565 fn not_applicable_for_imported_trait_for_function() {
566 check_assist_not_applicable(
567 qualify_path,
568 r"
569 mod test_mod {
570 pub trait TestTrait {
571 fn test_function();
572 }
573 pub trait TestTrait2 {
574 fn test_function();
575 }
576 pub enum TestEnum {
577 One,
578 Two,
579 }
580 impl TestTrait2 for TestEnum {
581 fn test_function() {}
582 }
583 impl TestTrait for TestEnum {
584 fn test_function() {}
585 }
586 }
587
588 use test_mod::TestTrait2;
589 fn main() {
590 test_mod::TestEnum::test_function<|>;
591 }
592 ",
593 )
594 }
595
596 #[test]
597 fn associated_trait_const() {
598 mark::check!(qualify_path_trait_assoc_item);
599 check_assist(
600 qualify_path,
601 r"
602 mod test_mod {
603 pub trait TestTrait {
604 const TEST_CONST: u8;
605 }
606 pub struct TestStruct {}
607 impl TestTrait for TestStruct {
608 const TEST_CONST: u8 = 42;
609 }
610 }
611
612 fn main() {
613 test_mod::TestStruct::TEST_CONST<|>
614 }
615 ",
616 r"
617 mod test_mod {
618 pub trait TestTrait {
619 const TEST_CONST: u8;
620 }
621 pub struct TestStruct {}
622 impl TestTrait for TestStruct {
623 const TEST_CONST: u8 = 42;
624 }
625 }
626
627 fn main() {
628 <test_mod::TestStruct as test_mod::TestTrait>::TEST_CONST
629 }
630 ",
631 );
632 }
633
634 #[test]
635 fn not_applicable_for_imported_trait_for_const() {
636 check_assist_not_applicable(
637 qualify_path,
638 r"
639 mod test_mod {
640 pub trait TestTrait {
641 const TEST_CONST: u8;
642 }
643 pub trait TestTrait2 {
644 const TEST_CONST: f64;
645 }
646 pub enum TestEnum {
647 One,
648 Two,
649 }
650 impl TestTrait2 for TestEnum {
651 const TEST_CONST: f64 = 42.0;
652 }
653 impl TestTrait for TestEnum {
654 const TEST_CONST: u8 = 42;
655 }
656 }
657
658 use test_mod::TestTrait2;
659 fn main() {
660 test_mod::TestEnum::TEST_CONST<|>;
661 }
662 ",
663 )
664 }
665
666 #[test]
667 fn trait_method() {
668 mark::check!(qualify_path_trait_method);
669 check_assist(
670 qualify_path,
671 r"
672 mod test_mod {
673 pub trait TestTrait {
674 fn test_method(&self);
675 }
676 pub struct TestStruct {}
677 impl TestTrait for TestStruct {
678 fn test_method(&self) {}
679 }
680 }
681
682 fn main() {
683 let test_struct = test_mod::TestStruct {};
684 test_struct.test_meth<|>od()
685 }
686 ",
687 r"
688 mod test_mod {
689 pub trait TestTrait {
690 fn test_method(&self);
691 }
692 pub struct TestStruct {}
693 impl TestTrait for TestStruct {
694 fn test_method(&self) {}
695 }
696 }
697
698 fn main() {
699 let test_struct = test_mod::TestStruct {};
700 test_mod::TestTrait::test_method(&test_struct)
701 }
702 ",
703 );
704 }
705
706 #[test]
707 fn trait_method_multi_params() {
708 check_assist(
709 qualify_path,
710 r"
711 mod test_mod {
712 pub trait TestTrait {
713 fn test_method(&self, test: i32);
714 }
715 pub struct TestStruct {}
716 impl TestTrait for TestStruct {
717 fn test_method(&self, test: i32) {}
718 }
719 }
720
721 fn main() {
722 let test_struct = test_mod::TestStruct {};
723 test_struct.test_meth<|>od(42)
724 }
725 ",
726 r"
727 mod test_mod {
728 pub trait TestTrait {
729 fn test_method(&self, test: i32);
730 }
731 pub struct TestStruct {}
732 impl TestTrait for TestStruct {
733 fn test_method(&self, test: i32) {}
734 }
735 }
736
737 fn main() {
738 let test_struct = test_mod::TestStruct {};
739 test_mod::TestTrait::test_method(&test_struct, 42)
740 }
741 ",
742 );
743 }
744
745 #[test]
746 fn trait_method_consume() {
747 check_assist(
748 qualify_path,
749 r"
750 mod test_mod {
751 pub trait TestTrait {
752 fn test_method(self);
753 }
754 pub struct TestStruct {}
755 impl TestTrait for TestStruct {
756 fn test_method(self) {}
757 }
758 }
759
760 fn main() {
761 let test_struct = test_mod::TestStruct {};
762 test_struct.test_meth<|>od()
763 }
764 ",
765 r"
766 mod test_mod {
767 pub trait TestTrait {
768 fn test_method(self);
769 }
770 pub struct TestStruct {}
771 impl TestTrait for TestStruct {
772 fn test_method(self) {}
773 }
774 }
775
776 fn main() {
777 let test_struct = test_mod::TestStruct {};
778 test_mod::TestTrait::test_method(test_struct)
779 }
780 ",
781 );
782 }
783
784 #[test]
785 fn trait_method_cross_crate() {
786 check_assist(
787 qualify_path,
788 r"
789 //- /main.rs crate:main deps:dep
790 fn main() {
791 let test_struct = dep::test_mod::TestStruct {};
792 test_struct.test_meth<|>od()
793 }
794 //- /dep.rs crate:dep
795 pub mod test_mod {
796 pub trait TestTrait {
797 fn test_method(&self);
798 }
799 pub struct TestStruct {}
800 impl TestTrait for TestStruct {
801 fn test_method(&self) {}
802 }
803 }
804 ",
805 r"
806 fn main() {
807 let test_struct = dep::test_mod::TestStruct {};
808 dep::test_mod::TestTrait::test_method(&test_struct)
809 }
810 ",
811 );
812 }
813
814 #[test]
815 fn assoc_fn_cross_crate() {
816 check_assist(
817 qualify_path,
818 r"
819 //- /main.rs crate:main deps:dep
820 fn main() {
821 dep::test_mod::TestStruct::test_func<|>tion
822 }
823 //- /dep.rs crate:dep
824 pub mod test_mod {
825 pub trait TestTrait {
826 fn test_function();
827 }
828 pub struct TestStruct {}
829 impl TestTrait for TestStruct {
830 fn test_function() {}
831 }
832 }
833 ",
834 r"
835 fn main() {
836 <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::test_function
837 }
838 ",
839 );
840 }
841
842 #[test]
843 fn assoc_const_cross_crate() {
844 check_assist(
845 qualify_path,
846 r"
847 //- /main.rs crate:main deps:dep
848 fn main() {
849 dep::test_mod::TestStruct::CONST<|>
850 }
851 //- /dep.rs crate:dep
852 pub mod test_mod {
853 pub trait TestTrait {
854 const CONST: bool;
855 }
856 pub struct TestStruct {}
857 impl TestTrait for TestStruct {
858 const CONST: bool = true;
859 }
860 }
861 ",
862 r"
863 fn main() {
864 <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::CONST
865 }
866 ",
867 );
868 }
869
870 #[test]
871 fn assoc_fn_as_method_cross_crate() {
872 check_assist_not_applicable(
873 qualify_path,
874 r"
875 //- /main.rs crate:main deps:dep
876 fn main() {
877 let test_struct = dep::test_mod::TestStruct {};
878 test_struct.test_func<|>tion()
879 }
880 //- /dep.rs crate:dep
881 pub mod test_mod {
882 pub trait TestTrait {
883 fn test_function();
884 }
885 pub struct TestStruct {}
886 impl TestTrait for TestStruct {
887 fn test_function() {}
888 }
889 }
890 ",
891 );
892 }
893
894 #[test]
895 fn private_trait_cross_crate() {
896 check_assist_not_applicable(
897 qualify_path,
898 r"
899 //- /main.rs crate:main deps:dep
900 fn main() {
901 let test_struct = dep::test_mod::TestStruct {};
902 test_struct.test_meth<|>od()
903 }
904 //- /dep.rs crate:dep
905 pub mod test_mod {
906 trait TestTrait {
907 fn test_method(&self);
908 }
909 pub struct TestStruct {}
910 impl TestTrait for TestStruct {
911 fn test_method(&self) {}
912 }
913 }
914 ",
915 );
916 }
917
918 #[test]
919 fn not_applicable_for_imported_trait_for_method() {
920 check_assist_not_applicable(
921 qualify_path,
922 r"
923 mod test_mod {
924 pub trait TestTrait {
925 fn test_method(&self);
926 }
927 pub trait TestTrait2 {
928 fn test_method(&self);
929 }
930 pub enum TestEnum {
931 One,
932 Two,
933 }
934 impl TestTrait2 for TestEnum {
935 fn test_method(&self) {}
936 }
937 impl TestTrait for TestEnum {
938 fn test_method(&self) {}
939 }
940 }
941
942 use test_mod::TestTrait2;
943 fn main() {
944 let one = test_mod::TestEnum::One;
945 one.test<|>_method();
946 }
947 ",
948 )
949 }
950
951 #[test]
952 fn dep_import() {
953 check_assist(
954 qualify_path,
955 r"
956//- /lib.rs crate:dep
957pub struct Struct;
958
959//- /main.rs crate:main deps:dep
960fn main() {
961 Struct<|>
962}
963",
964 r"
965fn main() {
966 dep::Struct
967}
968",
969 );
970 }
971
972 #[test]
973 fn whole_segment() {
974 // Tests that only imports whose last segment matches the identifier get suggested.
975 check_assist(
976 qualify_path,
977 r"
978//- /lib.rs crate:dep
979pub mod fmt {
980 pub trait Display {}
981}
982
983pub fn panic_fmt() {}
984
985//- /main.rs crate:main deps:dep
986struct S;
987
988impl f<|>mt::Display for S {}
989",
990 r"
991struct S;
992
993impl dep::fmt::Display for S {}
994",
995 );
996 }
997
998 #[test]
999 fn macro_generated() {
1000 // Tests that macro-generated items are suggested from external crates.
1001 check_assist(
1002 qualify_path,
1003 r"
1004//- /lib.rs crate:dep
1005macro_rules! mac {
1006 () => {
1007 pub struct Cheese;
1008 };
1009}
1010
1011mac!();
1012
1013//- /main.rs crate:main deps:dep
1014fn main() {
1015 Cheese<|>;
1016}
1017",
1018 r"
1019fn main() {
1020 dep::Cheese;
1021}
1022",
1023 );
1024 }
1025
1026 #[test]
1027 fn casing() {
1028 // Tests that differently cased names don't interfere and we only suggest the matching one.
1029 check_assist(
1030 qualify_path,
1031 r"
1032//- /lib.rs crate:dep
1033pub struct FMT;
1034pub struct fmt;
1035
1036//- /main.rs crate:main deps:dep
1037fn main() {
1038 FMT<|>;
1039}
1040",
1041 r"
1042fn main() {
1043 dep::FMT;
1044}
1045",
1046 );
1047 }
1048}
diff --git a/crates/assists/src/handlers/replace_string_with_char.rs b/crates/assists/src/handlers/replace_string_with_char.rs
new file mode 100644
index 000000000..4ca87a8ec
--- /dev/null
+++ b/crates/assists/src/handlers/replace_string_with_char.rs
@@ -0,0 +1,141 @@
1use syntax::{
2 ast::{self, HasStringValue},
3 AstToken,
4 SyntaxKind::STRING,
5};
6
7use crate::{AssistContext, AssistId, AssistKind, Assists};
8
9// Assist: replace_string_with_char
10//
11// Replace string with char.
12//
13// ```
14// fn main() {
15// find("{<|>");
16// }
17// ```
18// ->
19// ```
20// fn main() {
21// find('{');
22// }
23// ```
24pub(crate) fn replace_string_with_char(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
25 let token = ctx.find_token_at_offset(STRING).and_then(ast::String::cast)?;
26 let value = token.value()?;
27 let target = token.syntax().text_range();
28
29 if value.chars().take(2).count() != 1 {
30 return None;
31 }
32
33 acc.add(
34 AssistId("replace_string_with_char", AssistKind::RefactorRewrite),
35 "Replace string with char",
36 target,
37 |edit| {
38 edit.replace(token.syntax().text_range(), format!("'{}'", value));
39 },
40 )
41}
42
43#[cfg(test)]
44mod tests {
45 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
46
47 use super::*;
48
49 #[test]
50 fn replace_string_with_char_target() {
51 check_assist_target(
52 replace_string_with_char,
53 r#"
54 fn f() {
55 let s = "<|>c";
56 }
57 "#,
58 r#""c""#,
59 );
60 }
61
62 #[test]
63 fn replace_string_with_char_assist() {
64 check_assist(
65 replace_string_with_char,
66 r#"
67 fn f() {
68 let s = "<|>c";
69 }
70 "#,
71 r##"
72 fn f() {
73 let s = 'c';
74 }
75 "##,
76 )
77 }
78
79 #[test]
80 fn replace_string_with_char_assist_with_emoji() {
81 check_assist(
82 replace_string_with_char,
83 r#"
84 fn f() {
85 let s = "<|>😀";
86 }
87 "#,
88 r##"
89 fn f() {
90 let s = '😀';
91 }
92 "##,
93 )
94 }
95
96 #[test]
97 fn replace_string_with_char_assist_not_applicable() {
98 check_assist_not_applicable(
99 replace_string_with_char,
100 r#"
101 fn f() {
102 let s = "<|>test";
103 }
104 "#,
105 )
106 }
107
108 #[test]
109 fn replace_string_with_char_works_inside_macros() {
110 check_assist(
111 replace_string_with_char,
112 r#"
113 fn f() {
114 format!(<|>"x", 92)
115 }
116 "#,
117 r##"
118 fn f() {
119 format!('x', 92)
120 }
121 "##,
122 )
123 }
124
125 #[test]
126 fn replace_string_with_char_works_func_args() {
127 check_assist(
128 replace_string_with_char,
129 r#"
130 fn f() {
131 find(<|>"x");
132 }
133 "#,
134 r##"
135 fn f() {
136 find('x');
137 }
138 "##,
139 )
140 }
141}
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs
index a2bec818c..8a664f654 100644
--- a/crates/assists/src/lib.rs
+++ b/crates/assists/src/lib.rs
@@ -150,6 +150,7 @@ mod handlers {
150 mod merge_match_arms; 150 mod merge_match_arms;
151 mod move_bounds; 151 mod move_bounds;
152 mod move_guard; 152 mod move_guard;
153 mod qualify_path;
153 mod raw_string; 154 mod raw_string;
154 mod remove_dbg; 155 mod remove_dbg;
155 mod remove_mut; 156 mod remove_mut;
@@ -159,6 +160,7 @@ mod handlers {
159 mod replace_impl_trait_with_generic; 160 mod replace_impl_trait_with_generic;
160 mod replace_let_with_if_let; 161 mod replace_let_with_if_let;
161 mod replace_qualified_name_with_use; 162 mod replace_qualified_name_with_use;
163 mod replace_string_with_char;
162 mod replace_unwrap_with_match; 164 mod replace_unwrap_with_match;
163 mod split_import; 165 mod split_import;
164 mod unwrap_block; 166 mod unwrap_block;
@@ -196,6 +198,7 @@ mod handlers {
196 move_bounds::move_bounds_to_where_clause, 198 move_bounds::move_bounds_to_where_clause,
197 move_guard::move_arm_cond_to_match_guard, 199 move_guard::move_arm_cond_to_match_guard,
198 move_guard::move_guard_to_arm_body, 200 move_guard::move_guard_to_arm_body,
201 qualify_path::qualify_path,
199 raw_string::add_hash, 202 raw_string::add_hash,
200 raw_string::make_raw_string, 203 raw_string::make_raw_string,
201 raw_string::make_usual_string, 204 raw_string::make_usual_string,
@@ -208,6 +211,7 @@ mod handlers {
208 replace_impl_trait_with_generic::replace_impl_trait_with_generic, 211 replace_impl_trait_with_generic::replace_impl_trait_with_generic,
209 replace_let_with_if_let::replace_let_with_if_let, 212 replace_let_with_if_let::replace_let_with_if_let,
210 replace_qualified_name_with_use::replace_qualified_name_with_use, 213 replace_qualified_name_with_use::replace_qualified_name_with_use,
214 replace_string_with_char::replace_string_with_char,
211 replace_unwrap_with_match::replace_unwrap_with_match, 215 replace_unwrap_with_match::replace_unwrap_with_match,
212 split_import::split_import, 216 split_import::split_import,
213 unwrap_block::unwrap_block, 217 unwrap_block::unwrap_block,
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs
index 41f536574..acbf5b652 100644
--- a/crates/assists/src/tests/generated.rs
+++ b/crates/assists/src/tests/generated.rs
@@ -713,6 +713,25 @@ fn handle(action: Action) {
713} 713}
714 714
715#[test] 715#[test]
716fn doctest_qualify_path() {
717 check_doc_test(
718 "qualify_path",
719 r#####"
720fn main() {
721 let map = HashMap<|>::new();
722}
723pub mod std { pub mod collections { pub struct HashMap { } } }
724"#####,
725 r#####"
726fn main() {
727 let map = std::collections::HashMap::new();
728}
729pub mod std { pub mod collections { pub struct HashMap { } } }
730"#####,
731 )
732}
733
734#[test]
716fn doctest_remove_dbg() { 735fn doctest_remove_dbg() {
717 check_doc_test( 736 check_doc_test(
718 "remove_dbg", 737 "remove_dbg",
@@ -882,6 +901,23 @@ fn process(map: HashMap<String, String>) {}
882} 901}
883 902
884#[test] 903#[test]
904fn doctest_replace_string_with_char() {
905 check_doc_test(
906 "replace_string_with_char",
907 r#####"
908fn main() {
909 find("{<|>");
910}
911"#####,
912 r#####"
913fn main() {
914 find('{');
915}
916"#####,
917 )
918}
919
920#[test]
885fn doctest_replace_unwrap_with_match() { 921fn doctest_replace_unwrap_with_match() {
886 check_doc_test( 922 check_doc_test(
887 "replace_unwrap_with_match", 923 "replace_unwrap_with_match",
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs
index b37b0d2b6..1a6b48b45 100644
--- a/crates/assists/src/utils.rs
+++ b/crates/assists/src/utils.rs
@@ -275,7 +275,7 @@ impl TryEnum {
275/// somewhat similar to the known paths infra inside hir, but it different; We 275/// somewhat similar to the known paths infra inside hir, but it different; We
276/// want to make sure that IDE specific paths don't become interesting inside 276/// want to make sure that IDE specific paths don't become interesting inside
277/// the compiler itself as well. 277/// the compiler itself as well.
278pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Crate); 278pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Option<Crate>);
279 279
280#[allow(non_snake_case)] 280#[allow(non_snake_case)]
281impl FamousDefs<'_, '_> { 281impl FamousDefs<'_, '_> {
@@ -362,6 +362,10 @@ pub mod prelude {
362pub use prelude::*; 362pub use prelude::*;
363"#; 363"#;
364 364
365 pub fn core(&self) -> Option<Crate> {
366 self.find_crate("core")
367 }
368
365 pub(crate) fn core_convert_From(&self) -> Option<Trait> { 369 pub(crate) fn core_convert_From(&self) -> Option<Trait> {
366 self.find_trait("core:convert:From") 370 self.find_trait("core:convert:From")
367 } 371 }
@@ -399,21 +403,20 @@ pub use prelude::*;
399 } 403 }
400 } 404 }
401 405
406 fn find_crate(&self, name: &str) -> Option<Crate> {
407 let krate = self.1?;
408 let db = self.0.db;
409 let res =
410 krate.dependencies(db).into_iter().find(|dep| dep.name.to_string() == name)?.krate;
411 Some(res)
412 }
413
402 fn find_def(&self, path: &str) -> Option<ScopeDef> { 414 fn find_def(&self, path: &str) -> Option<ScopeDef> {
403 let db = self.0.db; 415 let db = self.0.db;
404 let mut path = path.split(':'); 416 let mut path = path.split(':');
405 let trait_ = path.next_back()?; 417 let trait_ = path.next_back()?;
406 let std_crate = path.next()?; 418 let std_crate = path.next()?;
407 let std_crate = if self 419 let std_crate = self.find_crate(std_crate)?;
408 .1
409 .declaration_name(db)
410 .map(|name| name.to_string() == std_crate)
411 .unwrap_or(false)
412 {
413 self.1
414 } else {
415 self.1.dependencies(db).into_iter().find(|dep| dep.name.to_string() == std_crate)?.krate
416 };
417 let mut module = std_crate.root_module(db); 420 let mut module = std_crate.root_module(db);
418 for segment in path { 421 for segment in path {
419 module = module.children(db).find_map(|child| { 422 module = module.children(db).find_map(|child| {
diff --git a/crates/assists/src/utils/import_assets.rs b/crates/assists/src/utils/import_assets.rs
index 601f51098..23db3a74b 100644
--- a/crates/assists/src/utils/import_assets.rs
+++ b/crates/assists/src/utils/import_assets.rs
@@ -1,6 +1,4 @@
1//! Look up accessible paths for items. 1//! Look up accessible paths for items.
2use std::collections::BTreeSet;
3
4use either::Either; 2use either::Either;
5use hir::{AsAssocItem, AssocItemContainer, ModuleDef, Semantics}; 3use hir::{AsAssocItem, AssocItemContainer, ModuleDef, Semantics};
6use ide_db::{imports_locator, RootDatabase}; 4use ide_db::{imports_locator, RootDatabase};
@@ -29,12 +27,12 @@ pub(crate) enum ImportCandidate {
29#[derive(Debug)] 27#[derive(Debug)]
30pub(crate) struct TraitImportCandidate { 28pub(crate) struct TraitImportCandidate {
31 pub ty: hir::Type, 29 pub ty: hir::Type,
32 pub name: String, 30 pub name: ast::NameRef,
33} 31}
34 32
35#[derive(Debug)] 33#[derive(Debug)]
36pub(crate) struct PathImportCandidate { 34pub(crate) struct PathImportCandidate {
37 pub name: String, 35 pub name: ast::NameRef,
38} 36}
39 37
40#[derive(Debug)] 38#[derive(Debug)]
@@ -86,9 +84,9 @@ impl ImportAssets {
86 fn get_search_query(&self) -> &str { 84 fn get_search_query(&self) -> &str {
87 match &self.import_candidate { 85 match &self.import_candidate {
88 ImportCandidate::UnqualifiedName(candidate) 86 ImportCandidate::UnqualifiedName(candidate)
89 | ImportCandidate::QualifierStart(candidate) => &candidate.name, 87 | ImportCandidate::QualifierStart(candidate) => candidate.name.text(),
90 ImportCandidate::TraitAssocItem(candidate) 88 ImportCandidate::TraitAssocItem(candidate)
91 | ImportCandidate::TraitMethod(candidate) => &candidate.name, 89 | ImportCandidate::TraitMethod(candidate) => candidate.name.text(),
92 } 90 }
93 } 91 }
94 92
@@ -96,7 +94,7 @@ impl ImportAssets {
96 &self, 94 &self,
97 sema: &Semantics<RootDatabase>, 95 sema: &Semantics<RootDatabase>,
98 config: &InsertUseConfig, 96 config: &InsertUseConfig,
99 ) -> BTreeSet<hir::ModPath> { 97 ) -> Vec<(hir::ModPath, hir::ItemInNs)> {
100 let _p = profile::span("import_assists::search_for_imports"); 98 let _p = profile::span("import_assists::search_for_imports");
101 self.search_for(sema, Some(config.prefix_kind)) 99 self.search_for(sema, Some(config.prefix_kind))
102 } 100 }
@@ -106,7 +104,7 @@ impl ImportAssets {
106 pub(crate) fn search_for_relative_paths( 104 pub(crate) fn search_for_relative_paths(
107 &self, 105 &self,
108 sema: &Semantics<RootDatabase>, 106 sema: &Semantics<RootDatabase>,
109 ) -> BTreeSet<hir::ModPath> { 107 ) -> Vec<(hir::ModPath, hir::ItemInNs)> {
110 let _p = profile::span("import_assists::search_for_relative_paths"); 108 let _p = profile::span("import_assists::search_for_relative_paths");
111 self.search_for(sema, None) 109 self.search_for(sema, None)
112 } 110 }
@@ -115,7 +113,7 @@ impl ImportAssets {
115 &self, 113 &self,
116 sema: &Semantics<RootDatabase>, 114 sema: &Semantics<RootDatabase>,
117 prefixed: Option<hir::PrefixKind>, 115 prefixed: Option<hir::PrefixKind>,
118 ) -> BTreeSet<hir::ModPath> { 116 ) -> Vec<(hir::ModPath, hir::ItemInNs)> {
119 let db = sema.db; 117 let db = sema.db;
120 let mut trait_candidates = FxHashSet::default(); 118 let mut trait_candidates = FxHashSet::default();
121 let current_crate = self.module_with_name_to_import.krate(); 119 let current_crate = self.module_with_name_to_import.krate();
@@ -181,7 +179,7 @@ impl ImportAssets {
181 } 179 }
182 }; 180 };
183 181
184 imports_locator::find_imports(sema, current_crate, &self.get_search_query()) 182 let mut res = imports_locator::find_imports(sema, current_crate, &self.get_search_query())
185 .into_iter() 183 .into_iter()
186 .filter_map(filter) 184 .filter_map(filter)
187 .filter_map(|candidate| { 185 .filter_map(|candidate| {
@@ -191,10 +189,13 @@ impl ImportAssets {
191 } else { 189 } else {
192 self.module_with_name_to_import.find_use_path(db, item) 190 self.module_with_name_to_import.find_use_path(db, item)
193 } 191 }
192 .map(|path| (path, item))
194 }) 193 })
195 .filter(|use_path| !use_path.segments.is_empty()) 194 .filter(|(use_path, _)| !use_path.segments.is_empty())
196 .take(20) 195 .take(20)
197 .collect::<BTreeSet<_>>() 196 .collect::<Vec<_>>();
197 res.sort_by_key(|(path, _)| path.clone());
198 res
198 } 199 }
199 200
200 fn assoc_to_trait(assoc: AssocItemContainer) -> Option<hir::Trait> { 201 fn assoc_to_trait(assoc: AssocItemContainer) -> Option<hir::Trait> {
@@ -215,7 +216,7 @@ impl ImportCandidate {
215 Some(_) => None, 216 Some(_) => None,
216 None => Some(Self::TraitMethod(TraitImportCandidate { 217 None => Some(Self::TraitMethod(TraitImportCandidate {
217 ty: sema.type_of_expr(&method_call.receiver()?)?, 218 ty: sema.type_of_expr(&method_call.receiver()?)?,
218 name: method_call.name_ref()?.syntax().to_string(), 219 name: method_call.name_ref()?,
219 })), 220 })),
220 } 221 }
221 } 222 }
@@ -243,24 +244,17 @@ impl ImportCandidate {
243 hir::PathResolution::Def(hir::ModuleDef::Adt(assoc_item_path)) => { 244 hir::PathResolution::Def(hir::ModuleDef::Adt(assoc_item_path)) => {
244 ImportCandidate::TraitAssocItem(TraitImportCandidate { 245 ImportCandidate::TraitAssocItem(TraitImportCandidate {
245 ty: assoc_item_path.ty(sema.db), 246 ty: assoc_item_path.ty(sema.db),
246 name: segment.syntax().to_string(), 247 name: segment.name_ref()?,
247 }) 248 })
248 } 249 }
249 _ => return None, 250 _ => return None,
250 } 251 }
251 } else { 252 } else {
252 ImportCandidate::QualifierStart(PathImportCandidate { 253 ImportCandidate::QualifierStart(PathImportCandidate { name: qualifier_start })
253 name: qualifier_start.syntax().to_string(),
254 })
255 } 254 }
256 } else { 255 } else {
257 ImportCandidate::UnqualifiedName(PathImportCandidate { 256 ImportCandidate::UnqualifiedName(PathImportCandidate {
258 name: segment 257 name: segment.syntax().descendants().find_map(ast::NameRef::cast)?,
259 .syntax()
260 .descendants()
261 .find_map(ast::NameRef::cast)?
262 .syntax()
263 .to_string(),
264 }) 258 })
265 }; 259 };
266 Some(candidate) 260 Some(candidate)
diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs
index 72f1fd667..66e6443cb 100644
--- a/crates/base_db/src/fixture.rs
+++ b/crates/base_db/src/fixture.rs
@@ -158,7 +158,7 @@ impl ChangeFixture {
158 let crate_id = crate_graph.add_crate_root( 158 let crate_id = crate_graph.add_crate_root(
159 file_id, 159 file_id,
160 meta.edition, 160 meta.edition,
161 Some(crate_name.clone()), 161 Some(crate_name.clone().into()),
162 meta.cfg, 162 meta.cfg,
163 meta.env, 163 meta.env,
164 Default::default(), 164 Default::default(),
@@ -187,7 +187,7 @@ impl ChangeFixture {
187 crate_graph.add_crate_root( 187 crate_graph.add_crate_root(
188 crate_root, 188 crate_root,
189 Edition::Edition2018, 189 Edition::Edition2018,
190 Some(CrateName::new("test").unwrap()), 190 Some(CrateName::new("test").unwrap().into()),
191 default_cfg, 191 default_cfg,
192 Env::default(), 192 Env::default(),
193 Default::default(), 193 Default::default(),
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs
index 215ac4b41..87f0a0ce5 100644
--- a/crates/base_db/src/input.rs
+++ b/crates/base_db/src/input.rs
@@ -102,11 +102,46 @@ impl fmt::Display for CrateName {
102 102
103impl ops::Deref for CrateName { 103impl ops::Deref for CrateName {
104 type Target = str; 104 type Target = str;
105 fn deref(&self) -> &Self::Target { 105 fn deref(&self) -> &str {
106 &*self.0 106 &*self.0
107 } 107 }
108} 108}
109 109
110#[derive(Debug, Clone, PartialEq, Eq, Hash)]
111pub struct CrateDisplayName {
112 // The name we use to display various paths (with `_`).
113 crate_name: CrateName,
114 // The name as specified in Cargo.toml (with `-`).
115 canonical_name: String,
116}
117
118impl From<CrateName> for CrateDisplayName {
119 fn from(crate_name: CrateName) -> CrateDisplayName {
120 let canonical_name = crate_name.to_string();
121 CrateDisplayName { crate_name, canonical_name }
122 }
123}
124
125impl fmt::Display for CrateDisplayName {
126 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
127 write!(f, "{}", self.crate_name)
128 }
129}
130
131impl ops::Deref for CrateDisplayName {
132 type Target = str;
133 fn deref(&self) -> &str {
134 &*self.crate_name
135 }
136}
137
138impl CrateDisplayName {
139 pub fn from_canonical_name(canonical_name: String) -> CrateDisplayName {
140 let crate_name = CrateName::normalize_dashes(&canonical_name);
141 CrateDisplayName { crate_name, canonical_name }
142 }
143}
144
110#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 145#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
111pub struct ProcMacroId(pub u32); 146pub struct ProcMacroId(pub u32);
112 147
@@ -127,11 +162,13 @@ impl PartialEq for ProcMacro {
127pub struct CrateData { 162pub struct CrateData {
128 pub root_file_id: FileId, 163 pub root_file_id: FileId,
129 pub edition: Edition, 164 pub edition: Edition,
130 /// A name used in the package's project declaration: for Cargo projects, it's [package].name, 165 /// A name used in the package's project declaration: for Cargo projects,
131 /// can be different for other project types or even absent (a dummy crate for the code snippet, for example). 166 /// it's [package].name, can be different for other project types or even
132 /// NOTE: The crate can be referenced as a dependency under a different name, 167 /// absent (a dummy crate for the code snippet, for example).
133 /// this one should be used when working with crate hierarchies. 168 ///
134 pub declaration_name: Option<CrateName>, 169 /// For purposes of analysis, crates are anonymous (only names in
170 /// `Dependency` matters), this name should only be used for UI.
171 pub display_name: Option<CrateDisplayName>,
135 pub cfg_options: CfgOptions, 172 pub cfg_options: CfgOptions,
136 pub env: Env, 173 pub env: Env,
137 pub dependencies: Vec<Dependency>, 174 pub dependencies: Vec<Dependency>,
@@ -160,7 +197,7 @@ impl CrateGraph {
160 &mut self, 197 &mut self,
161 file_id: FileId, 198 file_id: FileId,
162 edition: Edition, 199 edition: Edition,
163 declaration_name: Option<CrateName>, 200 display_name: Option<CrateDisplayName>,
164 cfg_options: CfgOptions, 201 cfg_options: CfgOptions,
165 env: Env, 202 env: Env,
166 proc_macro: Vec<(SmolStr, Arc<dyn tt::TokenExpander>)>, 203 proc_macro: Vec<(SmolStr, Arc<dyn tt::TokenExpander>)>,
@@ -171,7 +208,7 @@ impl CrateGraph {
171 let data = CrateData { 208 let data = CrateData {
172 root_file_id: file_id, 209 root_file_id: file_id,
173 edition, 210 edition,
174 declaration_name, 211 display_name,
175 cfg_options, 212 cfg_options,
176 env, 213 env,
177 proc_macro, 214 proc_macro,
@@ -290,6 +327,29 @@ impl CrateGraph {
290 } 327 }
291 false 328 false
292 } 329 }
330
331 // Work around for https://github.com/rust-analyzer/rust-analyzer/issues/6038.
332 // As hacky as it gets.
333 pub fn patch_cfg_if(&mut self) -> bool {
334 let cfg_if = self.hacky_find_crate("cfg_if");
335 let std = self.hacky_find_crate("std");
336 match (cfg_if, std) {
337 (Some(cfg_if), Some(std)) => {
338 self.arena.get_mut(&cfg_if).unwrap().dependencies.clear();
339 self.arena
340 .get_mut(&std)
341 .unwrap()
342 .dependencies
343 .push(Dependency { crate_id: cfg_if, name: CrateName::new("cfg_if").unwrap() });
344 true
345 }
346 _ => false,
347 }
348 }
349
350 fn hacky_find_crate(&self, display_name: &str) -> Option<CrateId> {
351 self.iter().find(|it| self[*it].display_name.as_deref() == Some(display_name))
352 }
293} 353}
294 354
295impl ops::Index<CrateId> for CrateGraph { 355impl ops::Index<CrateId> for CrateGraph {
diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs
index e38aa7257..0804202d6 100644
--- a/crates/base_db/src/lib.rs
+++ b/crates/base_db/src/lib.rs
@@ -13,8 +13,8 @@ pub use crate::{
13 cancellation::Canceled, 13 cancellation::Canceled,
14 change::Change, 14 change::Change,
15 input::{ 15 input::{
16 CrateData, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, FileId, ProcMacroId, 16 CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, Dependency, Edition, Env,
17 SourceRoot, SourceRootId, 17 FileId, ProcMacroId, SourceRoot, SourceRootId,
18 }, 18 },
19}; 19};
20pub use salsa; 20pub use salsa;
diff --git a/crates/call_info/Cargo.toml b/crates/call_info/Cargo.toml
new file mode 100644
index 000000000..98c0bd6db
--- /dev/null
+++ b/crates/call_info/Cargo.toml
@@ -0,0 +1,26 @@
1[package]
2name = "call_info"
3version = "0.0.0"
4description = "TBD"
5license = "MIT OR Apache-2.0"
6authors = ["rust-analyzer developers"]
7edition = "2018"
8
9[lib]
10doctest = false
11
12[dependencies]
13either = "1.5.3"
14
15stdx = { path = "../stdx", version = "0.0.0" }
16syntax = { path = "../syntax", version = "0.0.0" }
17base_db = { path = "../base_db", version = "0.0.0" }
18ide_db = { path = "../ide_db", version = "0.0.0" }
19test_utils = { path = "../test_utils", version = "0.0.0" }
20
21# call_info crate should depend only on the top-level `hir` package. if you need
22# something from some `hir_xxx` subpackage, reexport the API via `hir`.
23hir = { path = "../hir", version = "0.0.0" }
24
25[dev-dependencies]
26expect-test = "1.0"
diff --git a/crates/ide/src/call_info.rs b/crates/call_info/src/lib.rs
index d7b2b926e..c45406c25 100644
--- a/crates/ide/src/call_info.rs
+++ b/crates/call_info/src/lib.rs
@@ -1,4 +1,5 @@
1//! FIXME: write short doc here 1//! This crate provides primitives for tracking the information about a call site.
2use base_db::FilePosition;
2use either::Either; 3use either::Either;
3use hir::{HasAttrs, HirDisplay, Semantics, Type}; 4use hir::{HasAttrs, HirDisplay, Semantics, Type};
4use ide_db::RootDatabase; 5use ide_db::RootDatabase;
@@ -9,8 +10,6 @@ use syntax::{
9}; 10};
10use test_utils::mark; 11use test_utils::mark;
11 12
12use crate::FilePosition;
13
14/// Contains information about a call site. Specifically the 13/// Contains information about a call site. Specifically the
15/// `FunctionSignature`and current parameter. 14/// `FunctionSignature`and current parameter.
16#[derive(Debug)] 15#[derive(Debug)]
@@ -40,7 +39,7 @@ impl CallInfo {
40} 39}
41 40
42/// Computes parameter information for the given call expression. 41/// Computes parameter information for the given call expression.
43pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> { 42pub fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> {
44 let sema = Semantics::new(db); 43 let sema = Semantics::new(db);
45 let file = sema.parse(position.file_id); 44 let file = sema.parse(position.file_id);
46 let file = file.syntax(); 45 let file = file.syntax();
@@ -141,13 +140,13 @@ fn call_info_impl(
141} 140}
142 141
143#[derive(Debug)] 142#[derive(Debug)]
144pub(crate) struct ActiveParameter { 143pub struct ActiveParameter {
145 pub(crate) ty: Type, 144 pub ty: Type,
146 pub(crate) name: String, 145 pub name: String,
147} 146}
148 147
149impl ActiveParameter { 148impl ActiveParameter {
150 pub(crate) fn at(db: &RootDatabase, position: FilePosition) -> Option<Self> { 149 pub fn at(db: &RootDatabase, position: FilePosition) -> Option<Self> {
151 let sema = Semantics::new(db); 150 let sema = Semantics::new(db);
152 let file = sema.parse(position.file_id); 151 let file = sema.parse(position.file_id);
153 let file = file.syntax(); 152 let file = file.syntax();
@@ -156,7 +155,7 @@ impl ActiveParameter {
156 Self::at_token(&sema, token) 155 Self::at_token(&sema, token)
157 } 156 }
158 157
159 pub(crate) fn at_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Self> { 158 pub fn at_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Self> {
160 let (signature, active_parameter) = call_info_impl(&sema, token)?; 159 let (signature, active_parameter) = call_info_impl(&sema, token)?;
161 160
162 let idx = active_parameter?; 161 let idx = active_parameter?;
@@ -172,7 +171,7 @@ impl ActiveParameter {
172} 171}
173 172
174#[derive(Debug)] 173#[derive(Debug)]
175pub(crate) enum FnCallNode { 174pub enum FnCallNode {
176 CallExpr(ast::CallExpr), 175 CallExpr(ast::CallExpr),
177 MethodCallExpr(ast::MethodCallExpr), 176 MethodCallExpr(ast::MethodCallExpr),
178} 177}
@@ -196,7 +195,7 @@ impl FnCallNode {
196 }) 195 })
197 } 196 }
198 197
199 pub(crate) fn with_node_exact(node: &SyntaxNode) -> Option<FnCallNode> { 198 pub fn with_node_exact(node: &SyntaxNode) -> Option<FnCallNode> {
200 match_ast! { 199 match_ast! {
201 match node { 200 match node {
202 ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)), 201 ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)),
@@ -206,7 +205,7 @@ impl FnCallNode {
206 } 205 }
207 } 206 }
208 207
209 pub(crate) fn name_ref(&self) -> Option<ast::NameRef> { 208 pub fn name_ref(&self) -> Option<ast::NameRef> {
210 match self { 209 match self {
211 FnCallNode::CallExpr(call_expr) => Some(match call_expr.expr()? { 210 FnCallNode::CallExpr(call_expr) => Some(match call_expr.expr()? {
212 ast::Expr::PathExpr(path_expr) => path_expr.path()?.segment()?.name_ref()?, 211 ast::Expr::PathExpr(path_expr) => path_expr.path()?.segment()?.name_ref()?,
@@ -229,14 +228,28 @@ impl FnCallNode {
229 228
230#[cfg(test)] 229#[cfg(test)]
231mod tests { 230mod tests {
231 use base_db::{fixture::ChangeFixture, FilePosition};
232 use expect_test::{expect, Expect}; 232 use expect_test::{expect, Expect};
233 use test_utils::mark; 233 use ide_db::RootDatabase;
234 234 use test_utils::{mark, RangeOrOffset};
235 use crate::fixture; 235
236 /// Creates analysis from a multi-file fixture, returns positions marked with <|>.
237 pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
238 let change_fixture = ChangeFixture::parse(ra_fixture);
239 let mut database = RootDatabase::default();
240 database.apply_change(change_fixture.change);
241 let (file_id, range_or_offset) =
242 change_fixture.file_position.expect("expected a marker (<|>)");
243 let offset = match range_or_offset {
244 RangeOrOffset::Range(_) => panic!(),
245 RangeOrOffset::Offset(it) => it,
246 };
247 (database, FilePosition { file_id, offset })
248 }
236 249
237 fn check(ra_fixture: &str, expect: Expect) { 250 fn check(ra_fixture: &str, expect: Expect) {
238 let (analysis, position) = fixture::position(ra_fixture); 251 let (db, position) = position(ra_fixture);
239 let call_info = analysis.call_info(position).unwrap(); 252 let call_info = crate::call_info(&db, position);
240 let actual = match call_info { 253 let actual = match call_info {
241 Some(call_info) => { 254 Some(call_info) => {
242 let docs = match &call_info.doc { 255 let docs = match &call_info.doc {
diff --git a/crates/completion/Cargo.toml b/crates/completion/Cargo.toml
new file mode 100644
index 000000000..25192456a
--- /dev/null
+++ b/crates/completion/Cargo.toml
@@ -0,0 +1,32 @@
1[package]
2name = "completion"
3version = "0.0.0"
4description = "TBD"
5license = "MIT OR Apache-2.0"
6authors = ["rust-analyzer developers"]
7edition = "2018"
8
9[lib]
10doctest = false
11
12[dependencies]
13itertools = "0.9.0"
14log = "0.4.8"
15rustc-hash = "1.1.0"
16
17stdx = { path = "../stdx", version = "0.0.0" }
18syntax = { path = "../syntax", version = "0.0.0" }
19text_edit = { path = "../text_edit", version = "0.0.0" }
20base_db = { path = "../base_db", version = "0.0.0" }
21ide_db = { path = "../ide_db", version = "0.0.0" }
22profile = { path = "../profile", version = "0.0.0" }
23test_utils = { path = "../test_utils", version = "0.0.0" }
24assists = { path = "../assists", version = "0.0.0" }
25call_info = { path = "../call_info", version = "0.0.0" }
26
27# completions crate should depend only on the top-level `hir` package. if you need
28# something from some `hir_xxx` subpackage, reexport the API via `hir`.
29hir = { path = "../hir", version = "0.0.0" }
30
31[dev-dependencies]
32expect-test = "1.0"
diff --git a/crates/ide/src/completion/complete_attribute.rs b/crates/completion/src/complete_attribute.rs
index f4a9864d1..f97ab7dd0 100644
--- a/crates/ide/src/completion/complete_attribute.rs
+++ b/crates/completion/src/complete_attribute.rs
@@ -6,10 +6,10 @@
6use rustc_hash::FxHashSet; 6use rustc_hash::FxHashSet;
7use syntax::{ast, AstNode, SyntaxKind}; 7use syntax::{ast, AstNode, SyntaxKind};
8 8
9use crate::completion::{ 9use crate::{
10 completion_context::CompletionContext, 10 completion_context::CompletionContext,
11 completion_item::{CompletionItem, CompletionItemKind, CompletionKind, Completions}, 11 completion_item::{CompletionItem, CompletionItemKind, CompletionKind, Completions},
12 generated_features::FEATURES, 12 generated_lint_completions::{CLIPPY_LINTS, FEATURES},
13}; 13};
14 14
15pub(super) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { 15pub(super) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
@@ -23,14 +23,15 @@ pub(super) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext)
23 complete_derive(acc, ctx, token_tree) 23 complete_derive(acc, ctx, token_tree)
24 } 24 }
25 (Some(path), Some(token_tree)) if path.to_string() == "feature" => { 25 (Some(path), Some(token_tree)) if path.to_string() == "feature" => {
26 complete_lint(acc, ctx, token_tree, FEATURES) 26 complete_lint(acc, ctx, token_tree, FEATURES);
27 } 27 }
28 (Some(path), Some(token_tree)) 28 (Some(path), Some(token_tree))
29 if ["allow", "warn", "deny", "forbid"] 29 if ["allow", "warn", "deny", "forbid"]
30 .iter() 30 .iter()
31 .any(|lint_level| lint_level == &path.to_string()) => 31 .any(|lint_level| lint_level == &path.to_string()) =>
32 { 32 {
33 complete_lint(acc, ctx, token_tree, DEFAULT_LINT_COMPLETIONS) 33 complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINT_COMPLETIONS);
34 complete_lint(acc, ctx, token_tree, CLIPPY_LINTS);
34 } 35 }
35 (_, Some(_token_tree)) => {} 36 (_, Some(_token_tree)) => {}
36 _ => complete_attribute_start(acc, ctx, attribute), 37 _ => complete_attribute_start(acc, ctx, attribute),
@@ -389,7 +390,7 @@ const DEFAULT_LINT_COMPLETIONS: &[LintCompletion] = &[
389mod tests { 390mod tests {
390 use expect_test::{expect, Expect}; 391 use expect_test::{expect, Expect};
391 392
392 use crate::completion::{test_utils::completion_list, CompletionKind}; 393 use crate::{test_utils::completion_list, CompletionKind};
393 394
394 fn check(ra_fixture: &str, expect: Expect) { 395 fn check(ra_fixture: &str, expect: Expect) {
395 let actual = completion_list(ra_fixture, CompletionKind::Attribute); 396 let actual = completion_list(ra_fixture, CompletionKind::Attribute);
@@ -418,130 +419,6 @@ struct Test {}
418 } 419 }
419 420
420 #[test] 421 #[test]
421 fn empty_lint_completion() {
422 check(
423 r#"#[allow(<|>)]"#,
424 expect![[r#"
425 at absolute_paths_not_starting_with_crate fully qualified paths that start with a module name instead of `crate`, `self`, or an extern crate name
426 at ambiguous_associated_items ambiguous associated items
427 at anonymous_parameters detects anonymous parameters
428 at arithmetic_overflow arithmetic operation overflows
429 at array_into_iter detects calling `into_iter` on arrays
430 at asm_sub_register using only a subset of a register for inline asm inputs
431 at bare_trait_objects suggest using `dyn Trait` for trait objects
432 at bindings_with_variant_name detects pattern bindings with the same name as one of the matched variants
433 at box_pointers use of owned (Box type) heap memory
434 at cenum_impl_drop_cast a C-like enum implementing Drop is cast
435 at clashing_extern_declarations detects when an extern fn has been declared with the same name but different types
436 at coherence_leak_check distinct impls distinguished only by the leak-check code
437 at conflicting_repr_hints conflicts between `#[repr(..)]` hints that were previously accepted and used in practice
438 at confusable_idents detects visually confusable pairs between identifiers
439 at const_err constant evaluation detected erroneous expression
440 at dead_code detect unused, unexported items
441 at deprecated detects use of deprecated items
442 at deprecated_in_future detects use of items that will be deprecated in a future version
443 at elided_lifetimes_in_paths hidden lifetime parameters in types are deprecated
444 at ellipsis_inclusive_range_patterns `...` range patterns are deprecated
445 at explicit_outlives_requirements outlives requirements can be inferred
446 at exported_private_dependencies public interface leaks type from a private dependency
447 at ill_formed_attribute_input ill-formed attribute inputs that were previously accepted and used in practice
448 at illegal_floating_point_literal_pattern floating-point literals cannot be used in patterns
449 at improper_ctypes proper use of libc types in foreign modules
450 at improper_ctypes_definitions proper use of libc types in foreign item definitions
451 at incomplete_features incomplete features that may function improperly in some or all cases
452 at incomplete_include trailing content in included file
453 at indirect_structural_match pattern with const indirectly referencing non-structural-match type
454 at inline_no_sanitize detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`
455 at intra_doc_link_resolution_failure failures in resolving intra-doc link targets
456 at invalid_codeblock_attributes codeblock attribute looks a lot like a known one
457 at invalid_type_param_default type parameter default erroneously allowed in invalid location
458 at invalid_value an invalid value is being created (such as a NULL reference)
459 at irrefutable_let_patterns detects irrefutable patterns in if-let and while-let statements
460 at keyword_idents detects edition keywords being used as an identifier
461 at late_bound_lifetime_arguments detects generic lifetime arguments in path segments with late bound lifetime parameters
462 at macro_expanded_macro_exports_accessed_by_absolute_paths macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths
463 at macro_use_extern_crate the `#[macro_use]` attribute is now deprecated in favor of using macros via the module system
464 at meta_variable_misuse possible meta-variable misuse at macro definition
465 at missing_copy_implementations detects potentially-forgotten implementations of `Copy`
466 at missing_crate_level_docs detects crates with no crate-level documentation
467 at missing_debug_implementations detects missing implementations of Debug
468 at missing_doc_code_examples detects publicly-exported items without code samples in their documentation
469 at missing_docs detects missing documentation for public members
470 at missing_fragment_specifier detects missing fragment specifiers in unused `macro_rules!` patterns
471 at mixed_script_confusables detects Unicode scripts whose mixed script confusables codepoints are solely used
472 at mutable_borrow_reservation_conflict reservation of a two-phased borrow conflicts with other shared borrows
473 at mutable_transmutes mutating transmuted &mut T from &T may cause undefined behavior
474 at no_mangle_const_items const items will not have their symbols exported
475 at no_mangle_generic_items generic items must be mangled
476 at non_ascii_idents detects non-ASCII identifiers
477 at non_camel_case_types types, variants, traits and type parameters should have camel case names
478 at non_shorthand_field_patterns using `Struct { x: x }` instead of `Struct { x }` in a pattern
479 at non_snake_case variables, methods, functions, lifetime parameters and modules should have snake case names
480 at non_upper_case_globals static constants should have uppercase identifiers
481 at order_dependent_trait_objects trait-object types were treated as different depending on marker-trait order
482 at overflowing_literals literal out of range for its type
483 at overlapping_patterns detects overlapping patterns
484 at path_statements path statements with no effect
485 at patterns_in_fns_without_body patterns in functions without body were erroneously allowed
486 at private_doc_tests detects code samples in docs of private items not documented by rustdoc
487 at private_in_public detect private items in public interfaces not caught by the old implementation
488 at proc_macro_derive_resolution_fallback detects proc macro derives using inaccessible names from parent modules
489 at pub_use_of_private_extern_crate detect public re-exports of private extern crates
490 at redundant_semicolons detects unnecessary trailing semicolons
491 at renamed_and_removed_lints lints that have been renamed or removed
492 at safe_packed_borrows safe borrows of fields of packed structs were erroneously allowed
493 at single_use_lifetimes detects lifetime parameters that are only used once
494 at soft_unstable a feature gate that doesn't break dependent crates
495 at stable_features stable features found in `#[feature]` directive
496 at trivial_bounds these bounds don't depend on an type parameters
497 at trivial_casts detects trivial casts which could be removed
498 at trivial_numeric_casts detects trivial casts of numeric types which could be removed
499 at type_alias_bounds bounds in type aliases are not enforced
500 at tyvar_behind_raw_pointer raw pointer to an inference variable
501 at unaligned_references detects unaligned references to fields of packed structs
502 at uncommon_codepoints detects uncommon Unicode codepoints in identifiers
503 at unconditional_panic operation will cause a panic at runtime
504 at unconditional_recursion functions that cannot return without calling themselves
505 at unknown_crate_types unknown crate type found in `#[crate_type]` directive
506 at unknown_lints unrecognized lint attribute
507 at unnameable_test_items detects an item that cannot be named being marked as `#[test_case]`
508 at unreachable_code detects unreachable code paths
509 at unreachable_patterns detects unreachable patterns
510 at unreachable_pub `pub` items not reachable from crate root
511 at unsafe_code usage of `unsafe` code
512 at unsafe_op_in_unsafe_fn unsafe operations in unsafe functions without an explicit unsafe block are deprecated
513 at unstable_features enabling unstable features (deprecated. do not use)
514 at unstable_name_collisions detects name collision with an existing but unstable method
515 at unused_allocation detects unnecessary allocations that can be eliminated
516 at unused_assignments detect assignments that will never be read
517 at unused_attributes detects attributes that were not used by the compiler
518 at unused_braces unnecessary braces around an expression
519 at unused_comparisons comparisons made useless by limits of the types involved
520 at unused_crate_dependencies crate dependencies that are never used
521 at unused_doc_comments detects doc comments that aren't used by rustdoc
522 at unused_extern_crates extern crates that are never used
523 at unused_features unused features found in crate-level `#[feature]` directives
524 at unused_import_braces unnecessary braces around an imported item
525 at unused_imports imports that are never used
526 at unused_labels detects labels that are never used
527 at unused_lifetimes detects lifetime parameters that are never used
528 at unused_macros detects macros that were not used
529 at unused_must_use unused result of a type flagged as `#[must_use]`
530 at unused_mut detect mut variables which don't need to be mutable
531 at unused_parens `if`, `match`, `while` and `return` do not need parentheses
532 at unused_qualifications detects unnecessarily qualified names
533 at unused_results unused result of an expression in a statement
534 at unused_unsafe unnecessary use of an `unsafe` block
535 at unused_variables detect variables which are not used in any way
536 at variant_size_differences detects enums with widely varying variant sizes
537 at warnings mass-change the level for lints which produce warnings
538 at where_clauses_object_safety checks the object safety of where clauses
539 at while_true suggest using `loop { }` instead of `while true { }`
540 "#]],
541 )
542 }
543
544 #[test]
545 fn no_completion_for_incorrect_derive() { 422 fn no_completion_for_incorrect_derive() {
546 check( 423 check(
547 r#" 424 r#"
diff --git a/crates/ide/src/completion/complete_dot.rs b/crates/completion/src/complete_dot.rs
index 0b9f1798a..0eabb48ae 100644
--- a/crates/ide/src/completion/complete_dot.rs
+++ b/crates/completion/src/complete_dot.rs
@@ -4,7 +4,7 @@ use hir::{HasVisibility, Type};
4use rustc_hash::FxHashSet; 4use rustc_hash::FxHashSet;
5use test_utils::mark; 5use test_utils::mark;
6 6
7use crate::completion::{completion_context::CompletionContext, completion_item::Completions}; 7use crate::{completion_context::CompletionContext, completion_item::Completions};
8 8
9/// Complete dot accesses, i.e. fields or methods. 9/// Complete dot accesses, i.e. fields or methods.
10pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { 10pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
@@ -64,7 +64,7 @@ mod tests {
64 use expect_test::{expect, Expect}; 64 use expect_test::{expect, Expect};
65 use test_utils::mark; 65 use test_utils::mark;
66 66
67 use crate::completion::{test_utils::completion_list, CompletionKind}; 67 use crate::{test_utils::completion_list, CompletionKind};
68 68
69 fn check(ra_fixture: &str, expect: Expect) { 69 fn check(ra_fixture: &str, expect: Expect) {
70 let actual = completion_list(ra_fixture, CompletionKind::Reference); 70 let actual = completion_list(ra_fixture, CompletionKind::Reference);
@@ -413,4 +413,19 @@ fn foo() {
413 "#]], 413 "#]],
414 ); 414 );
415 } 415 }
416
417 #[test]
418 fn completes_method_call_when_receiver_is_a_macro_call() {
419 check(
420 r#"
421struct S;
422impl S { fn foo(&self) {} }
423macro_rules! make_s { () => { S }; }
424fn main() { make_s!().f<|>; }
425"#,
426 expect![[r#"
427 me foo() fn foo(&self)
428 "#]],
429 )
430 }
416} 431}
diff --git a/crates/ide/src/completion/complete_fn_param.rs b/crates/completion/src/complete_fn_param.rs
index 9efe25461..918996727 100644
--- a/crates/ide/src/completion/complete_fn_param.rs
+++ b/crates/completion/src/complete_fn_param.rs
@@ -6,7 +6,7 @@ use syntax::{
6 match_ast, AstNode, 6 match_ast, AstNode,
7}; 7};
8 8
9use crate::completion::{CompletionContext, CompletionItem, CompletionKind, Completions}; 9use crate::{CompletionContext, CompletionItem, CompletionKind, Completions};
10 10
11/// Complete repeated parameters, both name and type. For example, if all 11/// Complete repeated parameters, both name and type. For example, if all
12/// functions in a file have a `spam: &mut Spam` parameter, a completion with 12/// functions in a file have a `spam: &mut Spam` parameter, a completion with
@@ -68,7 +68,7 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
68mod tests { 68mod tests {
69 use expect_test::{expect, Expect}; 69 use expect_test::{expect, Expect};
70 70
71 use crate::completion::{test_utils::completion_list, CompletionKind}; 71 use crate::{test_utils::completion_list, CompletionKind};
72 72
73 fn check(ra_fixture: &str, expect: Expect) { 73 fn check(ra_fixture: &str, expect: Expect) {
74 let actual = completion_list(ra_fixture, CompletionKind::Magic); 74 let actual = completion_list(ra_fixture, CompletionKind::Magic);
diff --git a/crates/ide/src/completion/complete_keyword.rs b/crates/completion/src/complete_keyword.rs
index e59747095..ace914f3f 100644
--- a/crates/ide/src/completion/complete_keyword.rs
+++ b/crates/completion/src/complete_keyword.rs
@@ -1,11 +1,9 @@
1//! FIXME: write short doc here 1//! Completes keywords.
2 2
3use syntax::{ast, SyntaxKind}; 3use syntax::{ast, SyntaxKind};
4use test_utils::mark; 4use test_utils::mark;
5 5
6use crate::completion::{ 6use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions};
7 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
8};
9 7
10pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) { 8pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) {
11 // complete keyword "crate" in use stmt 9 // complete keyword "crate" in use stmt
@@ -177,7 +175,7 @@ fn complete_return(
177mod tests { 175mod tests {
178 use expect_test::{expect, Expect}; 176 use expect_test::{expect, Expect};
179 177
180 use crate::completion::{ 178 use crate::{
181 test_utils::{check_edit, completion_list}, 179 test_utils::{check_edit, completion_list},
182 CompletionKind, 180 CompletionKind,
183 }; 181 };
diff --git a/crates/ide/src/completion/complete_macro_in_item_position.rs b/crates/completion/src/complete_macro_in_item_position.rs
index fc8625d8e..d1d8c23d2 100644
--- a/crates/ide/src/completion/complete_macro_in_item_position.rs
+++ b/crates/completion/src/complete_macro_in_item_position.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! Completes macro invocations used in item position.
2 2
3use crate::completion::{CompletionContext, Completions}; 3use crate::{CompletionContext, Completions};
4 4
5pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) { 5pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) {
6 // Show only macros in top level. 6 // Show only macros in top level.
@@ -17,7 +17,7 @@ pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &Compl
17mod tests { 17mod tests {
18 use expect_test::{expect, Expect}; 18 use expect_test::{expect, Expect};
19 19
20 use crate::completion::{test_utils::completion_list, CompletionKind}; 20 use crate::{test_utils::completion_list, CompletionKind};
21 21
22 fn check(ra_fixture: &str, expect: Expect) { 22 fn check(ra_fixture: &str, expect: Expect) {
23 let actual = completion_list(ra_fixture, CompletionKind::Reference); 23 let actual = completion_list(ra_fixture, CompletionKind::Reference);
diff --git a/crates/ide/src/completion/complete_mod.rs b/crates/completion/src/complete_mod.rs
index c7a99bdc3..35a57aba3 100644
--- a/crates/ide/src/completion/complete_mod.rs
+++ b/crates/completion/src/complete_mod.rs
@@ -150,7 +150,7 @@ fn module_chain_to_containing_module_file(
150 150
151#[cfg(test)] 151#[cfg(test)]
152mod tests { 152mod tests {
153 use crate::completion::{test_utils::completion_list, CompletionKind}; 153 use crate::{test_utils::completion_list, CompletionKind};
154 use expect_test::{expect, Expect}; 154 use expect_test::{expect, Expect};
155 155
156 fn check(ra_fixture: &str, expect: Expect) { 156 fn check(ra_fixture: &str, expect: Expect) {
diff --git a/crates/ide/src/completion/complete_pattern.rs b/crates/completion/src/complete_pattern.rs
index 5a13574d4..5606dcdd9 100644
--- a/crates/ide/src/completion/complete_pattern.rs
+++ b/crates/completion/src/complete_pattern.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! Completes constats and paths in patterns.
2 2
3use crate::completion::{CompletionContext, Completions}; 3use crate::{CompletionContext, Completions};
4 4
5/// Completes constats and paths in patterns. 5/// Completes constats and paths in patterns.
6pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { 6pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
@@ -35,7 +35,7 @@ pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
35mod tests { 35mod tests {
36 use expect_test::{expect, Expect}; 36 use expect_test::{expect, Expect};
37 37
38 use crate::completion::{test_utils::completion_list, CompletionKind}; 38 use crate::{test_utils::completion_list, CompletionKind};
39 39
40 fn check(ra_fixture: &str, expect: Expect) { 40 fn check(ra_fixture: &str, expect: Expect) {
41 let actual = completion_list(ra_fixture, CompletionKind::Reference); 41 let actual = completion_list(ra_fixture, CompletionKind::Reference);
diff --git a/crates/ide/src/completion/complete_postfix.rs b/crates/completion/src/complete_postfix.rs
index db5319618..700573cf2 100644
--- a/crates/ide/src/completion/complete_postfix.rs
+++ b/crates/completion/src/complete_postfix.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! Postfix completions, like `Ok(10).ifl<|>` => `if let Ok() = Ok(10) { <|> }`.
2 2
3mod format_like; 3mod format_like;
4 4
@@ -11,11 +11,9 @@ use text_edit::TextEdit;
11 11
12use self::format_like::add_format_like_completions; 12use self::format_like::add_format_like_completions;
13use crate::{ 13use crate::{
14 completion::{ 14 completion_config::SnippetCap,
15 completion_config::SnippetCap, 15 completion_context::CompletionContext,
16 completion_context::CompletionContext, 16 completion_item::{Builder, CompletionKind, Completions},
17 completion_item::{Builder, CompletionKind, Completions},
18 },
19 CompletionItem, CompletionItemKind, 17 CompletionItem, CompletionItemKind,
20}; 18};
21 19
@@ -263,7 +261,7 @@ fn postfix_snippet(
263mod tests { 261mod tests {
264 use expect_test::{expect, Expect}; 262 use expect_test::{expect, Expect};
265 263
266 use crate::completion::{ 264 use crate::{
267 test_utils::{check_edit, completion_list}, 265 test_utils::{check_edit, completion_list},
268 CompletionKind, 266 CompletionKind,
269 }; 267 };
diff --git a/crates/ide/src/completion/complete_postfix/format_like.rs b/crates/completion/src/complete_postfix/format_like.rs
index 50d1e5c81..205c384e2 100644
--- a/crates/ide/src/completion/complete_postfix/format_like.rs
+++ b/crates/completion/src/complete_postfix/format_like.rs
@@ -14,7 +14,7 @@
14// + `logw` -> `log::warn!(...)` 14// + `logw` -> `log::warn!(...)`
15// + `loge` -> `log::error!(...)` 15// + `loge` -> `log::error!(...)`
16 16
17use crate::completion::{ 17use crate::{
18 complete_postfix::postfix_snippet, completion_config::SnippetCap, 18 complete_postfix::postfix_snippet, completion_config::SnippetCap,
19 completion_context::CompletionContext, completion_item::Completions, 19 completion_context::CompletionContext, completion_item::Completions,
20}; 20};
diff --git a/crates/ide/src/completion/complete_qualified_path.rs b/crates/completion/src/complete_qualified_path.rs
index 2fafedd47..80b271fdf 100644
--- a/crates/ide/src/completion/complete_qualified_path.rs
+++ b/crates/completion/src/complete_qualified_path.rs
@@ -5,7 +5,7 @@ use rustc_hash::FxHashSet;
5use syntax::AstNode; 5use syntax::AstNode;
6use test_utils::mark; 6use test_utils::mark;
7 7
8use crate::completion::{CompletionContext, Completions}; 8use crate::{CompletionContext, Completions};
9 9
10pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) { 10pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) {
11 let path = match &ctx.path_qual { 11 let path = match &ctx.path_qual {
@@ -149,7 +149,7 @@ mod tests {
149 use expect_test::{expect, Expect}; 149 use expect_test::{expect, Expect};
150 use test_utils::mark; 150 use test_utils::mark;
151 151
152 use crate::completion::{ 152 use crate::{
153 test_utils::{check_edit, completion_list}, 153 test_utils::{check_edit, completion_list},
154 CompletionKind, 154 CompletionKind,
155 }; 155 };
diff --git a/crates/ide/src/completion/complete_record.rs b/crates/completion/src/complete_record.rs
index ceb8d16c1..129ddc055 100644
--- a/crates/ide/src/completion/complete_record.rs
+++ b/crates/completion/src/complete_record.rs
@@ -1,5 +1,5 @@
1//! Complete fields in record literals and patterns. 1//! Complete fields in record literals and patterns.
2use crate::completion::{CompletionContext, Completions}; 2use crate::{CompletionContext, Completions};
3 3
4pub(super) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { 4pub(super) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
5 let missing_fields = match (ctx.record_pat_syntax.as_ref(), ctx.record_lit_syntax.as_ref()) { 5 let missing_fields = match (ctx.record_pat_syntax.as_ref(), ctx.record_lit_syntax.as_ref()) {
@@ -20,7 +20,7 @@ pub(super) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
20mod tests { 20mod tests {
21 use expect_test::{expect, Expect}; 21 use expect_test::{expect, Expect};
22 22
23 use crate::completion::{test_utils::completion_list, CompletionKind}; 23 use crate::{test_utils::completion_list, CompletionKind};
24 24
25 fn check(ra_fixture: &str, expect: Expect) { 25 fn check(ra_fixture: &str, expect: Expect) {
26 let actual = completion_list(ra_fixture, CompletionKind::Reference); 26 let actual = completion_list(ra_fixture, CompletionKind::Reference);
diff --git a/crates/ide/src/completion/complete_snippet.rs b/crates/completion/src/complete_snippet.rs
index 4837d2910..06096722b 100644
--- a/crates/ide/src/completion/complete_snippet.rs
+++ b/crates/completion/src/complete_snippet.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! This file provides snippet completions, like `pd` => `eprintln!(...)`.
2 2
3use crate::completion::{ 3use crate::{
4 completion_config::SnippetCap, completion_item::Builder, CompletionContext, CompletionItem, 4 completion_config::SnippetCap, completion_item::Builder, CompletionContext, CompletionItem,
5 CompletionItemKind, CompletionKind, Completions, 5 CompletionItemKind, CompletionKind, Completions,
6}; 6};
@@ -71,7 +71,7 @@ fn ${1:feature}() {
71mod tests { 71mod tests {
72 use expect_test::{expect, Expect}; 72 use expect_test::{expect, Expect};
73 73
74 use crate::completion::{test_utils::completion_list, CompletionKind}; 74 use crate::{test_utils::completion_list, CompletionKind};
75 75
76 fn check(ra_fixture: &str, expect: Expect) { 76 fn check(ra_fixture: &str, expect: Expect) {
77 let actual = completion_list(ra_fixture, CompletionKind::Snippet); 77 let actual = completion_list(ra_fixture, CompletionKind::Snippet);
diff --git a/crates/ide/src/completion/complete_trait_impl.rs b/crates/completion/src/complete_trait_impl.rs
index ff115df92..c06af99e2 100644
--- a/crates/ide/src/completion/complete_trait_impl.rs
+++ b/crates/completion/src/complete_trait_impl.rs
@@ -35,15 +35,18 @@ use assists::utils::get_missing_assoc_items;
35use hir::{self, HasAttrs, HasSource}; 35use hir::{self, HasAttrs, HasSource};
36use syntax::{ 36use syntax::{
37 ast::{self, edit, Impl}, 37 ast::{self, edit, Impl},
38 display::function_declaration,
38 AstNode, SyntaxKind, SyntaxNode, TextRange, T, 39 AstNode, SyntaxKind, SyntaxNode, TextRange, T,
39}; 40};
40use text_edit::TextEdit; 41use text_edit::TextEdit;
41 42
42use crate::{ 43use crate::{
43 completion::{ 44 CompletionContext,
44 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, 45 CompletionItem,
45 }, 46 CompletionItemKind,
46 display::function_declaration, 47 CompletionKind,
48 Completions,
49 // display::function_declaration,
47}; 50};
48 51
49#[derive(Debug, PartialEq, Eq)] 52#[derive(Debug, PartialEq, Eq)]
@@ -237,7 +240,7 @@ fn make_const_compl_syntax(const_: &ast::Const) -> String {
237mod tests { 240mod tests {
238 use expect_test::{expect, Expect}; 241 use expect_test::{expect, Expect};
239 242
240 use crate::completion::{ 243 use crate::{
241 test_utils::{check_edit, completion_list}, 244 test_utils::{check_edit, completion_list},
242 CompletionKind, 245 CompletionKind,
243 }; 246 };
diff --git a/crates/ide/src/completion/complete_unqualified_path.rs b/crates/completion/src/complete_unqualified_path.rs
index 8b6757195..5464a160d 100644
--- a/crates/ide/src/completion/complete_unqualified_path.rs
+++ b/crates/completion/src/complete_unqualified_path.rs
@@ -4,7 +4,7 @@ use hir::{Adt, ModuleDef, ScopeDef, Type};
4use syntax::AstNode; 4use syntax::AstNode;
5use test_utils::mark; 5use test_utils::mark;
6 6
7use crate::completion::{CompletionContext, Completions}; 7use crate::{CompletionContext, Completions};
8 8
9pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { 9pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
10 if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) { 10 if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) {
@@ -68,7 +68,7 @@ mod tests {
68 use expect_test::{expect, Expect}; 68 use expect_test::{expect, Expect};
69 use test_utils::mark; 69 use test_utils::mark;
70 70
71 use crate::completion::{ 71 use crate::{
72 test_utils::{check_edit, completion_list}, 72 test_utils::{check_edit, completion_list},
73 CompletionKind, 73 CompletionKind,
74 }; 74 };
diff --git a/crates/ide/src/completion/completion_config.rs b/crates/completion/src/completion_config.rs
index 71b49ace8..71b49ace8 100644
--- a/crates/ide/src/completion/completion_config.rs
+++ b/crates/completion/src/completion_config.rs
diff --git a/crates/ide/src/completion/completion_context.rs b/crates/completion/src/completion_context.rs
index 8dea8a4bf..dc4e136c6 100644
--- a/crates/ide/src/completion/completion_context.rs
+++ b/crates/completion/src/completion_context.rs
@@ -1,6 +1,7 @@
1//! FIXME: write short doc here 1//! See `CompletionContext` structure.
2 2
3use base_db::SourceDatabase; 3use base_db::{FilePosition, SourceDatabase};
4use call_info::ActiveParameter;
4use hir::{Local, ScopeDef, Semantics, SemanticsScope, Type}; 5use hir::{Local, ScopeDef, Semantics, SemanticsScope, Type};
5use ide_db::RootDatabase; 6use ide_db::RootDatabase;
6use syntax::{ 7use syntax::{
@@ -13,17 +14,14 @@ use test_utils::mark;
13use text_edit::Indel; 14use text_edit::Indel;
14 15
15use crate::{ 16use crate::{
16 call_info::ActiveParameter, 17 patterns::{
17 completion::{ 18 fn_is_prev, for_is_prev2, has_bind_pat_parent, has_block_expr_parent,
18 patterns::{ 19 has_field_list_parent, has_impl_as_prev_sibling, has_impl_parent,
19 has_bind_pat_parent, has_block_expr_parent, has_field_list_parent, 20 has_item_list_or_source_file_parent, has_ref_parent, has_trait_as_prev_sibling,
20 has_impl_as_prev_sibling, has_impl_parent, has_item_list_or_source_file_parent, 21 has_trait_parent, if_is_prev, inside_impl_trait_block, is_in_loop_body, is_match_arm,
21 has_ref_parent, has_trait_as_prev_sibling, has_trait_parent, if_is_prev, 22 unsafe_is_prev,
22 is_in_loop_body, is_match_arm, unsafe_is_prev,
23 },
24 CompletionConfig,
25 }, 23 },
26 FilePosition, 24 CompletionConfig,
27}; 25};
28 26
29/// `CompletionContext` is created early during completion to figure out, where 27/// `CompletionContext` is created early during completion to figure out, where
@@ -86,11 +84,14 @@ pub(crate) struct CompletionContext<'a> {
86 pub(super) in_loop_body: bool, 84 pub(super) in_loop_body: bool,
87 pub(super) has_trait_parent: bool, 85 pub(super) has_trait_parent: bool,
88 pub(super) has_impl_parent: bool, 86 pub(super) has_impl_parent: bool,
87 pub(super) inside_impl_trait_block: bool,
89 pub(super) has_field_list_parent: bool, 88 pub(super) has_field_list_parent: bool,
90 pub(super) trait_as_prev_sibling: bool, 89 pub(super) trait_as_prev_sibling: bool,
91 pub(super) impl_as_prev_sibling: bool, 90 pub(super) impl_as_prev_sibling: bool,
92 pub(super) is_match_arm: bool, 91 pub(super) is_match_arm: bool,
93 pub(super) has_item_list_or_source_file_parent: bool, 92 pub(super) has_item_list_or_source_file_parent: bool,
93 pub(super) for_is_prev2: bool,
94 pub(super) fn_is_prev: bool,
94 pub(super) locals: Vec<(String, Local)>, 95 pub(super) locals: Vec<(String, Local)>,
95} 96}
96 97
@@ -168,12 +169,15 @@ impl<'a> CompletionContext<'a> {
168 block_expr_parent: false, 169 block_expr_parent: false,
169 has_trait_parent: false, 170 has_trait_parent: false,
170 has_impl_parent: false, 171 has_impl_parent: false,
172 inside_impl_trait_block: false,
171 has_field_list_parent: false, 173 has_field_list_parent: false,
172 trait_as_prev_sibling: false, 174 trait_as_prev_sibling: false,
173 impl_as_prev_sibling: false, 175 impl_as_prev_sibling: false,
174 if_is_prev: false, 176 if_is_prev: false,
175 is_match_arm: false, 177 is_match_arm: false,
176 has_item_list_or_source_file_parent: false, 178 has_item_list_or_source_file_parent: false,
179 for_is_prev2: false,
180 fn_is_prev: false,
177 locals, 181 locals,
178 }; 182 };
179 183
@@ -221,6 +225,15 @@ impl<'a> CompletionContext<'a> {
221 Some(ctx) 225 Some(ctx)
222 } 226 }
223 227
228 /// Checks whether completions in that particular case don't make much sense.
229 /// Examples:
230 /// - `fn <|>` -- we expect function name, it's unlikely that "hint" will be helpful.
231 /// Exception for this case is `impl Trait for Foo`, where we would like to hint trait method names.
232 /// - `for _ i<|>` -- obviously, it'll be "in" keyword.
233 pub(crate) fn no_completion_required(&self) -> bool {
234 (self.fn_is_prev && !self.inside_impl_trait_block) || self.for_is_prev2
235 }
236
224 /// The range of the identifier that is being completed. 237 /// The range of the identifier that is being completed.
225 pub(crate) fn source_range(&self) -> TextRange { 238 pub(crate) fn source_range(&self) -> TextRange {
226 // check kind of macro-expanded token, but use range of original token 239 // check kind of macro-expanded token, but use range of original token
@@ -244,6 +257,7 @@ impl<'a> CompletionContext<'a> {
244 self.in_loop_body = is_in_loop_body(syntax_element.clone()); 257 self.in_loop_body = is_in_loop_body(syntax_element.clone());
245 self.has_trait_parent = has_trait_parent(syntax_element.clone()); 258 self.has_trait_parent = has_trait_parent(syntax_element.clone());
246 self.has_impl_parent = has_impl_parent(syntax_element.clone()); 259 self.has_impl_parent = has_impl_parent(syntax_element.clone());
260 self.inside_impl_trait_block = inside_impl_trait_block(syntax_element.clone());
247 self.has_field_list_parent = has_field_list_parent(syntax_element.clone()); 261 self.has_field_list_parent = has_field_list_parent(syntax_element.clone());
248 self.impl_as_prev_sibling = has_impl_as_prev_sibling(syntax_element.clone()); 262 self.impl_as_prev_sibling = has_impl_as_prev_sibling(syntax_element.clone());
249 self.trait_as_prev_sibling = has_trait_as_prev_sibling(syntax_element.clone()); 263 self.trait_as_prev_sibling = has_trait_as_prev_sibling(syntax_element.clone());
@@ -253,6 +267,8 @@ impl<'a> CompletionContext<'a> {
253 self.mod_declaration_under_caret = 267 self.mod_declaration_under_caret =
254 find_node_at_offset::<ast::Module>(&file_with_fake_ident, offset) 268 find_node_at_offset::<ast::Module>(&file_with_fake_ident, offset)
255 .filter(|module| module.item_list().is_none()); 269 .filter(|module| module.item_list().is_none());
270 self.for_is_prev2 = for_is_prev2(syntax_element.clone());
271 self.fn_is_prev = fn_is_prev(syntax_element.clone());
256 } 272 }
257 273
258 fn fill( 274 fn fill(
diff --git a/crates/ide/src/completion/completion_item.rs b/crates/completion/src/completion_item.rs
index 9377cdc57..f8be0ad2b 100644
--- a/crates/ide/src/completion/completion_item.rs
+++ b/crates/completion/src/completion_item.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! See `CompletionItem` structure.
2 2
3use std::fmt; 3use std::fmt;
4 4
@@ -6,7 +6,7 @@ use hir::Documentation;
6use syntax::TextRange; 6use syntax::TextRange;
7use text_edit::TextEdit; 7use text_edit::TextEdit;
8 8
9use crate::completion::completion_config::SnippetCap; 9use crate::completion_config::SnippetCap;
10 10
11/// `CompletionItem` describes a single completion variant in the editor pop-up. 11/// `CompletionItem` describes a single completion variant in the editor pop-up.
12/// It is basically a POD with various properties. To construct a 12/// It is basically a POD with various properties. To construct a
@@ -360,15 +360,15 @@ impl<'a> Into<CompletionItem> for Builder {
360 360
361/// Represents an in-progress set of completions being built. 361/// Represents an in-progress set of completions being built.
362#[derive(Debug, Default)] 362#[derive(Debug, Default)]
363pub(crate) struct Completions { 363pub struct Completions {
364 buf: Vec<CompletionItem>, 364 buf: Vec<CompletionItem>,
365} 365}
366 366
367impl Completions { 367impl Completions {
368 pub(crate) fn add(&mut self, item: impl Into<CompletionItem>) { 368 pub fn add(&mut self, item: impl Into<CompletionItem>) {
369 self.buf.push(item.into()) 369 self.buf.push(item.into())
370 } 370 }
371 pub(crate) fn add_all<I>(&mut self, items: I) 371 pub fn add_all<I>(&mut self, items: I)
372 where 372 where
373 I: IntoIterator, 373 I: IntoIterator,
374 I::Item: Into<CompletionItem>, 374 I::Item: Into<CompletionItem>,
diff --git a/crates/completion/src/generated_lint_completions.rs b/crates/completion/src/generated_lint_completions.rs
new file mode 100644
index 000000000..5a7dba1f5
--- /dev/null
+++ b/crates/completion/src/generated_lint_completions.rs
@@ -0,0 +1,5 @@
1//! Generated file, do not edit by hand, see `xtask/src/codegen`
2
3use crate::complete_attribute::LintCompletion;
4pub (super) const FEATURES : & [LintCompletion] = & [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 : "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 : "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 : "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 : "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 : "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<R = ()> {\n type Yield;\n type Return;\n fn resume(self: Pin<&mut Self>, resume: R) -> GeneratorState<Self::Yield, Self::Return>;\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<Y, R> {\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<i32, &'static str> {\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 : "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<!-- NOTE(ignore) this example is specific to the nvptx targets -->\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 : "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<U> {}\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 : "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 : "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 : "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<T: 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<dyn Foo>;\n println!(\"{:?}\", b);\n}\n```\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::<notification::Icon>();\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 : "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<T>(*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<T: ?Sized>(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 : "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<T: Copy> { // 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::<T>()` is equal to\n`size_of::<Option<T>>()`, 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 : "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<!-- NOTE(ignore) this example is specific to the msp430 target -->\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 <TIM0_VECTOR>:\n fff2: 00 c0 interrupt service routine at 0xc000\n\nDisassembly of section .text:\n\n0000c000 <int::tim0>:\n c000: 00 13 reti\n```\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 : "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>(T);\n\nfn must_be_valid<T: 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<T> {\n data: T,\n next: Option<Box<List<T>>>,\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<T> {\n data: T,\n next: Option<Box<List<T>>>,\n}\n\nunsafe impl<T> Send for List<T>\nwhere\n T: Send, // from the field `data`\n Option<Box<List<T>>>: 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<Box<List>>: Send`, which will in turn require\n`Box<List>: 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 : "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 : "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<T, U>(x: T) -> U;\n\n fn offset<T>(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 : "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 : "ffi_const" , description : "# `ffi_const`\n\nThe tracking issue for this feature is: [#58328]\n\n------\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[#58328]: https://github.com/rust-lang/rust/issues/58328\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 : "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<dyn Any> = 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<T: ?Sized> {\n content: T,\n}\n\nstruct MyTupleStruct<T: ?Sized>(T);\n\nfn answer() -> Box<dyn Any> {\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<T: ?Sized> 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<T: ?Sized> Foo for T {}\n\nfn main () {\n let slice: Box<dyn Foo> = Box::new([1, 2, 3]);\n // doesn't compile yet\n <dyn Foo as Foo>::foo(*slice);\n}\n```\n\nOne of the objectives of this feature is to allow `Box<dyn FnOnce>`.\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<T: Ord>(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 : "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<U> where U: 'static { // <-- currently required\n bar: Bar<U>\n}\nstruct Bar<T: 'static> {\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<U> {\n bar: Bar<U>\n}\nstruct Bar<T: 'static> {\n x: T,\n}\n```\n\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 : "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 : "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<Foo>) {\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 : "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<T: Copy> 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<T: CheapToClone, U: CheapToClone> CheapToClone for (T, U) {}\nimpl<T: CheapToClone> CheapToClone for std::ops::Range<T> {}\n\nfn cheap_clone<T: CheapToClone>(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 : "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 : "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<T> 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 : "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 : "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 : "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 : "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::<usize>();\n }\n sum\n}\n```\n" } , LintCompletion { label : "ffi_pure" , description : "# `ffi_pure`\n\nThe tracking issue for this feature is: [#58329]\n\n------\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[#58329]: https://github.com/rust-lang/rust/issues/58329\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 : "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 : "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 : "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(<int-type>)]` 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 : "cmse_nonsecure_entry" , description : "# `cmse_nonsecure_entry`\n\nThe tracking issue for this feature is: [#75835]\n\n[#75835]: https://github.com/rust-lang/rust/issues/75835\n\n------------------------\n\nThe [TrustZone-M\nfeature](https://developer.arm.com/documentation/100690/latest/) is available\nfor targets with the Armv8-M architecture profile (`thumbv8m` in their target\nname).\nLLVM, the Rust compiler and the linker are providing\n[support](https://developer.arm.com/documentation/ecm0359818/latest/) for the\nTrustZone-M feature.\n\nOne of the things provided, with this unstable feature, is the\n`cmse_nonsecure_entry` attribute. This attribute marks a Secure function as an\nentry function (see [section\n5.4](https://developer.arm.com/documentation/ecm0359818/latest/) for details).\nWith this attribute, the compiler will do the following:\n* add a special symbol on the function which is the `__acle_se_` prefix and the\n standard function name\n* constrain the number of parameters to avoid using the Non-Secure stack\n* before returning from the function, clear registers that might contain Secure\n information\n* use the `BXNS` instruction to return\n\nBecause the stack can not be used to pass parameters, there will be compilation\nerrors if:\n* the total size of all parameters is too big (for example more than four 32\n bits integers)\n* the entry function is not using a C ABI\n\nThe special symbol `__acle_se_` will be used by the linker to generate a secure\ngateway veneer.\n\n<!-- NOTE(ignore) this example is specific to thumbv8m targets -->\n\n``` rust,ignore\n#![feature(cmse_nonsecure_entry)]\n\n#[no_mangle]\n#[cmse_nonsecure_entry]\npub extern \"C\" fn entry_function(input: u32) -> u32 {\n input + 6\n}\n```\n\n``` text\n$ rustc --emit obj --crate-type lib --target thumbv8m.main-none-eabi function.rs\n$ arm-none-eabi-objdump -D function.o\n\n00000000 <entry_function>:\n 0: b580 push {r7, lr}\n 2: 466f mov r7, sp\n 4: b082 sub sp, #8\n 6: 9001 str r0, [sp, #4]\n 8: 1d81 adds r1, r0, #6\n a: 460a mov r2, r1\n c: 4281 cmp r1, r0\n e: 9200 str r2, [sp, #0]\n 10: d30b bcc.n 2a <entry_function+0x2a>\n 12: e7ff b.n 14 <entry_function+0x14>\n 14: 9800 ldr r0, [sp, #0]\n 16: b002 add sp, #8\n 18: e8bd 4080 ldmia.w sp!, {r7, lr}\n 1c: 4671 mov r1, lr\n 1e: 4672 mov r2, lr\n 20: 4673 mov r3, lr\n 22: 46f4 mov ip, lr\n 24: f38e 8800 msr CPSR_f, lr\n 28: 4774 bxns lr\n 2a: f240 0000 movw r0, #0\n 2e: f2c0 0000 movt r0, #0\n 32: f240 0200 movw r2, #0\n 36: f2c0 0200 movt r2, #0\n 3a: 211c movs r1, #28\n 3c: f7ff fffe bl 0 <_ZN4core9panicking5panic17h5c028258ca2fb3f5E>\n 40: defe udf #254 ; 0xfe\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 : "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 : "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`, `align`,\n`abi`. Note that it only works on sized types 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 : "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 : "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> **<sup>Lexer:<sup>** \n> IDENTIFIER : \n> &nbsp;&nbsp; &nbsp;&nbsp; XID_start XID_continue<sup>\\*</sup> \n> &nbsp;&nbsp; | `_` XID_continue<sup>+</sup> \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 : "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<i32, ParseIntError> = try {\n \"1\".parse::<i32>()?\n + \"2\".parse::<i32>()?\n + \"3\".parse::<i32>()?\n};\nassert_eq!(result, Ok(6));\n\nlet result: Result<i32, ParseIntError> = try {\n \"1\".parse::<i32>()?\n + \"foo\".parse::<i32>()?\n + \"3\".parse::<i32>()?\n};\nassert!(result.is_err());\n```\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<T>`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 : "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 : "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<T: ?Sized> !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 : "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 : "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 : "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" } , 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 : "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 : "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 : "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 : "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 : "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 : "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 : "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 : "rt" , description : "# `rt`\n\nThis feature is internal to the Rust compiler and is not intended for general use.\n\n------------------------\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 other architectures are also supported.\n\nInline assembly is currently supported on the following architectures:\n- x86 and x86-64\n- ARM\n- AArch64\n- RISC-V\n- NVPTX\n- Hexagon\n- MIPS32r2 and MIPS64r2\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## Memory address operands\n\nSometimes assembly instructions require operands passed via memory addresses/memory locations.\nYou have to manually use the memory address syntax specified by the respectively architectures.\nFor example, in x86/x86_64 and intel assembly syntax, you should wrap inputs/outputs in `[]`\nto indicate they are memory operands:\n\n```rust,allow_fail\n# #![feature(asm, llvm_asm)]\n# fn load_fpu_control_word(control: u16) {\nunsafe {\n asm!(\"fldcw [{}]\", in(reg) &control, options(nostack));\n\n // Previously this would have been written with the deprecated `llvm_asm!` like this\n llvm_asm!(\"fldcw $0\" :: \"m\" (control) :: \"volatile\");\n}\n# }\n```\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 := <register class> / \"<explicit register>\"\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\" / \"nostack\" / \"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(<reg>) <expr>`\n - `<reg>` 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 `<expr>` 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(<reg>) <expr>`\n - `<reg>` 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 - `<expr>` 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(<reg>) <expr>`\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(<reg>) <expr>`\n - `<reg>` 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 `<expr>` at the start of the asm code.\n - `<expr>` 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(<reg>) <in expr> => <out expr>`\n - Same as `inout` except that the initial value of the register is taken from the value of `<in expr>`.\n - `<out expr>` 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 `<out expr>`, which will cause the contents of the register to be discarded at the end of the asm code (effectively acting as a clobber).\n - `<in expr>` and `<out expr>` may have different types.\n* `inlateout(<reg>) <expr>` / `inlateout(<reg>) <in expr> => <out expr>`\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 <expr>`\n - `<expr>` 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 <path>`\n - `<path>` 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 - `<path>` 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| MIPS | `reg` | `$[2-25]` | `r` |\n| MIPS | `freg` | `$f[0-31]` | `f` |\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| ------------ | ---------