aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock16
-rw-r--r--crates/assists/src/ast_transform.rs2
-rw-r--r--crates/assists/src/handlers/add_missing_impl_members.rs25
-rw-r--r--crates/assists/src/handlers/extract_struct_from_enum_variant.rs2
-rw-r--r--crates/assists/src/handlers/qualify_path.rs2
-rw-r--r--crates/cfg/src/dnf.rs2
-rw-r--r--crates/completion/src/completions/attribute.rs35
-rw-r--r--crates/completion/src/completions/unqualified_path.rs2
-rw-r--r--crates/completion/src/render/function.rs2
-rw-r--r--crates/hir/src/code_model.rs47
-rw-r--r--crates/hir/src/lib.rs9
-rw-r--r--crates/hir/src/semantics.rs46
-rw-r--r--crates/hir/src/source_analyzer.rs2
-rw-r--r--crates/hir_def/src/attr.rs8
-rw-r--r--crates/hir_def/src/builtin_attr.rs430
-rw-r--r--crates/hir_def/src/generics.rs69
-rw-r--r--crates/hir_def/src/item_tree.rs7
-rw-r--r--crates/hir_def/src/item_tree/lower.rs20
-rw-r--r--crates/hir_def/src/lib.rs8
-rw-r--r--crates/hir_def/src/path.rs4
-rw-r--r--crates/hir_def/src/path/lower.rs12
-rw-r--r--crates/hir_def/src/type_ref.rs50
-rw-r--r--crates/hir_expand/src/name.rs7
-rw-r--r--crates/hir_ty/src/diagnostics.rs10
-rw-r--r--crates/hir_ty/src/display.rs25
-rw-r--r--crates/hir_ty/src/infer/expr.rs30
-rw-r--r--crates/hir_ty/src/lib.rs10
-rw-r--r--crates/hir_ty/src/lower.rs74
-rw-r--r--crates/hir_ty/src/tests/regression.rs37
-rw-r--r--crates/hir_ty/src/tests/simple.rs56
-rw-r--r--crates/hir_ty/src/utils.rs24
-rw-r--r--crates/ide/src/display/navigation_target.rs52
-rw-r--r--crates/ide/src/hover.rs16
-rw-r--r--crates/ide/src/runnables.rs18
-rw-r--r--crates/mbe/src/mbe_expander/matcher.rs32
-rw-r--r--crates/mbe/src/tests.rs13
-rw-r--r--crates/project_model/src/sysroot.rs2
-rw-r--r--crates/project_model/src/workspace.rs2
-rw-r--r--crates/rust-analyzer/src/cli.rs23
-rw-r--r--crates/rust-analyzer/src/cli/analysis_bench.rs5
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs8
-rw-r--r--crates/rust-analyzer/src/lib.rs21
-rw-r--r--crates/rust-analyzer/src/main_loop.rs1
-rw-r--r--crates/syntax/src/ast/node_ext.rs2
-rw-r--r--crates/syntax/src/ast/token_ext.rs2
-rw-r--r--docs/user/generated_diagnostic.adoc119
-rw-r--r--docs/user/manual.adoc19
-rw-r--r--editors/code/language-configuration.json38
-rw-r--r--editors/code/package.json11
-rw-r--r--xtask/src/codegen/gen_assists_docs.rs2
-rw-r--r--xtask/src/metrics.rs4
51 files changed, 1104 insertions, 359 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 321766b82..ec8ad11cb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -261,9 +261,9 @@ dependencies = [
261 261
262[[package]] 262[[package]]
263name = "const_fn" 263name = "const_fn"
264version = "0.4.3" 264version = "0.4.4"
265source = "registry+https://github.com/rust-lang/crates.io-index" 265source = "registry+https://github.com/rust-lang/crates.io-index"
266checksum = "c478836e029dcef17fb47c89023448c64f781a046e0300e257ad8225ae59afab" 266checksum = "cd51eab21ab4fd6a3bf889e2d0958c0a6e3a61ad04260325e919e652a2a62826"
267 267
268[[package]] 268[[package]]
269name = "crc32fast" 269name = "crc32fast"
@@ -979,9 +979,9 @@ dependencies = [
979 979
980[[package]] 980[[package]]
981name = "net2" 981name = "net2"
982version = "0.2.36" 982version = "0.2.37"
983source = "registry+https://github.com/rust-lang/crates.io-index" 983source = "registry+https://github.com/rust-lang/crates.io-index"
984checksum = "d7cf75f38f16cb05ea017784dc6dbfd354f76c223dba37701734c4f5a9337d02" 984checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae"
985dependencies = [ 985dependencies = [
986 "cfg-if 0.1.10", 986 "cfg-if 0.1.10",
987 "libc", 987 "libc",
@@ -1990,18 +1990,18 @@ dependencies = [
1990 1990
1991[[package]] 1991[[package]]
1992name = "xshell" 1992name = "xshell"
1993version = "0.1.6" 1993version = "0.1.7"
1994source = "registry+https://github.com/rust-lang/crates.io-index" 1994source = "registry+https://github.com/rust-lang/crates.io-index"
1995checksum = "3e9bbfccbb2233e6b0473b7870d4b0811a402e9e249a5e8394e768e5a5c9c37d" 1995checksum = "ed0728d188f2ae530490b7d92435728aba53c6aed06d07e1951da9bd4c1d0798"
1996dependencies = [ 1996dependencies = [
1997 "xshell-macros", 1997 "xshell-macros",
1998] 1998]
1999 1999
2000[[package]] 2000[[package]]
2001name = "xshell-macros" 2001name = "xshell-macros"
2002version = "0.1.6" 2002version = "0.1.7"
2003source = "registry+https://github.com/rust-lang/crates.io-index" 2003source = "registry+https://github.com/rust-lang/crates.io-index"
2004checksum = "b94f1c632d730a1704b21dc551a4c74fbed713cfa59593708f94943548206134" 2004checksum = "367f903cc3f8bc4f4b2400d47dfa6c9e3e121ffb51a30cf0fb67a72c0a0f9617"
2005 2005
2006[[package]] 2006[[package]]
2007name = "xtask" 2007name = "xtask"
diff --git a/crates/assists/src/ast_transform.rs b/crates/assists/src/ast_transform.rs
index 66e4634b1..da94e9987 100644
--- a/crates/assists/src/ast_transform.rs
+++ b/crates/assists/src/ast_transform.rs
@@ -89,7 +89,7 @@ impl<'a> SubstituteTypeParams<'a> {
89 let substs = get_syntactic_substs(impl_def).unwrap_or_default(); 89 let substs = get_syntactic_substs(impl_def).unwrap_or_default();
90 let generic_def: hir::GenericDef = trait_.into(); 90 let generic_def: hir::GenericDef = trait_.into();
91 let substs_by_param: FxHashMap<_, _> = generic_def 91 let substs_by_param: FxHashMap<_, _> = generic_def
92 .params(source_scope.db) 92 .type_params(source_scope.db)
93 .into_iter() 93 .into_iter()
94 // this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky 94 // this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky
95 .skip(1) 95 .skip(1)
diff --git a/crates/assists/src/handlers/add_missing_impl_members.rs b/crates/assists/src/handlers/add_missing_impl_members.rs
index bbb71e261..e413505d3 100644
--- a/crates/assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/assists/src/handlers/add_missing_impl_members.rs
@@ -784,4 +784,29 @@ impl Test for () {
784"#, 784"#,
785 ) 785 )
786 } 786 }
787
788 #[test]
789 fn missing_generic_type() {
790 check_assist(
791 add_missing_impl_members,
792 r#"
793trait Foo<BAR> {
794 fn foo(&self, bar: BAR);
795}
796impl Foo for () {
797 <|>
798}
799"#,
800 r#"
801trait Foo<BAR> {
802 fn foo(&self, bar: BAR);
803}
804impl Foo for () {
805 fn foo(&self, bar: BAR) {
806 ${0:todo!()}
807 }
808}
809"#,
810 )
811 }
787} 812}
diff --git a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
index d85767b4e..2e56bd7ff 100644
--- a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -212,7 +212,7 @@ fn update_reference(
212 find_node_at_offset::<ast::PathExpr>(source_file.syntax(), offset) 212 find_node_at_offset::<ast::PathExpr>(source_file.syntax(), offset)
213 { 213 {
214 // tuple variant 214 // tuple variant
215 (path_expr.path()?.segment()?, path_expr.syntax().parent()?.clone()) 215 (path_expr.path()?.segment()?, path_expr.syntax().parent()?)
216 } else if let Some(record_expr) = 216 } else if let Some(record_expr) =
217 find_node_at_offset::<ast::RecordExpr>(source_file.syntax(), offset) 217 find_node_at_offset::<ast::RecordExpr>(source_file.syntax(), offset)
218 { 218 {
diff --git a/crates/assists/src/handlers/qualify_path.rs b/crates/assists/src/handlers/qualify_path.rs
index 6f9810fe8..98cb09214 100644
--- a/crates/assists/src/handlers/qualify_path.rs
+++ b/crates/assists/src/handlers/qualify_path.rs
@@ -150,7 +150,7 @@ impl QualifyCandidate<'_> {
150 import, 150 import,
151 trait_method_name, 151 trait_method_name,
152 generics, 152 generics,
153 match arg_list.clone() { 153 match arg_list {
154 Some(args) => make::arg_list(iter::once(receiver).chain(args)), 154 Some(args) => make::arg_list(iter::once(receiver).chain(args)),
155 None => make::arg_list(iter::once(receiver)), 155 None => make::arg_list(iter::once(receiver)),
156 } 156 }
diff --git a/crates/cfg/src/dnf.rs b/crates/cfg/src/dnf.rs
index 580c9a9a2..30f4bcdf7 100644
--- a/crates/cfg/src/dnf.rs
+++ b/crates/cfg/src/dnf.rs
@@ -30,7 +30,7 @@ impl DnfExpr {
30 pub fn new(expr: CfgExpr) -> Self { 30 pub fn new(expr: CfgExpr) -> Self {
31 let builder = Builder { expr: DnfExpr { conjunctions: Vec::new() } }; 31 let builder = Builder { expr: DnfExpr { conjunctions: Vec::new() } };
32 32
33 builder.lower(expr.clone()) 33 builder.lower(expr)
34 } 34 }
35 35
36 /// Computes a list of present or absent atoms in `opts` that cause this expression to evaluate 36 /// Computes a list of present or absent atoms in `opts` that cause this expression to evaluate
diff --git a/crates/completion/src/completions/attribute.rs b/crates/completion/src/completions/attribute.rs
index 5404145d5..acce2e7e7 100644
--- a/crates/completion/src/completions/attribute.rs
+++ b/crates/completion/src/completions/attribute.rs
@@ -3,6 +3,7 @@
3//! This module uses a bit of static metadata to provide completions 3//! This module uses a bit of static metadata to provide completions
4//! for built-in attributes. 4//! for built-in attributes.
5 5
6use itertools::Itertools;
6use rustc_hash::FxHashSet; 7use rustc_hash::FxHashSet;
7use syntax::{ast, AstNode, SyntaxKind}; 8use syntax::{ast, AstNode, SyntaxKind};
8 9
@@ -162,19 +163,20 @@ const ATTRIBUTES: &[AttrCompletion] = &[
162fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, derive_input: ast::TokenTree) { 163fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, derive_input: ast::TokenTree) {
163 if let Ok(existing_derives) = parse_comma_sep_input(derive_input) { 164 if let Ok(existing_derives) = parse_comma_sep_input(derive_input) {
164 for derive_completion in DEFAULT_DERIVE_COMPLETIONS 165 for derive_completion in DEFAULT_DERIVE_COMPLETIONS
165 .into_iter() 166 .iter()
166 .filter(|completion| !existing_derives.contains(completion.label)) 167 .filter(|completion| !existing_derives.contains(completion.label))
167 { 168 {
168 let mut label = derive_completion.label.to_owned(); 169 let mut components = vec![derive_completion.label];
169 for dependency in derive_completion 170 components.extend(
170 .dependencies 171 derive_completion
171 .into_iter() 172 .dependencies
172 .filter(|&&dependency| !existing_derives.contains(dependency)) 173 .iter()
173 { 174 .filter(|&&dependency| !existing_derives.contains(dependency)),
174 label.push_str(", "); 175 );
175 label.push_str(dependency); 176 let lookup = components.join(", ");
176 } 177 let label = components.iter().rev().join(", ");
177 CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label) 178 CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label)
179 .lookup_by(lookup)
178 .kind(CompletionItemKind::Attribute) 180 .kind(CompletionItemKind::Attribute)
179 .add_to(acc) 181 .add_to(acc)
180 } 182 }
@@ -264,7 +266,6 @@ struct DeriveCompletion {
264 266
265/// Standard Rust derives and the information about their dependencies 267/// Standard Rust derives and the information about their dependencies
266/// (the dependencies are needed so that the main derive don't break the compilation when added) 268/// (the dependencies are needed so that the main derive don't break the compilation when added)
267#[rustfmt::skip]
268const DEFAULT_DERIVE_COMPLETIONS: &[DeriveCompletion] = &[ 269const DEFAULT_DERIVE_COMPLETIONS: &[DeriveCompletion] = &[
269 DeriveCompletion { label: "Clone", dependencies: &[] }, 270 DeriveCompletion { label: "Clone", dependencies: &[] },
270 DeriveCompletion { label: "Copy", dependencies: &["Clone"] }, 271 DeriveCompletion { label: "Copy", dependencies: &["Clone"] },
@@ -421,14 +422,14 @@ struct Test {}
421 "#, 422 "#,
422 expect![[r#" 423 expect![[r#"
423 at Clone 424 at Clone
424 at Copy, Clone 425 at Clone, Copy
425 at Debug 426 at Debug
426 at Default 427 at Default
427 at Eq, PartialEq
428 at Hash 428 at Hash
429 at Ord, PartialOrd, Eq, PartialEq
430 at PartialEq 429 at PartialEq
431 at PartialOrd, PartialEq 430 at PartialEq, Eq
431 at PartialEq, Eq, PartialOrd, Ord
432 at PartialEq, PartialOrd
432 "#]], 433 "#]],
433 ); 434 );
434 } 435 }
@@ -453,12 +454,12 @@ struct Test {}
453"#, 454"#,
454 expect![[r#" 455 expect![[r#"
455 at Clone 456 at Clone
456 at Copy, Clone 457 at Clone, Copy
457 at Debug 458 at Debug
458 at Default 459 at Default
459 at Eq 460 at Eq
461 at Eq, PartialOrd, Ord
460 at Hash 462 at Hash
461 at Ord, PartialOrd, Eq
462 at PartialOrd 463 at PartialOrd
463 "#]], 464 "#]],
464 ) 465 )
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs
index 2b0924ae5..b9315f6c0 100644
--- a/crates/completion/src/completions/unqualified_path.rs
+++ b/crates/completion/src/completions/unqualified_path.rs
@@ -147,7 +147,7 @@ fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()
147 .filter_map(|(import_path, definition)| { 147 .filter_map(|(import_path, definition)| {
148 render_resolution_with_import( 148 render_resolution_with_import(
149 RenderContext::new(ctx), 149 RenderContext::new(ctx),
150 ImportEdit { import_path: import_path.clone(), import_scope: import_scope.clone() }, 150 ImportEdit { import_path, import_scope: import_scope.clone() },
151 &definition, 151 &definition,
152 ) 152 )
153 }); 153 });
diff --git a/crates/completion/src/render/function.rs b/crates/completion/src/render/function.rs
index d16005249..316e05b52 100644
--- a/crates/completion/src/render/function.rs
+++ b/crates/completion/src/render/function.rs
@@ -91,7 +91,7 @@ impl<'a> FunctionRender<'a> {
91 .zip(params_ty) 91 .zip(params_ty)
92 .flat_map(|(pat, param_ty)| { 92 .flat_map(|(pat, param_ty)| {
93 let pat = pat?; 93 let pat = pat?;
94 let name = pat.to_string(); 94 let name = pat;
95 let arg = name.trim_start_matches("mut ").trim_start_matches('_'); 95 let arg = name.trim_start_matches("mut ").trim_start_matches('_');
96 Some(self.add_arg(arg, param_ty.ty())) 96 Some(self.add_arg(arg, param_ty.ty()))
97 }) 97 })
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
index 9a1e9ba49..fcc42c6bb 100644
--- a/crates/hir/src/code_model.rs
+++ b/crates/hir/src/code_model.rs
@@ -19,8 +19,9 @@ use hir_def::{
19 src::HasSource as _, 19 src::HasSource as _,
20 type_ref::{Mutability, TypeRef}, 20 type_ref::{Mutability, TypeRef},
21 AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, DefWithBodyId, EnumId, 21 AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, DefWithBodyId, EnumId,
22 FunctionId, GenericDefId, HasModule, ImplId, LocalEnumVariantId, LocalFieldId, LocalModuleId, 22 FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, LocalEnumVariantId, LocalFieldId,
23 Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, 23 LocalModuleId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId,
24 UnionId,
24}; 25};
25use hir_def::{find_path::PrefixKind, item_scope::ItemInNs, visibility::Visibility}; 26use hir_def::{find_path::PrefixKind, item_scope::ItemInNs, visibility::Visibility};
26use hir_expand::{ 27use hir_expand::{
@@ -831,7 +832,7 @@ impl SelfParam {
831 .params 832 .params
832 .first() 833 .first()
833 .map(|param| match *param { 834 .map(|param| match *param {
834 TypeRef::Reference(_, mutability) => mutability.into(), 835 TypeRef::Reference(.., mutability) => mutability.into(),
835 _ => Access::Owned, 836 _ => Access::Owned,
836 }) 837 })
837 .unwrap_or(Access::Owned) 838 .unwrap_or(Access::Owned)
@@ -1098,8 +1099,25 @@ impl_from!(
1098); 1099);
1099 1100
1100impl GenericDef { 1101impl GenericDef {
1101 pub fn params(self, db: &dyn HirDatabase) -> Vec<TypeParam> { 1102 pub fn params(self, db: &dyn HirDatabase) -> Vec<GenericParam> {
1102 let generics: Arc<hir_def::generics::GenericParams> = db.generic_params(self.into()); 1103 let generics = db.generic_params(self.into());
1104 let ty_params = generics
1105 .types
1106 .iter()
1107 .map(|(local_id, _)| TypeParam { id: TypeParamId { parent: self.into(), local_id } })
1108 .map(GenericParam::TypeParam);
1109 let lt_params = generics
1110 .lifetimes
1111 .iter()
1112 .map(|(local_id, _)| LifetimeParam {
1113 id: LifetimeParamId { parent: self.into(), local_id },
1114 })
1115 .map(GenericParam::LifetimeParam);
1116 ty_params.chain(lt_params).collect()
1117 }
1118
1119 pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeParam> {
1120 let generics = db.generic_params(self.into());
1103 generics 1121 generics
1104 .types 1122 .types
1105 .iter() 1123 .iter()
@@ -1176,6 +1194,13 @@ impl Local {
1176} 1194}
1177 1195
1178#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 1196#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1197pub enum GenericParam {
1198 TypeParam(TypeParam),
1199 LifetimeParam(LifetimeParam),
1200}
1201impl_from!(TypeParam, LifetimeParam for GenericParam);
1202
1203#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1179pub struct TypeParam { 1204pub struct TypeParam {
1180 pub(crate) id: TypeParamId, 1205 pub(crate) id: TypeParamId,
1181} 1206}
@@ -1215,6 +1240,18 @@ impl TypeParam {
1215 } 1240 }
1216} 1241}
1217 1242
1243#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1244pub struct LifetimeParam {
1245 pub(crate) id: LifetimeParamId,
1246}
1247
1248impl LifetimeParam {
1249 pub fn name(self, db: &dyn HirDatabase) -> Name {
1250 let params = db.generic_params(self.id.parent);
1251 params.lifetimes[self.id.local_id].name.clone()
1252 }
1253}
1254
1218// FIXME: rename from `ImplDef` to `Impl` 1255// FIXME: rename from `ImplDef` to `Impl`
1219#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 1256#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1220pub struct ImplDef { 1257pub struct ImplDef {
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 302a52491..0f399a2c6 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -35,8 +35,8 @@ pub use crate::{
35 code_model::{ 35 code_model::{
36 Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, Callable, CallableKind, Const, 36 Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, Callable, CallableKind, Const,
37 Crate, CrateDependency, DefWithBody, Enum, EnumVariant, Field, FieldSource, Function, 37 Crate, CrateDependency, DefWithBody, Enum, EnumVariant, Field, FieldSource, Function,
38 GenericDef, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef, Static, 38 GenericDef, HasVisibility, ImplDef, LifetimeParam, Local, MacroDef, Module, ModuleDef,
39 Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, 39 ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef,
40 }, 40 },
41 has_source::HasSource, 41 has_source::HasSource,
42 semantics::{PathResolution, Semantics, SemanticsScope}, 42 semantics::{PathResolution, Semantics, SemanticsScope},
@@ -56,8 +56,9 @@ pub use hir_def::{
56 visibility::Visibility, 56 visibility::Visibility,
57}; 57};
58pub use hir_expand::{ 58pub use hir_expand::{
59 name::known, name::AsName, name::Name, ExpandResult, HirFileId, InFile, MacroCallId, 59 name::{known, AsName, Name},
60 MacroCallLoc, /* FIXME */ MacroDefId, MacroFile, Origin, 60 ExpandResult, HirFileId, InFile, MacroCallId, MacroCallLoc, /* FIXME */ MacroDefId,
61 MacroFile, Origin,
61}; 62};
62pub use hir_ty::display::HirDisplay; 63pub use hir_ty::display::HirDisplay;
63 64
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 4315ad48b..4bd22ed27 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -294,9 +294,8 @@ impl<'db> SemanticsImpl<'db> {
294 } 294 }
295 295
296 fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { 296 fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
297 let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call); 297 let sa = self.analyze(macro_call.syntax());
298 let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); 298 let file_id = sa.expand(self.db, InFile::new(sa.file_id, macro_call))?;
299 let file_id = sa.expand(self.db, macro_call)?;
300 let node = self.db.parse_or_expand(file_id)?; 299 let node = self.db.parse_or_expand(file_id)?;
301 self.cache(node.clone(), file_id); 300 self.cache(node.clone(), file_id);
302 Some(node) 301 Some(node)
@@ -308,9 +307,8 @@ impl<'db> SemanticsImpl<'db> {
308 hypothetical_args: &ast::TokenTree, 307 hypothetical_args: &ast::TokenTree,
309 token_to_map: SyntaxToken, 308 token_to_map: SyntaxToken,
310 ) -> Option<(SyntaxNode, SyntaxToken)> { 309 ) -> Option<(SyntaxNode, SyntaxToken)> {
311 let macro_call = 310 let sa = self.analyze(actual_macro_call.syntax());
312 self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call); 311 let macro_call = InFile::new(sa.file_id, actual_macro_call);
313 let sa = self.analyze2(macro_call.map(|it| it.syntax()), None);
314 let krate = sa.resolver.krate()?; 312 let krate = sa.resolver.krate()?;
315 let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| { 313 let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| {
316 sa.resolver.resolve_path_as_macro(self.db.upcast(), &path) 314 sa.resolver.resolve_path_as_macro(self.db.upcast(), &path)
@@ -326,10 +324,9 @@ impl<'db> SemanticsImpl<'db> {
326 fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken { 324 fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken {
327 let _p = profile::span("descend_into_macros"); 325 let _p = profile::span("descend_into_macros");
328 let parent = token.parent(); 326 let parent = token.parent();
329 let parent = self.find_file(parent); 327 let sa = self.analyze(&parent);
330 let sa = self.analyze2(parent.as_ref(), None);
331 328
332 let token = successors(Some(parent.with_value(token)), |token| { 329 let token = successors(Some(InFile::new(sa.file_id, token)), |token| {
333 self.db.check_canceled(); 330 self.db.check_canceled();
334 let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?; 331 let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?;
335 let tt = macro_call.token_tree()?; 332 let tt = macro_call.token_tree()?;
@@ -486,15 +483,13 @@ impl<'db> SemanticsImpl<'db> {
486 } 483 }
487 484
488 fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> { 485 fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> {
489 let node = self.find_file(node.clone()); 486 let sa = self.analyze(node);
490 let resolver = self.analyze2(node.as_ref(), None).resolver; 487 SemanticsScope { db: self.db, file_id: sa.file_id, resolver: sa.resolver }
491 SemanticsScope { db: self.db, file_id: node.file_id, resolver }
492 } 488 }
493 489
494 fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> { 490 fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> {
495 let node = self.find_file(node.clone()); 491 let sa = self.analyze_with_offset(node, offset);
496 let resolver = self.analyze2(node.as_ref(), Some(offset)).resolver; 492 SemanticsScope { db: self.db, file_id: sa.file_id, resolver: sa.resolver }
497 SemanticsScope { db: self.db, file_id: node.file_id, resolver }
498 } 493 }
499 494
500 fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> { 495 fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> {
@@ -504,21 +499,24 @@ impl<'db> SemanticsImpl<'db> {
504 } 499 }
505 500
506 fn analyze(&self, node: &SyntaxNode) -> SourceAnalyzer { 501 fn analyze(&self, node: &SyntaxNode) -> SourceAnalyzer {
507 let src = self.find_file(node.clone()); 502 self.analyze_impl(node, None)
508 self.analyze2(src.as_ref(), None)
509 } 503 }
504 fn analyze_with_offset(&self, node: &SyntaxNode, offset: TextSize) -> SourceAnalyzer {
505 self.analyze_impl(node, Some(offset))
506 }
507 fn analyze_impl(&self, node: &SyntaxNode, offset: Option<TextSize>) -> SourceAnalyzer {
508 let _p = profile::span("Semantics::analyze_impl");
509 let node = self.find_file(node.clone());
510 let node = node.as_ref();
510 511
511 fn analyze2(&self, src: InFile<&SyntaxNode>, offset: Option<TextSize>) -> SourceAnalyzer { 512 let container = match self.with_ctx(|ctx| ctx.find_container(node)) {
512 let _p = profile::span("Semantics::analyze2");
513
514 let container = match self.with_ctx(|ctx| ctx.find_container(src)) {
515 Some(it) => it, 513 Some(it) => it,
516 None => return SourceAnalyzer::new_for_resolver(Resolver::default(), src), 514 None => return SourceAnalyzer::new_for_resolver(Resolver::default(), node),
517 }; 515 };
518 516
519 let resolver = match container { 517 let resolver = match container {
520 ChildContainer::DefWithBodyId(def) => { 518 ChildContainer::DefWithBodyId(def) => {
521 return SourceAnalyzer::new_for_body(self.db, def, src, offset) 519 return SourceAnalyzer::new_for_body(self.db, def, node, offset)
522 } 520 }
523 ChildContainer::TraitId(it) => it.resolver(self.db.upcast()), 521 ChildContainer::TraitId(it) => it.resolver(self.db.upcast()),
524 ChildContainer::ImplId(it) => it.resolver(self.db.upcast()), 522 ChildContainer::ImplId(it) => it.resolver(self.db.upcast()),
@@ -528,7 +526,7 @@ impl<'db> SemanticsImpl<'db> {
528 ChildContainer::TypeAliasId(it) => it.resolver(self.db.upcast()), 526 ChildContainer::TypeAliasId(it) => it.resolver(self.db.upcast()),
529 ChildContainer::GenericDefId(it) => it.resolver(self.db.upcast()), 527 ChildContainer::GenericDefId(it) => it.resolver(self.db.upcast()),
530 }; 528 };
531 SourceAnalyzer::new_for_resolver(resolver, src) 529 SourceAnalyzer::new_for_resolver(resolver, node)
532 } 530 }
533 531
534 fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) { 532 fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) {
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 1aef0f33f..bf0c959fe 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -37,7 +37,7 @@ use base_db::CrateId;
37/// original source files. It should not be used inside the HIR itself. 37/// original source files. It should not be used inside the HIR itself.
38#[derive(Debug)] 38#[derive(Debug)]
39pub(crate) struct SourceAnalyzer { 39pub(crate) struct SourceAnalyzer {
40 file_id: HirFileId, 40 pub(crate) file_id: HirFileId,
41 pub(crate) resolver: Resolver, 41 pub(crate) resolver: Resolver,
42 body: Option<Arc<Body>>, 42 body: Option<Arc<Body>>,
43 body_source_map: Option<Arc<BodySourceMap>>, 43 body_source_map: Option<Arc<BodySourceMap>>,
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 228d706db..c64b78445 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -23,7 +23,7 @@ use crate::{
23}; 23};
24 24
25/// Holds documentation 25/// Holds documentation
26#[derive(Debug, Clone, PartialEq, Eq)] 26#[derive(Debug, Clone, PartialEq, Eq, Hash)]
27pub struct Documentation(String); 27pub struct Documentation(String);
28 28
29impl Documentation { 29impl Documentation {
@@ -32,9 +32,9 @@ impl Documentation {
32 } 32 }
33} 33}
34 34
35impl Into<String> for Documentation { 35impl From<Documentation> for String {
36 fn into(self) -> String { 36 fn from(Documentation(string): Documentation) -> Self {
37 self.0 37 string
38 } 38 }
39} 39}
40 40
diff --git a/crates/hir_def/src/builtin_attr.rs b/crates/hir_def/src/builtin_attr.rs
new file mode 100644
index 000000000..2e989c504
--- /dev/null
+++ b/crates/hir_def/src/builtin_attr.rs
@@ -0,0 +1,430 @@
1//! Builtin attributes resolved by nameres.
2//!
3//! The actual definitions were copied from rustc's `compiler/rustc_feature/src/builtin_attrs.rs`.
4//!
5//! It was last synchronized with upstream commit 2225ee1b62ff089917434aefd9b2bf509cfa087f.
6//!
7//! The macros were adjusted to only expand to the attribute name, since that is all we need to do
8//! name resolution, and `BUILTIN_ATTRIBUTES` is almost entirely unchanged from the original, to
9//! ease updating.
10
11/// Ignored attribute namespaces used by tools.
12pub const TOOL_MODULES: &[&str] = &["rustfmt", "clippy"];
13
14type BuiltinAttribute = &'static str;
15
16macro_rules! ungated {
17 ($attr:ident, $typ:expr, $tpl:expr $(,)?) => {
18 stringify!($attr)
19 };
20}
21
22macro_rules! gated {
23 ($attr:ident $($rest:tt)*) => {
24 stringify!($attr)
25 };
26}
27
28macro_rules! rustc_attr {
29 (TEST, $attr:ident $($rest:tt)*) => {
30 stringify!($attr)
31 };
32 ($attr:ident $($rest:tt)*) => {
33 stringify!($attr)
34 };
35}
36
37/// Attributes that have a special meaning to rustc or rustdoc.
38#[rustfmt::skip]
39pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
40 // ==========================================================================
41 // Stable attributes:
42 // ==========================================================================
43
44 // Conditional compilation:
45 ungated!(cfg, Normal, template!(List: "predicate")),
46 ungated!(cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ...")),
47
48 // Testing:
49 ungated!(ignore, Normal, template!(Word, NameValueStr: "reason")),
50 ungated!(
51 should_panic, Normal,
52 template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"),
53 ),
54 // FIXME(Centril): This can be used on stable but shouldn't.
55 ungated!(reexport_test_harness_main, Normal, template!(NameValueStr: "name")),
56
57 // Macros:
58 ungated!(derive, Normal, template!(List: "Trait1, Trait2, ...")),
59 ungated!(automatically_derived, Normal, template!(Word)),
60 // FIXME(#14407)
61 ungated!(macro_use, Normal, template!(Word, List: "name1, name2, ...")),
62 ungated!(macro_escape, Normal, template!(Word)), // Deprecated synonym for `macro_use`.
63 ungated!(macro_export, Normal, template!(Word, List: "local_inner_macros")),
64 ungated!(proc_macro, Normal, template!(Word)),
65 ungated!(
66 proc_macro_derive, Normal,
67 template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)"),
68 ),
69 ungated!(proc_macro_attribute, Normal, template!(Word)),
70
71 // Lints:
72 ungated!(warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)),
73 ungated!(allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)),
74 ungated!(forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)),
75 ungated!(deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)),
76 ungated!(must_use, AssumedUsed, template!(Word, NameValueStr: "reason")),
77 // FIXME(#14407)
78 ungated!(
79 deprecated, Normal,
80 template!(
81 Word,
82 List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#,
83 NameValueStr: "reason"
84 ),
85 ),
86
87 // Crate properties:
88 ungated!(crate_name, CrateLevel, template!(NameValueStr: "name")),
89 ungated!(crate_type, CrateLevel, template!(NameValueStr: "bin|lib|...")),
90 ungated!(crate_id, CrateLevel, template!(NameValueStr: "ignored")),
91
92 // ABI, linking, symbols, and FFI
93 ungated!(
94 link, AssumedUsed,
95 template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...""#),
96 ),
97 ungated!(link_name, AssumedUsed, template!(NameValueStr: "name")),
98 ungated!(no_link, Normal, template!(Word)),
99 ungated!(repr, Normal, template!(List: "C")),
100 ungated!(export_name, AssumedUsed, template!(NameValueStr: "name")),
101 ungated!(link_section, AssumedUsed, template!(NameValueStr: "name")),
102 ungated!(no_mangle, AssumedUsed, template!(Word)),
103 ungated!(used, AssumedUsed, template!(Word)),
104
105 // Limits:
106 ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N")),
107 ungated!(type_length_limit, CrateLevel, template!(NameValueStr: "N")),
108 gated!(
109 const_eval_limit, CrateLevel, template!(NameValueStr: "N"), const_eval_limit,
110 experimental!(const_eval_limit)
111 ),
112
113 // Entry point:
114 ungated!(main, Normal, template!(Word)),
115 ungated!(start, Normal, template!(Word)),
116 ungated!(no_start, CrateLevel, template!(Word)),
117 ungated!(no_main, CrateLevel, template!(Word)),
118
119 // Modules, prelude, and resolution:
120 ungated!(path, Normal, template!(NameValueStr: "file")),
121 ungated!(no_std, CrateLevel, template!(Word)),
122 ungated!(no_implicit_prelude, Normal, template!(Word)),
123 ungated!(non_exhaustive, AssumedUsed, template!(Word)),
124
125 // Runtime
126 ungated!(windows_subsystem, AssumedUsed, template!(NameValueStr: "windows|console")),
127 ungated!(panic_handler, Normal, template!(Word)), // RFC 2070
128
129 // Code generation:
130 ungated!(inline, AssumedUsed, template!(Word, List: "always|never")),
131 ungated!(cold, AssumedUsed, template!(Word)),
132 ungated!(no_builtins, AssumedUsed, template!(Word)),
133 ungated!(target_feature, AssumedUsed, template!(List: r#"enable = "name""#)),
134 ungated!(track_caller, AssumedUsed, template!(Word)),
135 gated!(
136 no_sanitize, AssumedUsed,
137 template!(List: "address, memory, thread"),
138 experimental!(no_sanitize)
139 ),
140
141 // FIXME: #14408 assume docs are used since rustdoc looks at them.
142 ungated!(doc, AssumedUsed, template!(List: "hidden|inline|...", NameValueStr: "string")),
143
144 // ==========================================================================
145 // Unstable attributes:
146 // ==========================================================================
147
148 // Linking:
149 gated!(naked, AssumedUsed, template!(Word), naked_functions, experimental!(naked)),
150 gated!(
151 link_args, Normal, template!(NameValueStr: "args"),
152 "the `link_args` attribute is experimental and not portable across platforms, \
153 it is recommended to use `#[link(name = \"foo\")] instead",
154 ),
155 gated!(
156 link_ordinal, AssumedUsed, template!(List: "ordinal"), raw_dylib,
157 experimental!(link_ordinal)
158 ),
159
160 // Plugins:
161 // XXX Modified for use in rust-analyzer
162 gated!(plugin_registrar),
163 gated!(plugin),
164
165 // Testing:
166 gated!(allow_fail, Normal, template!(Word), experimental!(allow_fail)),
167 gated!(
168 test_runner, CrateLevel, template!(List: "path"), custom_test_frameworks,
169 "custom test frameworks are an unstable feature",
170 ),
171 // RFC #1268
172 gated!(marker, Normal, template!(Word), marker_trait_attr, experimental!(marker)),
173 gated!(
174 thread_local, AssumedUsed, template!(Word),
175 "`#[thread_local]` is an experimental feature, and does not currently handle destructors",
176 ),
177 gated!(no_core, CrateLevel, template!(Word), experimental!(no_core)),
178 // RFC 2412
179 gated!(
180 optimize, AssumedUsed, template!(List: "size|speed"), optimize_attribute,
181 experimental!(optimize),
182 ),
183 // RFC 2867
184 gated!(instruction_set, AssumedUsed, template!(List: "set"), isa_attribute, experimental!(instruction_set)),
185
186 gated!(ffi_returns_twice, AssumedUsed, template!(Word), experimental!(ffi_returns_twice)),
187 gated!(ffi_pure, AssumedUsed, template!(Word), experimental!(ffi_pure)),
188 gated!(ffi_const, AssumedUsed, template!(Word), experimental!(ffi_const)),
189 gated!(
190 register_attr, CrateLevel, template!(List: "attr1, attr2, ..."),
191 experimental!(register_attr),
192 ),
193 gated!(
194 register_tool, CrateLevel, template!(List: "tool1, tool2, ..."),
195 experimental!(register_tool),
196 ),
197
198 gated!(cmse_nonsecure_entry, AssumedUsed, template!(Word), experimental!(cmse_nonsecure_entry)),
199
200 // ==========================================================================
201 // Internal attributes: Stability, deprecation, and unsafe:
202 // ==========================================================================
203
204 ungated!(feature, CrateLevel, template!(List: "name1, name1, ...")),
205 // FIXME(#14407) -- only looked at on-demand so we can't
206 // guarantee they'll have already been checked.
207 ungated!(
208 rustc_deprecated, AssumedUsed,
209 template!(List: r#"since = "version", reason = "...""#)
210 ),
211 // FIXME(#14407)
212 ungated!(stable, AssumedUsed, template!(List: r#"feature = "name", since = "version""#)),
213 // FIXME(#14407)
214 ungated!(
215 unstable, AssumedUsed,
216 template!(List: r#"feature = "name", reason = "...", issue = "N""#),
217 ),
218 // FIXME(#14407)
219 ungated!(rustc_const_unstable, AssumedUsed, template!(List: r#"feature = "name""#)),
220 // FIXME(#14407)
221 ungated!(rustc_const_stable, AssumedUsed, template!(List: r#"feature = "name""#)),
222 gated!(
223 allow_internal_unstable, AssumedUsed, template!(Word, List: "feat1, feat2, ..."),
224 "allow_internal_unstable side-steps feature gating and stability checks",
225 ),
226 gated!(
227 rustc_allow_const_fn_unstable, AssumedUsed, template!(Word, List: "feat1, feat2, ..."),
228 "rustc_allow_const_fn_unstable side-steps feature gating and stability checks"
229 ),
230 gated!(
231 allow_internal_unsafe, Normal, template!(Word),
232 "allow_internal_unsafe side-steps the unsafe_code lint",
233 ),
234
235 // ==========================================================================
236 // Internal attributes: Type system related:
237 // ==========================================================================
238
239 gated!(fundamental, AssumedUsed, template!(Word), experimental!(fundamental)),
240 gated!(
241 may_dangle, Normal, template!(Word), dropck_eyepatch,
242 "`may_dangle` has unstable semantics and may be removed in the future",
243 ),
244
245 // ==========================================================================
246 // Internal attributes: Runtime related:
247 // ==========================================================================
248
249 rustc_attr!(rustc_allocator, AssumedUsed, template!(Word), IMPL_DETAIL),
250 rustc_attr!(rustc_allocator_nounwind, AssumedUsed, template!(Word), IMPL_DETAIL),
251 gated!(alloc_error_handler, Normal, template!(Word), experimental!(alloc_error_handler)),
252 gated!(
253 default_lib_allocator, AssumedUsed, template!(Word), allocator_internals,
254 experimental!(default_lib_allocator),
255 ),
256 gated!(
257 needs_allocator, Normal, template!(Word), allocator_internals,
258 experimental!(needs_allocator),
259 ),
260 gated!(panic_runtime, AssumedUsed, template!(Word), experimental!(panic_runtime)),
261 gated!(needs_panic_runtime, AssumedUsed, template!(Word), experimental!(needs_panic_runtime)),
262 gated!(
263 unwind, AssumedUsed, template!(List: "allowed|aborts"), unwind_attributes,
264 experimental!(unwind),
265 ),
266 gated!(
267 compiler_builtins, AssumedUsed, template!(Word),
268 "the `#[compiler_builtins]` attribute is used to identify the `compiler_builtins` crate \
269 which contains compiler-rt intrinsics and will never be stable",
270 ),
271 gated!(
272 profiler_runtime, AssumedUsed, template!(Word),
273 "the `#[profiler_runtime]` attribute is used to identify the `profiler_builtins` crate \
274 which contains the profiler runtime and will never be stable",
275 ),
276
277 // ==========================================================================
278 // Internal attributes, Linkage:
279 // ==========================================================================
280
281 gated!(
282 linkage, AssumedUsed, template!(NameValueStr: "external|internal|..."),
283 "the `linkage` attribute is experimental and not portable across platforms",
284 ),
285 rustc_attr!(rustc_std_internal_symbol, AssumedUsed, template!(Word), INTERNAL_UNSTABLE),
286
287 // ==========================================================================
288 // Internal attributes, Macro related:
289 // ==========================================================================
290
291 rustc_attr!(rustc_builtin_macro, AssumedUsed, template!(Word), IMPL_DETAIL),
292 rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), INTERNAL_UNSTABLE),
293 rustc_attr!(
294 rustc_macro_transparency, AssumedUsed,
295 template!(NameValueStr: "transparent|semitransparent|opaque"),
296 "used internally for testing macro hygiene",
297 ),
298
299 // ==========================================================================
300 // Internal attributes, Diagnostics related:
301 // ==========================================================================
302
303 rustc_attr!(
304 rustc_on_unimplemented, AssumedUsed,
305 template!(
306 List: r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#,
307 NameValueStr: "message"
308 ),
309 INTERNAL_UNSTABLE
310 ),
311 // Enumerates "identity-like" conversion methods to suggest on type mismatch.
312 rustc_attr!(rustc_conversion_suggestion, AssumedUsed, template!(Word), INTERNAL_UNSTABLE),
313
314 // ==========================================================================
315 // Internal attributes, Const related:
316 // ==========================================================================
317
318 rustc_attr!(rustc_promotable, AssumedUsed, template!(Word), IMPL_DETAIL),
319 rustc_attr!(rustc_args_required_const, AssumedUsed, template!(List: "N"), INTERNAL_UNSTABLE),
320
321 // ==========================================================================
322 // Internal attributes, Layout related:
323 // ==========================================================================
324
325 rustc_attr!(
326 rustc_layout_scalar_valid_range_start, AssumedUsed, template!(List: "value"),
327 "the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \
328 niche optimizations in libcore and will never be stable",
329 ),
330 rustc_attr!(
331 rustc_layout_scalar_valid_range_end, AssumedUsed, template!(List: "value"),
332 "the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
333 niche optimizations in libcore and will never be stable",
334 ),
335 rustc_attr!(
336 rustc_nonnull_optimization_guaranteed, AssumedUsed, template!(Word),
337 "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable \
338 niche optimizations in libcore and will never be stable",
339 ),
340
341 // ==========================================================================
342 // Internal attributes, Misc:
343 // ==========================================================================
344 gated!(
345 lang, Normal, template!(NameValueStr: "name"), lang_items,
346 "language items are subject to change",
347 ),
348 gated!(rustc_diagnostic_item), // XXX modified in rust-analyzer
349 gated!(
350 // Used in resolve:
351 prelude_import, AssumedUsed, template!(Word),
352 "`#[prelude_import]` is for use by rustc only",
353 ),
354 gated!(
355 rustc_paren_sugar, Normal, template!(Word), unboxed_closures,
356 "unboxed_closures are still evolving",
357 ),
358 rustc_attr!(
359 rustc_inherit_overflow_checks, AssumedUsed, template!(Word),
360 "the `#[rustc_inherit_overflow_checks]` attribute is just used to control \
361 overflow checking behavior of several libcore functions that are inlined \
362 across crates and will never be stable",
363 ),
364 rustc_attr!(rustc_reservation_impl, Normal, template!(NameValueStr: "reservation message"),
365 "the `#[rustc_reservation_impl]` attribute is internally used \
366 for reserving for `for<T> From<!> for T` impl"
367 ),
368 rustc_attr!(
369 rustc_test_marker, Normal, template!(Word),
370 "the `#[rustc_test_marker]` attribute is used internally to track tests",
371 ),
372 rustc_attr!(
373 rustc_unsafe_specialization_marker, Normal, template!(Word),
374 "the `#[rustc_unsafe_specialization_marker]` attribute is used to check specializations"
375 ),
376 rustc_attr!(
377 rustc_specialization_trait, Normal, template!(Word),
378 "the `#[rustc_specialization_trait]` attribute is used to check specializations"
379 ),
380
381 // ==========================================================================
382 // Internal attributes, Testing:
383 // ==========================================================================
384
385 rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)),
386 rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word)),
387 rustc_attr!(TEST, rustc_variance, Normal, template!(Word)),
388 rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")),
389 rustc_attr!(TEST, rustc_regions, Normal, template!(Word)),
390 rustc_attr!(
391 TEST, rustc_error, AssumedUsed,
392 template!(Word, List: "delay_span_bug_from_inside_query")
393 ),
394 rustc_attr!(TEST, rustc_dump_user_substs, AssumedUsed, template!(Word)),
395 rustc_attr!(TEST, rustc_if_this_changed, AssumedUsed, template!(Word, List: "DepNode")),
396 rustc_attr!(TEST, rustc_then_this_would_need, AssumedUsed, template!(List: "DepNode")),
397 rustc_attr!(
398 TEST, rustc_dirty, AssumedUsed,
399 template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
400 ),
401 rustc_attr!(
402 TEST, rustc_clean, AssumedUsed,
403 template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
404 ),
405 rustc_attr!(
406 TEST, rustc_partition_reused, AssumedUsed,
407 template!(List: r#"cfg = "...", module = "...""#),
408 ),
409 rustc_attr!(
410 TEST, rustc_partition_codegened, AssumedUsed,
411 template!(List: r#"cfg = "...", module = "...""#),
412 ),
413 rustc_attr!(
414 TEST, rustc_expected_cgu_reuse, AssumedUsed,
415 template!(List: r#"cfg = "...", module = "...", kind = "...""#),
416 ),
417 rustc_attr!(TEST, rustc_synthetic, AssumedUsed, template!(Word)),
418 rustc_attr!(TEST, rustc_symbol_name, AssumedUsed, template!(Word)),
419 rustc_attr!(TEST, rustc_polymorphize_error, AssumedUsed, template!(Word)),
420 rustc_attr!(TEST, rustc_def_path, AssumedUsed, template!(Word)),
421 rustc_attr!(TEST, rustc_mir, AssumedUsed, template!(List: "arg1, arg2, ...")),
422 rustc_attr!(TEST, rustc_dump_program_clauses, AssumedUsed, template!(Word)),
423 rustc_attr!(TEST, rustc_dump_env_program_clauses, AssumedUsed, template!(Word)),
424 rustc_attr!(TEST, rustc_object_lifetime_default, AssumedUsed, template!(Word)),
425 rustc_attr!(TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/)),
426 gated!(
427 omit_gdb_pretty_printer_section, AssumedUsed, template!(Word),
428 "the `#[omit_gdb_pretty_printer_section]` attribute is just used for the Rust test suite",
429 ),
430];
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs
index 835fe3fbd..5189c7e9f 100644
--- a/crates/hir_def/src/generics.rs
+++ b/crates/hir_def/src/generics.rs
@@ -21,7 +21,7 @@ use crate::{
21 keys, 21 keys,
22 src::HasChildSource, 22 src::HasChildSource,
23 src::HasSource, 23 src::HasSource,
24 type_ref::{TypeBound, TypeRef}, 24 type_ref::{LifetimeRef, TypeBound, TypeRef},
25 AdtId, GenericDefId, LocalTypeParamId, Lookup, TypeParamId, 25 AdtId, GenericDefId, LocalTypeParamId, Lookup, TypeParamId,
26}; 26};
27 27
@@ -33,6 +33,12 @@ pub struct TypeParamData {
33 pub provenance: TypeParamProvenance, 33 pub provenance: TypeParamProvenance,
34} 34}
35 35
36/// Data about a generic parameter (to a function, struct, impl, ...).
37#[derive(Clone, PartialEq, Eq, Debug)]
38pub struct LifetimeParamData {
39 pub name: Name,
40}
41
36#[derive(Copy, Clone, PartialEq, Eq, Debug)] 42#[derive(Copy, Clone, PartialEq, Eq, Debug)]
37pub enum TypeParamProvenance { 43pub enum TypeParamProvenance {
38 TypeParamList, 44 TypeParamList,
@@ -44,7 +50,7 @@ pub enum TypeParamProvenance {
44#[derive(Clone, PartialEq, Eq, Debug, Default)] 50#[derive(Clone, PartialEq, Eq, Debug, Default)]
45pub struct GenericParams { 51pub struct GenericParams {
46 pub types: Arena<TypeParamData>, 52 pub types: Arena<TypeParamData>,
47 // lifetimes: Arena<LocalLifetimeParamId, LifetimeParamData>, 53 pub lifetimes: Arena<LifetimeParamData>,
48 pub where_predicates: Vec<WherePredicate>, 54 pub where_predicates: Vec<WherePredicate>,
49} 55}
50 56
@@ -53,16 +59,17 @@ pub struct GenericParams {
53/// It might still result in multiple actual predicates though, because of 59/// It might still result in multiple actual predicates though, because of
54/// associated type bindings like `Iterator<Item = u32>`. 60/// associated type bindings like `Iterator<Item = u32>`.
55#[derive(Clone, PartialEq, Eq, Debug)] 61#[derive(Clone, PartialEq, Eq, Debug)]
56pub struct WherePredicate { 62pub enum WherePredicate {
57 pub target: WherePredicateTarget, 63 TypeBound { target: WherePredicateTypeTarget, bound: TypeBound },
58 pub bound: TypeBound, 64 Lifetime { target: LifetimeRef, bound: LifetimeRef },
59} 65}
60 66
61#[derive(Clone, PartialEq, Eq, Debug)] 67#[derive(Clone, PartialEq, Eq, Debug)]
62pub enum WherePredicateTarget { 68pub enum WherePredicateTypeTarget {
63 TypeRef(TypeRef), 69 TypeRef(TypeRef),
64 /// For desugared where predicates that can directly refer to a type param. 70 /// For desugared where predicates that can directly refer to a type param.
65 TypeParam(LocalTypeParamId), 71 TypeParam(LocalTypeParamId),
72 // FIXME: ForLifetime(Vec<LifetimeParamId>, TypeRef)
66} 73}
67 74
68type SourceMap = ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>; 75type SourceMap = ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>;
@@ -123,7 +130,7 @@ impl GenericParams {
123 } 130 }
124 131
125 fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) { 132 fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) {
126 let mut generics = GenericParams { types: Arena::default(), where_predicates: Vec::new() }; 133 let mut generics = GenericParams::default();
127 let mut sm = ArenaMap::default(); 134 let mut sm = ArenaMap::default();
128 135
129 // FIXME: add `: Sized` bound for everything except for `Self` in traits 136 // FIXME: add `: Sized` bound for everything except for `Self` in traits
@@ -171,7 +178,7 @@ impl GenericParams {
171 // add super traits as bounds on Self 178 // add super traits as bounds on Self
172 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar 179 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
173 let self_param = TypeRef::Path(name![Self].into()); 180 let self_param = TypeRef::Path(name![Self].into());
174 generics.fill_bounds(&lower_ctx, &src.value, self_param); 181 generics.fill_bounds(&lower_ctx, &src.value, Either::Left(self_param));
175 182
176 generics.fill(&lower_ctx, &mut sm, &src.value); 183 generics.fill(&lower_ctx, &mut sm, &src.value);
177 src.file_id 184 src.file_id
@@ -218,12 +225,12 @@ impl GenericParams {
218 &mut self, 225 &mut self,
219 lower_ctx: &LowerCtx, 226 lower_ctx: &LowerCtx,
220 node: &dyn ast::TypeBoundsOwner, 227 node: &dyn ast::TypeBoundsOwner,
221 type_ref: TypeRef, 228 target: Either<TypeRef, LifetimeRef>,
222 ) { 229 ) {
223 for bound in 230 for bound in
224 node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds()) 231 node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds())
225 { 232 {
226 self.add_where_predicate_from_bound(lower_ctx, bound, type_ref.clone()); 233 self.add_where_predicate_from_bound(lower_ctx, bound, target.clone());
227 } 234 }
228 } 235 }
229 236
@@ -246,19 +253,30 @@ impl GenericParams {
246 sm.insert(param_id, Either::Right(type_param.clone())); 253 sm.insert(param_id, Either::Right(type_param.clone()));
247 254
248 let type_ref = TypeRef::Path(name.into()); 255 let type_ref = TypeRef::Path(name.into());
249 self.fill_bounds(&lower_ctx, &type_param, type_ref); 256 self.fill_bounds(&lower_ctx, &type_param, Either::Left(type_ref));
257 }
258 for lifetime_param in params.lifetime_params() {
259 let name = lifetime_param
260 .lifetime_token()
261 .map_or_else(Name::missing, |tok| Name::new_lifetime(&tok));
262 let param = LifetimeParamData { name: name.clone() };
263 let _param_id = self.lifetimes.alloc(param);
264 let lifetime_ref = LifetimeRef::new_name(name);
265 self.fill_bounds(&lower_ctx, &lifetime_param, Either::Right(lifetime_ref));
250 } 266 }
251 } 267 }
252 268
253 fn fill_where_predicates(&mut self, lower_ctx: &LowerCtx, where_clause: ast::WhereClause) { 269 fn fill_where_predicates(&mut self, lower_ctx: &LowerCtx, where_clause: ast::WhereClause) {
254 for pred in where_clause.predicates() { 270 for pred in where_clause.predicates() {
255 let type_ref = match pred.ty() { 271 let target = if let Some(type_ref) = pred.ty() {
256 Some(type_ref) => type_ref, 272 Either::Left(TypeRef::from_ast(lower_ctx, type_ref))
257 None => continue, 273 } else if let Some(lifetime_tok) = pred.lifetime_token() {
274 Either::Right(LifetimeRef::from_token(lifetime_tok))
275 } else {
276 continue;
258 }; 277 };
259 let type_ref = TypeRef::from_ast(lower_ctx, type_ref);
260 for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) { 278 for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) {
261 self.add_where_predicate_from_bound(lower_ctx, bound, type_ref.clone()); 279 self.add_where_predicate_from_bound(lower_ctx, bound, target.clone());
262 } 280 }
263 } 281 }
264 } 282 }
@@ -267,15 +285,24 @@ impl GenericParams {
267 &mut self, 285 &mut self,
268 lower_ctx: &LowerCtx, 286 lower_ctx: &LowerCtx,
269 bound: ast::TypeBound, 287 bound: ast::TypeBound,
270 type_ref: TypeRef, 288 target: Either<TypeRef, LifetimeRef>,
271 ) { 289 ) {
272 if bound.question_mark_token().is_some() { 290 if bound.question_mark_token().is_some() {
273 // FIXME: remove this bound 291 // FIXME: remove this bound
274 return; 292 return;
275 } 293 }
276 let bound = TypeBound::from_ast(lower_ctx, bound); 294 let bound = TypeBound::from_ast(lower_ctx, bound);
277 self.where_predicates 295 let predicate = match (target, bound) {
278 .push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound }); 296 (Either::Left(type_ref), bound) => WherePredicate::TypeBound {
297 target: WherePredicateTypeTarget::TypeRef(type_ref),
298 bound,
299 },
300 (Either::Right(lifetime), TypeBound::Lifetime(bound)) => {
301 WherePredicate::Lifetime { target: lifetime, bound }
302 }
303 _ => return,
304 };
305 self.where_predicates.push(predicate);
279 } 306 }
280 307
281 pub(crate) fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) { 308 pub(crate) fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) {
@@ -288,8 +315,8 @@ impl GenericParams {
288 }; 315 };
289 let param_id = self.types.alloc(param); 316 let param_id = self.types.alloc(param);
290 for bound in bounds { 317 for bound in bounds {
291 self.where_predicates.push(WherePredicate { 318 self.where_predicates.push(WherePredicate::TypeBound {
292 target: WherePredicateTarget::TypeParam(param_id), 319 target: WherePredicateTypeTarget::TypeParam(param_id),
293 bound: bound.clone(), 320 bound: bound.clone(),
294 }); 321 });
295 } 322 }
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index c017b352d..b08167281 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -246,7 +246,10 @@ struct GenericParamsStorage {
246 246
247impl GenericParamsStorage { 247impl GenericParamsStorage {
248 fn alloc(&mut self, params: GenericParams) -> GenericParamsId { 248 fn alloc(&mut self, params: GenericParams) -> GenericParamsId {
249 if params.types.is_empty() && params.where_predicates.is_empty() { 249 if params.types.is_empty()
250 && params.lifetimes.is_empty()
251 && params.where_predicates.is_empty()
252 {
250 return GenericParamsId::EMPTY; 253 return GenericParamsId::EMPTY;
251 } 254 }
252 255
@@ -255,7 +258,7 @@ impl GenericParamsStorage {
255} 258}
256 259
257static EMPTY_GENERICS: GenericParams = 260static EMPTY_GENERICS: GenericParams =
258 GenericParams { types: Arena::new(), where_predicates: Vec::new() }; 261 GenericParams { types: Arena::new(), lifetimes: Arena::new(), where_predicates: Vec::new() };
259 262
260#[derive(Default, Debug, Eq, PartialEq)] 263#[derive(Default, Debug, Eq, PartialEq)]
261struct ItemTreeData { 264struct ItemTreeData {
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 63b2826f8..f7ce2e26d 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -13,6 +13,7 @@ use syntax::{
13use crate::{ 13use crate::{
14 attr::Attrs, 14 attr::Attrs,
15 generics::{GenericParams, TypeParamData, TypeParamProvenance}, 15 generics::{GenericParams, TypeParamData, TypeParamProvenance},
16 type_ref::LifetimeRef,
16}; 17};
17 18
18use super::*; 19use super::*;
@@ -292,12 +293,16 @@ impl Ctx {
292 let self_type = TypeRef::Path(name![Self].into()); 293 let self_type = TypeRef::Path(name![Self].into());
293 match self_param.kind() { 294 match self_param.kind() {
294 ast::SelfParamKind::Owned => self_type, 295 ast::SelfParamKind::Owned => self_type,
295 ast::SelfParamKind::Ref => { 296 ast::SelfParamKind::Ref => TypeRef::Reference(
296 TypeRef::Reference(Box::new(self_type), Mutability::Shared) 297 Box::new(self_type),
297 } 298 self_param.lifetime_token().map(LifetimeRef::from_token),
298 ast::SelfParamKind::MutRef => { 299 Mutability::Shared,
299 TypeRef::Reference(Box::new(self_type), Mutability::Mut) 300 ),
300 } 301 ast::SelfParamKind::MutRef => TypeRef::Reference(
302 Box::new(self_type),
303 self_param.lifetime_token().map(LifetimeRef::from_token),
304 Mutability::Mut,
305 ),
301 } 306 }
302 } 307 }
303 }; 308 };
@@ -629,8 +634,7 @@ impl Ctx {
629 // add super traits as bounds on Self 634 // add super traits as bounds on Self
630 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar 635 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
631 let self_param = TypeRef::Path(name![Self].into()); 636 let self_param = TypeRef::Path(name![Self].into());
632 generics.fill_bounds(&self.body_ctx, trait_def, self_param); 637 generics.fill_bounds(&self.body_ctx, trait_def, Either::Left(self_param));
633
634 generics.fill(&self.body_ctx, &mut sm, node); 638 generics.fill(&self.body_ctx, &mut sm, node);
635 } 639 }
636 GenericsOwner::Impl => { 640 GenericsOwner::Impl => {
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index 02ed30e4d..7e2199a9c 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -18,6 +18,7 @@ pub mod attr;
18pub mod path; 18pub mod path;
19pub mod type_ref; 19pub mod type_ref;
20pub mod builtin_type; 20pub mod builtin_type;
21pub mod builtin_attr;
21pub mod diagnostics; 22pub mod diagnostics;
22pub mod per_ns; 23pub mod per_ns;
23pub mod item_scope; 24pub mod item_scope;
@@ -224,6 +225,13 @@ pub struct TypeParamId {
224pub type LocalTypeParamId = Idx<generics::TypeParamData>; 225pub type LocalTypeParamId = Idx<generics::TypeParamData>;
225 226
226#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 227#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
228pub struct LifetimeParamId {
229 pub parent: GenericDefId,
230 pub local_id: LocalLifetimeParamId,
231}
232pub type LocalLifetimeParamId = Idx<generics::LifetimeParamData>;
233
234#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
227pub enum ContainerId { 235pub enum ContainerId {
228 ModuleId(ModuleId), 236 ModuleId(ModuleId),
229 DefWithBodyId(DefWithBodyId), 237 DefWithBodyId(DefWithBodyId),
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs
index 5b8c1e449..00a69a8a6 100644
--- a/crates/hir_def/src/path.rs
+++ b/crates/hir_def/src/path.rs
@@ -7,7 +7,7 @@ use std::{
7 sync::Arc, 7 sync::Arc,
8}; 8};
9 9
10use crate::body::LowerCtx; 10use crate::{body::LowerCtx, type_ref::LifetimeRef};
11use base_db::CrateId; 11use base_db::CrateId;
12use hir_expand::{ 12use hir_expand::{
13 hygiene::Hygiene, 13 hygiene::Hygiene,
@@ -145,7 +145,7 @@ pub struct AssociatedTypeBinding {
145#[derive(Debug, Clone, PartialEq, Eq, Hash)] 145#[derive(Debug, Clone, PartialEq, Eq, Hash)]
146pub enum GenericArg { 146pub enum GenericArg {
147 Type(TypeRef), 147 Type(TypeRef),
148 // or lifetime... 148 Lifetime(LifetimeRef),
149} 149}
150 150
151impl Path { 151impl Path {
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs
index 07b9723ce..60fa7646b 100644
--- a/crates/hir_def/src/path/lower.rs
+++ b/crates/hir_def/src/path/lower.rs
@@ -15,7 +15,7 @@ use super::AssociatedTypeBinding;
15use crate::{ 15use crate::{
16 body::LowerCtx, 16 body::LowerCtx,
17 path::{GenericArg, GenericArgs, ModPath, Path, PathKind}, 17 path::{GenericArg, GenericArgs, ModPath, Path, PathKind},
18 type_ref::{TypeBound, TypeRef}, 18 type_ref::{LifetimeRef, TypeBound, TypeRef},
19}; 19};
20 20
21pub(super) use lower_use::lower_use_tree; 21pub(super) use lower_use::lower_use_tree;
@@ -170,8 +170,14 @@ pub(super) fn lower_generic_args(
170 bindings.push(AssociatedTypeBinding { name, type_ref, bounds }); 170 bindings.push(AssociatedTypeBinding { name, type_ref, bounds });
171 } 171 }
172 } 172 }
173 // Lifetimes and constants are ignored for now. 173 ast::GenericArg::LifetimeArg(lifetime_arg) => {
174 ast::GenericArg::LifetimeArg(_) | ast::GenericArg::ConstArg(_) => (), 174 if let Some(lifetime) = lifetime_arg.lifetime_token() {
175 let lifetime_ref = LifetimeRef::from_token(lifetime);
176 args.push(GenericArg::Lifetime(lifetime_ref))
177 }
178 }
179 // constants are ignored for now.
180 ast::GenericArg::ConstArg(_) => (),
175 } 181 }
176 } 182 }
177 183
diff --git a/crates/hir_def/src/type_ref.rs b/crates/hir_def/src/type_ref.rs
index 1a78c1444..347ceabb9 100644
--- a/crates/hir_def/src/type_ref.rs
+++ b/crates/hir_def/src/type_ref.rs
@@ -1,6 +1,7 @@
1//! HIR for references to types. Paths in these are not yet resolved. They can 1//! HIR for references to types. Paths in these are not yet resolved. They can
2//! be directly created from an ast::TypeRef, without further queries. 2//! be directly created from an ast::TypeRef, without further queries.
3use syntax::ast::{self}; 3use hir_expand::name::Name;
4use syntax::{ast, SyntaxToken};
4 5
5use crate::{body::LowerCtx, path::Path}; 6use crate::{body::LowerCtx, path::Path};
6 7
@@ -58,7 +59,7 @@ pub enum TypeRef {
58 Tuple(Vec<TypeRef>), 59 Tuple(Vec<TypeRef>),
59 Path(Path), 60 Path(Path),
60 RawPtr(Box<TypeRef>, Mutability), 61 RawPtr(Box<TypeRef>, Mutability),
61 Reference(Box<TypeRef>, Mutability), 62 Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
62 Array(Box<TypeRef> /*, Expr*/), 63 Array(Box<TypeRef> /*, Expr*/),
63 Slice(Box<TypeRef>), 64 Slice(Box<TypeRef>),
64 /// A fn pointer. Last element of the vector is the return type. 65 /// A fn pointer. Last element of the vector is the return type.
@@ -70,10 +71,29 @@ pub enum TypeRef {
70} 71}
71 72
72#[derive(Clone, PartialEq, Eq, Hash, Debug)] 73#[derive(Clone, PartialEq, Eq, Hash, Debug)]
74pub struct LifetimeRef {
75 pub name: Name,
76}
77
78impl LifetimeRef {
79 pub(crate) fn new_name(name: Name) -> Self {
80 LifetimeRef { name }
81 }
82
83 pub(crate) fn from_token(token: SyntaxToken) -> Self {
84 LifetimeRef { name: Name::new_lifetime(&token) }
85 }
86
87 pub fn missing() -> LifetimeRef {
88 LifetimeRef { name: Name::missing() }
89 }
90}
91
92#[derive(Clone, PartialEq, Eq, Hash, Debug)]
73pub enum TypeBound { 93pub enum TypeBound {
74 Path(Path), 94 Path(Path),
75 // also for<> bounds 95 // ForLifetime(Vec<LifetimeRef>, Path), FIXME ForLifetime
76 // also Lifetimes 96 Lifetime(LifetimeRef),
77 Error, 97 Error,
78} 98}
79 99
@@ -107,8 +127,9 @@ impl TypeRef {
107 } 127 }
108 ast::Type::RefType(inner) => { 128 ast::Type::RefType(inner) => {
109 let inner_ty = TypeRef::from_ast_opt(&ctx, inner.ty()); 129 let inner_ty = TypeRef::from_ast_opt(&ctx, inner.ty());
130 let lifetime = inner.lifetime_token().map(|t| LifetimeRef::from_token(t));
110 let mutability = Mutability::from_mutable(inner.mut_token().is_some()); 131 let mutability = Mutability::from_mutable(inner.mut_token().is_some());
111 TypeRef::Reference(Box::new(inner_ty), mutability) 132 TypeRef::Reference(Box::new(inner_ty), lifetime, mutability)
112 } 133 }
113 ast::Type::InferType(_inner) => TypeRef::Placeholder, 134 ast::Type::InferType(_inner) => TypeRef::Placeholder,
114 ast::Type::FnPtrType(inner) => { 135 ast::Type::FnPtrType(inner) => {
@@ -163,14 +184,14 @@ impl TypeRef {
163 types.iter().for_each(|t| go(t, f)) 184 types.iter().for_each(|t| go(t, f))
164 } 185 }
165 TypeRef::RawPtr(type_ref, _) 186 TypeRef::RawPtr(type_ref, _)
166 | TypeRef::Reference(type_ref, _) 187 | TypeRef::Reference(type_ref, ..)
167 | TypeRef::Array(type_ref) 188 | TypeRef::Array(type_ref)
168 | TypeRef::Slice(type_ref) => go(&type_ref, f), 189 | TypeRef::Slice(type_ref) => go(&type_ref, f),
169 TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => { 190 TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
170 for bound in bounds { 191 for bound in bounds {
171 match bound { 192 match bound {
172 TypeBound::Path(path) => go_path(path, f), 193 TypeBound::Path(path) => go_path(path, f),
173 TypeBound::Error => (), 194 TypeBound::Lifetime(_) | TypeBound::Error => (),
174 } 195 }
175 } 196 }
176 } 197 }
@@ -186,8 +207,12 @@ impl TypeRef {
186 for segment in path.segments().iter() { 207 for segment in path.segments().iter() {
187 if let Some(args_and_bindings) = segment.args_and_bindings { 208 if let Some(args_and_bindings) = segment.args_and_bindings {
188 for arg in &args_and_bindings.args { 209 for arg in &args_and_bindings.args {
189 let crate::path::GenericArg::Type(type_ref) = arg; 210 match arg {
190 go(type_ref, f); 211 crate::path::GenericArg::Type(type_ref) => {
212 go(type_ref, f);
213 }
214 crate::path::GenericArg::Lifetime(_) => {}
215 }
191 } 216 }
192 for binding in &args_and_bindings.bindings { 217 for binding in &args_and_bindings.bindings {
193 if let Some(type_ref) = &binding.type_ref { 218 if let Some(type_ref) = &binding.type_ref {
@@ -196,7 +221,7 @@ impl TypeRef {
196 for bound in &binding.bounds { 221 for bound in &binding.bounds {
197 match bound { 222 match bound {
198 TypeBound::Path(path) => go_path(path, f), 223 TypeBound::Path(path) => go_path(path, f),
199 TypeBound::Error => (), 224 TypeBound::Lifetime(_) | TypeBound::Error => (),
200 } 225 }
201 } 226 }
202 } 227 }
@@ -232,7 +257,10 @@ impl TypeBound {
232 }; 257 };
233 TypeBound::Path(path) 258 TypeBound::Path(path)
234 } 259 }
235 ast::TypeBoundKind::ForType(_) | ast::TypeBoundKind::Lifetime(_) => TypeBound::Error, 260 ast::TypeBoundKind::ForType(_) => TypeBound::Error, // FIXME ForType
261 ast::TypeBoundKind::Lifetime(lifetime) => {
262 TypeBound::Lifetime(LifetimeRef::from_token(lifetime))
263 }
236 } 264 }
237 } 265 }
238 266
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs
index b26ffa1ef..583ed6142 100644
--- a/crates/hir_expand/src/name.rs
+++ b/crates/hir_expand/src/name.rs
@@ -38,7 +38,7 @@ impl Name {
38 } 38 }
39 39
40 pub fn new_lifetime(lt: &syntax::SyntaxToken) -> Name { 40 pub fn new_lifetime(lt: &syntax::SyntaxToken) -> Name {
41 assert!(lt.kind() == syntax::SyntaxKind::LIFETIME); 41 assert_eq!(lt.kind(), syntax::SyntaxKind::LIFETIME);
42 Name(Repr::Text(lt.text().clone())) 42 Name(Repr::Text(lt.text().clone()))
43 } 43 }
44 44
@@ -250,6 +250,8 @@ pub mod known {
250 pub const SELF_PARAM: super::Name = super::Name::new_inline("self"); 250 pub const SELF_PARAM: super::Name = super::Name::new_inline("self");
251 pub const SELF_TYPE: super::Name = super::Name::new_inline("Self"); 251 pub const SELF_TYPE: super::Name = super::Name::new_inline("Self");
252 252
253 pub const STATIC_LIFETIME: super::Name = super::Name::new_inline("'static");
254
253 #[macro_export] 255 #[macro_export]
254 macro_rules! name { 256 macro_rules! name {
255 (self) => { 257 (self) => {
@@ -258,6 +260,9 @@ pub mod known {
258 (Self) => { 260 (Self) => {
259 $crate::name::known::SELF_TYPE 261 $crate::name::known::SELF_TYPE
260 }; 262 };
263 ('static) => {
264 $crate::name::known::STATIC_LIFETIME
265 };
261 ($ident:ident) => { 266 ($ident:ident) => {
262 $crate::name::known::$ident 267 $crate::name::known::$ident
263 }; 268 };
diff --git a/crates/hir_ty/src/diagnostics.rs b/crates/hir_ty/src/diagnostics.rs
index e59487e54..1c72f766e 100644
--- a/crates/hir_ty/src/diagnostics.rs
+++ b/crates/hir_ty/src/diagnostics.rs
@@ -624,4 +624,14 @@ fn foo() { break; }
624"#, 624"#,
625 ); 625 );
626 } 626 }
627
628 #[test]
629 fn missing_semicolon() {
630 check_diagnostics(
631 r#"
632 fn test() -> i32 { 123; }
633 //^^^ Remove this semicolon
634 "#,
635 );
636 }
627} 637}
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index e77481906..0e827a29e 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -4,7 +4,7 @@ use std::fmt;
4 4
5use crate::{ 5use crate::{
6 db::HirDatabase, utils::generics, ApplicationTy, CallableDefId, FnSig, GenericPredicate, 6 db::HirDatabase, utils::generics, ApplicationTy, CallableDefId, FnSig, GenericPredicate,
7 Obligation, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, 7 Lifetime, Obligation, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
8}; 8};
9use hir_def::{ 9use hir_def::{
10 find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId, AssocContainerId, 10 find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId, AssocContainerId,
@@ -178,6 +178,7 @@ impl DisplayTarget {
178#[derive(Debug)] 178#[derive(Debug)]
179pub enum DisplaySourceCodeError { 179pub enum DisplaySourceCodeError {
180 PathNotFound, 180 PathNotFound,
181 UnknownType,
181} 182}
182 183
183pub enum HirDisplayError { 184pub enum HirDisplayError {
@@ -558,7 +559,14 @@ impl HirDisplay for Ty {
558 } 559 }
559 }; 560 };
560 } 561 }
561 Ty::Unknown => write!(f, "{{unknown}}")?, 562 Ty::Unknown => {
563 if f.display_target.is_source_code() {
564 return Err(HirDisplayError::DisplaySourceCodeError(
565 DisplaySourceCodeError::UnknownType,
566 ));
567 }
568 write!(f, "{{unknown}}")?;
569 }
562 Ty::Infer(..) => write!(f, "_")?, 570 Ty::Infer(..) => write!(f, "_")?,
563 } 571 }
564 Ok(()) 572 Ok(())
@@ -710,6 +718,19 @@ impl HirDisplay for GenericPredicate {
710 } 718 }
711} 719}
712 720
721impl HirDisplay for Lifetime {
722 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
723 match self {
724 Lifetime::Parameter(id) => {
725 let generics = generics(f.db.upcast(), id.parent);
726 let param_data = &generics.params.lifetimes[id.local_id];
727 write!(f, "{}", &param_data.name)
728 }
729 Lifetime::Static => write!(f, "'static"),
730 }
731 }
732}
733
713impl HirDisplay for Obligation { 734impl HirDisplay for Obligation {
714 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { 735 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
715 match self { 736 match self {
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 605951b10..2cdce2cef 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -137,10 +137,24 @@ impl<'a> InferenceContext<'a> {
137 137
138 self.coerce_merge_branch(&then_ty, &else_ty) 138 self.coerce_merge_branch(&then_ty, &else_ty)
139 } 139 }
140 Expr::Block { statements, tail, .. } => { 140 Expr::Block { statements, tail, label } => match label {
141 // FIXME: Breakable block inference 141 Some(_) => {
142 self.infer_block(statements, *tail, expected) 142 let break_ty = self.table.new_type_var();
143 } 143 self.breakables.push(BreakableContext {
144 may_break: false,
145 break_ty: break_ty.clone(),
146 label: label.clone(),
147 });
148 let ty = self.infer_block(statements, *tail, &Expectation::has_type(break_ty));
149 let ctxt = self.breakables.pop().expect("breakable stack broken");
150 if ctxt.may_break {
151 ctxt.break_ty
152 } else {
153 ty
154 }
155 }
156 None => self.infer_block(statements, *tail, expected),
157 },
144 Expr::Unsafe { body } => self.infer_expr(*body, expected), 158 Expr::Unsafe { body } => self.infer_expr(*body, expected),
145 Expr::TryBlock { body } => { 159 Expr::TryBlock { body } => {
146 let _inner = self.infer_expr(*body, expected); 160 let _inner = self.infer_expr(*body, expected);
@@ -842,12 +856,18 @@ impl<'a> InferenceContext<'a> {
842 // handle provided type arguments 856 // handle provided type arguments
843 if let Some(generic_args) = generic_args { 857 if let Some(generic_args) = generic_args {
844 // if args are provided, it should be all of them, but we can't rely on that 858 // if args are provided, it should be all of them, but we can't rely on that
845 for arg in generic_args.args.iter().take(type_params) { 859 for arg in generic_args
860 .args
861 .iter()
862 .filter(|arg| matches!(arg, GenericArg::Type(_)))
863 .take(type_params)
864 {
846 match arg { 865 match arg {
847 GenericArg::Type(type_ref) => { 866 GenericArg::Type(type_ref) => {
848 let ty = self.make_ty(type_ref); 867 let ty = self.make_ty(type_ref);
849 substs.push(ty); 868 substs.push(ty);
850 } 869 }
870 GenericArg::Lifetime(_) => {}
851 } 871 }
852 } 872 }
853 }; 873 };
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 5a8c97198..357bd92f9 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -29,8 +29,8 @@ use base_db::{salsa, CrateId};
29use hir_def::{ 29use hir_def::{
30 expr::ExprId, 30 expr::ExprId,
31 type_ref::{Mutability, Rawness}, 31 type_ref::{Mutability, Rawness},
32 AdtId, AssocContainerId, DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId, 32 AdtId, AssocContainerId, DefWithBodyId, GenericDefId, HasModule, LifetimeParamId, Lookup,
33 TypeParamId, 33 TraitId, TypeAliasId, TypeParamId,
34}; 34};
35use itertools::Itertools; 35use itertools::Itertools;
36 36
@@ -52,6 +52,12 @@ pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironmen
52 52
53pub use chalk_ir::{BoundVar, DebruijnIndex}; 53pub use chalk_ir::{BoundVar, DebruijnIndex};
54 54
55#[derive(Clone, PartialEq, Eq, Debug, Hash)]
56pub enum Lifetime {
57 Parameter(LifetimeParamId),
58 Static,
59}
60
55/// A type constructor or type name: this might be something like the primitive 61/// A type constructor or type name: this might be something like the primitive
56/// type `bool`, a struct like `Vec`, or things like function pointers or 62/// type `bool`, a struct like `Vec`, or things like function pointers or
57/// tuples. 63/// tuples.
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 708e2af0f..8392cb770 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -12,7 +12,7 @@ use base_db::CrateId;
12use hir_def::{ 12use hir_def::{
13 adt::StructKind, 13 adt::StructKind,
14 builtin_type::BuiltinType, 14 builtin_type::BuiltinType,
15 generics::{TypeParamProvenance, WherePredicate, WherePredicateTarget}, 15 generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
16 path::{GenericArg, Path, PathSegment, PathSegments}, 16 path::{GenericArg, Path, PathSegment, PathSegments},
17 resolver::{HasResolver, Resolver, TypeNs}, 17 resolver::{HasResolver, Resolver, TypeNs},
18 type_ref::{TypeBound, TypeRef}, 18 type_ref::{TypeBound, TypeRef},
@@ -171,7 +171,7 @@ impl Ty {
171 let inner_ty = Ty::from_hir(ctx, inner); 171 let inner_ty = Ty::from_hir(ctx, inner);
172 Ty::apply_one(TypeCtor::Slice, inner_ty) 172 Ty::apply_one(TypeCtor::Slice, inner_ty)
173 } 173 }
174 TypeRef::Reference(inner, mutability) => { 174 TypeRef::Reference(inner, _, mutability) => {
175 let inner_ty = Ty::from_hir(ctx, inner); 175 let inner_ty = Ty::from_hir(ctx, inner);
176 Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty) 176 Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty)
177 } 177 }
@@ -555,7 +555,7 @@ fn substs_from_path_segment(
555 555
556 substs.extend(iter::repeat(Ty::Unknown).take(parent_params)); 556 substs.extend(iter::repeat(Ty::Unknown).take(parent_params));
557 557
558 let mut had_explicit_args = false; 558 let mut had_explicit_type_args = false;
559 559
560 if let Some(generic_args) = &segment.args_and_bindings { 560 if let Some(generic_args) = &segment.args_and_bindings {
561 if !generic_args.has_self_type { 561 if !generic_args.has_self_type {
@@ -565,13 +565,20 @@ fn substs_from_path_segment(
565 if generic_args.has_self_type { self_params + type_params } else { type_params }; 565 if generic_args.has_self_type { self_params + type_params } else { type_params };
566 let skip = if generic_args.has_self_type && self_params == 0 { 1 } else { 0 }; 566 let skip = if generic_args.has_self_type && self_params == 0 { 1 } else { 0 };
567 // if args are provided, it should be all of them, but we can't rely on that 567 // if args are provided, it should be all of them, but we can't rely on that
568 for arg in generic_args.args.iter().skip(skip).take(expected_num) { 568 for arg in generic_args
569 .args
570 .iter()
571 .filter(|arg| matches!(arg, GenericArg::Type(_)))
572 .skip(skip)
573 .take(expected_num)
574 {
569 match arg { 575 match arg {
570 GenericArg::Type(type_ref) => { 576 GenericArg::Type(type_ref) => {
571 had_explicit_args = true; 577 had_explicit_type_args = true;
572 let ty = Ty::from_hir(ctx, type_ref); 578 let ty = Ty::from_hir(ctx, type_ref);
573 substs.push(ty); 579 substs.push(ty);
574 } 580 }
581 GenericArg::Lifetime(_) => {}
575 } 582 }
576 } 583 }
577 } 584 }
@@ -579,7 +586,7 @@ fn substs_from_path_segment(
579 // handle defaults. In expression or pattern path segments without 586 // handle defaults. In expression or pattern path segments without
580 // explicitly specified type arguments, missing type arguments are inferred 587 // explicitly specified type arguments, missing type arguments are inferred
581 // (i.e. defaults aren't used). 588 // (i.e. defaults aren't used).
582 if !infer_args || had_explicit_args { 589 if !infer_args || had_explicit_type_args {
583 if let Some(def_generic) = def_generic { 590 if let Some(def_generic) = def_generic {
584 let defaults = ctx.db.generic_defaults(def_generic); 591 let defaults = ctx.db.generic_defaults(def_generic);
585 assert_eq!(total_len, defaults.len()); 592 assert_eq!(total_len, defaults.len());
@@ -657,7 +664,7 @@ impl TraitRef {
657 ) -> Option<TraitRef> { 664 ) -> Option<TraitRef> {
658 match bound { 665 match bound {
659 TypeBound::Path(path) => TraitRef::from_path(ctx, path, Some(self_ty)), 666 TypeBound::Path(path) => TraitRef::from_path(ctx, path, Some(self_ty)),
660 TypeBound::Error => None, 667 TypeBound::Lifetime(_) | TypeBound::Error => None,
661 } 668 }
662 } 669 }
663} 670}
@@ -667,22 +674,30 @@ impl GenericPredicate {
667 ctx: &'a TyLoweringContext<'a>, 674 ctx: &'a TyLoweringContext<'a>,
668 where_predicate: &'a WherePredicate, 675 where_predicate: &'a WherePredicate,
669 ) -> impl Iterator<Item = GenericPredicate> + 'a { 676 ) -> impl Iterator<Item = GenericPredicate> + 'a {
670 let self_ty = match &where_predicate.target { 677 match where_predicate {
671 WherePredicateTarget::TypeRef(type_ref) => Ty::from_hir(ctx, type_ref), 678 WherePredicate::TypeBound { target, bound } => {
672 WherePredicateTarget::TypeParam(param_id) => { 679 let self_ty = match target {
673 let generic_def = ctx.resolver.generic_def().expect("generics in scope"); 680 WherePredicateTypeTarget::TypeRef(type_ref) => Ty::from_hir(ctx, type_ref),
674 let generics = generics(ctx.db.upcast(), generic_def); 681 WherePredicateTypeTarget::TypeParam(param_id) => {
675 let param_id = hir_def::TypeParamId { parent: generic_def, local_id: *param_id }; 682 let generic_def = ctx.resolver.generic_def().expect("generics in scope");
676 match ctx.type_param_mode { 683 let generics = generics(ctx.db.upcast(), generic_def);
677 TypeParamLoweringMode::Placeholder => Ty::Placeholder(param_id), 684 let param_id =
678 TypeParamLoweringMode::Variable => { 685 hir_def::TypeParamId { parent: generic_def, local_id: *param_id };
679 let idx = generics.param_idx(param_id).expect("matching generics"); 686 match ctx.type_param_mode {
680 Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, idx)) 687 TypeParamLoweringMode::Placeholder => Ty::Placeholder(param_id),
688 TypeParamLoweringMode::Variable => {
689 let idx = generics.param_idx(param_id).expect("matching generics");
690 Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, idx))
691 }
692 }
681 } 693 }
682 } 694 };
695 GenericPredicate::from_type_bound(ctx, bound, self_ty)
696 .collect::<Vec<_>>()
697 .into_iter()
683 } 698 }
684 }; 699 WherePredicate::Lifetime { .. } => vec![].into_iter(),
685 GenericPredicate::from_type_bound(ctx, &where_predicate.bound, self_ty) 700 }
686 } 701 }
687 702
688 pub(crate) fn from_type_bound<'a>( 703 pub(crate) fn from_type_bound<'a>(
@@ -707,7 +722,7 @@ fn assoc_type_bindings_from_type_bound<'a>(
707) -> impl Iterator<Item = GenericPredicate> + 'a { 722) -> impl Iterator<Item = GenericPredicate> + 'a {
708 let last_segment = match bound { 723 let last_segment = match bound {
709 TypeBound::Path(path) => path.segments().last(), 724 TypeBound::Path(path) => path.segments().last(),
710 TypeBound::Error => None, 725 TypeBound::Error | TypeBound::Lifetime(_) => None,
711 }; 726 };
712 last_segment 727 last_segment
713 .into_iter() 728 .into_iter()
@@ -872,11 +887,16 @@ pub(crate) fn generic_predicates_for_param_query(
872 resolver 887 resolver
873 .where_predicates_in_scope() 888 .where_predicates_in_scope()
874 // we have to filter out all other predicates *first*, before attempting to lower them 889 // we have to filter out all other predicates *first*, before attempting to lower them
875 .filter(|pred| match &pred.target { 890 .filter(|pred| match pred {
876 WherePredicateTarget::TypeRef(type_ref) => { 891 WherePredicate::TypeBound {
877 Ty::from_hir_only_param(&ctx, type_ref) == Some(param_id) 892 target: WherePredicateTypeTarget::TypeRef(type_ref),
878 } 893 ..
879 WherePredicateTarget::TypeParam(local_id) => *local_id == param_id.local_id, 894 } => Ty::from_hir_only_param(&ctx, type_ref) == Some(param_id),
895 WherePredicate::TypeBound {
896 target: WherePredicateTypeTarget::TypeParam(local_id),
897 ..
898 } => *local_id == param_id.local_id,
899 WherePredicate::Lifetime { .. } => false,
880 }) 900 })
881 .flat_map(|pred| { 901 .flat_map(|pred| {
882 GenericPredicate::from_where_predicate(&ctx, pred) 902 GenericPredicate::from_where_predicate(&ctx, pred)
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index 8cf4e7012..da8170417 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -883,3 +883,40 @@ fn issue_6628() {
883 "#]], 883 "#]],
884 ); 884 );
885} 885}
886
887#[test]
888fn issue_6852() {
889 check_infer(
890 r#"
891 #[lang = "deref"]
892 pub trait Deref {
893 type Target;
894 }
895
896 struct BufWriter {}
897
898 struct Mutex<T> {}
899 struct MutexGuard<'a, T> {}
900 impl<T> Mutex<T> {
901 fn lock(&self) -> MutexGuard<'_, T> {}
902 }
903 impl<'a, T: 'a> Deref for MutexGuard<'a, T> {
904 type Target = T;
905 }
906 fn flush(&self) {
907 let w: &Mutex<BufWriter>;
908 *(w.lock());
909 }
910 "#,
911 expect![[r#"
912 156..160 'self': &Mutex<T>
913 183..185 '{}': ()
914 267..271 'self': &{unknown}
915 273..323 '{ ...()); }': ()
916 283..284 'w': &Mutex<BufWriter>
917 309..320 '*(w.lock())': BufWriter
918 311..312 'w': &Mutex<BufWriter>
919 311..319 'w.lock()': MutexGuard<BufWriter>
920 "#]],
921 );
922}
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index 4f72582b6..a569223b4 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -2075,6 +2075,62 @@ fn infer_labelled_break_with_val() {
2075} 2075}
2076 2076
2077#[test] 2077#[test]
2078fn infer_labelled_block_break_with_val() {
2079 check_infer(
2080 r#"
2081 fn default<T>() -> T { loop {} }
2082 fn foo() {
2083 let _x = 'outer: {
2084 let inner = 'inner: {
2085 let i = default();
2086 if (break 'outer i) {
2087 break 'inner 5i8;
2088 } else if true {
2089 break 'inner 6;
2090 }
2091 break 'inner 'innermost: { 0 };
2092 42
2093 };
2094 break 'outer inner < 8;
2095 };
2096 }
2097 "#,
2098 expect![[r#"
2099 21..32 '{ loop {} }': T
2100 23..30 'loop {}': !
2101 28..30 '{}': ()
2102 42..381 '{ ... }; }': ()
2103 52..54 '_x': bool
2104 65..378 '{ ... }': bool
2105 79..84 'inner': i8
2106 95..339 '{ ... }': i8
2107 113..114 'i': bool
2108 117..124 'default': fn default<bool>() -> bool
2109 117..126 'default()': bool
2110 140..270 'if (br... }': ()
2111 144..158 'break 'outer i': !
2112 157..158 'i': bool
2113 160..209 '{ ... }': ()
2114 178..194 'break ...er 5i8': !
2115 191..194 '5i8': i8
2116 215..270 'if tru... }': ()
2117 218..222 'true': bool
2118 223..270 '{ ... }': ()
2119 241..255 'break 'inner 6': !
2120 254..255 '6': i8
2121 283..313 'break ... { 0 }': !
2122 308..313 '{ 0 }': i8
2123 310..311 '0': i8
2124 327..329 '42': i8
2125 349..371 'break ...er < 8': !
2126 362..367 'inner': i8
2127 362..371 'inner < 8': bool
2128 370..371 '8': i8
2129 "#]],
2130 );
2131}
2132
2133#[test]
2078fn generic_default() { 2134fn generic_default() {
2079 check_infer( 2135 check_infer(
2080 r#" 2136 r#"
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs
index e3e244268..af880c065 100644
--- a/crates/hir_ty/src/utils.rs
+++ b/crates/hir_ty/src/utils.rs
@@ -2,11 +2,10 @@
2//! query, but can't be computed directly from `*Data` (ie, which need a `db`). 2//! query, but can't be computed directly from `*Data` (ie, which need a `db`).
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_def::generics::WherePredicateTarget;
6use hir_def::{ 5use hir_def::{
7 adt::VariantData, 6 adt::VariantData,
8 db::DefDatabase, 7 db::DefDatabase,
9 generics::{GenericParams, TypeParamData, TypeParamProvenance}, 8 generics::{GenericParams, TypeParamData, TypeParamProvenance, WherePredicateTypeTarget},
10 path::Path, 9 path::Path,
11 resolver::{HasResolver, TypeNs}, 10 resolver::{HasResolver, TypeNs},
12 type_ref::TypeRef, 11 type_ref::TypeRef,
@@ -27,14 +26,19 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
27 generic_params 26 generic_params
28 .where_predicates 27 .where_predicates
29 .iter() 28 .iter()
30 .filter_map(|pred| match &pred.target { 29 .filter_map(|pred| match pred {
31 WherePredicateTarget::TypeRef(TypeRef::Path(p)) if p == &Path::from(name![Self]) => { 30 hir_def::generics::WherePredicate::TypeBound { target, bound } => match target {
32 pred.bound.as_path() 31 WherePredicateTypeTarget::TypeRef(TypeRef::Path(p))
33 } 32 if p == &Path::from(name![Self]) =>
34 WherePredicateTarget::TypeParam(local_id) if Some(*local_id) == trait_self => { 33 {
35 pred.bound.as_path() 34 bound.as_path()
36 } 35 }
37 _ => None, 36 WherePredicateTypeTarget::TypeParam(local_id) if Some(*local_id) == trait_self => {
37 bound.as_path()
38 }
39 _ => None,
40 },
41 hir_def::generics::WherePredicate::Lifetime { .. } => None,
38 }) 42 })
39 .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) { 43 .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) {
40 Some(TypeNs::TraitId(t)) => Some(t), 44 Some(TypeNs::TraitId(t)) => Some(t),
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index 4790d648a..234f80a3a 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -1,11 +1,13 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use either::Either; 3use either::Either;
4use hir::{AssocItem, FieldSource, HasSource, InFile, ModuleSource}; 4use hir::{
5 AssocItem, Documentation, FieldSource, HasAttrs, HasSource, HirFileId, InFile, ModuleSource,
6};
5use ide_db::base_db::{FileId, SourceDatabase}; 7use ide_db::base_db::{FileId, SourceDatabase};
6use ide_db::{defs::Definition, RootDatabase}; 8use ide_db::{defs::Definition, RootDatabase};
7use syntax::{ 9use syntax::{
8 ast::{self, DocCommentsOwner, NameOwner}, 10 ast::{self, NameOwner},
9 match_ast, AstNode, SmolStr, 11 match_ast, AstNode, SmolStr,
10 SyntaxKind::{self, IDENT_PAT, TYPE_PARAM}, 12 SyntaxKind::{self, IDENT_PAT, TYPE_PARAM},
11 TextRange, 13 TextRange,
@@ -43,7 +45,7 @@ pub struct NavigationTarget {
43 pub kind: SyntaxKind, 45 pub kind: SyntaxKind,
44 pub container_name: Option<SmolStr>, 46 pub container_name: Option<SmolStr>,
45 pub description: Option<String>, 47 pub description: Option<String>,
46 pub docs: Option<String>, 48 pub docs: Option<Documentation>,
47} 49}
48 50
49pub(crate) trait ToNav { 51pub(crate) trait ToNav {
@@ -71,7 +73,7 @@ impl NavigationTarget {
71 frange.range, 73 frange.range,
72 src.value.syntax().kind(), 74 src.value.syntax().kind(),
73 ); 75 );
74 res.docs = src.value.doc_comment_text(); 76 res.docs = module.attrs(db).docs();
75 res.description = src.value.short_label(); 77 res.description = src.value.short_label();
76 return res; 78 return res;
77 } 79 }
@@ -214,14 +216,14 @@ impl ToNavFromAst for hir::Trait {}
214 216
215impl<D> ToNav for D 217impl<D> ToNav for D
216where 218where
217 D: HasSource + ToNavFromAst + Copy, 219 D: HasSource + ToNavFromAst + Copy + HasAttrs,
218 D::Ast: ast::DocCommentsOwner + ast::NameOwner + ShortLabel, 220 D::Ast: ast::NameOwner + ShortLabel,
219{ 221{
220 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 222 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
221 let src = self.source(db); 223 let src = self.source(db);
222 let mut res = 224 let mut res =
223 NavigationTarget::from_named(db, src.as_ref().map(|it| it as &dyn ast::NameOwner)); 225 NavigationTarget::from_named(db, src.as_ref().map(|it| it as &dyn ast::NameOwner));
224 res.docs = src.value.doc_comment_text(); 226 res.docs = self.docs(db);
225 res.description = src.value.short_label(); 227 res.description = src.value.short_label();
226 res 228 res
227 } 229 }
@@ -274,7 +276,7 @@ impl ToNav for hir::Field {
274 match &src.value { 276 match &src.value {
275 FieldSource::Named(it) => { 277 FieldSource::Named(it) => {
276 let mut res = NavigationTarget::from_named(db, src.with_value(it)); 278 let mut res = NavigationTarget::from_named(db, src.with_value(it));
277 res.docs = it.doc_comment_text(); 279 res.docs = self.docs(db);
278 res.description = it.short_label(); 280 res.description = it.short_label();
279 res 281 res
280 } 282 }
@@ -298,7 +300,7 @@ impl ToNav for hir::MacroDef {
298 log::debug!("nav target {:#?}", src.value.syntax()); 300 log::debug!("nav target {:#?}", src.value.syntax());
299 let mut res = 301 let mut res =
300 NavigationTarget::from_named(db, src.as_ref().map(|it| it as &dyn ast::NameOwner)); 302 NavigationTarget::from_named(db, src.as_ref().map(|it| it as &dyn ast::NameOwner));
301 res.docs = src.value.doc_comment_text(); 303 res.docs = self.docs(db);
302 res 304 res
303 } 305 }
304} 306}
@@ -374,26 +376,28 @@ impl ToNav for hir::TypeParam {
374 } 376 }
375} 377}
376 378
377pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> { 379pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<Documentation> {
378 let parse = db.parse(symbol.file_id); 380 let parse = db.parse(symbol.file_id);
379 let node = symbol.ptr.to_node(parse.tree().syntax()); 381 let node = symbol.ptr.to_node(parse.tree().syntax());
382 let file_id = HirFileId::from(symbol.file_id);
380 383
381 match_ast! { 384 let it = match_ast! {
382 match node { 385 match node {
383 ast::Fn(it) => it.doc_comment_text(), 386 ast::Fn(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)),
384 ast::Struct(it) => it.doc_comment_text(), 387 ast::Struct(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)),
385 ast::Enum(it) => it.doc_comment_text(), 388 ast::Enum(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)),
386 ast::Trait(it) => it.doc_comment_text(), 389 ast::Trait(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)),
387 ast::Module(it) => it.doc_comment_text(), 390 ast::Module(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)),
388 ast::TypeAlias(it) => it.doc_comment_text(), 391 ast::TypeAlias(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)),
389 ast::Const(it) => it.doc_comment_text(), 392 ast::Const(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)),
390 ast::Static(it) => it.doc_comment_text(), 393 ast::Static(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)),
391 ast::RecordField(it) => it.doc_comment_text(), 394 ast::RecordField(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)),
392 ast::Variant(it) => it.doc_comment_text(), 395 ast::Variant(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)),
393 ast::MacroCall(it) => it.doc_comment_text(), 396 ast::MacroCall(it) => hir::Attrs::from_attrs_owner(db, InFile::new(file_id, &it)),
394 _ => None, 397 _ => return None,
395 } 398 }
396 } 399 };
400 it.docs()
397} 401}
398 402
399/// Get a description of a symbol. 403/// Get a description of a symbol.
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index cf04c3de0..ab017d2ad 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -139,6 +139,11 @@ pub(crate) fn hover(
139 } 139 }
140 } 140 }
141 141
142 if token.kind() == syntax::SyntaxKind::COMMENT {
143 // don't highlight the entire parent node on comment hover
144 return None;
145 }
146
142 let node = token.ancestors().find(|n| { 147 let node = token.ancestors().find(|n| {
143 ast::Expr::can_cast(n.kind()) 148 ast::Expr::can_cast(n.kind())
144 || ast::Pat::can_cast(n.kind()) 149 || ast::Pat::can_cast(n.kind())
@@ -3419,4 +3424,15 @@ mod Foo<|> {
3419 "#]], 3424 "#]],
3420 ); 3425 );
3421 } 3426 }
3427
3428 #[test]
3429 fn hover_comments_dont_highlight_parent() {
3430 check_hover_no_result(
3431 r#"
3432fn no_hover() {
3433 // no<|>hover
3434}
3435"#,
3436 );
3437 }
3422} 3438}
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index e15411777..646f63704 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -6,7 +6,7 @@ use hir::{AsAssocItem, Attrs, HirFileId, InFile, Semantics};
6use ide_db::RootDatabase; 6use ide_db::RootDatabase;
7use itertools::Itertools; 7use itertools::Itertools;
8use syntax::{ 8use syntax::{
9 ast::{self, AstNode, AttrsOwner, DocCommentsOwner, ModuleItemOwner, NameOwner}, 9 ast::{self, AstNode, AttrsOwner, ModuleItemOwner, NameOwner},
10 match_ast, SyntaxNode, 10 match_ast, SyntaxNode,
11}; 11};
12 12
@@ -118,6 +118,7 @@ fn runnable_fn(
118) -> Option<Runnable> { 118) -> Option<Runnable> {
119 let name_string = fn_def.name()?.text().to_string(); 119 let name_string = fn_def.name()?.text().to_string();
120 120
121 let attrs = Attrs::from_attrs_owner(sema.db, InFile::new(HirFileId::from(file_id), &fn_def));
121 let kind = if name_string == "main" { 122 let kind = if name_string == "main" {
122 RunnableKind::Bin 123 RunnableKind::Bin
123 } else { 124 } else {
@@ -162,14 +163,13 @@ fn runnable_fn(
162 RunnableKind::Test { test_id, attr } 163 RunnableKind::Test { test_id, attr }
163 } else if fn_def.has_atom_attr("bench") { 164 } else if fn_def.has_atom_attr("bench") {
164 RunnableKind::Bench { test_id } 165 RunnableKind::Bench { test_id }
165 } else if has_runnable_doc_test(&fn_def) { 166 } else if has_runnable_doc_test(&attrs) {
166 RunnableKind::DocTest { test_id } 167 RunnableKind::DocTest { test_id }
167 } else { 168 } else {
168 return None; 169 return None;
169 } 170 }
170 }; 171 };
171 172
172 let attrs = Attrs::from_attrs_owner(sema.db, InFile::new(HirFileId::from(file_id), &fn_def));
173 let cfg = attrs.cfg(); 173 let cfg = attrs.cfg();
174 174
175 let nav = if let RunnableKind::DocTest { .. } = kind { 175 let nav = if let RunnableKind::DocTest { .. } = kind {
@@ -189,13 +189,13 @@ fn runnable_struct(
189 struct_def: ast::Struct, 189 struct_def: ast::Struct,
190 file_id: FileId, 190 file_id: FileId,
191) -> Option<Runnable> { 191) -> Option<Runnable> {
192 if !has_runnable_doc_test(&struct_def) {
193 return None;
194 }
195 let name_string = struct_def.name()?.text().to_string(); 192 let name_string = struct_def.name()?.text().to_string();
196 193
197 let attrs = 194 let attrs =
198 Attrs::from_attrs_owner(sema.db, InFile::new(HirFileId::from(file_id), &struct_def)); 195 Attrs::from_attrs_owner(sema.db, InFile::new(HirFileId::from(file_id), &struct_def));
196 if !has_runnable_doc_test(&attrs) {
197 return None;
198 }
199 let cfg = attrs.cfg(); 199 let cfg = attrs.cfg();
200 200
201 let test_id = match sema.to_def(&struct_def).map(|def| def.module(sema.db)) { 201 let test_id = match sema.to_def(&struct_def).map(|def| def.module(sema.db)) {
@@ -240,11 +240,11 @@ const RUSTDOC_FENCE: &str = "```";
240const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] = 240const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] =
241 &["", "rust", "should_panic", "edition2015", "edition2018"]; 241 &["", "rust", "should_panic", "edition2015", "edition2018"];
242 242
243fn has_runnable_doc_test(def: &dyn DocCommentsOwner) -> bool { 243fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool {
244 def.doc_comment_text().map_or(false, |comments_text| { 244 attrs.docs().map_or(false, |doc| {
245 let mut in_code_block = false; 245 let mut in_code_block = false;
246 246
247 for line in comments_text.lines() { 247 for line in String::from(doc).lines() {
248 if let Some(header) = line.strip_prefix(RUSTDOC_FENCE) { 248 if let Some(header) = line.strip_prefix(RUSTDOC_FENCE) {
249 in_code_block = !in_code_block; 249 in_code_block = !in_code_block;
250 250
diff --git a/crates/mbe/src/mbe_expander/matcher.rs b/crates/mbe/src/mbe_expander/matcher.rs
index 3f8445897..93ee77908 100644
--- a/crates/mbe/src/mbe_expander/matcher.rs
+++ b/crates/mbe/src/mbe_expander/matcher.rs
@@ -356,6 +356,18 @@ impl<'a> TtIter<'a> {
356 ExpandResult { value: _, err: Some(_) } => None, 356 ExpandResult { value: _, err: Some(_) } => None,
357 } 357 }
358 } 358 }
359
360 pub(crate) fn eat_char(&mut self, c: char) -> Option<tt::TokenTree> {
361 let mut fork = self.clone();
362 match fork.expect_char(c) {
363 Ok(_) => {
364 let tt = self.next().cloned();
365 *self = fork;
366 tt
367 }
368 Err(_) => None,
369 }
370 }
359} 371}
360 372
361pub(super) fn match_repeat( 373pub(super) fn match_repeat(
@@ -447,10 +459,22 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragmen
447 .expect_lifetime() 459 .expect_lifetime()
448 .map(|tt| Some(tt)) 460 .map(|tt| Some(tt))
449 .map_err(|()| err!("expected lifetime")), 461 .map_err(|()| err!("expected lifetime")),
450 "literal" => input 462 "literal" => {
451 .expect_literal() 463 let neg = input.eat_char('-');
452 .map(|literal| Some(tt::Leaf::from(literal.clone()).into())) 464 input
453 .map_err(|()| err!()), 465 .expect_literal()
466 .map(|literal| {
467 let lit = tt::Leaf::from(literal.clone());
468 match neg {
469 None => Some(lit.into()),
470 Some(neg) => Some(tt::TokenTree::Subtree(tt::Subtree {
471 delimiter: None,
472 token_trees: vec![neg, lit.into()],
473 })),
474 }
475 })
476 .map_err(|()| err!())
477 }
454 // `vis` is optional 478 // `vis` is optional
455 "vis" => match input.eat_vis() { 479 "vis" => match input.eat_vis() {
456 Some(vis) => Ok(Some(vis)), 480 Some(vis) => Ok(Some(vis)),
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs
index 0796ceee1..843054fe8 100644
--- a/crates/mbe/src/tests.rs
+++ b/crates/mbe/src/tests.rs
@@ -1008,11 +1008,20 @@ fn test_literal() {
1008 parse_macro( 1008 parse_macro(
1009 r#" 1009 r#"
1010 macro_rules! foo { 1010 macro_rules! foo {
1011 ($ type:ty $ lit:literal) => { const VALUE: $ type = $ lit;}; 1011 ($ type:ty , $ lit:literal) => { const VALUE: $ type = $ lit;};
1012 } 1012 }
1013"#, 1013"#,
1014 ) 1014 )
1015 .assert_expand_items(r#"foo!(u8 0);"#, r#"const VALUE : u8 = 0 ;"#); 1015 .assert_expand_items(r#"foo!(u8,0);"#, r#"const VALUE : u8 = 0 ;"#);
1016
1017 parse_macro(
1018 r#"
1019 macro_rules! foo {
1020 ($ type:ty , $ lit:literal) => { const VALUE: $ type = $ lit;};
1021 }
1022"#,
1023 )
1024 .assert_expand_items(r#"foo!(i32,-1);"#, r#"const VALUE : i32 = - 1 ;"#);
1016} 1025}
1017 1026
1018#[test] 1027#[test]
diff --git a/crates/project_model/src/sysroot.rs b/crates/project_model/src/sysroot.rs
index f0a43eaf6..95b622715 100644
--- a/crates/project_model/src/sysroot.rs
+++ b/crates/project_model/src/sysroot.rs
@@ -143,7 +143,7 @@ fn discover_sysroot_src_dir(current_dir: &AbsPath) -> Result<AbsPathBuf> {
143can't load standard library from sysroot 143can't load standard library from sysroot
144{} 144{}
145(discovered via `rustc --print sysroot`) 145(discovered via `rustc --print sysroot`)
146try running `rustup component add rust-src` or set `RUST_SRC_PATH`", 146try installing the Rust source the same way you installed rustc",
147 sysroot_path.display(), 147 sysroot_path.display(),
148 ) 148 )
149 }) 149 })
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index 7f4a7e56b..68a235ce3 100644
--- a/crates/project_model/src/workspace.rs
+++ b/crates/project_model/src/workspace.rs
@@ -475,7 +475,7 @@ fn add_target_crate_root(
475 Some(display_name), 475 Some(display_name),
476 cfg_options, 476 cfg_options,
477 env, 477 env,
478 proc_macro.clone(), 478 proc_macro,
479 ); 479 );
480 480
481 crate_id 481 crate_id
diff --git a/crates/rust-analyzer/src/cli.rs b/crates/rust-analyzer/src/cli.rs
index 6966ee576..6879a462d 100644
--- a/crates/rust-analyzer/src/cli.rs
+++ b/crates/rust-analyzer/src/cli.rs
@@ -10,8 +10,9 @@ mod ssr;
10use std::io::Read; 10use std::io::Read;
11 11
12use anyhow::Result; 12use anyhow::Result;
13use ide::Analysis; 13use ide::{Analysis, AnalysisHost};
14use syntax::{AstNode, SourceFile}; 14use syntax::{AstNode, SourceFile};
15use vfs::Vfs;
15 16
16pub use self::{ 17pub use self::{
17 analysis_bench::{BenchCmd, BenchWhat, Position}, 18 analysis_bench::{BenchCmd, BenchWhat, Position},
@@ -82,3 +83,23 @@ fn report_metric(metric: &str, value: u64, unit: &str) {
82 } 83 }
83 println!("METRIC:{}:{}:{}", metric, value, unit) 84 println!("METRIC:{}:{}:{}", metric, value, unit)
84} 85}
86
87fn print_memory_usage(mut host: AnalysisHost, vfs: Vfs) {
88 let mut mem = host.per_query_memory_usage();
89
90 let before = profile::memory_usage();
91 drop(vfs);
92 let vfs = before.allocated - profile::memory_usage().allocated;
93 mem.push(("VFS".into(), vfs));
94
95 let before = profile::memory_usage();
96 drop(host);
97 mem.push(("Unaccounted".into(), before.allocated - profile::memory_usage().allocated));
98
99 mem.push(("Remaining".into(), profile::memory_usage().allocated));
100
101 for (name, bytes) in mem {
102 // NOTE: Not a debug print, so avoid going through the `eprintln` defined above.
103 eprintln!("{:>8} {}", bytes, name);
104 }
105}
diff --git a/crates/rust-analyzer/src/cli/analysis_bench.rs b/crates/rust-analyzer/src/cli/analysis_bench.rs
index 8e33986d5..5a8484c62 100644
--- a/crates/rust-analyzer/src/cli/analysis_bench.rs
+++ b/crates/rust-analyzer/src/cli/analysis_bench.rs
@@ -12,10 +12,7 @@ use ide_db::base_db::{
12}; 12};
13use vfs::AbsPathBuf; 13use vfs::AbsPathBuf;
14 14
15use crate::{ 15use crate::cli::{load_cargo::load_cargo, print_memory_usage, Verbosity};
16 cli::{load_cargo::load_cargo, Verbosity},
17 print_memory_usage,
18};
19 16
20pub struct BenchCmd { 17pub struct BenchCmd {
21 pub path: PathBuf, 18 pub path: PathBuf,
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 58d284d47..a23fb7a33 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -23,11 +23,9 @@ use rustc_hash::FxHashSet;
23use stdx::format_to; 23use stdx::format_to;
24use syntax::AstNode; 24use syntax::AstNode;
25 25
26use crate::{ 26use crate::cli::{
27 cli::{ 27 load_cargo::load_cargo, print_memory_usage, progress_report::ProgressReport, report_metric,
28 load_cargo::load_cargo, progress_report::ProgressReport, report_metric, Result, Verbosity, 28 Result, Verbosity,
29 },
30 print_memory_usage,
31}; 29};
32use profile::StopWatch; 30use profile::StopWatch;
33 31
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs
index ad08f1afb..79fe30e53 100644
--- a/crates/rust-analyzer/src/lib.rs
+++ b/crates/rust-analyzer/src/lib.rs
@@ -37,10 +37,8 @@ mod document;
37pub mod lsp_ext; 37pub mod lsp_ext;
38pub mod config; 38pub mod config;
39 39
40use ide::AnalysisHost;
41use serde::de::DeserializeOwned; 40use serde::de::DeserializeOwned;
42use std::fmt; 41use std::fmt;
43use vfs::Vfs;
44 42
45pub use crate::{caps::server_capabilities, main_loop::main_loop}; 43pub use crate::{caps::server_capabilities, main_loop::main_loop};
46 44
@@ -72,22 +70,3 @@ impl fmt::Display for LspError {
72} 70}
73 71
74impl std::error::Error for LspError {} 72impl std::error::Error for LspError {}
75
76fn print_memory_usage(mut host: AnalysisHost, vfs: Vfs) {
77 let mut mem = host.per_query_memory_usage();
78
79 let before = profile::memory_usage();
80 drop(vfs);
81 let vfs = before.allocated - profile::memory_usage().allocated;
82 mem.push(("VFS".into(), vfs));
83
84 let before = profile::memory_usage();
85 drop(host);
86 mem.push(("Unaccounted".into(), before.allocated - profile::memory_usage().allocated));
87
88 mem.push(("Remaining".into(), profile::memory_usage().allocated));
89
90 for (name, bytes) in mem {
91 eprintln!("{:>8} {}", bytes, name);
92 }
93}
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index a5f7647b8..ec3d5e060 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -658,7 +658,6 @@ impl GlobalState {
658 log::trace!("updating notifications for {:?}", subscriptions); 658 log::trace!("updating notifications for {:?}", subscriptions);
659 if self.config.publish_diagnostics { 659 if self.config.publish_diagnostics {
660 let snapshot = self.snapshot(); 660 let snapshot = self.snapshot();
661 let subscriptions = subscriptions.clone();
662 self.task_pool.handle.spawn(move || { 661 self.task_pool.handle.spawn(move || {
663 let diagnostics = subscriptions 662 let diagnostics = subscriptions
664 .into_iter() 663 .into_iter()
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index aa3a4b606..820af2d20 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -55,7 +55,7 @@ impl ast::Attr {
55 let key = self.simple_name()?; 55 let key = self.simple_name()?;
56 let value_token = lit.syntax().first_token()?; 56 let value_token = lit.syntax().first_token()?;
57 57
58 let value: SmolStr = ast::String::cast(value_token.clone())?.value()?.into(); 58 let value: SmolStr = ast::String::cast(value_token)?.value()?.into();
59 59
60 Some((key, value)) 60 Some((key, value))
61 } 61 }
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs
index 52b7285dd..5e9620a40 100644
--- a/crates/syntax/src/ast/token_ext.rs
+++ b/crates/syntax/src/ast/token_ext.rs
@@ -599,7 +599,7 @@ impl ast::IntNumber {
599 text = &text[radix.prefix_len()..]; 599 text = &text[radix.prefix_len()..];
600 600
601 let buf; 601 let buf;
602 if text.contains("_") { 602 if text.contains('_') {
603 buf = text.replace('_', ""); 603 buf = text.replace('_', "");
604 text = buf.as_str(); 604 text = buf.as_str();
605 }; 605 };
diff --git a/docs/user/generated_diagnostic.adoc b/docs/user/generated_diagnostic.adoc
deleted file mode 100644
index ec8581a03..000000000
--- a/docs/user/generated_diagnostic.adoc
+++ /dev/null
@@ -1,119 +0,0 @@
1//Generated file, do not edit by hand, see `xtask/src/codegen`
2=== break-outside-of-loop
3**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_ty/src/diagnostics.rs#L219[diagnostics.rs]
4
5This diagnostic is triggered if `break` keyword is used outside of a loop.
6
7
8=== inactive-code
9**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_def/src/diagnostics.rs#L98[diagnostics.rs]
10
11This diagnostic is shown for code with inactive `#[cfg]` attributes.
12
13
14=== incorrect-ident-case
15**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_ty/src/diagnostics.rs#L319[diagnostics.rs]
16
17This diagnostic is triggered if item name doesn't follow https://doc.rust-lang.org/1.0.0/style/style/naming/README.html[Rust naming convention].
18
19
20=== macro-error
21**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_def/src/diagnostics.rs#L167[diagnostics.rs]
22
23This diagnostic is shown for macro expansion errors.
24
25
26=== mismatched-arg-count
27**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_ty/src/diagnostics.rs#L267[diagnostics.rs]
28
29This diagnostic is triggered if function is invoked with an incorrect amount of arguments.
30
31
32=== missing-match-arm
33**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_ty/src/diagnostics.rs#L162[diagnostics.rs]
34
35This diagnostic is triggered if `match` block is missing one or more match arms.
36
37
38=== missing-ok-in-tail-expr
39**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_ty/src/diagnostics.rs#L187[diagnostics.rs]
40
41This diagnostic is triggered if block that should return `Result` returns a value not wrapped in `Ok`.
42
43Example:
44
45```rust
46fn foo() -> Result<u8, ()> {
47 10
48}
49```
50
51
52=== missing-pat-fields
53**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_ty/src/diagnostics.rs#L113[diagnostics.rs]
54
55This diagnostic is triggered if pattern lacks some fields that exist in the corresponding structure.
56
57Example:
58
59```rust
60struct A { a: u8, b: u8 }
61
62let a = A { a: 10, b: 20 };
63
64if let A { a } = a {
65 // ...
66}
67```
68
69
70=== missing-structure-fields
71**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_ty/src/diagnostics.rs#L66[diagnostics.rs]
72
73This diagnostic is triggered if record lacks some fields that exist in the corresponding structure.
74
75Example:
76
77```rust
78struct A { a: u8, b: u8 }
79
80let a = A { a: 10 };
81```
82
83
84=== missing-unsafe
85**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_ty/src/diagnostics.rs#L243[diagnostics.rs]
86
87This diagnostic is triggered if operation marked as `unsafe` is used outside of `unsafe` function or block.
88
89
90=== no-such-field
91**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_ty/src/diagnostics.rs#L39[diagnostics.rs]
92
93This diagnostic is triggered if created structure does not have field provided in record.
94
95
96=== unresolved-extern-crate
97**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_def/src/diagnostics.rs#L43[diagnostics.rs]
98
99This diagnostic is triggered if rust-analyzer is unable to discover referred extern crate.
100
101
102=== unresolved-import
103**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_def/src/diagnostics.rs#L67[diagnostics.rs]
104
105This diagnostic is triggered if rust-analyzer is unable to discover imported module.
106
107
108=== unresolved-module
109**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_def/src/diagnostics.rs#L18[diagnostics.rs]
110
111This diagnostic is triggered if rust-analyzer is unable to discover referred module.
112
113
114=== unresolved-proc-macro
115**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_def/src/diagnostics.rs#L131[diagnostics.rs]
116
117This diagnostic is shown when a procedural macro can not be found. This usually means that
118procedural macro support is simply disabled (and hence is only a weak hint instead of an error),
119but can also indicate project setup problems.
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index 9d4f52a93..1ec6e81bb 100644
--- a/docs/user/manual.adoc
+++ b/docs/user/manual.adoc
@@ -95,6 +95,23 @@ If you don't want to be asked for `Download now` every day when the new nightly
95 95
96NOTE: Nightly extension should **only** be installed via the `Download now` action from VS Code. 96NOTE: Nightly extension should **only** be installed via the `Download now` action from VS Code.
97 97
98==== Manual installation
99
100Alternatively, procure both `rust-analyzer.vsix` and your platform's matching `rust-analyzer-{platform}`, for example from the
101https://github.com/rust-analyzer/rust-analyzer/releases[releases] page.
102
103Install the extension with the `Extensions: Install from VSIX` command within VS Code, or from the command line via:
104[source]
105----
106$ code --install-extension /path/to/rust-analyzer.vsix
107----
108
109Copy the `rust-analyzer-{platform}` binary anywhere, then add the path to your settings.json, for example:
110[source,json]
111----
112{ "rust-analyzer.serverPath": "~/.local/bin/rust-analyzer-linux" }
113----
114
98==== Building From Source 115==== Building From Source
99 116
100Alternatively, both the server and the Code plugin can be installed from source: 117Alternatively, both the server and the Code plugin can be installed from source:
@@ -272,6 +289,8 @@ GNOME Builder 3.37.1 and newer has native `rust-analyzer` support. If the LSP bi
272 289
273== Configuration 290== Configuration
274 291
292**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/rust-analyzer/src/config.rs[config.rs]
293
275rust-analyzer is configured via LSP messages, which means that it's up to the editor to decide on the exact format and location of configuration files. 294rust-analyzer is configured via LSP messages, which means that it's up to the editor to decide on the exact format and location of configuration files.
276Please consult your editor's documentation to learn how to configure LSP servers. 295Please consult your editor's documentation to learn how to configure LSP servers.
277 296
diff --git a/editors/code/language-configuration.json b/editors/code/language-configuration.json
new file mode 100644
index 000000000..b20e0d978
--- /dev/null
+++ b/editors/code/language-configuration.json
@@ -0,0 +1,38 @@
1{
2 "comments": {
3 "lineComment": "//",
4 "blockComment": [ "/*", "*/" ]
5 },
6 "brackets": [
7 ["{", "}"],
8 ["[", "]"],
9 ["(", ")"],
10 ["<", ">"]
11 ],
12 "autoClosingPairs": [
13 { "open": "{", "close": "}" },
14 { "open": "[", "close": "]" },
15 { "open": "(", "close": ")" },
16 { "open": "\"", "close": "\"", "notIn": ["string"] },
17 { "open": "/*", "close": " */" }
18 ],
19 "autoCloseBefore": ";:.,=}])> \n\t",
20 "surroundingPairs": [
21 ["{", "}"],
22 ["[", "]"],
23 ["(", ")"],
24 ["<", ">"],
25 ["\"", "\""],
26 ["'", "'"]
27 ],
28 "indentationRules": {
29 "increaseIndentPattern": "^.*\\{[^}\"']*$|^.*\\([^\\)\"']*$",
30 "decreaseIndentPattern": "^\\s*(\\s*\\/[*].*[*]\\/\\s*)*[})]"
31 },
32 "folding": {
33 "markers": {
34 "start": "^\\s*//\\s*#?region\\b",
35 "end": "^\\s*//\\s*#?endregion\\b"
36 }
37 }
38}
diff --git a/editors/code/package.json b/editors/code/package.json
index ca5f2ebc8..160a62e46 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -734,6 +734,17 @@
734 "extensions": [ 734 "extensions": [
735 ".rast" 735 ".rast"
736 ] 736 ]
737 },
738 {
739 "id": "rust",
740 "extensions": [
741 ".rs"
742 ],
743 "aliases": [
744 "Rust",
745 "rs"
746 ],
747 "configuration": "language-configuration.json"
737 } 748 }
738 ], 749 ],
739 "grammars": [ 750 "grammars": [
diff --git a/xtask/src/codegen/gen_assists_docs.rs b/xtask/src/codegen/gen_assists_docs.rs
index d7c85ebe9..be218dea1 100644
--- a/xtask/src/codegen/gen_assists_docs.rs
+++ b/xtask/src/codegen/gen_assists_docs.rs
@@ -134,7 +134,7 @@ r#####"
134 134
135 buf.push_str(&test) 135 buf.push_str(&test)
136 } 136 }
137 let buf = reformat(&buf.to_string())?; 137 let buf = reformat(&buf)?;
138 codegen::update(&project_root().join("crates/assists/src/tests/generated.rs"), &buf, mode) 138 codegen::update(&project_root().join("crates/assists/src/tests/generated.rs"), &buf, mode)
139} 139}
140 140
diff --git a/xtask/src/metrics.rs b/xtask/src/metrics.rs
index e0d1aaf97..624ad3b7e 100644
--- a/xtask/src/metrics.rs
+++ b/xtask/src/metrics.rs
@@ -81,7 +81,9 @@ impl Metrics {
81 } 81 }
82 fn measure_analysis_stats_path(&mut self, name: &str, path: &str) -> Result<()> { 82 fn measure_analysis_stats_path(&mut self, name: &str, path: &str) -> Result<()> {
83 eprintln!("\nMeasuring analysis-stats/{}", name); 83 eprintln!("\nMeasuring analysis-stats/{}", name);
84 let output = cmd!("./target/release/rust-analyzer analysis-stats --quiet {path}").read()?; 84 let output =
85 cmd!("./target/release/rust-analyzer analysis-stats --quiet --memory-usage {path}")
86 .read()?;
85 for (metric, value, unit) in parse_metrics(&output) { 87 for (metric, value, unit) in parse_metrics(&output) {
86 self.report(&format!("analysis-stats/{}/{}", name, metric), value, unit.into()); 88 self.report(&format!("analysis-stats/{}/{}", name, metric), value, unit.into());
87 } 89 }