aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/assists/src/ast_transform.rs3
-rw-r--r--crates/assists/src/handlers/extract_assignment.rs325
-rw-r--r--crates/assists/src/lib.rs2
-rw-r--r--crates/assists/src/tests/generated.rs29
-rw-r--r--crates/base_db/src/input.rs7
-rw-r--r--crates/hir/src/code_model.rs38
-rw-r--r--crates/hir/src/from_id.rs1
-rw-r--r--crates/hir/src/has_source.rs12
-rw-r--r--crates/hir/src/lib.rs6
-rw-r--r--crates/hir/src/semantics.rs12
-rw-r--r--crates/hir/src/semantics/source_to_def.rs18
-rw-r--r--crates/hir/src/source_analyzer.rs1
-rw-r--r--crates/hir_def/src/generics.rs44
-rw-r--r--crates/hir_def/src/item_tree.rs9
-rw-r--r--crates/hir_def/src/keys.rs5
-rw-r--r--crates/hir_def/src/lib.rs7
-rw-r--r--crates/hir_def/src/resolver.rs17
-rw-r--r--crates/hir_expand/src/db.rs2
-rw-r--r--crates/hir_ty/src/db.rs7
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs26
-rw-r--r--crates/hir_ty/src/infer/path.rs1
-rw-r--r--crates/hir_ty/src/lib.rs4
-rw-r--r--crates/hir_ty/src/lower.rs15
-rw-r--r--crates/hir_ty/src/tests/regression.rs18
-rw-r--r--crates/hir_ty/src/tests/simple.rs16
-rw-r--r--crates/ide/src/display/navigation_target.rs19
-rw-r--r--crates/ide/src/doc_links.rs1
-rw-r--r--crates/ide/src/hover.rs47
-rw-r--r--crates/ide/src/references.rs16
-rw-r--r--crates/ide/src/runnables.rs2
-rw-r--r--crates/ide/src/syntax_highlighting.rs1
-rw-r--r--crates/ide/src/syntax_highlighting/injection.rs13
-rw-r--r--crates/ide/src/syntax_highlighting/tags.rs1
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html4
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs4
-rw-r--r--crates/ide_db/src/defs.rs13
-rw-r--r--crates/project_model/src/project_json.rs3
-rw-r--r--crates/rust-analyzer/src/markdown.rs13
-rw-r--r--crates/rust-analyzer/src/semantic_tokens.rs1
-rw-r--r--crates/rust-analyzer/src/to_proto.rs2
40 files changed, 712 insertions, 53 deletions
diff --git a/crates/assists/src/ast_transform.rs b/crates/assists/src/ast_transform.rs
index da94e9987..4a3ed7783 100644
--- a/crates/assists/src/ast_transform.rs
+++ b/crates/assists/src/ast_transform.rs
@@ -204,7 +204,8 @@ impl<'a> AstTransform<'a> for QualifyPaths<'a> {
204 } 204 }
205 PathResolution::Local(_) 205 PathResolution::Local(_)
206 | PathResolution::TypeParam(_) 206 | PathResolution::TypeParam(_)
207 | PathResolution::SelfType(_) => None, 207 | PathResolution::SelfType(_)
208 | PathResolution::ConstParam(_) => None,
208 PathResolution::Macro(_) => None, 209 PathResolution::Macro(_) => None,
209 PathResolution::AssocItem(_) => None, 210 PathResolution::AssocItem(_) => None,
210 } 211 }
diff --git a/crates/assists/src/handlers/extract_assignment.rs b/crates/assists/src/handlers/extract_assignment.rs
new file mode 100644
index 000000000..281cf5d24
--- /dev/null
+++ b/crates/assists/src/handlers/extract_assignment.rs
@@ -0,0 +1,325 @@
1use hir::AsName;
2use syntax::{
3 ast::{self, edit::AstNodeEdit, make},
4 AstNode,
5};
6use test_utils::mark;
7
8use crate::{
9 assist_context::{AssistContext, Assists},
10 AssistId, AssistKind,
11};
12
13// Assist: extract_assignment
14//
15// Extracts variable assigment to outside an if or match statement.
16//
17// ```
18// fn main() {
19// let mut foo = 6;
20//
21// if true {
22// <|>foo = 5;
23// } else {
24// foo = 4;
25// }
26// }
27// ```
28// ->
29// ```
30// fn main() {
31// let mut foo = 6;
32//
33// foo = if true {
34// 5
35// } else {
36// 4
37// };
38// }
39// ```
40pub(crate) fn extract_assigment(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
41 let name = ctx.find_node_at_offset::<ast::NameRef>()?.as_name();
42
43 let (old_stmt, new_stmt) = if let Some(if_expr) = ctx.find_node_at_offset::<ast::IfExpr>() {
44 (
45 ast::Expr::cast(if_expr.syntax().to_owned())?,
46 exprify_if(&if_expr, &name)?.indent(if_expr.indent_level()),
47 )
48 } else if let Some(match_expr) = ctx.find_node_at_offset::<ast::MatchExpr>() {
49 (ast::Expr::cast(match_expr.syntax().to_owned())?, exprify_match(&match_expr, &name)?)
50 } else {
51 return None;
52 };
53
54 let expr_stmt = make::expr_stmt(new_stmt);
55
56 acc.add(
57 AssistId("extract_assignment", AssistKind::RefactorExtract),
58 "Extract assignment",
59 old_stmt.syntax().text_range(),
60 move |edit| {
61 edit.replace(old_stmt.syntax().text_range(), format!("{} = {};", name, expr_stmt));
62 },
63 )
64}
65
66fn exprify_match(match_expr: &ast::MatchExpr, name: &hir::Name) -> Option<ast::Expr> {
67 let new_arm_list = match_expr
68 .match_arm_list()?
69 .arms()
70 .map(|arm| {
71 if let ast::Expr::BlockExpr(block) = arm.expr()? {
72 let new_block = exprify_block(&block, name)?.indent(block.indent_level());
73 Some(arm.replace_descendant(block, new_block))
74 } else {
75 None
76 }
77 })
78 .collect::<Option<Vec<_>>>()?;
79 let new_arm_list = match_expr
80 .match_arm_list()?
81 .replace_descendants(match_expr.match_arm_list()?.arms().zip(new_arm_list));
82 Some(make::expr_match(match_expr.expr()?, new_arm_list))
83}
84
85fn exprify_if(statement: &ast::IfExpr, name: &hir::Name) -> Option<ast::Expr> {
86 let then_branch = exprify_block(&statement.then_branch()?, name)?;
87 let else_branch = match statement.else_branch()? {
88 ast::ElseBranch::Block(ref block) => ast::ElseBranch::Block(exprify_block(block, name)?),
89 ast::ElseBranch::IfExpr(expr) => {
90 mark::hit!(test_extract_assigment_chained_if);
91 ast::ElseBranch::IfExpr(ast::IfExpr::cast(
92 exprify_if(&expr, name)?.syntax().to_owned(),
93 )?)
94 }
95 };
96 Some(make::expr_if(statement.condition()?, then_branch, Some(else_branch)))
97}
98
99fn exprify_block(block: &ast::BlockExpr, name: &hir::Name) -> Option<ast::BlockExpr> {
100 if block.expr().is_some() {
101 return None;
102 }
103
104 let mut stmts: Vec<_> = block.statements().collect();
105 let stmt = stmts.pop()?;
106
107 if let ast::Stmt::ExprStmt(stmt) = stmt {
108 if let ast::Expr::BinExpr(expr) = stmt.expr()? {
109 if expr.op_kind()? == ast::BinOp::Assignment
110 && &expr.lhs()?.name_ref()?.as_name() == name
111 {
112 // The last statement in the block is an assignment to the name we want
113 return Some(make::block_expr(stmts, Some(expr.rhs()?)));
114 }
115 }
116 }
117 None
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123
124 use crate::tests::{check_assist, check_assist_not_applicable};
125
126 #[test]
127 fn test_extract_assignment_if() {
128 check_assist(
129 extract_assigment,
130 r#"
131fn foo() {
132 let mut a = 1;
133
134 if true {
135 <|>a = 2;
136 } else {
137 a = 3;
138 }
139}"#,
140 r#"
141fn foo() {
142 let mut a = 1;
143
144 a = if true {
145 2
146 } else {
147 3
148 };
149}"#,
150 );
151 }
152
153 #[test]
154 fn test_extract_assignment_match() {
155 check_assist(
156 extract_assigment,
157 r#"
158fn foo() {
159 let mut a = 1;
160
161 match 1 {
162 1 => {
163 <|>a = 2;
164 },
165 2 => {
166 a = 3;
167 },
168 3 => {
169 a = 4;
170 }
171 }
172}"#,
173 r#"
174fn foo() {
175 let mut a = 1;
176
177 a = match 1 {
178 1 => {
179 2
180 },
181 2 => {
182 3
183 },
184 3 => {
185 4
186 }
187 };
188}"#,
189 );
190 }
191
192 #[test]
193 fn test_extract_assignment_not_last_not_applicable() {
194 check_assist_not_applicable(
195 extract_assigment,
196 r#"
197fn foo() {
198 let mut a = 1;
199
200 if true {
201 <|>a = 2;
202 b = a;
203 } else {
204 a = 3;
205 }
206}"#,
207 )
208 }
209
210 #[test]
211 fn test_extract_assignment_chained_if() {
212 mark::check!(test_extract_assigment_chained_if);
213 check_assist(
214 extract_assigment,
215 r#"
216fn foo() {
217 let mut a = 1;
218
219 if true {
220 <|>a = 2;
221 } else if false {
222 a = 3;
223 } else {
224 a = 4;
225 }
226}"#,
227 r#"
228fn foo() {
229 let mut a = 1;
230
231 a = if true {
232 2
233 } else if false {
234 3
235 } else {
236 4
237 };
238}"#,
239 );
240 }
241
242 #[test]
243 fn test_extract_assigment_retains_stmts() {
244 check_assist(
245 extract_assigment,
246 r#"
247fn foo() {
248 let mut a = 1;
249
250 if true {
251 let b = 2;
252 <|>a = 2;
253 } else {
254 let b = 3;
255 a = 3;
256 }
257}"#,
258 r#"
259fn foo() {
260 let mut a = 1;
261
262 a = if true {
263 let b = 2;
264 2
265 } else {
266 let b = 3;
267 3
268 };
269}"#,
270 )
271 }
272
273 #[test]
274 fn extract_assignment_let_stmt_not_applicable() {
275 check_assist_not_applicable(
276 extract_assigment,
277 r#"
278fn foo() {
279 let mut a = 1;
280
281 let b = if true {
282 <|>a = 2
283 } else {
284 a = 3
285 };
286}"#,
287 )
288 }
289
290 #[test]
291 fn extract_assignment_if_missing_assigment_not_applicable() {
292 check_assist_not_applicable(
293 extract_assigment,
294 r#"
295fn foo() {
296 let mut a = 1;
297
298 if true {
299 <|>a = 2;
300 } else {}
301}"#,
302 )
303 }
304
305 #[test]
306 fn extract_assignment_match_missing_assigment_not_applicable() {
307 check_assist_not_applicable(
308 extract_assigment,
309 r#"
310fn foo() {
311 let mut a = 1;
312
313 match 1 {
314 1 => {
315 <|>a = 2;
316 },
317 2 => {
318 a = 3;
319 },
320 3 => {},
321 }
322}"#,
323 )
324 }
325}
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs
index fdec886e9..212464f85 100644
--- a/crates/assists/src/lib.rs
+++ b/crates/assists/src/lib.rs
@@ -116,6 +116,7 @@ mod handlers {
116 mod convert_integer_literal; 116 mod convert_integer_literal;
117 mod early_return; 117 mod early_return;
118 mod expand_glob_import; 118 mod expand_glob_import;
119 mod extract_assignment;
119 mod extract_module_to_file; 120 mod extract_module_to_file;
120 mod extract_struct_from_enum_variant; 121 mod extract_struct_from_enum_variant;
121 mod extract_variable; 122 mod extract_variable;
@@ -167,6 +168,7 @@ mod handlers {
167 convert_integer_literal::convert_integer_literal, 168 convert_integer_literal::convert_integer_literal,
168 early_return::convert_to_guarded_return, 169 early_return::convert_to_guarded_return,
169 expand_glob_import::expand_glob_import, 170 expand_glob_import::expand_glob_import,
171 extract_assignment::extract_assigment,
170 extract_module_to_file::extract_module_to_file, 172 extract_module_to_file::extract_module_to_file,
171 extract_struct_from_enum_variant::extract_struct_from_enum_variant, 173 extract_struct_from_enum_variant::extract_struct_from_enum_variant,
172 extract_variable::extract_variable, 174 extract_variable::extract_variable,
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs
index d3dfe24e7..b91a816e8 100644
--- a/crates/assists/src/tests/generated.rs
+++ b/crates/assists/src/tests/generated.rs
@@ -238,6 +238,35 @@ fn qux(bar: Bar, baz: Baz) {}
238} 238}
239 239
240#[test] 240#[test]
241fn doctest_extract_assignment() {
242 check_doc_test(
243 "extract_assignment",
244 r#####"
245fn main() {
246 let mut foo = 6;
247
248 if true {
249 <|>foo = 5;
250 } else {
251 foo = 4;
252 }
253}
254"#####,
255 r#####"
256fn main() {
257 let mut foo = 6;
258
259 foo = if true {
260 5
261 } else {
262 4
263 };
264}
265"#####,
266 )
267}
268
269#[test]
241fn doctest_extract_module_to_file() { 270fn doctest_extract_module_to_file() {
242 check_doc_test( 271 check_doc_test(
243 "extract_module_to_file", 272 "extract_module_to_file",
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs
index 9567bcc42..2dd8fbe67 100644
--- a/crates/base_db/src/input.rs
+++ b/crates/base_db/src/input.rs
@@ -190,10 +190,11 @@ pub struct CrateData {
190 pub proc_macro: Vec<ProcMacro>, 190 pub proc_macro: Vec<ProcMacro>,
191} 191}
192 192
193#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 193#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
194pub enum Edition { 194pub enum Edition {
195 Edition2018,
196 Edition2015, 195 Edition2015,
196 Edition2018,
197 Edition2021,
197} 198}
198 199
199#[derive(Default, Debug, Clone, PartialEq, Eq)] 200#[derive(Default, Debug, Clone, PartialEq, Eq)]
@@ -393,6 +394,7 @@ impl FromStr for Edition {
393 let res = match s { 394 let res = match s {
394 "2015" => Edition::Edition2015, 395 "2015" => Edition::Edition2015,
395 "2018" => Edition::Edition2018, 396 "2018" => Edition::Edition2018,
397 "2021" => Edition::Edition2021,
396 _ => return Err(ParseEditionError { invalid_input: s.to_string() }), 398 _ => return Err(ParseEditionError { invalid_input: s.to_string() }),
397 }; 399 };
398 Ok(res) 400 Ok(res)
@@ -404,6 +406,7 @@ impl fmt::Display for Edition {
404 f.write_str(match self { 406 f.write_str(match self {
405 Edition::Edition2015 => "2015", 407 Edition::Edition2015 => "2015",
406 Edition::Edition2018 => "2018", 408 Edition::Edition2018 => "2018",
409 Edition::Edition2021 => "2021",
407 }) 410 })
408 } 411 }
409} 412}
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
index b7ded3478..97b7a8b5f 100644
--- a/crates/hir/src/code_model.rs
+++ b/crates/hir/src/code_model.rs
@@ -18,10 +18,10 @@ use hir_def::{
18 resolver::{HasResolver, Resolver}, 18 resolver::{HasResolver, Resolver},
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, ConstParamId,
22 FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, LocalEnumVariantId, LocalFieldId, 22 DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId,
23 LocalModuleId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, 23 LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StaticId, StructId, TraitId,
24 UnionId, 24 TypeAliasId, TypeParamId, UnionId,
25}; 25};
26use hir_def::{find_path::PrefixKind, item_scope::ItemInNs, visibility::Visibility}; 26use hir_def::{find_path::PrefixKind, item_scope::ItemInNs, visibility::Visibility};
27use hir_expand::{ 27use hir_expand::{
@@ -1125,7 +1125,12 @@ impl GenericDef {
1125 id: LifetimeParamId { parent: self.into(), local_id }, 1125 id: LifetimeParamId { parent: self.into(), local_id },
1126 }) 1126 })
1127 .map(GenericParam::LifetimeParam); 1127 .map(GenericParam::LifetimeParam);
1128 ty_params.chain(lt_params).collect() 1128 let const_params = generics
1129 .consts
1130 .iter()
1131 .map(|(local_id, _)| ConstParam { id: ConstParamId { parent: self.into(), local_id } })
1132 .map(GenericParam::ConstParam);
1133 ty_params.chain(lt_params).chain(const_params).collect()
1129 } 1134 }
1130 1135
1131 pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeParam> { 1136 pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeParam> {
@@ -1237,8 +1242,9 @@ impl Label {
1237pub enum GenericParam { 1242pub enum GenericParam {
1238 TypeParam(TypeParam), 1243 TypeParam(TypeParam),
1239 LifetimeParam(LifetimeParam), 1244 LifetimeParam(LifetimeParam),
1245 ConstParam(ConstParam),
1240} 1246}
1241impl_from!(TypeParam, LifetimeParam for GenericParam); 1247impl_from!(TypeParam, LifetimeParam, ConstParam for GenericParam);
1242 1248
1243#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 1249#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1244pub struct TypeParam { 1250pub struct TypeParam {
@@ -1300,6 +1306,26 @@ impl LifetimeParam {
1300 } 1306 }
1301} 1307}
1302 1308
1309#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1310pub struct ConstParam {
1311 pub(crate) id: ConstParamId,
1312}
1313
1314impl ConstParam {
1315 pub fn name(self, db: &dyn HirDatabase) -> Name {
1316 let params = db.generic_params(self.id.parent);
1317 params.consts[self.id.local_id].name.clone()
1318 }
1319
1320 pub fn module(self, db: &dyn HirDatabase) -> Module {
1321 self.id.parent.module(db.upcast()).into()
1322 }
1323
1324 pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef {
1325 self.id.parent.into()
1326 }
1327}
1328
1303#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 1329#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1304pub struct Impl { 1330pub struct Impl {
1305 pub(crate) id: ImplId, 1331 pub(crate) id: ImplId,
diff --git a/crates/hir/src/from_id.rs b/crates/hir/src/from_id.rs
index a0792b9a6..2422887e3 100644
--- a/crates/hir/src/from_id.rs
+++ b/crates/hir/src/from_id.rs
@@ -44,6 +44,7 @@ from_id![
44 (hir_def::ImplId, crate::Impl), 44 (hir_def::ImplId, crate::Impl),
45 (hir_def::TypeParamId, crate::TypeParam), 45 (hir_def::TypeParamId, crate::TypeParam),
46 (hir_def::LifetimeParamId, crate::LifetimeParam), 46 (hir_def::LifetimeParamId, crate::LifetimeParam),
47 (hir_def::ConstParamId, crate::ConstParam),
47 (hir_expand::MacroDefId, crate::MacroDef) 48 (hir_expand::MacroDefId, crate::MacroDef)
48]; 49];
49 50
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs
index 0dc07c33e..dd7c0c570 100644
--- a/crates/hir/src/has_source.rs
+++ b/crates/hir/src/has_source.rs
@@ -10,8 +10,8 @@ use hir_expand::InFile;
10use syntax::ast; 10use syntax::ast;
11 11
12use crate::{ 12use crate::{
13 db::HirDatabase, Const, Enum, Field, FieldSource, Function, Impl, LifetimeParam, MacroDef, 13 db::HirDatabase, Const, ConstParam, Enum, Field, FieldSource, Function, Impl, LifetimeParam,
14 Module, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant, 14 MacroDef, Module, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant,
15}; 15};
16 16
17pub trait HasSource { 17pub trait HasSource {
@@ -140,3 +140,11 @@ impl HasSource for LifetimeParam {
140 child_source.map(|it| it[self.id.local_id].clone()) 140 child_source.map(|it| it[self.id.local_id].clone())
141 } 141 }
142} 142}
143
144impl HasSource for ConstParam {
145 type Ast = ast::ConstParam;
146 fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> {
147 let child_source = self.id.parent.child_source(db.upcast());
148 child_source.map(|it| it[self.id.local_id].clone())
149 }
150}
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 7ac9fd507..8ac27e2dd 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -34,9 +34,9 @@ pub use crate::{
34 attrs::{HasAttrs, Namespace}, 34 attrs::{HasAttrs, Namespace},
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, Field, FieldSource, Function, GenericDef, 37 ConstParam, Crate, CrateDependency, DefWithBody, Enum, Field, FieldSource, Function,
38 HasVisibility, Impl, Label, LifetimeParam, Local, MacroDef, Module, ModuleDef, ScopeDef, 38 GenericDef, HasVisibility, Impl, Label, LifetimeParam, Local, MacroDef, Module, ModuleDef,
39 Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, Variant, VariantDef, 39 ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, Variant, VariantDef,
40 }, 40 },
41 has_source::HasSource, 41 has_source::HasSource,
42 semantics::{PathResolution, Semantics, SemanticsScope}, 42 semantics::{PathResolution, Semantics, SemanticsScope},
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 67cd16e31..cd689c869 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -25,9 +25,9 @@ use crate::{
25 diagnostics::Diagnostic, 25 diagnostics::Diagnostic,
26 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, 26 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
27 source_analyzer::{resolve_hir_path, SourceAnalyzer}, 27 source_analyzer::{resolve_hir_path, SourceAnalyzer},
28 AssocItem, Callable, Crate, Field, Function, HirFileId, Impl, InFile, Label, LifetimeParam, 28 AssocItem, Callable, ConstParam, Crate, Field, Function, HirFileId, Impl, InFile, Label,
29 Local, MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, 29 LifetimeParam, Local, MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type,
30 VariantDef, 30 TypeAlias, TypeParam, VariantDef,
31}; 31};
32 32
33#[derive(Debug, Clone, PartialEq, Eq)] 33#[derive(Debug, Clone, PartialEq, Eq)]
@@ -38,6 +38,7 @@ pub enum PathResolution {
38 Local(Local), 38 Local(Local),
39 /// A generic parameter 39 /// A generic parameter
40 TypeParam(TypeParam), 40 TypeParam(TypeParam),
41 ConstParam(ConstParam),
41 SelfType(Impl), 42 SelfType(Impl),
42 Macro(MacroDef), 43 Macro(MacroDef),
43 AssocItem(AssocItem), 44 AssocItem(AssocItem),
@@ -59,7 +60,9 @@ impl PathResolution {
59 PathResolution::Def(ModuleDef::TypeAlias(alias)) => { 60 PathResolution::Def(ModuleDef::TypeAlias(alias)) => {
60 Some(TypeNs::TypeAliasId((*alias).into())) 61 Some(TypeNs::TypeAliasId((*alias).into()))
61 } 62 }
62 PathResolution::Local(_) | PathResolution::Macro(_) => None, 63 PathResolution::Local(_) | PathResolution::Macro(_) | PathResolution::ConstParam(_) => {
64 None
65 }
63 PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())), 66 PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())),
64 PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())), 67 PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())),
65 PathResolution::AssocItem(AssocItem::Const(_)) 68 PathResolution::AssocItem(AssocItem::Const(_))
@@ -744,6 +747,7 @@ to_def_impls![
744 (crate::Variant, ast::Variant, enum_variant_to_def), 747 (crate::Variant, ast::Variant, enum_variant_to_def),
745 (crate::TypeParam, ast::TypeParam, type_param_to_def), 748 (crate::TypeParam, ast::TypeParam, type_param_to_def),
746 (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def), 749 (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def),
750 (crate::ConstParam, ast::ConstParam, const_param_to_def),
747 (crate::MacroDef, ast::MacroRules, macro_rules_to_def), 751 (crate::MacroDef, ast::MacroRules, macro_rules_to_def),
748 (crate::Local, ast::IdentPat, bind_pat_to_def), 752 (crate::Local, ast::IdentPat, bind_pat_to_def),
749 (crate::Label, ast::Label, label_to_def), 753 (crate::Label, ast::Label, label_to_def),
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index 424e6e8a9..4b9ebff72 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -6,9 +6,9 @@ use hir_def::{
6 dyn_map::DynMap, 6 dyn_map::DynMap,
7 expr::{LabelId, PatId}, 7 expr::{LabelId, PatId},
8 keys::{self, Key}, 8 keys::{self, Key},
9 ConstId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId, GenericDefId, ImplId, 9 ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId, GenericDefId,
10 LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, 10 ImplId, LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId,
11 VariantId, 11 UnionId, VariantId,
12}; 12};
13use hir_expand::{name::AsName, AstId, MacroDefKind}; 13use hir_expand::{name::AsName, AstId, MacroDefKind};
14use rustc_hash::FxHashMap; 14use rustc_hash::FxHashMap;
@@ -157,6 +157,18 @@ impl SourceToDefCtx<'_, '_> {
157 dyn_map[keys::LIFETIME_PARAM].get(&src).copied() 157 dyn_map[keys::LIFETIME_PARAM].get(&src).copied()
158 } 158 }
159 159
160 pub(super) fn const_param_to_def(
161 &mut self,
162 src: InFile<ast::ConstParam>,
163 ) -> Option<ConstParamId> {
164 let container: ChildContainer =
165 self.find_generic_param_container(src.as_ref().map(|it| it.syntax()))?.into();
166 let db = self.db;
167 let dyn_map =
168 &*self.cache.entry(container).or_insert_with(|| container.child_by_source(db));
169 dyn_map[keys::CONST_PARAM].get(&src).copied()
170 }
171
160 // FIXME: use DynMap as well? 172 // FIXME: use DynMap as well?
161 pub(super) fn macro_rules_to_def( 173 pub(super) fn macro_rules_to_def(
162 &mut self, 174 &mut self,
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index bddc49c05..30a8e513d 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -479,6 +479,7 @@ pub(crate) fn resolve_hir_path(
479 ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()), 479 ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()),
480 ValueNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()), 480 ValueNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()),
481 ValueNs::ImplSelf(impl_id) => PathResolution::SelfType(impl_id.into()), 481 ValueNs::ImplSelf(impl_id) => PathResolution::SelfType(impl_id.into()),
482 ValueNs::GenericParam(it) => PathResolution::ConstParam(it.into()),
482 }; 483 };
483 Some(res) 484 Some(res)
484 }); 485 });
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs
index bb8fca009..9b5b886c2 100644
--- a/crates/hir_def/src/generics.rs
+++ b/crates/hir_def/src/generics.rs
@@ -21,11 +21,11 @@ use crate::{
21 keys, 21 keys,
22 src::{HasChildSource, HasSource}, 22 src::{HasChildSource, HasSource},
23 type_ref::{LifetimeRef, TypeBound, TypeRef}, 23 type_ref::{LifetimeRef, TypeBound, TypeRef},
24 AdtId, GenericDefId, LifetimeParamId, LocalLifetimeParamId, LocalTypeParamId, Lookup, 24 AdtId, ConstParamId, GenericDefId, LifetimeParamId, LocalConstParamId, LocalLifetimeParamId,
25 TypeParamId, 25 LocalTypeParamId, Lookup, TypeParamId,
26}; 26};
27 27
28/// Data about a generic parameter (to a function, struct, impl, ...). 28/// Data about a generic type parameter (to a function, struct, impl, ...).
29#[derive(Clone, PartialEq, Eq, Debug)] 29#[derive(Clone, PartialEq, Eq, Debug)]
30pub struct TypeParamData { 30pub struct TypeParamData {
31 pub name: Option<Name>, 31 pub name: Option<Name>,
@@ -33,12 +33,19 @@ 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, ...). 36/// Data about a generic lifetime parameter (to a function, struct, impl, ...).
37#[derive(Clone, PartialEq, Eq, Debug)] 37#[derive(Clone, PartialEq, Eq, Debug)]
38pub struct LifetimeParamData { 38pub struct LifetimeParamData {
39 pub name: Name, 39 pub name: Name,
40} 40}
41 41
42/// Data about a generic const parameter (to a function, struct, impl, ...).
43#[derive(Clone, PartialEq, Eq, Debug)]
44pub struct ConstParamData {
45 pub name: Name,
46 pub ty: TypeRef,
47}
48
42#[derive(Copy, Clone, PartialEq, Eq, Debug)] 49#[derive(Copy, Clone, PartialEq, Eq, Debug)]
43pub enum TypeParamProvenance { 50pub enum TypeParamProvenance {
44 TypeParamList, 51 TypeParamList,
@@ -51,6 +58,7 @@ pub enum TypeParamProvenance {
51pub struct GenericParams { 58pub struct GenericParams {
52 pub types: Arena<TypeParamData>, 59 pub types: Arena<TypeParamData>,
53 pub lifetimes: Arena<LifetimeParamData>, 60 pub lifetimes: Arena<LifetimeParamData>,
61 pub consts: Arena<ConstParamData>,
54 pub where_predicates: Vec<WherePredicate>, 62 pub where_predicates: Vec<WherePredicate>,
55} 63}
56 64
@@ -76,6 +84,7 @@ pub enum WherePredicateTypeTarget {
76pub(crate) struct SourceMap { 84pub(crate) struct SourceMap {
77 pub(crate) type_params: ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>, 85 pub(crate) type_params: ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>,
78 lifetime_params: ArenaMap<LocalLifetimeParamId, ast::LifetimeParam>, 86 lifetime_params: ArenaMap<LocalLifetimeParamId, ast::LifetimeParam>,
87 const_params: ArenaMap<LocalConstParamId, ast::ConstParam>,
79} 88}
80 89
81impl GenericParams { 90impl GenericParams {
@@ -268,6 +277,13 @@ impl GenericParams {
268 let lifetime_ref = LifetimeRef::new_name(name); 277 let lifetime_ref = LifetimeRef::new_name(name);
269 self.fill_bounds(&lower_ctx, &lifetime_param, Either::Right(lifetime_ref)); 278 self.fill_bounds(&lower_ctx, &lifetime_param, Either::Right(lifetime_ref));
270 } 279 }
280 for const_param in params.const_params() {
281 let name = const_param.name().map_or_else(Name::missing, |it| it.as_name());
282 let ty = const_param.ty().map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it));
283 let param = ConstParamData { name, ty };
284 let param_id = self.consts.alloc(param);
285 sm.const_params.insert(param_id, const_param.clone());
286 }
271 } 287 }
272 288
273 fn fill_where_predicates(&mut self, lower_ctx: &LowerCtx, where_clause: ast::WhereClause) { 289 fn fill_where_predicates(&mut self, lower_ctx: &LowerCtx, where_clause: ast::WhereClause) {
@@ -353,12 +369,16 @@ impl GenericParams {
353 }); 369 });
354 } 370 }
355 371
356 pub fn find_by_name(&self, name: &Name) -> Option<LocalTypeParamId> { 372 pub fn find_type_by_name(&self, name: &Name) -> Option<LocalTypeParamId> {
357 self.types 373 self.types
358 .iter() 374 .iter()
359 .find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None }) 375 .find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None })
360 } 376 }
361 377
378 pub fn find_const_by_name(&self, name: &Name) -> Option<LocalConstParamId> {
379 self.consts.iter().find_map(|(id, p)| if p.name == *name { Some(id) } else { None })
380 }
381
362 pub fn find_trait_self_param(&self) -> Option<LocalTypeParamId> { 382 pub fn find_trait_self_param(&self) -> Option<LocalTypeParamId> {
363 self.types.iter().find_map(|(id, p)| { 383 self.types.iter().find_map(|(id, p)| {
364 if p.provenance == TypeParamProvenance::TraitSelf { 384 if p.provenance == TypeParamProvenance::TraitSelf {
@@ -390,6 +410,16 @@ impl HasChildSource<LocalLifetimeParamId> for GenericDefId {
390 } 410 }
391} 411}
392 412
413impl HasChildSource<LocalConstParamId> for GenericDefId {
414 type Value = ast::ConstParam;
415 fn child_source(
416 &self,
417 db: &dyn DefDatabase,
418 ) -> InFile<ArenaMap<LocalConstParamId, Self::Value>> {
419 GenericParams::new(db, *self).1.map(|source_maps| source_maps.const_params)
420 }
421}
422
393impl ChildBySource for GenericDefId { 423impl ChildBySource for GenericDefId {
394 fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { 424 fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
395 let mut res = DynMap::default(); 425 let mut res = DynMap::default();
@@ -406,6 +436,10 @@ impl ChildBySource for GenericDefId {
406 let id = LifetimeParamId { parent: *self, local_id }; 436 let id = LifetimeParamId { parent: *self, local_id };
407 res[keys::LIFETIME_PARAM].insert(sm.with_value(src.clone()), id); 437 res[keys::LIFETIME_PARAM].insert(sm.with_value(src.clone()), id);
408 } 438 }
439 for (local_id, src) in sm.value.const_params.iter() {
440 let id = ConstParamId { parent: *self, local_id };
441 res[keys::CONST_PARAM].insert(sm.with_value(src.clone()), id);
442 }
409 res 443 res
410 } 444 }
411} 445}
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 100dbf5d6..b6f510731 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -260,6 +260,7 @@ impl GenericParamsStorage {
260 fn alloc(&mut self, params: GenericParams) -> GenericParamsId { 260 fn alloc(&mut self, params: GenericParams) -> GenericParamsId {
261 if params.types.is_empty() 261 if params.types.is_empty()
262 && params.lifetimes.is_empty() 262 && params.lifetimes.is_empty()
263 && params.consts.is_empty()
263 && params.where_predicates.is_empty() 264 && params.where_predicates.is_empty()
264 { 265 {
265 return GenericParamsId::EMPTY; 266 return GenericParamsId::EMPTY;
@@ -269,8 +270,12 @@ impl GenericParamsStorage {
269 } 270 }
270} 271}
271 272
272static EMPTY_GENERICS: GenericParams = 273static EMPTY_GENERICS: GenericParams = GenericParams {
273 GenericParams { types: Arena::new(), lifetimes: Arena::new(), where_predicates: Vec::new() }; 274 types: Arena::new(),
275 lifetimes: Arena::new(),
276 consts: Arena::new(),
277 where_predicates: Vec::new(),
278};
274 279
275#[derive(Default, Debug, Eq, PartialEq)] 280#[derive(Default, Debug, Eq, PartialEq)]
276struct ItemTreeData { 281struct ItemTreeData {
diff --git a/crates/hir_def/src/keys.rs b/crates/hir_def/src/keys.rs
index 9c585de2c..89b3ed868 100644
--- a/crates/hir_def/src/keys.rs
+++ b/crates/hir_def/src/keys.rs
@@ -8,8 +8,8 @@ use syntax::{ast, AstNode, AstPtr};
8 8
9use crate::{ 9use crate::{
10 dyn_map::{DynMap, Policy}, 10 dyn_map::{DynMap, Policy},
11 ConstId, EnumId, EnumVariantId, FieldId, FunctionId, ImplId, LifetimeParamId, StaticId, 11 ConstId, ConstParamId, EnumId, EnumVariantId, FieldId, FunctionId, ImplId, LifetimeParamId,
12 StructId, TraitId, TypeAliasId, TypeParamId, UnionId, 12 StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId,
13}; 13};
14 14
15pub type Key<K, V> = crate::dyn_map::Key<InFile<K>, V, AstPtrPolicy<K, V>>; 15pub type Key<K, V> = crate::dyn_map::Key<InFile<K>, V, AstPtrPolicy<K, V>>;
@@ -29,6 +29,7 @@ pub const TUPLE_FIELD: Key<ast::TupleField, FieldId> = Key::new();
29pub const RECORD_FIELD: Key<ast::RecordField, FieldId> = Key::new(); 29pub const RECORD_FIELD: Key<ast::RecordField, FieldId> = Key::new();
30pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new(); 30pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new();
31pub const LIFETIME_PARAM: Key<ast::LifetimeParam, LifetimeParamId> = Key::new(); 31pub const LIFETIME_PARAM: Key<ast::LifetimeParam, LifetimeParamId> = Key::new();
32pub const CONST_PARAM: Key<ast::ConstParam, ConstParamId> = Key::new();
32 33
33pub const MACRO: Key<ast::MacroCall, MacroDefId> = Key::new(); 34pub const MACRO: Key<ast::MacroCall, MacroDefId> = Key::new();
34 35
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index ba09a9126..25f460504 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -232,6 +232,13 @@ pub struct LifetimeParamId {
232pub type LocalLifetimeParamId = Idx<generics::LifetimeParamData>; 232pub type LocalLifetimeParamId = Idx<generics::LifetimeParamData>;
233 233
234#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 234#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
235pub struct ConstParamId {
236 pub parent: GenericDefId,
237 pub local_id: LocalConstParamId,
238}
239pub type LocalConstParamId = Idx<generics::ConstParamData>;
240
241#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
235pub enum ContainerId { 242pub enum ContainerId {
236 ModuleId(ModuleId), 243 ModuleId(ModuleId),
237 DefWithBodyId(DefWithBodyId), 244 DefWithBodyId(DefWithBodyId),
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs
index f8cc5e075..129f1dbac 100644
--- a/crates/hir_def/src/resolver.rs
+++ b/crates/hir_def/src/resolver.rs
@@ -20,9 +20,9 @@ use crate::{
20 path::{ModPath, PathKind}, 20 path::{ModPath, PathKind},
21 per_ns::PerNs, 21 per_ns::PerNs,
22 visibility::{RawVisibility, Visibility}, 22 visibility::{RawVisibility, Visibility},
23 AdtId, AssocContainerId, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId, 23 AdtId, AssocContainerId, ConstId, ConstParamId, ContainerId, DefWithBodyId, EnumId,
24 FunctionId, GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId, 24 EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId,
25 StaticId, StructId, TraitId, TypeAliasId, TypeParamId, VariantId, 25 ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, VariantId,
26}; 26};
27 27
28#[derive(Debug, Clone, Default)] 28#[derive(Debug, Clone, Default)]
@@ -93,6 +93,7 @@ pub enum ValueNs {
93 StaticId(StaticId), 93 StaticId(StaticId),
94 StructId(StructId), 94 StructId(StructId),
95 EnumVariantId(EnumVariantId), 95 EnumVariantId(EnumVariantId),
96 GenericParam(ConstParamId),
96} 97}
97 98
98impl Resolver { 99impl Resolver {
@@ -163,7 +164,7 @@ impl Resolver {
163 } 164 }
164 165
165 Scope::GenericParams { params, def } => { 166 Scope::GenericParams { params, def } => {
166 if let Some(local_id) = params.find_by_name(first_name) { 167 if let Some(local_id) = params.find_type_by_name(first_name) {
167 let idx = if path.segments.len() == 1 { None } else { Some(1) }; 168 let idx = if path.segments.len() == 1 { None } else { Some(1) };
168 return Some(( 169 return Some((
169 TypeNs::GenericParam(TypeParamId { local_id, parent: *def }), 170 TypeNs::GenericParam(TypeParamId { local_id, parent: *def }),
@@ -285,11 +286,17 @@ impl Resolver {
285 Scope::ExprScope(_) => continue, 286 Scope::ExprScope(_) => continue,
286 287
287 Scope::GenericParams { params, def } if n_segments > 1 => { 288 Scope::GenericParams { params, def } if n_segments > 1 => {
288 if let Some(local_id) = params.find_by_name(first_name) { 289 if let Some(local_id) = params.find_type_by_name(first_name) {
289 let ty = TypeNs::GenericParam(TypeParamId { local_id, parent: *def }); 290 let ty = TypeNs::GenericParam(TypeParamId { local_id, parent: *def });
290 return Some(ResolveValueResult::Partial(ty, 1)); 291 return Some(ResolveValueResult::Partial(ty, 1));
291 } 292 }
292 } 293 }
294 Scope::GenericParams { params, def } if n_segments == 1 => {
295 if let Some(local_id) = params.find_const_by_name(first_name) {
296 let val = ValueNs::GenericParam(ConstParamId { local_id, parent: *def });
297 return Some(ResolveValueResult::ValueNs(val));
298 }
299 }
293 Scope::GenericParams { .. } => continue, 300 Scope::GenericParams { .. } => continue,
294 301
295 Scope::ImplDefScope(impl_) => { 302 Scope::ImplDefScope(impl_) => {
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index 06f0a3ed9..0a0d021e0 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -404,7 +404,7 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
404 TRY_EXPR => FragmentKind::Expr, 404 TRY_EXPR => FragmentKind::Expr,
405 TUPLE_EXPR => FragmentKind::Expr, 405 TUPLE_EXPR => FragmentKind::Expr,
406 PAREN_EXPR => FragmentKind::Expr, 406 PAREN_EXPR => FragmentKind::Expr,
407 407 ARRAY_EXPR => FragmentKind::Expr,
408 FOR_EXPR => FragmentKind::Expr, 408 FOR_EXPR => FragmentKind::Expr,
409 PATH_EXPR => FragmentKind::Expr, 409 PATH_EXPR => FragmentKind::Expr,
410 CLOSURE_EXPR => FragmentKind::Expr, 410 CLOSURE_EXPR => FragmentKind::Expr,
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs
index 66bdb8e88..f3567c49e 100644
--- a/crates/hir_ty/src/db.rs
+++ b/crates/hir_ty/src/db.rs
@@ -5,8 +5,8 @@ use std::sync::Arc;
5use arena::map::ArenaMap; 5use arena::map::ArenaMap;
6use base_db::{impl_intern_key, salsa, CrateId, Upcast}; 6use base_db::{impl_intern_key, salsa, CrateId, Upcast};
7use hir_def::{ 7use hir_def::{
8 db::DefDatabase, expr::ExprId, DefWithBodyId, FunctionId, GenericDefId, ImplId, LocalFieldId, 8 db::DefDatabase, expr::ExprId, ConstParamId, DefWithBodyId, FunctionId, GenericDefId, ImplId,
9 TypeParamId, VariantId, 9 LocalFieldId, TypeParamId, VariantId,
10}; 10};
11 11
12use crate::{ 12use crate::{
@@ -37,6 +37,9 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
37 #[salsa::cycle(crate::lower::impl_self_ty_recover)] 37 #[salsa::cycle(crate::lower::impl_self_ty_recover)]
38 fn impl_self_ty(&self, def: ImplId) -> Binders<Ty>; 38 fn impl_self_ty(&self, def: ImplId) -> Binders<Ty>;
39 39
40 #[salsa::invoke(crate::lower::const_param_ty_query)]
41 fn const_param_ty(&self, def: ConstParamId) -> Ty;
42
40 #[salsa::invoke(crate::lower::impl_trait_query)] 43 #[salsa::invoke(crate::lower::impl_trait_query)]
41 fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>; 44 fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>;
42 45
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs
index 849415706..b4e453411 100644
--- a/crates/hir_ty/src/diagnostics/expr.rs
+++ b/crates/hir_ty/src/diagnostics/expr.rs
@@ -156,7 +156,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
156 // FIXME: Due to shortcomings in the current type system implementation, only emit this 156 // FIXME: Due to shortcomings in the current type system implementation, only emit this
157 // diagnostic if there are no type mismatches in the containing function. 157 // diagnostic if there are no type mismatches in the containing function.
158 if self.infer.type_mismatches.iter().next().is_some() { 158 if self.infer.type_mismatches.iter().next().is_some() {
159 return Some(()); 159 return None;
160 } 160 }
161 161
162 let is_method_call = matches!(expr, Expr::MethodCall { .. }); 162 let is_method_call = matches!(expr, Expr::MethodCall { .. });
@@ -170,6 +170,14 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
170 let mut args = args.clone(); 170 let mut args = args.clone();
171 args.insert(0, *receiver); 171 args.insert(0, *receiver);
172 172
173 let receiver = &self.infer.type_of_expr[*receiver];
174 if receiver.strip_references().is_unknown() {
175 // if the receiver is of unknown type, it's very likely we
176 // don't know enough to correctly resolve the method call.
177 // This is kind of a band-aid for #6975.
178 return None;
179 }
180
173 // FIXME: note that we erase information about substs here. This 181 // FIXME: note that we erase information about substs here. This
174 // is not right, but, luckily, doesn't matter as we care only 182 // is not right, but, luckily, doesn't matter as we care only
175 // about the number of params 183 // about the number of params
@@ -505,6 +513,22 @@ fn f() {
505 } 513 }
506 514
507 #[test] 515 #[test]
516 fn method_unknown_receiver() {
517 // note: this is incorrect code, so there might be errors on this in the
518 // future, but we shouldn't emit an argument count diagnostic here
519 check_diagnostics(
520 r#"
521trait Foo { fn method(&self, arg: usize) {} }
522
523fn f() {
524 let x;
525 x.method();
526}
527"#,
528 );
529 }
530
531 #[test]
508 fn tuple_struct() { 532 fn tuple_struct() {
509 check_diagnostics( 533 check_diagnostics(
510 r#" 534 r#"
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index 80d7ed10e..5d541104e 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -89,6 +89,7 @@ impl<'a> InferenceContext<'a> {
89 return None; 89 return None;
90 } 90 }
91 } 91 }
92 ValueNs::GenericParam(it) => return Some(self.db.const_param_ty(it)),
92 }; 93 };
93 94
94 let ty = self.db.value_ty(typable); 95 let ty = self.db.value_ty(typable);
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 357bd92f9..e00c7e176 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -791,6 +791,10 @@ impl Ty {
791 matches!(self, Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. })) 791 matches!(self, Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. }))
792 } 792 }
793 793
794 pub fn is_unknown(&self) -> bool {
795 matches!(self, Ty::Unknown)
796 }
797
794 /// If this is a `dyn Trait` type, this returns the `Trait` part. 798 /// If this is a `dyn Trait` type, this returns the `Trait` part.
795 pub fn dyn_trait_ref(&self) -> Option<&TraitRef> { 799 pub fn dyn_trait_ref(&self) -> Option<&TraitRef> {
796 match self { 800 match self {
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 8da56cd11..222f61a11 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -16,9 +16,9 @@ use hir_def::{
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},
19 AdtId, AssocContainerId, AssocItemId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, 19 AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId,
20 HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, 20 GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
21 UnionId, VariantId, 21 TypeAliasId, TypeParamId, UnionId, VariantId,
22}; 22};
23use hir_expand::name::Name; 23use hir_expand::name::Name;
24use smallvec::SmallVec; 24use smallvec::SmallVec;
@@ -1221,6 +1221,15 @@ pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binde
1221 Binders::new(generics.len(), Ty::from_hir(&ctx, &impl_data.target_type)) 1221 Binders::new(generics.len(), Ty::from_hir(&ctx, &impl_data.target_type))
1222} 1222}
1223 1223
1224pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty {
1225 let parent_data = db.generic_params(def.parent);
1226 let data = &parent_data.consts[def.local_id];
1227 let resolver = def.parent.resolver(db.upcast());
1228 let ctx = TyLoweringContext::new(db, &resolver);
1229
1230 Ty::from_hir(&ctx, &data.ty)
1231}
1232
1224pub(crate) fn impl_self_ty_recover( 1233pub(crate) fn impl_self_ty_recover(
1225 db: &dyn HirDatabase, 1234 db: &dyn HirDatabase,
1226 _cycle: &[String], 1235 _cycle: &[String],
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index 307a257b1..cffe8630b 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -326,6 +326,24 @@ fn infer_paren_macro_call() {
326} 326}
327 327
328#[test] 328#[test]
329fn infer_array_macro_call() {
330 check_infer(
331 r#"
332 macro_rules! bar { () => {0u32} }
333 fn test() {
334 let a = [bar!()];
335 }
336 "#,
337 expect![[r#"
338 !0..4 '0u32': u32
339 44..69 '{ ...()]; }': ()
340 54..55 'a': [u32; _]
341 58..66 '[bar!()]': [u32; _]
342 "#]],
343 );
344}
345
346#[test]
329fn bug_1030() { 347fn bug_1030() {
330 check_infer( 348 check_infer(
331 r#" 349 r#"
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index a61282d5a..8d431b920 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -2375,3 +2375,19 @@ fn infer_operator_overload() {
2375 "#]], 2375 "#]],
2376 ); 2376 );
2377} 2377}
2378
2379#[test]
2380fn infer_const_params() {
2381 check_infer(
2382 r#"
2383 fn foo<const FOO: usize>() {
2384 let bar = FOO;
2385 }
2386 "#,
2387 expect![[r#"
2388 27..49 '{ ...FOO; }': ()
2389 37..40 'bar': usize
2390 43..46 'FOO': usize
2391 "#]],
2392 );
2393}
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index 6431e7d6d..bcde2b6f1 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -24,6 +24,7 @@ pub enum SymbolKind {
24 Impl, 24 Impl,
25 Field, 25 Field,
26 TypeParam, 26 TypeParam,
27 ConstParam,
27 LifetimeParam, 28 LifetimeParam,
28 ValueParam, 29 ValueParam,
29 SelfParam, 30 SelfParam,
@@ -225,6 +226,7 @@ impl TryToNav for Definition {
225 Definition::TypeParam(it) => Some(it.to_nav(db)), 226 Definition::TypeParam(it) => Some(it.to_nav(db)),
226 Definition::LifetimeParam(it) => Some(it.to_nav(db)), 227 Definition::LifetimeParam(it) => Some(it.to_nav(db)),
227 Definition::Label(it) => Some(it.to_nav(db)), 228 Definition::Label(it) => Some(it.to_nav(db)),
229 Definition::ConstParam(it) => Some(it.to_nav(db)),
228 } 230 }
229 } 231 }
230} 232}
@@ -485,6 +487,23 @@ impl ToNav for hir::LifetimeParam {
485 } 487 }
486} 488}
487 489
490impl ToNav for hir::ConstParam {
491 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
492 let src = self.source(db);
493 let full_range = src.value.syntax().text_range();
494 NavigationTarget {
495 file_id: src.file_id.original_file(db),
496 name: self.name(db).to_string().into(),
497 kind: Some(SymbolKind::ConstParam),
498 full_range,
499 focus_range: src.value.name().map(|n| n.syntax().text_range()),
500 container_name: None,
501 description: None,
502 docs: None,
503 }
504 }
505}
506
488/// Get a description of a symbol. 507/// Get a description of a symbol.
489/// 508///
490/// e.g. `struct Name`, `enum Name`, `fn Name` 509/// e.g. `struct Name`, `enum Name`, `fn Name`
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs
index e10516f43..367fac05e 100644
--- a/crates/ide/src/doc_links.rs
+++ b/crates/ide/src/doc_links.rs
@@ -193,6 +193,7 @@ fn rewrite_intra_doc_link(
193 Definition::SelfType(_) 193 Definition::SelfType(_)
194 | Definition::Local(_) 194 | Definition::Local(_)
195 | Definition::TypeParam(_) 195 | Definition::TypeParam(_)
196 | Definition::ConstParam(_)
196 | Definition::LifetimeParam(_) 197 | Definition::LifetimeParam(_)
197 | Definition::Label(_) => return None, 198 | Definition::Label(_) => return None,
198 }?; 199 }?;
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 73245fbe7..98c7bfbe5 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -109,6 +109,8 @@ pub(crate) fn hover(
109 match node { 109 match node {
110 ast::Name(name) => NameClass::classify(&sema, &name).and_then(|d| d.defined(sema.db)), 110 ast::Name(name) => NameClass::classify(&sema, &name).and_then(|d| d.defined(sema.db)),
111 ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), 111 ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)),
112 ast::Lifetime(lifetime) => NameClass::classify_lifetime(&sema, &lifetime)
113 .map_or_else(|| NameRefClass::classify_lifetime(&sema, &lifetime).map(|d| d.referenced(sema.db)), |d| d.defined(sema.db)),
112 _ => None, 114 _ => None,
113 } 115 }
114 }; 116 };
@@ -360,9 +362,9 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
360 ModuleDef::Static(it) => from_def_source(db, it, mod_path), 362 ModuleDef::Static(it) => from_def_source(db, it, mod_path),
361 ModuleDef::Trait(it) => from_def_source(db, it, mod_path), 363 ModuleDef::Trait(it) => from_def_source(db, it, mod_path),
362 ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path), 364 ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path),
363 ModuleDef::BuiltinType(it) => return Some(it.to_string().into()), 365 ModuleDef::BuiltinType(it) => Some(Markup::fenced_block(&it)),
364 }, 366 },
365 Definition::Local(it) => return Some(Markup::fenced_block(&it.ty(db).display(db))), 367 Definition::Local(it) => Some(Markup::fenced_block(&it.ty(db).display(db))),
366 Definition::SelfType(impl_def) => { 368 Definition::SelfType(impl_def) => {
367 impl_def.target_ty(db).as_adt().and_then(|adt| match adt { 369 impl_def.target_ty(db).as_adt().and_then(|adt| match adt {
368 Adt::Struct(it) => from_def_source(db, it, mod_path), 370 Adt::Struct(it) => from_def_source(db, it, mod_path),
@@ -370,7 +372,9 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
370 Adt::Enum(it) => from_def_source(db, it, mod_path), 372 Adt::Enum(it) => from_def_source(db, it, mod_path),
371 }) 373 })
372 } 374 }
373 Definition::TypeParam(_) | Definition::LifetimeParam(_) | Definition::Label(_) => { 375 Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))),
376 Definition::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))),
377 Definition::TypeParam(_) | Definition::ConstParam(_) => {
374 // FIXME: Hover for generic param 378 // FIXME: Hover for generic param
375 None 379 None
376 } 380 }
@@ -403,7 +407,7 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
403 return tokens.max_by_key(priority); 407 return tokens.max_by_key(priority);
404 fn priority(n: &SyntaxToken) -> usize { 408 fn priority(n: &SyntaxToken) -> usize {
405 match n.kind() { 409 match n.kind() {
406 IDENT | INT_NUMBER => 3, 410 IDENT | INT_NUMBER | LIFETIME_IDENT => 3,
407 T!['('] | T![')'] => 2, 411 T!['('] | T![')'] => 2,
408 kind if kind.is_trivia() => 0, 412 kind if kind.is_trivia() => 0,
409 _ => 1, 413 _ => 1,
@@ -1169,7 +1173,10 @@ fn f() { fo<|>o!(); }
1169 r#"struct TS(String, i32<|>);"#, 1173 r#"struct TS(String, i32<|>);"#,
1170 expect![[r#" 1174 expect![[r#"
1171 *i32* 1175 *i32*
1176
1177 ```rust
1172 i32 1178 i32
1179 ```
1173 "#]], 1180 "#]],
1174 ) 1181 )
1175 } 1182 }
@@ -3221,4 +3228,36 @@ fn no_hover() {
3221"#, 3228"#,
3222 ); 3229 );
3223 } 3230 }
3231
3232 #[test]
3233 fn hover_label() {
3234 check(
3235 r#"
3236fn foo() {
3237 'label<|>: loop {}
3238}
3239"#,
3240 expect![[r#"
3241 *'label*
3242
3243 ```rust
3244 'label
3245 ```
3246 "#]],
3247 );
3248 }
3249
3250 #[test]
3251 fn hover_lifetime() {
3252 check(
3253 r#"fn foo<'lifetime>(_: &'lifetime<|> ()) {}"#,
3254 expect![[r#"
3255 *'lifetime*
3256
3257 ```rust
3258 'lifetime
3259 ```
3260 "#]],
3261 );
3262 }
3224} 3263}
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 21b2d7ca1..fa58fc319 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -1144,4 +1144,20 @@ fn foo<'a>() -> &'a () {
1144 "#]], 1144 "#]],
1145 ); 1145 );
1146 } 1146 }
1147
1148 #[test]
1149 fn test_find_const_param() {
1150 check(
1151 r#"
1152fn foo<const FOO<|>: usize>() -> usize {
1153 FOO
1154}
1155"#,
1156 expect![[r#"
1157 FOO ConstParam FileId(0) 7..23 13..16 Other
1158
1159 FileId(0) 42..45 Other
1160 "#]],
1161 );
1162 }
1147} 1163}
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 891183266..c893afc7c 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -230,7 +230,7 @@ impl TestAttr {
230 230
231const RUSTDOC_FENCE: &str = "```"; 231const RUSTDOC_FENCE: &str = "```";
232const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] = 232const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] =
233 &["", "rust", "should_panic", "edition2015", "edition2018"]; 233 &["", "rust", "should_panic", "edition2015", "edition2018", "edition2021"];
234 234
235fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool { 235fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool {
236 attrs.docs().map_or(false, |doc| { 236 attrs.docs().map_or(false, |doc| {
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index 5ad96581b..ba0085244 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -819,6 +819,7 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
819 }, 819 },
820 Definition::SelfType(_) => HighlightTag::Symbol(SymbolKind::Impl), 820 Definition::SelfType(_) => HighlightTag::Symbol(SymbolKind::Impl),
821 Definition::TypeParam(_) => HighlightTag::Symbol(SymbolKind::TypeParam), 821 Definition::TypeParam(_) => HighlightTag::Symbol(SymbolKind::TypeParam),
822 Definition::ConstParam(_) => HighlightTag::Symbol(SymbolKind::ConstParam),
822 Definition::Local(local) => { 823 Definition::Local(local) => {
823 let tag = if local.is_param(db) { 824 let tag = if local.is_param(db) {
824 HighlightTag::Symbol(SymbolKind::ValueParam) 825 HighlightTag::Symbol(SymbolKind::ValueParam)
diff --git a/crates/ide/src/syntax_highlighting/injection.rs b/crates/ide/src/syntax_highlighting/injection.rs
index 9eb184c74..6cbd683c6 100644
--- a/crates/ide/src/syntax_highlighting/injection.rs
+++ b/crates/ide/src/syntax_highlighting/injection.rs
@@ -54,8 +54,17 @@ pub(super) fn highlight_injection(
54type RangesMap = BTreeMap<TextSize, TextSize>; 54type RangesMap = BTreeMap<TextSize, TextSize>;
55 55
56const RUSTDOC_FENCE: &'static str = "```"; 56const RUSTDOC_FENCE: &'static str = "```";
57const RUSTDOC_FENCE_TOKENS: &[&'static str] = 57const RUSTDOC_FENCE_TOKENS: &[&'static str] = &[
58 &["", "rust", "should_panic", "ignore", "no_run", "compile_fail", "edition2015", "edition2018"]; 58 "",
59 "rust",
60 "should_panic",
61 "ignore",
62 "no_run",
63 "compile_fail",
64 "edition2015",
65 "edition2018",
66 "edition2021",
67];
59 68
60/// Extracts Rust code from documentation comments as well as a mapping from 69/// Extracts Rust code from documentation comments as well as a mapping from
61/// the extracted source code back to the original source ranges. 70/// the extracted source code back to the original source ranges.
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs
index 2a6cc0cab..8b8867079 100644
--- a/crates/ide/src/syntax_highlighting/tags.rs
+++ b/crates/ide/src/syntax_highlighting/tags.rs
@@ -77,6 +77,7 @@ impl HighlightTag {
77 SymbolKind::Function => "function", 77 SymbolKind::Function => "function",
78 SymbolKind::TypeAlias => "type_alias", 78 SymbolKind::TypeAlias => "type_alias",
79 SymbolKind::TypeParam => "type_param", 79 SymbolKind::TypeParam => "type_param",
80 SymbolKind::ConstParam => "const_param",
80 SymbolKind::LifetimeParam => "lifetime", 81 SymbolKind::LifetimeParam => "lifetime",
81 SymbolKind::Macro => "macro", 82 SymbolKind::Macro => "macro",
82 SymbolKind::Local => "variable", 83 SymbolKind::Local => "variable",
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index 72ff9dd40..02270b077 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -118,6 +118,10 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
118 <span class="keyword control">loop</span> <span class="punctuation">{</span><span class="punctuation">}</span> 118 <span class="keyword control">loop</span> <span class="punctuation">{</span><span class="punctuation">}</span>
119<span class="punctuation">}</span> 119<span class="punctuation">}</span>
120 120
121<span class="keyword">fn</span> <span class="function declaration">const_param</span><span class="punctuation">&lt;</span><span class="keyword">const</span> <span class="const_param declaration">FOO</span><span class="punctuation">:</span> <span class="builtin_type">usize</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">usize</span> <span class="punctuation">{</span>
122 <span class="const_param">FOO</span>
123<span class="punctuation">}</span>
124
121<span class="keyword">use</span> <span class="module">ops</span><span class="operator">::</span><span class="trait">Fn</span><span class="punctuation">;</span> 125<span class="keyword">use</span> <span class="module">ops</span><span class="operator">::</span><span class="trait">Fn</span><span class="punctuation">;</span>
122<span class="keyword">fn</span> <span class="function declaration">baz</span><span class="punctuation">&lt;</span><span class="type_param declaration">F</span><span class="punctuation">:</span> <span class="trait">Fn</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="value_param declaration callable">f</span><span class="punctuation">:</span> <span class="type_param">F</span><span class="punctuation">)</span> <span class="punctuation">{</span> 126<span class="keyword">fn</span> <span class="function declaration">baz</span><span class="punctuation">&lt;</span><span class="type_param declaration">F</span><span class="punctuation">:</span> <span class="trait">Fn</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="value_param declaration callable">f</span><span class="punctuation">:</span> <span class="type_param">F</span><span class="punctuation">)</span> <span class="punctuation">{</span>
123 <span class="value_param callable">f</span><span class="punctuation">(</span><span class="punctuation">)</span> 127 <span class="value_param callable">f</span><span class="punctuation">(</span><span class="punctuation">)</span>
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index e0df0d2b5..30b5b648e 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -91,6 +91,10 @@ fn never() -> ! {
91 loop {} 91 loop {}
92} 92}
93 93
94fn const_param<const FOO: usize>() -> usize {
95 FOO
96}
97
94use ops::Fn; 98use ops::Fn;
95fn baz<F: Fn() -> ()>(f: F) { 99fn baz<F: Fn() -> ()>(f: F) {
96 f() 100 f()
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs
index d33a6cb86..cc5078bf0 100644
--- a/crates/ide_db/src/defs.rs
+++ b/crates/ide_db/src/defs.rs
@@ -6,8 +6,8 @@
6// FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). 6// FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).
7 7
8use hir::{ 8use hir::{
9 db::HirDatabase, Crate, Field, HasVisibility, Impl, Label, LifetimeParam, Local, MacroDef, 9 db::HirDatabase, ConstParam, Crate, Field, HasVisibility, Impl, Label, LifetimeParam, Local,
10 Module, ModuleDef, Name, PathResolution, Semantics, TypeParam, Visibility, 10 MacroDef, Module, ModuleDef, Name, PathResolution, Semantics, TypeParam, Visibility,
11}; 11};
12use syntax::{ 12use syntax::{
13 ast::{self, AstNode}, 13 ast::{self, AstNode},
@@ -26,6 +26,7 @@ pub enum Definition {
26 Local(Local), 26 Local(Local),
27 TypeParam(TypeParam), 27 TypeParam(TypeParam),
28 LifetimeParam(LifetimeParam), 28 LifetimeParam(LifetimeParam),
29 ConstParam(ConstParam),
29 Label(Label), 30 Label(Label),
30} 31}
31 32
@@ -39,6 +40,7 @@ impl Definition {
39 Definition::Local(it) => Some(it.module(db)), 40 Definition::Local(it) => Some(it.module(db)),
40 Definition::TypeParam(it) => Some(it.module(db)), 41 Definition::TypeParam(it) => Some(it.module(db)),
41 Definition::LifetimeParam(it) => Some(it.module(db)), 42 Definition::LifetimeParam(it) => Some(it.module(db)),
43 Definition::ConstParam(it) => Some(it.module(db)),
42 Definition::Label(it) => Some(it.module(db)), 44 Definition::Label(it) => Some(it.module(db)),
43 } 45 }
44 } 46 }
@@ -52,6 +54,7 @@ impl Definition {
52 Definition::Local(_) => None, 54 Definition::Local(_) => None,
53 Definition::TypeParam(_) => None, 55 Definition::TypeParam(_) => None,
54 Definition::LifetimeParam(_) => None, 56 Definition::LifetimeParam(_) => None,
57 Definition::ConstParam(_) => None,
55 Definition::Label(_) => None, 58 Definition::Label(_) => None,
56 } 59 }
57 } 60 }
@@ -79,6 +82,7 @@ impl Definition {
79 Definition::Local(it) => it.name(db)?, 82 Definition::Local(it) => it.name(db)?,
80 Definition::TypeParam(it) => it.name(db), 83 Definition::TypeParam(it) => it.name(db),
81 Definition::LifetimeParam(it) => it.name(db), 84 Definition::LifetimeParam(it) => it.name(db),
85 Definition::ConstParam(it) => it.name(db),
82 Definition::Label(it) => it.name(db), 86 Definition::Label(it) => it.name(db),
83 }; 87 };
84 Some(name) 88 Some(name)
@@ -233,6 +237,10 @@ impl NameClass {
233 let def = sema.to_def(&it)?; 237 let def = sema.to_def(&it)?;
234 Some(NameClass::Definition(Definition::TypeParam(def))) 238 Some(NameClass::Definition(Definition::TypeParam(def)))
235 }, 239 },
240 ast::ConstParam(it) => {
241 let def = sema.to_def(&it)?;
242 Some(NameClass::Definition(Definition::ConstParam(def)))
243 },
236 _ => None, 244 _ => None,
237 } 245 }
238 } 246 }
@@ -417,6 +425,7 @@ impl From<PathResolution> for Definition {
417 PathResolution::TypeParam(par) => Definition::TypeParam(par), 425 PathResolution::TypeParam(par) => Definition::TypeParam(par),
418 PathResolution::Macro(def) => Definition::Macro(def), 426 PathResolution::Macro(def) => Definition::Macro(def),
419 PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def), 427 PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def),
428 PathResolution::ConstParam(par) => Definition::ConstParam(par),
420 } 429 }
421 } 430 }
422} 431}
diff --git a/crates/project_model/src/project_json.rs b/crates/project_model/src/project_json.rs
index aab279223..af884eb84 100644
--- a/crates/project_model/src/project_json.rs
+++ b/crates/project_model/src/project_json.rs
@@ -139,6 +139,8 @@ enum EditionData {
139 Edition2015, 139 Edition2015,
140 #[serde(rename = "2018")] 140 #[serde(rename = "2018")]
141 Edition2018, 141 Edition2018,
142 #[serde(rename = "2021")]
143 Edition2021,
142} 144}
143 145
144impl From<EditionData> for Edition { 146impl From<EditionData> for Edition {
@@ -146,6 +148,7 @@ impl From<EditionData> for Edition {
146 match data { 148 match data {
147 EditionData::Edition2015 => Edition::Edition2015, 149 EditionData::Edition2015 => Edition::Edition2015,
148 EditionData::Edition2018 => Edition::Edition2018, 150 EditionData::Edition2018 => Edition::Edition2018,
151 EditionData::Edition2021 => Edition::Edition2021,
149 } 152 }
150 } 153 }
151} 154}
diff --git a/crates/rust-analyzer/src/markdown.rs b/crates/rust-analyzer/src/markdown.rs
index 968ea55f0..a49a58c00 100644
--- a/crates/rust-analyzer/src/markdown.rs
+++ b/crates/rust-analyzer/src/markdown.rs
@@ -1,8 +1,17 @@
1//! Transforms markdown 1//! Transforms markdown
2 2
3const RUSTDOC_FENCE: &str = "```"; 3const RUSTDOC_FENCE: &str = "```";
4const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUST_SPECIFIC: &[&str] = 4const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUST_SPECIFIC: &[&str] = &[
5 &["", "rust", "should_panic", "ignore", "no_run", "compile_fail", "edition2015", "edition2018"]; 5 "",
6 "rust",
7 "should_panic",
8 "ignore",
9 "no_run",
10 "compile_fail",
11 "edition2015",
12 "edition2018",
13 "edition2021",
14];
6 15
7pub(crate) fn format_docs(src: &str) -> String { 16pub(crate) fn format_docs(src: &str) -> String {
8 let mut processed_lines = Vec::new(); 17 let mut processed_lines = Vec::new();
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs
index c2f6a655d..5c4366f16 100644
--- a/crates/rust-analyzer/src/semantic_tokens.rs
+++ b/crates/rust-analyzer/src/semantic_tokens.rs
@@ -44,6 +44,7 @@ define_semantic_token_types![
44 (ESCAPE_SEQUENCE, "escapeSequence"), 44 (ESCAPE_SEQUENCE, "escapeSequence"),
45 (FORMAT_SPECIFIER, "formatSpecifier"), 45 (FORMAT_SPECIFIER, "formatSpecifier"),
46 (GENERIC, "generic"), 46 (GENERIC, "generic"),
47 (CONST_PARAMETER, "constParameter"),
47 (LIFETIME, "lifetime"), 48 (LIFETIME, "lifetime"),
48 (LABEL, "label"), 49 (LABEL, "label"),
49 (PUNCTUATION, "punctuation"), 50 (PUNCTUATION, "punctuation"),
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 1a38e79f0..999b18351 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -42,6 +42,7 @@ pub(crate) fn symbol_kind(symbol_kind: SymbolKind) -> lsp_types::SymbolKind {
42 SymbolKind::Field => lsp_types::SymbolKind::Field, 42 SymbolKind::Field => lsp_types::SymbolKind::Field,
43 SymbolKind::Static => lsp_types::SymbolKind::Constant, 43 SymbolKind::Static => lsp_types::SymbolKind::Constant,
44 SymbolKind::Const => lsp_types::SymbolKind::Constant, 44 SymbolKind::Const => lsp_types::SymbolKind::Constant,
45 SymbolKind::ConstParam => lsp_types::SymbolKind::Constant,
45 SymbolKind::Impl => lsp_types::SymbolKind::Object, 46 SymbolKind::Impl => lsp_types::SymbolKind::Object,
46 SymbolKind::Local 47 SymbolKind::Local
47 | SymbolKind::SelfParam 48 | SymbolKind::SelfParam
@@ -378,6 +379,7 @@ fn semantic_token_type_and_modifiers(
378 SymbolKind::Impl => lsp_types::SemanticTokenType::TYPE, 379 SymbolKind::Impl => lsp_types::SemanticTokenType::TYPE,
379 SymbolKind::Field => lsp_types::SemanticTokenType::PROPERTY, 380 SymbolKind::Field => lsp_types::SemanticTokenType::PROPERTY,
380 SymbolKind::TypeParam => lsp_types::SemanticTokenType::TYPE_PARAMETER, 381 SymbolKind::TypeParam => lsp_types::SemanticTokenType::TYPE_PARAMETER,
382 SymbolKind::ConstParam => semantic_tokens::CONST_PARAMETER,
381 SymbolKind::LifetimeParam => semantic_tokens::LIFETIME, 383 SymbolKind::LifetimeParam => semantic_tokens::LIFETIME,
382 SymbolKind::Label => semantic_tokens::LABEL, 384 SymbolKind::Label => semantic_tokens::LABEL,
383 SymbolKind::ValueParam => lsp_types::SemanticTokenType::PARAMETER, 385 SymbolKind::ValueParam => lsp_types::SemanticTokenType::PARAMETER,