diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/hir_def/src/intern.rs | 8 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 180 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/expr.rs | 22 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/match_check.rs | 12 | ||||
-rw-r--r-- | crates/hir_ty/src/infer.rs | 23 | ||||
-rw-r--r-- | crates/hir_ty/src/infer/expr.rs | 9 | ||||
-rw-r--r-- | crates/hir_ty/src/infer/pat.rs | 7 | ||||
-rw-r--r-- | crates/hir_ty/src/tests.rs | 5 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/patterns.rs | 58 | ||||
-rw-r--r-- | crates/ide/src/references/rename.rs | 12 | ||||
-rw-r--r-- | crates/rust-analyzer/src/caps.rs | 1 |
11 files changed, 291 insertions, 46 deletions
diff --git a/crates/hir_def/src/intern.rs b/crates/hir_def/src/intern.rs index abc304ef0..5cc7f2df6 100644 --- a/crates/hir_def/src/intern.rs +++ b/crates/hir_def/src/intern.rs | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | use std::{ | 5 | use std::{ |
6 | collections::HashMap, | 6 | collections::HashMap, |
7 | fmt::{self, Debug}, | 7 | fmt::{self, Debug, Display}, |
8 | hash::{BuildHasherDefault, Hash, Hasher}, | 8 | hash::{BuildHasherDefault, Hash, Hasher}, |
9 | ops::Deref, | 9 | ops::Deref, |
10 | sync::Arc, | 10 | sync::Arc, |
@@ -171,6 +171,12 @@ impl<T: Debug + Internable + ?Sized> Debug for Interned<T> { | |||
171 | } | 171 | } |
172 | } | 172 | } |
173 | 173 | ||
174 | impl<T: Display + Internable + ?Sized> Display for Interned<T> { | ||
175 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
176 | (*self.arc).fmt(f) | ||
177 | } | ||
178 | } | ||
179 | |||
174 | pub struct InternStorage<T: ?Sized> { | 180 | pub struct InternStorage<T: ?Sized> { |
175 | map: OnceCell<InternMap<T>>, | 181 | map: OnceCell<InternMap<T>>, |
176 | } | 182 | } |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index d4840be2f..221a5a556 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -21,6 +21,7 @@ use syntax::ast; | |||
21 | 21 | ||
22 | use crate::{ | 22 | use crate::{ |
23 | attr::{AttrId, Attrs}, | 23 | attr::{AttrId, Attrs}, |
24 | builtin_attr, | ||
24 | db::DefDatabase, | 25 | db::DefDatabase, |
25 | derive_macro_as_call_id, | 26 | derive_macro_as_call_id, |
26 | intern::Interned, | 27 | intern::Interned, |
@@ -99,6 +100,7 @@ pub(super) fn collect_defs( | |||
99 | proc_macros, | 100 | proc_macros, |
100 | exports_proc_macros: false, | 101 | exports_proc_macros: false, |
101 | from_glob_import: Default::default(), | 102 | from_glob_import: Default::default(), |
103 | ignore_attrs_on: FxHashSet::default(), | ||
102 | }; | 104 | }; |
103 | match block { | 105 | match block { |
104 | Some(block) => { | 106 | Some(block) => { |
@@ -217,6 +219,7 @@ struct MacroDirective { | |||
217 | enum MacroDirectiveKind { | 219 | enum MacroDirectiveKind { |
218 | FnLike { ast_id: AstIdWithPath<ast::MacroCall>, fragment: FragmentKind }, | 220 | FnLike { ast_id: AstIdWithPath<ast::MacroCall>, fragment: FragmentKind }, |
219 | Derive { ast_id: AstIdWithPath<ast::Item>, derive_attr: AttrId }, | 221 | Derive { ast_id: AstIdWithPath<ast::Item>, derive_attr: AttrId }, |
222 | Attr { ast_id: AstIdWithPath<ast::Item>, attr: AttrId, mod_item: ModItem }, | ||
220 | } | 223 | } |
221 | 224 | ||
222 | struct DefData<'a> { | 225 | struct DefData<'a> { |
@@ -243,6 +246,7 @@ struct DefCollector<'a> { | |||
243 | proc_macros: Vec<(Name, ProcMacroExpander)>, | 246 | proc_macros: Vec<(Name, ProcMacroExpander)>, |
244 | exports_proc_macros: bool, | 247 | exports_proc_macros: bool, |
245 | from_glob_import: PerNsGlobImports, | 248 | from_glob_import: PerNsGlobImports, |
249 | ignore_attrs_on: FxHashSet<ModItem>, | ||
246 | } | 250 | } |
247 | 251 | ||
248 | impl DefCollector<'_> { | 252 | impl DefCollector<'_> { |
@@ -292,16 +296,26 @@ impl DefCollector<'_> { | |||
292 | fn collect(&mut self) { | 296 | fn collect(&mut self) { |
293 | // main name resolution fixed-point loop. | 297 | // main name resolution fixed-point loop. |
294 | let mut i = 0; | 298 | let mut i = 0; |
295 | loop { | 299 | 'outer: loop { |
296 | self.db.check_canceled(); | 300 | loop { |
297 | self.resolve_imports(); | 301 | self.db.check_canceled(); |
302 | loop { | ||
303 | if self.resolve_imports() == ReachedFixedPoint::Yes { | ||
304 | break; | ||
305 | } | ||
306 | } | ||
307 | if self.resolve_macros() == ReachedFixedPoint::Yes { | ||
308 | break; | ||
309 | } | ||
298 | 310 | ||
299 | match self.resolve_macros() { | 311 | i += 1; |
300 | ReachedFixedPoint::Yes => break, | 312 | if i == FIXED_POINT_LIMIT { |
301 | ReachedFixedPoint::No => i += 1, | 313 | log::error!("name resolution is stuck"); |
314 | break 'outer; | ||
315 | } | ||
302 | } | 316 | } |
303 | if i == FIXED_POINT_LIMIT { | 317 | |
304 | log::error!("name resolution is stuck"); | 318 | if self.reseed_with_unresolved_attributes() == ReachedFixedPoint::Yes { |
305 | break; | 319 | break; |
306 | } | 320 | } |
307 | } | 321 | } |
@@ -343,6 +357,50 @@ impl DefCollector<'_> { | |||
343 | } | 357 | } |
344 | } | 358 | } |
345 | 359 | ||
360 | /// When the fixed-point loop reaches a stable state, we might still have some unresolved | ||
361 | /// attributes (or unexpanded attribute proc macros) left over. This takes them, and feeds the | ||
362 | /// item they're applied to back into name resolution. | ||
363 | /// | ||
364 | /// This effectively ignores the fact that the macro is there and just treats the items as | ||
365 | /// normal code. | ||
366 | /// | ||
367 | /// This improves UX when proc macros are turned off or don't work, and replicates the behavior | ||
368 | /// before we supported proc. attribute macros. | ||
369 | fn reseed_with_unresolved_attributes(&mut self) -> ReachedFixedPoint { | ||
370 | let mut added_items = false; | ||
371 | let unexpanded_macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); | ||
372 | for directive in &unexpanded_macros { | ||
373 | if let MacroDirectiveKind::Attr { mod_item, .. } = &directive.kind { | ||
374 | // Make sure to only add such items once. | ||
375 | if !self.ignore_attrs_on.insert(*mod_item) { | ||
376 | continue; | ||
377 | } | ||
378 | |||
379 | let file_id = self.def_map[directive.module_id].definition_source(self.db).file_id; | ||
380 | let item_tree = self.db.file_item_tree(file_id); | ||
381 | let mod_dir = self.mod_dirs[&directive.module_id].clone(); | ||
382 | ModCollector { | ||
383 | def_collector: &mut *self, | ||
384 | macro_depth: directive.depth, | ||
385 | module_id: directive.module_id, | ||
386 | file_id, | ||
387 | item_tree: &item_tree, | ||
388 | mod_dir, | ||
389 | } | ||
390 | .collect(&[*mod_item]); | ||
391 | added_items = true; | ||
392 | } | ||
393 | } | ||
394 | self.unexpanded_macros = unexpanded_macros; | ||
395 | |||
396 | if added_items { | ||
397 | // Continue name resolution with the new data. | ||
398 | ReachedFixedPoint::No | ||
399 | } else { | ||
400 | ReachedFixedPoint::Yes | ||
401 | } | ||
402 | } | ||
403 | |||
346 | /// Adds a definition of procedural macro `name` to the root module. | 404 | /// Adds a definition of procedural macro `name` to the root module. |
347 | /// | 405 | /// |
348 | /// # Notes on procedural macro resolution | 406 | /// # Notes on procedural macro resolution |
@@ -504,35 +562,35 @@ impl DefCollector<'_> { | |||
504 | } | 562 | } |
505 | } | 563 | } |
506 | 564 | ||
507 | /// Import resolution | 565 | /// Tries to resolve every currently unresolved import. |
508 | /// | 566 | fn resolve_imports(&mut self) -> ReachedFixedPoint { |
509 | /// This is a fix point algorithm. We resolve imports until no forward | 567 | let mut res = ReachedFixedPoint::Yes; |
510 | /// progress in resolving imports is made | 568 | let imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); |
511 | fn resolve_imports(&mut self) { | 569 | let imports = imports |
512 | let mut n_previous_unresolved = self.unresolved_imports.len() + 1; | 570 | .into_iter() |
513 | 571 | .filter_map(|mut directive| { | |
514 | while self.unresolved_imports.len() < n_previous_unresolved { | ||
515 | n_previous_unresolved = self.unresolved_imports.len(); | ||
516 | let imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); | ||
517 | for mut directive in imports { | ||
518 | directive.status = self.resolve_import(directive.module_id, &directive.import); | 572 | directive.status = self.resolve_import(directive.module_id, &directive.import); |
519 | match directive.status { | 573 | match directive.status { |
520 | PartialResolvedImport::Indeterminate(_) => { | 574 | PartialResolvedImport::Indeterminate(_) => { |
521 | self.record_resolved_import(&directive); | 575 | self.record_resolved_import(&directive); |
522 | // FIXME: For avoid performance regression, | 576 | // FIXME: For avoid performance regression, |
523 | // we consider an imported resolved if it is indeterminate (i.e not all namespace resolved) | 577 | // we consider an imported resolved if it is indeterminate (i.e not all namespace resolved) |
524 | self.resolved_imports.push(directive) | 578 | self.resolved_imports.push(directive); |
579 | res = ReachedFixedPoint::No; | ||
580 | None | ||
525 | } | 581 | } |
526 | PartialResolvedImport::Resolved(_) => { | 582 | PartialResolvedImport::Resolved(_) => { |
527 | self.record_resolved_import(&directive); | 583 | self.record_resolved_import(&directive); |
528 | self.resolved_imports.push(directive) | 584 | self.resolved_imports.push(directive); |
529 | } | 585 | res = ReachedFixedPoint::No; |
530 | PartialResolvedImport::Unresolved => { | 586 | None |
531 | self.unresolved_imports.push(directive); | ||
532 | } | 587 | } |
588 | PartialResolvedImport::Unresolved => Some(directive), | ||
533 | } | 589 | } |
534 | } | 590 | }) |
535 | } | 591 | .collect(); |
592 | self.unresolved_imports = imports; | ||
593 | res | ||
536 | } | 594 | } |
537 | 595 | ||
538 | fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport { | 596 | fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport { |
@@ -856,6 +914,9 @@ impl DefCollector<'_> { | |||
856 | Err(UnresolvedMacro { .. }) => (), | 914 | Err(UnresolvedMacro { .. }) => (), |
857 | } | 915 | } |
858 | } | 916 | } |
917 | MacroDirectiveKind::Attr { .. } => { | ||
918 | // not yet :) | ||
919 | } | ||
859 | } | 920 | } |
860 | 921 | ||
861 | true | 922 | true |
@@ -948,7 +1009,7 @@ impl DefCollector<'_> { | |||
948 | )); | 1009 | )); |
949 | } | 1010 | } |
950 | }, | 1011 | }, |
951 | MacroDirectiveKind::Derive { .. } => { | 1012 | MacroDirectiveKind::Derive { .. } | MacroDirectiveKind::Attr { .. } => { |
952 | // FIXME: we might want to diagnose this too | 1013 | // FIXME: we might want to diagnose this too |
953 | } | 1014 | } |
954 | } | 1015 | } |
@@ -1056,6 +1117,14 @@ impl ModCollector<'_, '_> { | |||
1056 | continue; | 1117 | continue; |
1057 | } | 1118 | } |
1058 | } | 1119 | } |
1120 | |||
1121 | if let Err(()) = self.resolve_attributes(&attrs, item) { | ||
1122 | // Do not process the item. It has at least one non-builtin attribute, which *must* | ||
1123 | // resolve to a proc macro (or fail to resolve), so we'll never see this item during | ||
1124 | // normal name resolution. | ||
1125 | continue; | ||
1126 | } | ||
1127 | |||
1059 | let module = self.def_collector.def_map.module_id(self.module_id); | 1128 | let module = self.def_collector.def_map.module_id(self.module_id); |
1060 | 1129 | ||
1061 | let mut def = None; | 1130 | let mut def = None; |
@@ -1362,6 +1431,62 @@ impl ModCollector<'_, '_> { | |||
1362 | res | 1431 | res |
1363 | } | 1432 | } |
1364 | 1433 | ||
1434 | /// Resolves attributes on an item. | ||
1435 | /// | ||
1436 | /// Returns `Err` when some attributes could not be resolved to builtins and have been | ||
1437 | /// registered as unresolved. | ||
1438 | fn resolve_attributes(&mut self, attrs: &Attrs, mod_item: ModItem) -> Result<(), ()> { | ||
1439 | fn is_builtin_attr(path: &ModPath) -> bool { | ||
1440 | if path.kind == PathKind::Plain { | ||
1441 | if let Some(tool_module) = path.segments().first() { | ||
1442 | let tool_module = tool_module.to_string(); | ||
1443 | if builtin_attr::TOOL_MODULES.iter().any(|m| tool_module == *m) { | ||
1444 | return true; | ||
1445 | } | ||
1446 | } | ||
1447 | |||
1448 | if let Some(name) = path.as_ident() { | ||
1449 | let name = name.to_string(); | ||
1450 | if builtin_attr::INERT_ATTRIBUTES | ||
1451 | .iter() | ||
1452 | .chain(builtin_attr::EXTRA_ATTRIBUTES) | ||
1453 | .any(|attr| name == *attr) | ||
1454 | { | ||
1455 | return true; | ||
1456 | } | ||
1457 | } | ||
1458 | } | ||
1459 | |||
1460 | false | ||
1461 | } | ||
1462 | |||
1463 | // We failed to resolve an attribute on this item earlier, and are falling back to treating | ||
1464 | // the item as-is. | ||
1465 | if self.def_collector.ignore_attrs_on.contains(&mod_item) { | ||
1466 | return Ok(()); | ||
1467 | } | ||
1468 | |||
1469 | match attrs.iter().find(|attr| !is_builtin_attr(&attr.path)) { | ||
1470 | Some(non_builtin_attr) => { | ||
1471 | log::debug!("non-builtin attribute {}", non_builtin_attr.path); | ||
1472 | |||
1473 | let ast_id = AstIdWithPath::new( | ||
1474 | self.file_id, | ||
1475 | mod_item.ast_id(self.item_tree), | ||
1476 | non_builtin_attr.path.as_ref().clone(), | ||
1477 | ); | ||
1478 | self.def_collector.unexpanded_macros.push(MacroDirective { | ||
1479 | module_id: self.module_id, | ||
1480 | depth: self.macro_depth + 1, | ||
1481 | kind: MacroDirectiveKind::Attr { ast_id, attr: non_builtin_attr.id, mod_item }, | ||
1482 | }); | ||
1483 | |||
1484 | Err(()) | ||
1485 | } | ||
1486 | None => Ok(()), | ||
1487 | } | ||
1488 | } | ||
1489 | |||
1365 | fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::Item>) { | 1490 | fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::Item>) { |
1366 | for derive in attrs.by_key("derive").attrs() { | 1491 | for derive in attrs.by_key("derive").attrs() { |
1367 | match derive.parse_derive() { | 1492 | match derive.parse_derive() { |
@@ -1594,6 +1719,7 @@ mod tests { | |||
1594 | proc_macros: Default::default(), | 1719 | proc_macros: Default::default(), |
1595 | exports_proc_macros: false, | 1720 | exports_proc_macros: false, |
1596 | from_glob_import: Default::default(), | 1721 | from_glob_import: Default::default(), |
1722 | ignore_attrs_on: FxHashSet::default(), | ||
1597 | }; | 1723 | }; |
1598 | collector.seed_with_top_level(); | 1724 | collector.seed_with_top_level(); |
1599 | collector.collect(); | 1725 | collector.collect(); |
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs index 47709c1e8..b9a69b79c 100644 --- a/crates/hir_ty/src/diagnostics/expr.rs +++ b/crates/hir_ty/src/diagnostics/expr.rs | |||
@@ -211,7 +211,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
211 | 211 | ||
212 | // FIXME: Due to shortcomings in the current type system implementation, only emit this | 212 | // FIXME: Due to shortcomings in the current type system implementation, only emit this |
213 | // diagnostic if there are no type mismatches in the containing function. | 213 | // diagnostic if there are no type mismatches in the containing function. |
214 | if self.infer.type_mismatches.iter().next().is_some() { | 214 | if self.infer.expr_type_mismatches().next().is_some() { |
215 | return; | 215 | return; |
216 | } | 216 | } |
217 | 217 | ||
@@ -311,11 +311,12 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
311 | // necessary. | 311 | // necessary. |
312 | // | 312 | // |
313 | // FIXME we should use the type checker for this. | 313 | // FIXME we should use the type checker for this. |
314 | if pat_ty == match_expr_ty | 314 | if (pat_ty == match_expr_ty |
315 | || match_expr_ty | 315 | || match_expr_ty |
316 | .as_reference() | 316 | .as_reference() |
317 | .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty) | 317 | .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty) |
318 | .unwrap_or(false) | 318 | .unwrap_or(false)) |
319 | && types_of_subpatterns_do_match(pat, &cx.body, &infer) | ||
319 | { | 320 | { |
320 | // If we had a NotUsefulMatchArm diagnostic, we could | 321 | // If we had a NotUsefulMatchArm diagnostic, we could |
321 | // check the usefulness of each pattern as we added it | 322 | // check the usefulness of each pattern as we added it |
@@ -496,6 +497,21 @@ pub fn record_pattern_missing_fields( | |||
496 | Some((variant_def, missed_fields, exhaustive)) | 497 | Some((variant_def, missed_fields, exhaustive)) |
497 | } | 498 | } |
498 | 499 | ||
500 | fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResult) -> bool { | ||
501 | fn walk(pat: PatId, body: &Body, infer: &InferenceResult, has_type_mismatches: &mut bool) { | ||
502 | match infer.type_mismatch_for_pat(pat) { | ||
503 | Some(_) => *has_type_mismatches = true, | ||
504 | None => { | ||
505 | body[pat].walk_child_pats(|subpat| walk(subpat, body, infer, has_type_mismatches)) | ||
506 | } | ||
507 | } | ||
508 | } | ||
509 | |||
510 | let mut has_type_mismatches = false; | ||
511 | walk(pat, body, infer, &mut has_type_mismatches); | ||
512 | !has_type_mismatches | ||
513 | } | ||
514 | |||
499 | #[cfg(test)] | 515 | #[cfg(test)] |
500 | mod tests { | 516 | mod tests { |
501 | use crate::diagnostics::tests::check_diagnostics; | 517 | use crate::diagnostics::tests::check_diagnostics; |
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs index 6ee0529c6..e8dd669bf 100644 --- a/crates/hir_ty/src/diagnostics/match_check.rs +++ b/crates/hir_ty/src/diagnostics/match_check.rs | |||
@@ -1128,6 +1128,18 @@ fn main() { | |||
1128 | } | 1128 | } |
1129 | 1129 | ||
1130 | #[test] | 1130 | #[test] |
1131 | fn mismatched_types_in_or_patterns() { | ||
1132 | check_diagnostics( | ||
1133 | r#" | ||
1134 | fn main() { | ||
1135 | match false { true | () => {} } | ||
1136 | match (false,) { (true | (),) => {} } | ||
1137 | } | ||
1138 | "#, | ||
1139 | ); | ||
1140 | } | ||
1141 | |||
1142 | #[test] | ||
1131 | fn malformed_match_arm_tuple_enum_missing_pattern() { | 1143 | fn malformed_match_arm_tuple_enum_missing_pattern() { |
1132 | // We are testing to be sure we don't panic here when the match | 1144 | // We are testing to be sure we don't panic here when the match |
1133 | // arm `Either::B` is missing its pattern. | 1145 | // arm `Either::B` is missing its pattern. |
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs index bf2da2d4a..0ee851a74 100644 --- a/crates/hir_ty/src/infer.rs +++ b/crates/hir_ty/src/infer.rs | |||
@@ -137,8 +137,12 @@ pub struct InferenceResult { | |||
137 | assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>, | 137 | assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>, |
138 | diagnostics: Vec<InferenceDiagnostic>, | 138 | diagnostics: Vec<InferenceDiagnostic>, |
139 | pub type_of_expr: ArenaMap<ExprId, Ty>, | 139 | pub type_of_expr: ArenaMap<ExprId, Ty>, |
140 | /// For each pattern record the type it resolves to. | ||
141 | /// | ||
142 | /// **Note**: When a pattern type is resolved it may still contain | ||
143 | /// unresolved or missing subpatterns or subpatterns of mismatched types. | ||
140 | pub type_of_pat: ArenaMap<PatId, Ty>, | 144 | pub type_of_pat: ArenaMap<PatId, Ty>, |
141 | pub(super) type_mismatches: ArenaMap<ExprId, TypeMismatch>, | 145 | type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>, |
142 | /// Interned Unknown to return references to. | 146 | /// Interned Unknown to return references to. |
143 | standard_types: InternedStandardTypes, | 147 | standard_types: InternedStandardTypes, |
144 | } | 148 | } |
@@ -163,7 +167,22 @@ impl InferenceResult { | |||
163 | self.assoc_resolutions.get(&id.into()).copied() | 167 | self.assoc_resolutions.get(&id.into()).copied() |
164 | } | 168 | } |
165 | pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> { | 169 | pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> { |
166 | self.type_mismatches.get(expr) | 170 | self.type_mismatches.get(&expr.into()) |
171 | } | ||
172 | pub fn type_mismatch_for_pat(&self, pat: PatId) -> Option<&TypeMismatch> { | ||
173 | self.type_mismatches.get(&pat.into()) | ||
174 | } | ||
175 | pub fn expr_type_mismatches(&self) -> impl Iterator<Item = (ExprId, &TypeMismatch)> { | ||
176 | self.type_mismatches.iter().filter_map(|(expr_or_pat, mismatch)| match *expr_or_pat { | ||
177 | ExprOrPatId::ExprId(expr) => Some((expr, mismatch)), | ||
178 | _ => None, | ||
179 | }) | ||
180 | } | ||
181 | pub fn pat_type_mismatches(&self) -> impl Iterator<Item = (PatId, &TypeMismatch)> { | ||
182 | self.type_mismatches.iter().filter_map(|(expr_or_pat, mismatch)| match *expr_or_pat { | ||
183 | ExprOrPatId::PatId(pat) => Some((pat, mismatch)), | ||
184 | _ => None, | ||
185 | }) | ||
167 | } | 186 | } |
168 | pub fn add_diagnostics( | 187 | pub fn add_diagnostics( |
169 | &self, | 188 | &self, |
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs index b6b5a1b75..7278faeec 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs | |||
@@ -42,7 +42,7 @@ impl<'a> InferenceContext<'a> { | |||
42 | let could_unify = self.unify(&ty, &expected.ty); | 42 | let could_unify = self.unify(&ty, &expected.ty); |
43 | if !could_unify { | 43 | if !could_unify { |
44 | self.result.type_mismatches.insert( | 44 | self.result.type_mismatches.insert( |
45 | tgt_expr, | 45 | tgt_expr.into(), |
46 | TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() }, | 46 | TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() }, |
47 | ); | 47 | ); |
48 | } | 48 | } |
@@ -54,9 +54,10 @@ impl<'a> InferenceContext<'a> { | |||
54 | pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty { | 54 | pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty { |
55 | let ty = self.infer_expr_inner(expr, &expected); | 55 | let ty = self.infer_expr_inner(expr, &expected); |
56 | let ty = if !self.coerce(&ty, &expected.coercion_target()) { | 56 | let ty = if !self.coerce(&ty, &expected.coercion_target()) { |
57 | self.result | 57 | self.result.type_mismatches.insert( |
58 | .type_mismatches | 58 | expr.into(), |
59 | .insert(expr, TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() }); | 59 | TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() }, |
60 | ); | ||
60 | // Return actual type when type mismatch. | 61 | // Return actual type when type mismatch. |
61 | // This is needed for diagnostic when return type mismatch. | 62 | // This is needed for diagnostic when return type mismatch. |
62 | ty | 63 | ty |
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs index 60b94a642..b15f4977d 100644 --- a/crates/hir_ty/src/infer/pat.rs +++ b/crates/hir_ty/src/infer/pat.rs | |||
@@ -10,7 +10,7 @@ use hir_def::{ | |||
10 | }; | 10 | }; |
11 | use hir_expand::name::Name; | 11 | use hir_expand::name::Name; |
12 | 12 | ||
13 | use super::{BindingMode, Expectation, InferenceContext}; | 13 | use super::{BindingMode, Expectation, InferenceContext, TypeMismatch}; |
14 | use crate::{ | 14 | use crate::{ |
15 | lower::lower_to_chalk_mutability, static_lifetime, Interner, Substitution, Ty, TyBuilder, | 15 | lower::lower_to_chalk_mutability, static_lifetime, Interner, Substitution, Ty, TyBuilder, |
16 | TyExt, TyKind, | 16 | TyExt, TyKind, |
@@ -266,7 +266,10 @@ impl<'a> InferenceContext<'a> { | |||
266 | // use a new type variable if we got error type here | 266 | // use a new type variable if we got error type here |
267 | let ty = self.insert_type_vars_shallow(ty); | 267 | let ty = self.insert_type_vars_shallow(ty); |
268 | if !self.unify(&ty, expected) { | 268 | if !self.unify(&ty, expected) { |
269 | // FIXME record mismatch, we need to change the type of self.type_mismatches for that | 269 | self.result.type_mismatches.insert( |
270 | pat.into(), | ||
271 | TypeMismatch { expected: expected.clone(), actual: ty.clone() }, | ||
272 | ); | ||
270 | } | 273 | } |
271 | let ty = self.resolve_ty_as_possible(ty); | 274 | let ty = self.resolve_ty_as_possible(ty); |
272 | self.write_pat_ty(pat, ty.clone()); | 275 | self.write_pat_ty(pat, ty.clone()); |
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs index ccfb88c52..cc819373c 100644 --- a/crates/hir_ty/src/tests.rs +++ b/crates/hir_ty/src/tests.rs | |||
@@ -130,7 +130,10 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { | |||
130 | } | 130 | } |
131 | Err(SyntheticSyntax) => continue, | 131 | Err(SyntheticSyntax) => continue, |
132 | }; | 132 | }; |
133 | types.push((syntax_ptr, ty)); | 133 | types.push((syntax_ptr.clone(), ty)); |
134 | if let Some(mismatch) = inference_result.type_mismatch_for_pat(pat) { | ||
135 | mismatches.push((syntax_ptr, mismatch)); | ||
136 | } | ||
134 | } | 137 | } |
135 | 138 | ||
136 | for (expr, ty) in inference_result.type_of_expr.iter() { | 139 | for (expr, ty) in inference_result.type_of_expr.iter() { |
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs index 787647e9f..ddbadbe40 100644 --- a/crates/hir_ty/src/tests/patterns.rs +++ b/crates/hir_ty/src/tests/patterns.rs | |||
@@ -546,7 +546,9 @@ fn infer_const_pattern() { | |||
546 | 273..276 'Bar': usize | 546 | 273..276 'Bar': usize |
547 | 280..283 'Bar': usize | 547 | 280..283 'Bar': usize |
548 | 200..223: expected (), got Foo | 548 | 200..223: expected (), got Foo |
549 | 211..214: expected (), got Foo | ||
549 | 262..285: expected (), got usize | 550 | 262..285: expected (), got usize |
551 | 273..276: expected (), got usize | ||
550 | "#]], | 552 | "#]], |
551 | ); | 553 | ); |
552 | } | 554 | } |
@@ -703,7 +705,7 @@ fn box_pattern() { | |||
703 | 705 | ||
704 | #[test] | 706 | #[test] |
705 | fn tuple_ellipsis_pattern() { | 707 | fn tuple_ellipsis_pattern() { |
706 | check_infer( | 708 | check_infer_with_mismatches( |
707 | r#" | 709 | r#" |
708 | fn foo(tuple: (u8, i16, f32)) { | 710 | fn foo(tuple: (u8, i16, f32)) { |
709 | match tuple { | 711 | match tuple { |
@@ -744,6 +746,8 @@ fn foo(tuple: (u8, i16, f32)) { | |||
744 | 186..200 '{/*too long*/}': () | 746 | 186..200 '{/*too long*/}': () |
745 | 209..210 '_': (u8, i16, f32) | 747 | 209..210 '_': (u8, i16, f32) |
746 | 214..216 '{}': () | 748 | 214..216 '{}': () |
749 | 136..142: expected (u8, i16, f32), got (u8, i16) | ||
750 | 170..182: expected (u8, i16, f32), got (u8, i16, f32, _) | ||
747 | "#]], | 751 | "#]], |
748 | ); | 752 | ); |
749 | } | 753 | } |
@@ -851,3 +855,55 @@ fn f(e: Enum) { | |||
851 | "#, | 855 | "#, |
852 | ) | 856 | ) |
853 | } | 857 | } |
858 | |||
859 | #[test] | ||
860 | fn type_mismatch_in_or_pattern() { | ||
861 | check_infer_with_mismatches( | ||
862 | r#" | ||
863 | fn main() { | ||
864 | match (false,) { | ||
865 | (true | (),) => {} | ||
866 | (() | true,) => {} | ||
867 | (_ | (),) => {} | ||
868 | (() | _,) => {} | ||
869 | } | ||
870 | } | ||
871 | "#, | ||
872 | expect![[r#" | ||
873 | 10..142 '{ ... } }': () | ||
874 | 16..140 'match ... }': () | ||
875 | 22..30 '(false,)': (bool,) | ||
876 | 23..28 'false': bool | ||
877 | 41..53 '(true | (),)': (bool,) | ||
878 | 42..46 'true': bool | ||
879 | 42..46 'true': bool | ||
880 | 42..51 'true | ()': bool | ||
881 | 49..51 '()': () | ||
882 | 57..59 '{}': () | ||
883 | 68..80 '(() | true,)': ((),) | ||
884 | 69..71 '()': () | ||
885 | 69..78 '() | true': () | ||
886 | 74..78 'true': bool | ||
887 | 74..78 'true': bool | ||
888 | 84..86 '{}': () | ||
889 | 95..104 '(_ | (),)': (bool,) | ||
890 | 96..97 '_': bool | ||
891 | 96..102 '_ | ()': bool | ||
892 | 100..102 '()': () | ||
893 | 108..110 '{}': () | ||
894 | 119..128 '(() | _,)': ((),) | ||
895 | 120..122 '()': () | ||
896 | 120..126 '() | _': () | ||
897 | 125..126 '_': bool | ||
898 | 132..134 '{}': () | ||
899 | 49..51: expected bool, got () | ||
900 | 68..80: expected (bool,), got ((),) | ||
901 | 69..71: expected bool, got () | ||
902 | 69..78: expected bool, got () | ||
903 | 100..102: expected bool, got () | ||
904 | 119..128: expected (bool,), got ((),) | ||
905 | 120..122: expected bool, got () | ||
906 | 120..126: expected bool, got () | ||
907 | "#]], | ||
908 | ); | ||
909 | } | ||
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs index 2bf953305..01fe3a1a1 100644 --- a/crates/ide/src/references/rename.rs +++ b/crates/ide/src/references/rename.rs | |||
@@ -55,12 +55,14 @@ pub(crate) fn prepare_rename( | |||
55 | match def { | 55 | match def { |
56 | Definition::SelfType(_) => bail!("Cannot rename `Self`"), | 56 | Definition::SelfType(_) => bail!("Cannot rename `Self`"), |
57 | Definition::ModuleDef(ModuleDef::BuiltinType(_)) => bail!("Cannot rename builtin type"), | 57 | Definition::ModuleDef(ModuleDef::BuiltinType(_)) => bail!("Cannot rename builtin type"), |
58 | _ => {} | 58 | Definition::ModuleDef(ModuleDef::Module(_)) => (), |
59 | _ => { | ||
60 | let nav = def | ||
61 | .try_to_nav(sema.db) | ||
62 | .ok_or_else(|| format_err!("No references found at position"))?; | ||
63 | nav.focus_range.ok_or_else(|| format_err!("No identifier available to rename"))?; | ||
64 | } | ||
59 | }; | 65 | }; |
60 | let nav = | ||
61 | def.try_to_nav(sema.db).ok_or_else(|| format_err!("No references found at position"))?; | ||
62 | nav.focus_range.ok_or_else(|| format_err!("No identifier available to rename"))?; | ||
63 | |||
64 | let name_like = sema | 66 | let name_like = sema |
65 | .find_node_at_offset_with_descend(&syntax, position.offset) | 67 | .find_node_at_offset_with_descend(&syntax, position.offset) |
66 | .ok_or_else(|| format_err!("No references found at position"))?; | 68 | .ok_or_else(|| format_err!("No references found at position"))?; |
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs index 3c87782f2..b2317618a 100644 --- a/crates/rust-analyzer/src/caps.rs +++ b/crates/rust-analyzer/src/caps.rs | |||
@@ -122,6 +122,7 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti | |||
122 | "runnables": { | 122 | "runnables": { |
123 | "kinds": [ "cargo" ], | 123 | "kinds": [ "cargo" ], |
124 | }, | 124 | }, |
125 | "workspaceSymbolScopeKindFiltering": true, | ||
125 | })), | 126 | })), |
126 | } | 127 | } |
127 | } | 128 | } |