aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_def/src/intern.rs8
-rw-r--r--crates/hir_def/src/nameres/collector.rs180
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs22
-rw-r--r--crates/hir_ty/src/diagnostics/match_check.rs12
-rw-r--r--crates/hir_ty/src/infer.rs23
-rw-r--r--crates/hir_ty/src/infer/expr.rs9
-rw-r--r--crates/hir_ty/src/infer/pat.rs7
-rw-r--r--crates/hir_ty/src/tests.rs5
-rw-r--r--crates/hir_ty/src/tests/patterns.rs58
-rw-r--r--crates/ide/src/references/rename.rs12
-rw-r--r--crates/rust-analyzer/src/caps.rs1
-rw-r--r--docs/dev/lsp-extensions.md28
12 files changed, 307 insertions, 58 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
5use std::{ 5use 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
174impl<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
174pub struct InternStorage<T: ?Sized> { 180pub 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
22use crate::{ 22use 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 {
217enum MacroDirectiveKind { 219enum 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
222struct DefData<'a> { 225struct 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
248impl DefCollector<'_> { 252impl 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
500fn 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)]
500mod tests { 516mod 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#"
1134fn 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};
11use hir_expand::name::Name; 11use hir_expand::name::Name;
12 12
13use super::{BindingMode, Expectation, InferenceContext}; 13use super::{BindingMode, Expectation, InferenceContext, TypeMismatch};
14use crate::{ 14use 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]
705fn tuple_ellipsis_pattern() { 707fn tuple_ellipsis_pattern() {
706 check_infer( 708 check_infer_with_mismatches(
707 r#" 709 r#"
708fn foo(tuple: (u8, i16, f32)) { 710fn 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]
860fn type_mismatch_in_or_pattern() {
861 check_infer_with_mismatches(
862 r#"
863fn 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}
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index 2d3787d0f..3c4eacfeb 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -651,32 +651,36 @@ export const enum Direction {
651} 651}
652``` 652```
653 653
654## Lookup workspace symbol search scope and kind 654## Workspace Symbols Filtering
655 655
656**Issue:** https://github.com/rust-analyzer/rust-analyzer/pull/7698 656**Issue:** https://github.com/rust-analyzer/rust-analyzer/pull/7698
657 657
658This request is sent from client to server to search for workspace symbols filtered by an 658**Experimental Server Capability:** `{ "workspaceSymbolScopeKindFiltering": boolean }`
659optional search scope and / or an optional symbol kind.
660 659
661**Method:** `workspace/symbol` 660Extends the existing `workspace/symbol` request with ability to filter symbols by broad scope and kind of symbol.
661If this capability is set, `workspace/symbol` parameter gains two new optional fields:
662 662
663**Request:** `WorkspaceSymbolParams`
664
665**Response:** `SymbolInformation[] | null`
666 663
667```typescript 664```typescript
668interface lsp_ext.WorkspaceSymbolParams extends WorkspaceSymbolParams { 665interface WorkspaceSymbolParams {
666 /**
667 * Return only the symbols defined in the specified scope.
668 */
669 searchScope?: WorkspaceSymbolSearchScope; 669 searchScope?: WorkspaceSymbolSearchScope;
670 /**
671 * Return only the symbols of specified kinds.
672 */
670 searchKind?: WorkspaceSymbolSearchKind; 673 searchKind?: WorkspaceSymbolSearchKind;
674 ...
671} 675}
672 676
673const enum WorkspaceSymbolSearchScope { 677const enum WorkspaceSymbolSearchScope {
674 Workspace = "Workspace", 678 Workspace = "workspace",
675 WorkspaceAndDependencies = "WorkspaceAndDependencies" 679 WorkspaceAndDependencies = "workspaceAndDependencies"
676} 680}
677 681
678const enum WorkspaceSymbolSearchKind { 682const enum WorkspaceSymbolSearchKind {
679 OnlyTypes = "OnlyTypes", 683 OnlyTypes = "onlyTypes",
680 AllSymbols = "AllSymbols" 684 AllSymbols = "allSymbols"
681} 685}
682``` 686```