diff options
Diffstat (limited to 'crates')
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 @@ | |||
1 | use hir::AsName; | ||
2 | use syntax::{ | ||
3 | ast::{self, edit::AstNodeEdit, make}, | ||
4 | AstNode, | ||
5 | }; | ||
6 | use test_utils::mark; | ||
7 | |||
8 | use 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 | // ``` | ||
40 | pub(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 | |||
66 | fn 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 | |||
85 | fn 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 | |||
99 | fn 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)] | ||
121 | mod 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#" | ||
131 | fn foo() { | ||
132 | let mut a = 1; | ||
133 | |||
134 | if true { | ||
135 | <|>a = 2; | ||
136 | } else { | ||
137 | a = 3; | ||
138 | } | ||
139 | }"#, | ||
140 | r#" | ||
141 | fn 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#" | ||
158 | fn 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#" | ||
174 | fn 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#" | ||
197 | fn 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#" | ||
216 | fn 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#" | ||
228 | fn 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#" | ||
247 | fn 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#" | ||
259 | fn 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#" | ||
278 | fn 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#" | ||
295 | fn 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#" | ||
310 | fn 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] |
241 | fn doctest_extract_assignment() { | ||
242 | check_doc_test( | ||
243 | "extract_assignment", | ||
244 | r#####" | ||
245 | fn main() { | ||
246 | let mut foo = 6; | ||
247 | |||
248 | if true { | ||
249 | <|>foo = 5; | ||
250 | } else { | ||
251 | foo = 4; | ||
252 | } | ||
253 | } | ||
254 | "#####, | ||
255 | r#####" | ||
256 | fn 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] | ||
241 | fn doctest_extract_module_to_file() { | 270 | fn 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)] |
194 | pub enum Edition { | 194 | pub 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 | }; |
26 | use hir_def::{find_path::PrefixKind, item_scope::ItemInNs, visibility::Visibility}; | 26 | use hir_def::{find_path::PrefixKind, item_scope::ItemInNs, visibility::Visibility}; |
27 | use hir_expand::{ | 27 | use 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 { | |||
1237 | pub enum GenericParam { | 1242 | pub enum GenericParam { |
1238 | TypeParam(TypeParam), | 1243 | TypeParam(TypeParam), |
1239 | LifetimeParam(LifetimeParam), | 1244 | LifetimeParam(LifetimeParam), |
1245 | ConstParam(ConstParam), | ||
1240 | } | 1246 | } |
1241 | impl_from!(TypeParam, LifetimeParam for GenericParam); | 1247 | impl_from!(TypeParam, LifetimeParam, ConstParam for GenericParam); |
1242 | 1248 | ||
1243 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | 1249 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
1244 | pub struct TypeParam { | 1250 | pub struct TypeParam { |
@@ -1300,6 +1306,26 @@ impl LifetimeParam { | |||
1300 | } | 1306 | } |
1301 | } | 1307 | } |
1302 | 1308 | ||
1309 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1310 | pub struct ConstParam { | ||
1311 | pub(crate) id: ConstParamId, | ||
1312 | } | ||
1313 | |||
1314 | impl 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)] |
1304 | pub struct Impl { | 1330 | pub 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; | |||
10 | use syntax::ast; | 10 | use syntax::ast; |
11 | 11 | ||
12 | use crate::{ | 12 | use 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 | ||
17 | pub trait HasSource { | 17 | pub 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 | |||
144 | impl 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 | }; |
13 | use hir_expand::{name::AsName, AstId, MacroDefKind}; | 13 | use hir_expand::{name::AsName, AstId, MacroDefKind}; |
14 | use rustc_hash::FxHashMap; | 14 | use 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)] |
30 | pub struct TypeParamData { | 30 | pub 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)] |
38 | pub struct LifetimeParamData { | 38 | pub 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)] | ||
44 | pub 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)] |
43 | pub enum TypeParamProvenance { | 50 | pub enum TypeParamProvenance { |
44 | TypeParamList, | 51 | TypeParamList, |
@@ -51,6 +58,7 @@ pub enum TypeParamProvenance { | |||
51 | pub struct GenericParams { | 58 | pub 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 { | |||
76 | pub(crate) struct SourceMap { | 84 | pub(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 | ||
81 | impl GenericParams { | 90 | impl 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 | ||
413 | impl 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 | |||
393 | impl ChildBySource for GenericDefId { | 423 | impl 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 | ||
272 | static EMPTY_GENERICS: GenericParams = | 273 | static 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)] |
276 | struct ItemTreeData { | 281 | struct 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 | ||
9 | use crate::{ | 9 | use 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 | ||
15 | pub type Key<K, V> = crate::dyn_map::Key<InFile<K>, V, AstPtrPolicy<K, V>>; | 15 | pub 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(); | |||
29 | pub const RECORD_FIELD: Key<ast::RecordField, FieldId> = Key::new(); | 29 | pub const RECORD_FIELD: Key<ast::RecordField, FieldId> = Key::new(); |
30 | pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new(); | 30 | pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new(); |
31 | pub const LIFETIME_PARAM: Key<ast::LifetimeParam, LifetimeParamId> = Key::new(); | 31 | pub const LIFETIME_PARAM: Key<ast::LifetimeParam, LifetimeParamId> = Key::new(); |
32 | pub const CONST_PARAM: Key<ast::ConstParam, ConstParamId> = Key::new(); | ||
32 | 33 | ||
33 | pub const MACRO: Key<ast::MacroCall, MacroDefId> = Key::new(); | 34 | pub 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 { | |||
232 | pub type LocalLifetimeParamId = Idx<generics::LifetimeParamData>; | 232 | pub type LocalLifetimeParamId = Idx<generics::LifetimeParamData>; |
233 | 233 | ||
234 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 234 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
235 | pub struct ConstParamId { | ||
236 | pub parent: GenericDefId, | ||
237 | pub local_id: LocalConstParamId, | ||
238 | } | ||
239 | pub type LocalConstParamId = Idx<generics::ConstParamData>; | ||
240 | |||
241 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
235 | pub enum ContainerId { | 242 | pub 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 | ||
98 | impl Resolver { | 99 | impl 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; | |||
5 | use arena::map::ArenaMap; | 5 | use arena::map::ArenaMap; |
6 | use base_db::{impl_intern_key, salsa, CrateId, Upcast}; | 6 | use base_db::{impl_intern_key, salsa, CrateId, Upcast}; |
7 | use hir_def::{ | 7 | use 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 | ||
12 | use crate::{ | 12 | use 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#" | ||
521 | trait Foo { fn method(&self, arg: usize) {} } | ||
522 | |||
523 | fn 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 | }; |
23 | use hir_expand::name::Name; | 23 | use hir_expand::name::Name; |
24 | use smallvec::SmallVec; | 24 | use 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 | ||
1224 | pub(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 | |||
1224 | pub(crate) fn impl_self_ty_recover( | 1233 | pub(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] |
329 | fn 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] | ||
329 | fn bug_1030() { | 347 | fn 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] | ||
2380 | fn 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 | ||
490 | impl 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#" | ||
3236 | fn 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#" | ||
1152 | fn 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 | ||
231 | const RUSTDOC_FENCE: &str = "```"; | 231 | const RUSTDOC_FENCE: &str = "```"; |
232 | const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] = | 232 | const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] = |
233 | &["", "rust", "should_panic", "edition2015", "edition2018"]; | 233 | &["", "rust", "should_panic", "edition2015", "edition2018", "edition2021"]; |
234 | 234 | ||
235 | fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool { | 235 | fn 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( | |||
54 | type RangesMap = BTreeMap<TextSize, TextSize>; | 54 | type RangesMap = BTreeMap<TextSize, TextSize>; |
55 | 55 | ||
56 | const RUSTDOC_FENCE: &'static str = "```"; | 56 | const RUSTDOC_FENCE: &'static str = "```"; |
57 | const RUSTDOC_FENCE_TOKENS: &[&'static str] = | 57 | const 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"><</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">></span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-></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"><</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">-></span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">></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"><</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">-></span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">></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 | ||
94 | fn const_param<const FOO: usize>() -> usize { | ||
95 | FOO | ||
96 | } | ||
97 | |||
94 | use ops::Fn; | 98 | use ops::Fn; |
95 | fn baz<F: Fn() -> ()>(f: F) { | 99 | fn 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 | ||
8 | use hir::{ | 8 | use 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 | }; |
12 | use syntax::{ | 12 | use 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 | ||
144 | impl From<EditionData> for Edition { | 146 | impl 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 | ||
3 | const RUSTDOC_FENCE: &str = "```"; | 3 | const RUSTDOC_FENCE: &str = "```"; |
4 | const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUST_SPECIFIC: &[&str] = | 4 | const 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 | ||
7 | pub(crate) fn format_docs(src: &str) -> String { | 16 | pub(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, |