aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/hir_def/src/data.rs17
-rw-r--r--crates/hir_def/src/item_tree/lower.rs11
-rw-r--r--crates/hir_def/src/item_tree/tests.rs38
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs23
-rw-r--r--crates/hir_ty/src/diagnostics/match_check.rs28
-rw-r--r--crates/hir_ty/src/diagnostics/match_check/usefulness.rs5
-rw-r--r--crates/hir_ty/src/infer.rs2
-rw-r--r--crates/hir_ty/src/infer/pat.rs11
-rw-r--r--crates/hir_ty/src/method_resolution.rs16
-rw-r--r--crates/hir_ty/src/tests/method_resolution.rs49
-rw-r--r--crates/hir_ty/src/tests/patterns.rs47
-rw-r--r--crates/ide/src/expand_macro.rs6
-rw-r--r--crates/ide_assists/src/handlers/extract_type_alias.rs68
-rw-r--r--crates/ide_completion/src/context.rs2
-rw-r--r--crates/mbe/src/benchmark.rs2
-rw-r--r--crates/mbe/src/expander/matcher.rs21
-rw-r--r--crates/mbe/src/lib.rs10
-rw-r--r--crates/mbe/src/parser.rs2
-rw-r--r--crates/mbe/src/syntax_bridge.rs5
-rw-r--r--crates/mbe/src/tt_iter.rs2
-rw-r--r--crates/parser/src/grammar/expressions/atom.rs8
-rw-r--r--crates/proc_macro_api/src/msg.rs2
-rw-r--r--crates/rust-analyzer/src/config.rs1
-rw-r--r--crates/rust-analyzer/src/handlers.rs2
-rw-r--r--crates/syntax/src/parsing/reparsing.rs8
-rw-r--r--crates/syntax/src/tests.rs2
-rw-r--r--crates/test_utils/src/lib.rs11
27 files changed, 297 insertions, 102 deletions
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs
index d2bb381be..52cb7777b 100644
--- a/crates/hir_def/src/data.rs
+++ b/crates/hir_def/src/data.rs
@@ -143,6 +143,10 @@ pub struct TraitData {
143 pub is_auto: bool, 143 pub is_auto: bool,
144 pub is_unsafe: bool, 144 pub is_unsafe: bool,
145 pub visibility: RawVisibility, 145 pub visibility: RawVisibility,
146 /// Whether the trait has `#[rust_skip_array_during_method_dispatch]`. `hir_ty` will ignore
147 /// method calls to this trait's methods when the receiver is an array and the crate edition is
148 /// 2015 or 2018.
149 pub skip_array_during_method_dispatch: bool,
146} 150}
147 151
148impl TraitData { 152impl TraitData {
@@ -157,6 +161,10 @@ impl TraitData {
157 let container = AssocContainerId::TraitId(tr); 161 let container = AssocContainerId::TraitId(tr);
158 let visibility = item_tree[tr_def.visibility].clone(); 162 let visibility = item_tree[tr_def.visibility].clone();
159 let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id); 163 let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id);
164 let skip_array_during_method_dispatch = item_tree
165 .attrs(db, tr_loc.container.krate(), ModItem::from(tr_loc.id.value).into())
166 .by_key("rustc_skip_array_during_method_dispatch")
167 .exists();
160 168
161 let items = collect_items( 169 let items = collect_items(
162 db, 170 db,
@@ -168,7 +176,14 @@ impl TraitData {
168 100, 176 100,
169 ); 177 );
170 178
171 Arc::new(TraitData { name, items, is_auto, is_unsafe, visibility }) 179 Arc::new(TraitData {
180 name,
181 items,
182 is_auto,
183 is_unsafe,
184 visibility,
185 skip_array_during_method_dispatch,
186 })
172 } 187 }
173 188
174 pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ { 189 pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 6208facd5..cfda7cb32 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -130,7 +130,7 @@ impl<'a> Ctx<'a> {
130 ast::Item::ExternBlock(ast) => self.lower_extern_block(ast).into(), 130 ast::Item::ExternBlock(ast) => self.lower_extern_block(ast).into(),
131 }; 131 };
132 132
133 self.add_attrs(item.into(), attrs.clone()); 133 self.add_attrs(item.into(), attrs);
134 134
135 Some(item) 135 Some(item)
136 } 136 }
@@ -276,10 +276,11 @@ impl<'a> Ctx<'a> {
276 let visibility = self.lower_visibility(enum_); 276 let visibility = self.lower_visibility(enum_);
277 let name = enum_.name()?.as_name(); 277 let name = enum_.name()?.as_name();
278 let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_); 278 let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_);
279 let variants = match &enum_.variant_list() { 279 let variants =
280 Some(variant_list) => self.lower_variants(variant_list), 280 self.with_inherited_visibility(visibility, |this| match &enum_.variant_list() {
281 None => IdRange::new(self.next_variant_idx()..self.next_variant_idx()), 281 Some(variant_list) => this.lower_variants(variant_list),
282 }; 282 None => IdRange::new(this.next_variant_idx()..this.next_variant_idx()),
283 });
283 let ast_id = self.source_ast_id_map.ast_id(enum_); 284 let ast_id = self.source_ast_id_map.ast_id(enum_);
284 let res = Enum { name, visibility, generic_params, variants, ast_id }; 285 let res = Enum { name, visibility, generic_params, variants, ast_id };
285 Some(id(self.data().enums.alloc(res))) 286 Some(id(self.data().enums.alloc(res)))
diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs
index b362add5c..57686dc6e 100644
--- a/crates/hir_def/src/item_tree/tests.rs
+++ b/crates/hir_def/src/item_tree/tests.rs
@@ -359,3 +359,41 @@ trait Tr<'a, T: 'a>: Super {}
359 "#]], 359 "#]],
360 ) 360 )
361} 361}
362
363#[test]
364fn inherit_visibility() {
365 check(
366 r#"
367pub(crate) enum En {
368 Var1(u8),
369 Var2 {
370 fld: u8,
371 },
372}
373
374pub(crate) trait Tr {
375 fn f();
376 fn method(&self) {}
377}
378 "#,
379 expect![[r#"
380 pub(crate) enum En {
381 Var1(
382 pub(crate) 0: u8,
383 ),
384 Var2 {
385 pub(crate) fld: u8,
386 },
387 }
388
389 pub(crate) trait Tr<Self> {
390 pub(crate) fn f() -> ();
391
392 // flags = 0x3
393 pub(crate) fn method(
394 _: &Self,
395 ) -> ();
396 }
397 "#]],
398 )
399}
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs
index 3efbce773..a2a4d61db 100644
--- a/crates/hir_ty/src/diagnostics/expr.rs
+++ b/crates/hir_ty/src/diagnostics/expr.rs
@@ -357,17 +357,20 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
357 infer: &infer, 357 infer: &infer,
358 db, 358 db,
359 pattern_arena: &pattern_arena, 359 pattern_arena: &pattern_arena,
360 eprint_panic_context: &|| { 360 panic_context: &|| {
361 use syntax::AstNode; 361 use syntax::AstNode;
362 if let Ok(scrutinee_sptr) = source_map.expr_syntax(match_expr) { 362 let match_expr_text = source_map
363 let root = scrutinee_sptr.file_syntax(db.upcast()); 363 .expr_syntax(match_expr)
364 if let Some(match_ast) = scrutinee_sptr.value.to_node(&root).syntax().parent() { 364 .ok()
365 eprintln!( 365 .and_then(|scrutinee_sptr| {
366 "Match checking is about to panic on this expression:\n{}", 366 let root = scrutinee_sptr.file_syntax(db.upcast());
367 match_ast.to_string(), 367 scrutinee_sptr.value.to_node(&root).syntax().parent()
368 ); 368 })
369 } 369 .map(|node| node.to_string());
370 } 370 format!(
371 "expression:\n{}",
372 match_expr_text.as_deref().unwrap_or("<synthesized expr>")
373 )
371 }, 374 },
372 }; 375 };
373 let report = compute_match_usefulness(&cx, &m_arms); 376 let report = compute_match_usefulness(&cx, &m_arms);
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs
index a9a99f57a..c8e1b23de 100644
--- a/crates/hir_ty/src/diagnostics/match_check.rs
+++ b/crates/hir_ty/src/diagnostics/match_check.rs
@@ -100,10 +100,19 @@ impl<'a> PatCtxt<'a> {
100 } 100 }
101 101
102 pub(crate) fn lower_pattern(&mut self, pat: hir_def::expr::PatId) -> Pat { 102 pub(crate) fn lower_pattern(&mut self, pat: hir_def::expr::PatId) -> Pat {
103 // FIXME: implement pattern adjustments (implicit pattern dereference; "RFC 2005-match-ergonomics") 103 // XXX(iDawer): Collecting pattern adjustments feels imprecise to me.
104 // When lowering of & and box patterns are implemented this should be tested
105 // in a manner of `match_ergonomics_issue_9095` test.
106 // Pattern adjustment is part of RFC 2005-match-ergonomics.
104 // More info https://github.com/rust-lang/rust/issues/42640#issuecomment-313535089 107 // More info https://github.com/rust-lang/rust/issues/42640#issuecomment-313535089
105 let unadjusted_pat = self.lower_pattern_unadjusted(pat); 108 let unadjusted_pat = self.lower_pattern_unadjusted(pat);
106 unadjusted_pat 109 self.infer.pat_adjustments.get(&pat).map(|it| &**it).unwrap_or_default().iter().rev().fold(
110 unadjusted_pat,
111 |subpattern, ref_ty| Pat {
112 ty: ref_ty.clone(),
113 kind: Box::new(PatKind::Deref { subpattern }),
114 },
115 )
107 } 116 }
108 117
109 fn lower_pattern_unadjusted(&mut self, pat: hir_def::expr::PatId) -> Pat { 118 fn lower_pattern_unadjusted(&mut self, pat: hir_def::expr::PatId) -> Pat {
@@ -1236,6 +1245,21 @@ fn main(f: Foo) {
1236 ); 1245 );
1237 } 1246 }
1238 1247
1248 #[test]
1249 fn match_ergonomics_issue_9095() {
1250 check_diagnostics(
1251 r#"
1252enum Foo<T> { A(T) }
1253fn main() {
1254 match &Foo::A(true) {
1255 _ => {}
1256 Foo::A(_) => {}
1257 }
1258}
1259"#,
1260 );
1261 }
1262
1239 mod false_negatives { 1263 mod false_negatives {
1240 //! The implementation of match checking here is a work in progress. As we roll this out, we 1264 //! The implementation of match checking here is a work in progress. As we roll this out, we
1241 //! prefer false negatives to false positives (ideally there would be no false positives). This 1265 //! prefer false negatives to false positives (ideally there would be no false positives). This
diff --git a/crates/hir_ty/src/diagnostics/match_check/usefulness.rs b/crates/hir_ty/src/diagnostics/match_check/usefulness.rs
index 83b094a89..bd76a606c 100644
--- a/crates/hir_ty/src/diagnostics/match_check/usefulness.rs
+++ b/crates/hir_ty/src/diagnostics/match_check/usefulness.rs
@@ -295,7 +295,7 @@ pub(crate) struct MatchCheckCtx<'a> {
295 pub(crate) db: &'a dyn HirDatabase, 295 pub(crate) db: &'a dyn HirDatabase,
296 /// Lowered patterns from arms plus generated by the check. 296 /// Lowered patterns from arms plus generated by the check.
297 pub(crate) pattern_arena: &'a RefCell<PatternArena>, 297 pub(crate) pattern_arena: &'a RefCell<PatternArena>,
298 pub(crate) eprint_panic_context: &'a dyn Fn(), 298 pub(crate) panic_context: &'a dyn Fn() -> String,
299} 299}
300 300
301impl<'a> MatchCheckCtx<'a> { 301impl<'a> MatchCheckCtx<'a> {
@@ -331,8 +331,7 @@ impl<'a> MatchCheckCtx<'a> {
331 331
332 #[track_caller] 332 #[track_caller]
333 pub(super) fn bug(&self, info: &str) -> ! { 333 pub(super) fn bug(&self, info: &str) -> ! {
334 (self.eprint_panic_context)(); 334 panic!("bug: {}\n{}", info, (self.panic_context)());
335 panic!("bug: {}", info);
336 } 335 }
337} 336}
338 337
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index 7a4268819..0e9f777da 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -150,6 +150,8 @@ pub struct InferenceResult {
150 type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>, 150 type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
151 /// Interned Unknown to return references to. 151 /// Interned Unknown to return references to.
152 standard_types: InternedStandardTypes, 152 standard_types: InternedStandardTypes,
153 /// Stores the types which were implicitly dereferenced in pattern binding modes.
154 pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
153} 155}
154 156
155impl InferenceResult { 157impl InferenceResult {
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs
index 83e0a7a9e..25dff7e49 100644
--- a/crates/hir_ty/src/infer/pat.rs
+++ b/crates/hir_ty/src/infer/pat.rs
@@ -101,7 +101,9 @@ impl<'a> InferenceContext<'a> {
101 let mut expected = self.resolve_ty_shallow(expected); 101 let mut expected = self.resolve_ty_shallow(expected);
102 102
103 if is_non_ref_pat(&body, pat) { 103 if is_non_ref_pat(&body, pat) {
104 let mut pat_adjustments = Vec::new();
104 while let Some((inner, _lifetime, mutability)) = expected.as_reference() { 105 while let Some((inner, _lifetime, mutability)) = expected.as_reference() {
106 pat_adjustments.push(expected.clone());
105 expected = self.resolve_ty_shallow(inner); 107 expected = self.resolve_ty_shallow(inner);
106 default_bm = match default_bm { 108 default_bm = match default_bm {
107 BindingMode::Move => BindingMode::Ref(mutability), 109 BindingMode::Move => BindingMode::Ref(mutability),
@@ -109,6 +111,11 @@ impl<'a> InferenceContext<'a> {
109 BindingMode::Ref(Mutability::Mut) => BindingMode::Ref(mutability), 111 BindingMode::Ref(Mutability::Mut) => BindingMode::Ref(mutability),
110 } 112 }
111 } 113 }
114
115 if !pat_adjustments.is_empty() {
116 pat_adjustments.shrink_to_fit();
117 self.result.pat_adjustments.insert(pat, pat_adjustments);
118 }
112 } else if let Pat::Ref { .. } = &body[pat] { 119 } else if let Pat::Ref { .. } = &body[pat] {
113 cov_mark::hit!(match_ergonomics_ref); 120 cov_mark::hit!(match_ergonomics_ref);
114 // When you encounter a `&pat` pattern, reset to Move. 121 // When you encounter a `&pat` pattern, reset to Move.
@@ -290,6 +297,10 @@ fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool {
290 Expr::Literal(Literal::String(..)) => false, 297 Expr::Literal(Literal::String(..)) => false,
291 _ => true, 298 _ => true,
292 }, 299 },
300 Pat::Bind { mode: BindingAnnotation::Mutable, subpat: Some(subpat), .. }
301 | Pat::Bind { mode: BindingAnnotation::Unannotated, subpat: Some(subpat), .. } => {
302 is_non_ref_pat(body, *subpat)
303 }
293 Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => false, 304 Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => false,
294 } 305 }
295} 306}
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index af6b6cda7..a23527f7d 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -5,7 +5,7 @@
5use std::{iter, sync::Arc}; 5use std::{iter, sync::Arc};
6 6
7use arrayvec::ArrayVec; 7use arrayvec::ArrayVec;
8use base_db::CrateId; 8use base_db::{CrateId, Edition};
9use chalk_ir::{cast::Cast, Mutability, UniverseIndex}; 9use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
10use hir_def::{ 10use hir_def::{
11 lang_item::LangItemTarget, nameres::DefMap, AssocContainerId, AssocItemId, FunctionId, 11 lang_item::LangItemTarget, nameres::DefMap, AssocContainerId, AssocItemId, FunctionId,
@@ -639,6 +639,7 @@ fn iterate_trait_method_candidates(
639 receiver_ty: Option<&Canonical<Ty>>, 639 receiver_ty: Option<&Canonical<Ty>>,
640 callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, 640 callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool,
641) -> bool { 641) -> bool {
642 let receiver_is_array = matches!(self_ty.value.kind(&Interner), chalk_ir::TyKind::Array(..));
642 // if ty is `dyn Trait`, the trait doesn't need to be in scope 643 // if ty is `dyn Trait`, the trait doesn't need to be in scope
643 let inherent_trait = 644 let inherent_trait =
644 self_ty.value.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t)); 645 self_ty.value.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t));
@@ -655,6 +656,19 @@ fn iterate_trait_method_candidates(
655 'traits: for t in traits { 656 'traits: for t in traits {
656 let data = db.trait_data(t); 657 let data = db.trait_data(t);
657 658
659 // Traits annotated with `#[rustc_skip_array_during_method_dispatch]` are skipped during
660 // method resolution, if the receiver is an array, and we're compiling for editions before
661 // 2021.
662 // This is to make `[a].into_iter()` not break code with the new `IntoIterator` impl for
663 // arrays.
664 if data.skip_array_during_method_dispatch && receiver_is_array {
665 // FIXME: this should really be using the edition of the method name's span, in case it
666 // comes from a macro
667 if db.crate_graph()[krate].edition < Edition::Edition2021 {
668 continue;
669 }
670 }
671
658 // we'll be lazy about checking whether the type implements the 672 // we'll be lazy about checking whether the type implements the
659 // trait, but if we find out it doesn't, we'll skip the rest of the 673 // trait, but if we find out it doesn't, we'll skip the rest of the
660 // iteration 674 // iteration
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs
index 058eb9129..f26b2c8a7 100644
--- a/crates/hir_ty/src/tests/method_resolution.rs
+++ b/crates/hir_ty/src/tests/method_resolution.rs
@@ -1349,3 +1349,52 @@ fn f() {
1349 "#, 1349 "#,
1350 ); 1350 );
1351} 1351}
1352
1353#[test]
1354fn skip_array_during_method_dispatch() {
1355 check_types(
1356 r#"
1357//- /main2018.rs crate:main2018 deps:core
1358use core::IntoIterator;
1359
1360fn f() {
1361 let v = [4].into_iter();
1362 v;
1363 //^ &i32
1364
1365 let a = [0, 1].into_iter();
1366 a;
1367 //^ &i32
1368}
1369
1370//- /main2021.rs crate:main2021 deps:core edition:2021
1371use core::IntoIterator;
1372
1373fn f() {
1374 let v = [4].into_iter();
1375 v;
1376 //^ i32
1377
1378 let a = [0, 1].into_iter();
1379 a;
1380 //^ &i32
1381}
1382
1383//- /core.rs crate:core
1384#[rustc_skip_array_during_method_dispatch]
1385pub trait IntoIterator {
1386 type Out;
1387 fn into_iter(self) -> Self::Out;
1388}
1389
1390impl<T> IntoIterator for [T; 1] {
1391 type Out = T;
1392 fn into_iter(self) -> Self::Out {}
1393}
1394impl<'a, T> IntoIterator for &'a [T] {
1395 type Out = &'a T;
1396 fn into_iter(self) -> Self::Out {}
1397}
1398 "#,
1399 );
1400}
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs
index cd08b5c7a..7d00cee9b 100644
--- a/crates/hir_ty/src/tests/patterns.rs
+++ b/crates/hir_ty/src/tests/patterns.rs
@@ -20,6 +20,8 @@ fn infer_pattern() {
20 let h = val; 20 let h = val;
21 } 21 }
22 22
23 if let x @ true = &true {}
24
23 let lambda = |a: u64, b, c: i32| { a + b; c }; 25 let lambda = |a: u64, b, c: i32| { a + b; c };
24 26
25 let ref ref_to_x = x; 27 let ref ref_to_x = x;
@@ -30,7 +32,7 @@ fn infer_pattern() {
30 "#, 32 "#,
31 expect![[r#" 33 expect![[r#"
32 8..9 'x': &i32 34 8..9 'x': &i32
33 17..368 '{ ...o_x; }': () 35 17..400 '{ ...o_x; }': ()
34 27..28 'y': &i32 36 27..28 'y': &i32
35 31..32 'x': &i32 37 31..32 'x': &i32
36 42..44 '&z': &i32 38 42..44 '&z': &i32
@@ -59,24 +61,31 @@ fn infer_pattern() {
59 176..204 '{ ... }': () 61 176..204 '{ ... }': ()
60 190..191 'h': {unknown} 62 190..191 'h': {unknown}
61 194..197 'val': {unknown} 63 194..197 'val': {unknown}
62 214..220 'lambda': |u64, u64, i32| -> i32 64 210..236 'if let...rue {}': ()
63 223..255 '|a: u6...b; c }': |u64, u64, i32| -> i32 65 217..225 'x @ true': &bool
64 224..225 'a': u64 66 221..225 'true': bool
65 232..233 'b': u64 67 221..225 'true': bool
66 235..236 'c': i32 68 228..233 '&true': &bool
67 243..255 '{ a + b; c }': i32 69 229..233 'true': bool
68 245..246 'a': u64 70 234..236 '{}': ()
69 245..250 'a + b': u64 71 246..252 'lambda': |u64, u64, i32| -> i32
70 249..250 'b': u64 72 255..287 '|a: u6...b; c }': |u64, u64, i32| -> i32
71 252..253 'c': i32 73 256..257 'a': u64
72 266..278 'ref ref_to_x': &&i32 74 264..265 'b': u64
73 281..282 'x': &i32 75 267..268 'c': i32
74 292..301 'mut mut_x': &i32 76 275..287 '{ a + b; c }': i32
75 304..305 'x': &i32 77 277..278 'a': u64
76 315..335 'ref mu...f_to_x': &mut &i32 78 277..282 'a + b': u64
77 338..339 'x': &i32 79 281..282 'b': u64
78 349..350 'k': &mut &i32 80 284..285 'c': i32
79 353..365 'mut_ref_to_x': &mut &i32 81 298..310 'ref ref_to_x': &&i32
82 313..314 'x': &i32
83 324..333 'mut mut_x': &i32
84 336..337 'x': &i32
85 347..367 'ref mu...f_to_x': &mut &i32
86 370..371 'x': &i32
87 381..382 'k': &mut &i32
88 385..397 'mut_ref_to_x': &mut &i32
80 "#]], 89 "#]],
81 ); 90 );
82} 91}
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs
index eebae5ebe..e0d01fa96 100644
--- a/crates/ide/src/expand_macro.rs
+++ b/crates/ide/src/expand_macro.rs
@@ -28,8 +28,8 @@ pub struct ExpandedMacro {
28pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<ExpandedMacro> { 28pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<ExpandedMacro> {
29 let sema = Semantics::new(db); 29 let sema = Semantics::new(db);
30 let file = sema.parse(position.file_id); 30 let file = sema.parse(position.file_id);
31 let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset)?; 31 let mac = find_node_at_offset::<ast::MacroCall>(file.syntax(), position.offset)?;
32 let mac = name_ref.syntax().ancestors().find_map(ast::MacroCall::cast)?; 32 let name = mac.path()?.segment()?.name_ref()?;
33 33
34 let expanded = expand_macro_recur(&sema, &mac)?; 34 let expanded = expand_macro_recur(&sema, &mac)?;
35 35
@@ -37,7 +37,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
37 // macro expansion may lose all white space information 37 // macro expansion may lose all white space information
38 // But we hope someday we can use ra_fmt for that 38 // But we hope someday we can use ra_fmt for that
39 let expansion = insert_whitespaces(expanded); 39 let expansion = insert_whitespaces(expanded);
40 Some(ExpandedMacro { name: name_ref.text().to_string(), expansion }) 40 Some(ExpandedMacro { name: name.to_string(), expansion })
41} 41}
42 42
43fn expand_macro_recur( 43fn expand_macro_recur(
diff --git a/crates/ide_assists/src/handlers/extract_type_alias.rs b/crates/ide_assists/src/handlers/extract_type_alias.rs
index 998e0de7b..eac8857c6 100644
--- a/crates/ide_assists/src/handlers/extract_type_alias.rs
+++ b/crates/ide_assists/src/handlers/extract_type_alias.rs
@@ -1,4 +1,7 @@
1use syntax::ast::{self, AstNode}; 1use syntax::{
2 ast::{self, edit::IndentLevel, AstNode},
3 match_ast,
4};
2 5
3use crate::{AssistContext, AssistId, AssistKind, Assists}; 6use crate::{AssistContext, AssistId, AssistKind, Assists};
4 7
@@ -25,12 +28,15 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext) -> Opti
25 } 28 }
26 29
27 let node = ctx.find_node_at_range::<ast::Type>()?; 30 let node = ctx.find_node_at_range::<ast::Type>()?;
28 let insert = ctx 31 let item = ctx.find_node_at_offset::<ast::Item>()?;
29 .find_node_at_offset::<ast::Impl>() 32 let insert = match_ast! {
30 .map(|imp| imp.syntax().clone()) 33 match (item.syntax().parent()?) {
31 .or_else(|| ctx.find_node_at_offset::<ast::Item>().map(|item| item.syntax().clone()))? 34 ast::AssocItemList(it) => it.syntax().parent()?,
32 .text_range() 35 _ => item.syntax().clone(),
33 .start(); 36 }
37 };
38 let indent = IndentLevel::from_node(&insert);
39 let insert = insert.text_range().start();
34 let target = node.syntax().text_range(); 40 let target = node.syntax().text_range();
35 41
36 acc.add( 42 acc.add(
@@ -42,10 +48,14 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext) -> Opti
42 builder.replace(target, "Type"); 48 builder.replace(target, "Type");
43 match ctx.config.snippet_cap { 49 match ctx.config.snippet_cap {
44 Some(cap) => { 50 Some(cap) => {
45 builder.insert_snippet(cap, insert, format!("type $0Type = {};\n\n", node)); 51 builder.insert_snippet(
52 cap,
53 insert,
54 format!("type $0Type = {};\n\n{}", node, indent),
55 );
46 } 56 }
47 None => { 57 None => {
48 builder.insert(insert, format!("type Type = {};\n\n", node)); 58 builder.insert(insert, format!("type Type = {};\n\n{}", node, indent));
49 } 59 }
50 } 60 }
51 }, 61 },
@@ -153,9 +163,9 @@ struct S {
153 } 163 }
154 164
155 #[test] 165 #[test]
156 fn extract_from_impl() { 166 fn extract_from_impl_or_trait() {
157 // When invoked in an impl, extracted type alias should be placed next to the impl, not 167 // When invoked in an impl/trait, extracted type alias should be placed next to the
158 // inside. 168 // impl/trait, not inside.
159 check_assist( 169 check_assist(
160 extract_type_alias, 170 extract_type_alias,
161 r#" 171 r#"
@@ -171,5 +181,39 @@ impl S {
171} 181}
172 "#, 182 "#,
173 ); 183 );
184 check_assist(
185 extract_type_alias,
186 r#"
187trait Tr {
188 fn f() -> $0(u8, u8)$0 {}
189}
190 "#,
191 r#"
192type $0Type = (u8, u8);
193
194trait Tr {
195 fn f() -> Type {}
196}
197 "#,
198 );
199 }
200
201 #[test]
202 fn indentation() {
203 check_assist(
204 extract_type_alias,
205 r#"
206mod m {
207 fn f() -> $0u8$0 {}
208}
209 "#,
210 r#"
211mod m {
212 type $0Type = u8;
213
214 fn f() -> Type {}
215}
216 "#,
217 );
174 } 218 }
175} 219}
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 6f685c02f..cb4f08e53 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -567,7 +567,7 @@ impl<'a> CompletionContext<'a> {
567 None => return, 567 None => return,
568 }; 568 };
569 569
570 if let Some(segment) = ast::PathSegment::cast(parent.clone()) { 570 if let Some(segment) = ast::PathSegment::cast(parent) {
571 let path = segment.parent_path(); 571 let path = segment.parent_path();
572 self.is_call = path 572 self.is_call = path
573 .syntax() 573 .syntax()
diff --git a/crates/mbe/src/benchmark.rs b/crates/mbe/src/benchmark.rs
index 38707ffa5..18eb97f0d 100644
--- a/crates/mbe/src/benchmark.rs
+++ b/crates/mbe/src/benchmark.rs
@@ -187,7 +187,7 @@ fn invocation_fixtures(rules: &FxHashMap<String, MacroRules>) -> Vec<(String, tt
187 let a = 1664525; 187 let a = 1664525;
188 let c = 1013904223; 188 let c = 1013904223;
189 *seed = usize::wrapping_add(usize::wrapping_mul(*seed, a), c); 189 *seed = usize::wrapping_add(usize::wrapping_mul(*seed, a), c);
190 return *seed; 190 *seed
191 } 191 }
192 fn make_ident(ident: &str) -> tt::TokenTree { 192 fn make_ident(ident: &str) -> tt::TokenTree {
193 tt::Leaf::Ident(tt::Ident { id: tt::TokenId::unspecified(), text: SmolStr::new(ident) }) 193 tt::Leaf::Ident(tt::Ident { id: tt::TokenId::unspecified(), text: SmolStr::new(ident) })
diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs
index 84ca3ff87..c982eb58f 100644
--- a/crates/mbe/src/expander/matcher.rs
+++ b/crates/mbe/src/expander/matcher.rs
@@ -219,7 +219,7 @@ impl BindingsBuilder {
219 bindings 219 bindings
220 } 220 }
221 221
222 fn build_inner(&self, bindings: &mut Bindings, link_nodes: &Vec<LinkNode<Rc<BindingKind>>>) { 222 fn build_inner(&self, bindings: &mut Bindings, link_nodes: &[LinkNode<Rc<BindingKind>>]) {
223 let mut nodes = Vec::new(); 223 let mut nodes = Vec::new();
224 self.collect_nodes(&link_nodes, &mut nodes); 224 self.collect_nodes(&link_nodes, &mut nodes);
225 225
@@ -301,7 +301,7 @@ impl BindingsBuilder {
301 301
302 fn collect_nodes<'a>( 302 fn collect_nodes<'a>(
303 &'a self, 303 &'a self,
304 link_nodes: &'a Vec<LinkNode<Rc<BindingKind>>>, 304 link_nodes: &'a [LinkNode<Rc<BindingKind>>],
305 nodes: &mut Vec<&'a Rc<BindingKind>>, 305 nodes: &mut Vec<&'a Rc<BindingKind>>,
306 ) { 306 ) {
307 link_nodes.iter().for_each(|it| match it { 307 link_nodes.iter().for_each(|it| match it {
@@ -494,15 +494,8 @@ fn match_loop_inner<'t>(
494 } 494 }
495 Some(err) => { 495 Some(err) => {
496 res.add_err(err); 496 res.add_err(err);
497 match match_res.value { 497 if let Some(fragment) = match_res.value {
498 Some(fragment) => { 498 bindings_builder.push_fragment(&mut item.bindings, &name, fragment);
499 bindings_builder.push_fragment(
500 &mut item.bindings,
501 &name,
502 fragment,
503 );
504 }
505 _ => {}
506 } 499 }
507 item.is_error = true; 500 item.is_error = true;
508 error_items.push(item); 501 error_items.push(item);
@@ -578,9 +571,9 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree) -> Match {
578 ); 571 );
579 stdx::always!(cur_items.is_empty()); 572 stdx::always!(cur_items.is_empty());
580 573
581 if error_items.len() > 0 { 574 if !error_items.is_empty() {
582 error_recover_item = error_items.pop().map(|it| it.bindings); 575 error_recover_item = error_items.pop().map(|it| it.bindings);
583 } else if eof_items.len() > 0 { 576 } else if !eof_items.is_empty() {
584 error_recover_item = Some(eof_items[0].bindings.clone()); 577 error_recover_item = Some(eof_items[0].bindings.clone());
585 } 578 }
586 579
@@ -793,7 +786,7 @@ impl<'a> TtIter<'a> {
793 _ => (), 786 _ => (),
794 } 787 }
795 788
796 let tt = self.next().ok_or_else(|| ())?.clone(); 789 let tt = self.next().ok_or(())?.clone();
797 let punct = match tt { 790 let punct = match tt {
798 tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if punct.spacing == tt::Spacing::Joint => { 791 tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if punct.spacing == tt::Spacing::Joint => {
799 punct 792 punct
diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs
index b95374b76..380a50744 100644
--- a/crates/mbe/src/lib.rs
+++ b/crates/mbe/src/lib.rs
@@ -295,8 +295,8 @@ fn validate(pattern: &MetaTemplate) -> Result<(), ParseError> {
295 // Checks that no repetition which could match an empty token 295 // Checks that no repetition which could match an empty token
296 // https://github.com/rust-lang/rust/blob/a58b1ed44f5e06976de2bdc4d7dc81c36a96934f/src/librustc_expand/mbe/macro_rules.rs#L558 296 // https://github.com/rust-lang/rust/blob/a58b1ed44f5e06976de2bdc4d7dc81c36a96934f/src/librustc_expand/mbe/macro_rules.rs#L558
297 297
298 if separator.is_none() { 298 if separator.is_none()
299 if subtree.iter().all(|child_op| { 299 && subtree.iter().all(|child_op| {
300 match child_op { 300 match child_op {
301 Op::Var { kind, .. } => { 301 Op::Var { kind, .. } => {
302 // vis is optional 302 // vis is optional
@@ -314,9 +314,9 @@ fn validate(pattern: &MetaTemplate) -> Result<(), ParseError> {
314 Op::Subtree { .. } => {} 314 Op::Subtree { .. } => {}
315 } 315 }
316 false 316 false
317 }) { 317 })
318 return Err(ParseError::RepetitionEmptyTokenTree); 318 {
319 } 319 return Err(ParseError::RepetitionEmptyTokenTree);
320 } 320 }
321 validate(subtree)? 321 validate(subtree)?
322 } 322 }
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs
index 61b2a4955..04c0d3e75 100644
--- a/crates/mbe/src/parser.rs
+++ b/crates/mbe/src/parser.rs
@@ -213,7 +213,7 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul
213 Ok(res) 213 Ok(res)
214} 214}
215 215
216fn eat_fragment_kind<'a>(src: &mut TtIter<'a>, mode: Mode) -> Result<Option<SmolStr>, ParseError> { 216fn eat_fragment_kind(src: &mut TtIter<'_>, mode: Mode) -> Result<Option<SmolStr>, ParseError> {
217 if let Mode::Pattern = mode { 217 if let Mode::Pattern = mode {
218 src.expect_char(':').map_err(|()| err!("bad fragment specifier 1"))?; 218 src.expect_char(':').map_err(|()| err!("bad fragment specifier 1"))?;
219 let ident = src.expect_ident().map_err(|()| err!("bad fragment specifier 1"))?; 219 let ident = src.expect_ident().map_err(|()| err!("bad fragment specifier 1"))?;
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs
index b11172caf..978c75747 100644
--- a/crates/mbe/src/syntax_bridge.rs
+++ b/crates/mbe/src/syntax_bridge.rs
@@ -243,8 +243,7 @@ trait TokenConvertor {
243 type Token: SrcToken; 243 type Token: SrcToken;
244 244
245 fn go(&mut self) -> tt::Subtree { 245 fn go(&mut self) -> tt::Subtree {
246 let mut subtree = tt::Subtree::default(); 246 let mut subtree = tt::Subtree { delimiter: None, ..Default::default() };
247 subtree.delimiter = None;
248 while self.peek().is_some() { 247 while self.peek().is_some() {
249 self.collect_leaf(&mut subtree.token_trees); 248 self.collect_leaf(&mut subtree.token_trees);
250 } 249 }
@@ -506,7 +505,7 @@ impl TokenConvertor for Convertor {
506 505
507 fn peek(&self) -> Option<Self::Token> { 506 fn peek(&self) -> Option<Self::Token> {
508 if let Some((punct, mut offset)) = self.punct_offset.clone() { 507 if let Some((punct, mut offset)) = self.punct_offset.clone() {
509 offset = offset + TextSize::of('.'); 508 offset += TextSize::of('.');
510 if usize::from(offset) < punct.text().len() { 509 if usize::from(offset) < punct.text().len() {
511 return Some(SynToken::Punch(punct, offset)); 510 return Some(SynToken::Punch(punct, offset));
512 } 511 }
diff --git a/crates/mbe/src/tt_iter.rs b/crates/mbe/src/tt_iter.rs
index 99a8d250b..bd54f2442 100644
--- a/crates/mbe/src/tt_iter.rs
+++ b/crates/mbe/src/tt_iter.rs
@@ -138,7 +138,7 @@ impl<'a> TtIter<'a> {
138 } 138 }
139 } 139 }
140 self.inner = self.inner.as_slice()[res.len()..].iter(); 140 self.inner = self.inner.as_slice()[res.len()..].iter();
141 if res.len() == 0 && err.is_none() { 141 if res.is_empty() && err.is_none() {
142 err = Some(err!("no tokens consumed")); 142 err = Some(err!("no tokens consumed"));
143 } 143 }
144 let res = match res.len() { 144 let res = match res.len() {
diff --git a/crates/parser/src/grammar/expressions/atom.rs b/crates/parser/src/grammar/expressions/atom.rs
index 269f223e6..abdfca1fe 100644
--- a/crates/parser/src/grammar/expressions/atom.rs
+++ b/crates/parser/src/grammar/expressions/atom.rs
@@ -252,12 +252,10 @@ fn closure_expr(p: &mut Parser) -> CompletedMarker {
252 // test lambda_ret_block 252 // test lambda_ret_block
253 // fn main() { || -> i32 { 92 }(); } 253 // fn main() { || -> i32 { 92 }(); }
254 block_expr(p); 254 block_expr(p);
255 } else if p.at_ts(EXPR_FIRST) {
256 expr(p);
255 } else { 257 } else {
256 if p.at_ts(EXPR_FIRST) { 258 p.error("expected expression");
257 expr(p);
258 } else {
259 p.error("expected expression");
260 }
261 } 259 }
262 m.complete(p, CLOSURE_EXPR) 260 m.complete(p, CLOSURE_EXPR)
263} 261}
diff --git a/crates/proc_macro_api/src/msg.rs b/crates/proc_macro_api/src/msg.rs
index f525df152..14eed4289 100644
--- a/crates/proc_macro_api/src/msg.rs
+++ b/crates/proc_macro_api/src/msg.rs
@@ -92,7 +92,7 @@ fn read_json<'a>(
92 92
93 // Some ill behaved macro try to use stdout for debugging 93 // Some ill behaved macro try to use stdout for debugging
94 // We ignore it here 94 // We ignore it here
95 if !buf.starts_with("{") { 95 if !buf.starts_with('{') {
96 log::error!("proc-macro tried to print : {}", buf); 96 log::error!("proc-macro tried to print : {}", buf);
97 continue; 97 continue;
98 } 98 }
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index ae78fd4f6..c33cdb740 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -92,6 +92,7 @@ config_data! {
92 checkOnSave_overrideCommand: Option<Vec<String>> = "null", 92 checkOnSave_overrideCommand: Option<Vec<String>> = "null",
93 93
94 /// Whether to add argument snippets when completing functions. 94 /// Whether to add argument snippets when completing functions.
95 /// Only applies when `#rust-analyzer.completion.addCallParenthesis#` is set.
95 completion_addCallArgumentSnippets: bool = "true", 96 completion_addCallArgumentSnippets: bool = "true",
96 /// Whether to add parenthesis when completing functions. 97 /// Whether to add parenthesis when completing functions.
97 completion_addCallParenthesis: bool = "true", 98 completion_addCallParenthesis: bool = "true",
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 456744603..49ee4b922 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -1640,7 +1640,7 @@ fn run_rustfmt(
1640 .into()); 1640 .into());
1641 } 1641 }
1642 1642
1643 let frange = from_proto::file_range(&snap, text_document.clone(), range)?; 1643 let frange = from_proto::file_range(&snap, text_document, range)?;
1644 let start_line = line_index.index.line_col(frange.range.start()).line; 1644 let start_line = line_index.index.line_col(frange.range.start()).line;
1645 let end_line = line_index.index.line_col(frange.range.end()).line; 1645 let end_line = line_index.index.line_col(frange.range.end()).line;
1646 1646
diff --git a/crates/syntax/src/parsing/reparsing.rs b/crates/syntax/src/parsing/reparsing.rs
index 4ad50ab72..304f47b3d 100644
--- a/crates/syntax/src/parsing/reparsing.rs
+++ b/crates/syntax/src/parsing/reparsing.rs
@@ -36,8 +36,8 @@ pub(crate) fn incremental_reparse(
36 None 36 None
37} 37}
38 38
39fn reparse_token<'node>( 39fn reparse_token(
40 root: &'node SyntaxNode, 40 root: &SyntaxNode,
41 edit: &Indel, 41 edit: &Indel,
42) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> { 42) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
43 let prev_token = root.covering_element(edit.delete).as_token()?.clone(); 43 let prev_token = root.covering_element(edit.delete).as_token()?.clone();
@@ -84,8 +84,8 @@ fn reparse_token<'node>(
84 } 84 }
85} 85}
86 86
87fn reparse_block<'node>( 87fn reparse_block(
88 root: &'node SyntaxNode, 88 root: &SyntaxNode,
89 edit: &Indel, 89 edit: &Indel,
90) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> { 90) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
91 let (node, reparser) = find_reparsable_node(root, edit.delete)?; 91 let (node, reparser) = find_reparsable_node(root, edit.delete)?;
diff --git a/crates/syntax/src/tests.rs b/crates/syntax/src/tests.rs
index 45f3c800f..9f2426171 100644
--- a/crates/syntax/src/tests.rs
+++ b/crates/syntax/src/tests.rs
@@ -236,7 +236,7 @@ where
236 } 236 }
237 }); 237 });
238 dir_tests(&test_data_dir(), err_paths, "rast", |text, path| { 238 dir_tests(&test_data_dir(), err_paths, "rast", |text, path| {
239 if let Ok(_) = f(text) { 239 if f(text).is_ok() {
240 panic!("'{:?}' successfully parsed when it should have errored", path); 240 panic!("'{:?}' successfully parsed when it should have errored", path);
241 } else { 241 } else {
242 "ERROR\n".to_owned() 242 "ERROR\n".to_owned()
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index bd017567c..ac5a9509d 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -238,14 +238,9 @@ fn extract_line_annotations(mut line: &str) -> Vec<LineAnnotation> {
238 let mut res = Vec::new(); 238 let mut res = Vec::new();
239 let mut offset: TextSize = 0.into(); 239 let mut offset: TextSize = 0.into();
240 let marker: fn(char) -> bool = if line.contains('^') { |c| c == '^' } else { |c| c == '|' }; 240 let marker: fn(char) -> bool = if line.contains('^') { |c| c == '^' } else { |c| c == '|' };
241 loop { 241 while let Some(idx) = line.find(marker) {
242 match line.find(marker) { 242 offset += TextSize::try_from(idx).unwrap();
243 Some(idx) => { 243 line = &line[idx..];
244 offset += TextSize::try_from(idx).unwrap();
245 line = &line[idx..];
246 }
247 None => break,
248 };
249 244
250 let mut len = line.chars().take_while(|&it| it == '^').count(); 245 let mut len = line.chars().take_while(|&it| it == '^').count();
251 let mut continuation = false; 246 let mut continuation = false;