From b2cb42d6a7b14b35e79f56228682148ecdd8a6a9 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Tue, 5 Jul 2022 07:19:13 +0000 Subject: [PATCH 1/6] Minimal implementation of implicit deref patterns --- compiler/rustc_hir/src/lang_items.rs | 2 + compiler/rustc_hir_typeck/src/pat.rs | 10 ++ .../rustc_mir_build/src/build/matches/test.rs | 33 +++++++ library/alloc/src/string.rs | 1 + src/test/ui/deref-patterns/basic.rs | 16 +++ src/test/ui/deref-patterns/basic.run.stdout | 3 + src/test/ui/deref-patterns/mir.rs | 10 ++ src/test/ui/deref-patterns/mir.stdout | 99 +++++++++++++++++++ 8 files changed, 174 insertions(+) create mode 100644 src/test/ui/deref-patterns/basic.rs create mode 100644 src/test/ui/deref-patterns/basic.run.stdout create mode 100644 src/test/ui/deref-patterns/mir.rs create mode 100644 src/test/ui/deref-patterns/mir.stdout diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index a55224d10972a..7e9d1078049b9 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -302,6 +302,8 @@ language_item_table! { Range, sym::Range, range_struct, Target::Struct, GenericRequirement::None; RangeToInclusive, sym::RangeToInclusive, range_to_inclusive_struct, Target::Struct, GenericRequirement::None; RangeTo, sym::RangeTo, range_to_struct, Target::Struct, GenericRequirement::None; + + String, sym::String, string, Target::Struct, GenericRequirement::None; } pub enum GenericRequirement { diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index eb10f3e2c107f..f2d5f754c6ff7 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -401,6 +401,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + if let hir::ExprKind::Lit(Spanned { node: ast::LitKind::Str(..), .. }) = lt.kind { + let tcx = self.tcx; + let expected = self.resolve_vars_if_possible(expected); + pat_ty = match expected.kind() { + ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().string() => expected, + ty::Str => tcx.mk_static_str(), + _ => pat_ty, + }; + } + // Somewhat surprising: in this case, the subtyping relation goes the // opposite way as the other cases. Actually what we really want is not // a subtyping relation at all but rather that there exists a LUB diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index b597ecfaa4d6d..e6c01b72b1bfe 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -240,6 +240,39 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } TestKind::Eq { value, ty } => { + let tcx = self.tcx; + if let ty::Adt(def, _) = ty.kind() && Some(def.did()) == tcx.lang_items().string() { + if !tcx.features().deref_patterns { + bug!("matching on `String` went through without enabling deref_patterns"); + } + let re_erased = tcx.lifetimes.re_erased; + let ref_string = self.temp(tcx.mk_imm_ref(re_erased, ty), test.span); + let ref_str_ty = tcx.mk_imm_ref(re_erased, tcx.types.str_); + let ref_str = self.temp(ref_str_ty, test.span); + let deref = tcx.require_lang_item(LangItem::Deref, None); + let method = trait_method(tcx, deref, sym::deref, ty, &[]); + let eq_block = self.cfg.start_new_block(); + self.cfg.push_assign(block, source_info, ref_string, Rvalue::Ref(re_erased, BorrowKind::Shared, place)); + self.cfg.terminate( + block, + source_info, + TerminatorKind::Call { + func: Operand::Constant(Box::new(Constant { + span: test.span, + user_ty: None, + literal: method, + })), + args: vec![Operand::Move(ref_string)], + destination: ref_str, + target: Some(eq_block), + cleanup: None, + from_hir_call: false, + fn_span: source_info.span + } + ); + self.non_scalar_compare(eq_block, make_target_blocks, source_info, value, ref_str, ref_str_ty); + return; + } if !ty.is_scalar() { // Use `PartialEq::eq` instead of `BinOp::Eq` // (the binop can only handle primitives) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index c9ba8921f6ecc..5799ef778c4f6 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -364,6 +364,7 @@ use crate::vec::Vec; #[derive(PartialOrd, Eq, Ord)] #[cfg_attr(not(test), rustc_diagnostic_item = "String")] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(bootstrap), lang = "String")] pub struct String { vec: Vec, } diff --git a/src/test/ui/deref-patterns/basic.rs b/src/test/ui/deref-patterns/basic.rs new file mode 100644 index 0000000000000..aa854ed7532fc --- /dev/null +++ b/src/test/ui/deref-patterns/basic.rs @@ -0,0 +1,16 @@ +// run-pass +// check-run-results + +fn main() { + test(Some(String::from("42"))); + test(Some(String::new())); + test(None); +} + +fn test(o: Option) { + match o { + Some("42") => println!("the answer"), + Some(_) => println!("something else?"), + None => println!("nil"), + } +} \ No newline at end of file diff --git a/src/test/ui/deref-patterns/basic.run.stdout b/src/test/ui/deref-patterns/basic.run.stdout new file mode 100644 index 0000000000000..e50df05828152 --- /dev/null +++ b/src/test/ui/deref-patterns/basic.run.stdout @@ -0,0 +1,3 @@ +the answer +something else? +nil diff --git a/src/test/ui/deref-patterns/mir.rs b/src/test/ui/deref-patterns/mir.rs new file mode 100644 index 0000000000000..3be4a82d76c65 --- /dev/null +++ b/src/test/ui/deref-patterns/mir.rs @@ -0,0 +1,10 @@ +// compile-flags: -Z unpretty=mir +// build-pass +fn main() { + let s = Some(String::new()); + let a; + match s { + Some("a") => a = 1234, + s => a = 4321, + } +} \ No newline at end of file diff --git a/src/test/ui/deref-patterns/mir.stdout b/src/test/ui/deref-patterns/mir.stdout new file mode 100644 index 0000000000000..211f50fa1a846 --- /dev/null +++ b/src/test/ui/deref-patterns/mir.stdout @@ -0,0 +1,99 @@ +// WARNING: This output format is intended for human consumers only +// and is subject to change without notice. Knock yourself out. +fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/mir.rs:3:11: 3:11 + let _1: std::option::Option; // in scope 0 at $DIR/mir.rs:4:9: 4:10 + let mut _2: std::string::String; // in scope 0 at $DIR/mir.rs:4:18: 4:31 + let mut _4: &std::string::String; // in scope 0 at $DIR/mir.rs:7:14: 7:17 + let mut _5: &str; // in scope 0 at $DIR/mir.rs:7:14: 7:17 + let mut _6: bool; // in scope 0 at $DIR/mir.rs:7:14: 7:17 + let mut _7: isize; // in scope 0 at $DIR/mir.rs:7:9: 7:18 + let mut _9: bool; // in scope 0 at $DIR/mir.rs:10:1: 10:2 + scope 1 { + debug s => _1; // in scope 1 at $DIR/mir.rs:4:9: 4:10 + let _3: i32; // in scope 1 at $DIR/mir.rs:5:9: 5:10 + scope 2 { + debug a => _3; // in scope 2 at $DIR/mir.rs:5:9: 5:10 + let _8: std::option::Option; // in scope 2 at $DIR/mir.rs:8:9: 8:10 + scope 3 { + debug s => _8; // in scope 3 at $DIR/mir.rs:8:9: 8:10 + } + } + } + + bb0: { + _9 = const false; // scope 0 at $DIR/mir.rs:4:9: 4:10 + _2 = String::new() -> bb1; // scope 0 at $DIR/mir.rs:4:18: 4:31 + // mir::Constant + // + span: $DIR/mir.rs:4:18: 4:29 + // + literal: Const { ty: fn() -> String {String::new}, val: Value(Scalar()) } + } + + bb1: { + _9 = const true; // scope 0 at $DIR/mir.rs:4:13: 4:32 + Deinit(_1); // scope 0 at $DIR/mir.rs:4:13: 4:32 + ((_1 as Some).0: std::string::String) = move _2; // scope 0 at $DIR/mir.rs:4:13: 4:32 + discriminant(_1) = 1; // scope 0 at $DIR/mir.rs:4:13: 4:32 + _7 = discriminant(_1); // scope 2 at $DIR/mir.rs:6:11: 6:12 + switchInt(move _7) -> [1_isize: bb3, otherwise: bb2]; // scope 2 at $DIR/mir.rs:6:5: 6:12 + } + + bb2: { + _9 = const false; // scope 2 at $DIR/mir.rs:8:9: 8:10 + _8 = move _1; // scope 2 at $DIR/mir.rs:8:9: 8:10 + _3 = const 4321_i32; // scope 3 at $DIR/mir.rs:8:14: 8:22 + drop(_8) -> [return: bb7, unwind: bb12]; // scope 2 at $DIR/mir.rs:8:21: 8:22 + } + + bb3: { + _4 = &((_1 as Some).0: std::string::String); // scope 2 at $DIR/mir.rs:7:14: 7:17 + _5 = ::deref(move _4) -> bb4; // scope 2 at $DIR/mir.rs:7:14: 7:17 + // mir::Constant + // + span: $DIR/mir.rs:7:14: 7:17 + // + literal: Const { ty: for<'r> fn(&'r String) -> &'r ::Target {::deref}, val: Value(Scalar()) } + } + + bb4: { + _6 = ::eq(_5, const "a") -> [return: bb5, unwind: bb12]; // scope 2 at $DIR/mir.rs:7:14: 7:17 + // mir::Constant + // + span: $DIR/mir.rs:7:14: 7:17 + // + literal: Const { ty: for<'r, 's> fn(&'r str, &'s str) -> bool {::eq}, val: Value(Scalar()) } + // mir::Constant + // + span: $DIR/mir.rs:7:14: 7:17 + // + literal: Const { ty: &str, val: Value(Slice(..)) } + } + + bb5: { + switchInt(move _6) -> [false: bb2, otherwise: bb6]; // scope 2 at $DIR/mir.rs:7:14: 7:17 + } + + bb6: { + _3 = const 1234_i32; // scope 2 at $DIR/mir.rs:7:22: 7:30 + goto -> bb7; // scope 2 at $DIR/mir.rs:7:22: 7:30 + } + + bb7: { + switchInt(_9) -> [false: bb8, otherwise: bb10]; // scope 0 at $DIR/mir.rs:10:1: 10:2 + } + + bb8: { + _9 = const false; // scope 0 at $DIR/mir.rs:10:1: 10:2 + return; // scope 0 at $DIR/mir.rs:10:2: 10:2 + } + + bb9 (cleanup): { + resume; // scope 0 at $DIR/mir.rs:3:1: 10:2 + } + + bb10: { + drop(_1) -> bb8; // scope 0 at $DIR/mir.rs:10:1: 10:2 + } + + bb11 (cleanup): { + drop(_1) -> bb9; // scope 0 at $DIR/mir.rs:10:1: 10:2 + } + + bb12 (cleanup): { + switchInt(_9) -> [false: bb9, otherwise: bb11]; // scope 0 at $DIR/mir.rs:10:1: 10:2 + } +} From 0537d301c520ffc1a6069df6dd5012c679fe29ca Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Tue, 5 Jul 2022 07:42:19 +0000 Subject: [PATCH 2/6] Add feature gate --- compiler/rustc_feature/src/active.rs | 2 + compiler/rustc_hir_typeck/src/pat.rs | 2 +- compiler/rustc_span/src/symbol.rs | 1 + src/test/ui/deref-patterns/basic.rs | 3 +- src/test/ui/deref-patterns/gate.rs | 7 +++ src/test/ui/deref-patterns/gate.stderr | 11 ++++ src/test/ui/deref-patterns/mir.rs | 4 +- src/test/ui/deref-patterns/mir.stdout | 84 +++++++++++++------------- 8 files changed, 69 insertions(+), 45 deletions(-) create mode 100644 src/test/ui/deref-patterns/gate.rs create mode 100644 src/test/ui/deref-patterns/gate.stderr diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 5cf2fdde39254..3a1db1193b3dd 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -376,6 +376,8 @@ declare_features! ( (active, deprecated_safe, "1.61.0", Some(94978), None), /// Allows having using `suggestion` in the `#[deprecated]` attribute. (active, deprecated_suggestion, "1.61.0", Some(94785), None), + /// Allows patterns to dereference values to match them. + (active, deref_patterns, "1.64.0", Some(87121), None), /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. (active, doc_auto_cfg, "1.58.0", Some(43781), None), /// Allows `#[doc(cfg(...))]`. diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index f2d5f754c6ff7..b20949bcbd54a 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -401,7 +401,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - if let hir::ExprKind::Lit(Spanned { node: ast::LitKind::Str(..), .. }) = lt.kind { + if self.tcx.features().deref_patterns && let hir::ExprKind::Lit(Spanned { node: ast::LitKind::Str(..), .. }) = lt.kind { let tcx = self.tcx; let expected = self.resolve_vars_if_possible(expected); pat_ty = match expected.kind() { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index a56450a3573d1..a06e613b82f46 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -597,6 +597,7 @@ symbols! { deref, deref_method, deref_mut, + deref_patterns, deref_target, derive, derive_const, diff --git a/src/test/ui/deref-patterns/basic.rs b/src/test/ui/deref-patterns/basic.rs index aa854ed7532fc..e03f2455954f8 100644 --- a/src/test/ui/deref-patterns/basic.rs +++ b/src/test/ui/deref-patterns/basic.rs @@ -1,5 +1,6 @@ // run-pass // check-run-results +#![feature(deref_patterns)] fn main() { test(Some(String::from("42"))); @@ -13,4 +14,4 @@ fn test(o: Option) { Some(_) => println!("something else?"), None => println!("nil"), } -} \ No newline at end of file +} diff --git a/src/test/ui/deref-patterns/gate.rs b/src/test/ui/deref-patterns/gate.rs new file mode 100644 index 0000000000000..90d0448e94a5f --- /dev/null +++ b/src/test/ui/deref-patterns/gate.rs @@ -0,0 +1,7 @@ +// gate-test-deref_patterns +fn main() { + match String::new() { + "" | _ => {} + //~^ mismatched types + } +} diff --git a/src/test/ui/deref-patterns/gate.stderr b/src/test/ui/deref-patterns/gate.stderr new file mode 100644 index 0000000000000..7ffd0eb7e6c03 --- /dev/null +++ b/src/test/ui/deref-patterns/gate.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/gate.rs:3:9 + | +LL | match String::new() { + | ------------- this expression has type `String` +LL | "" | _ => {} + | ^^ expected struct `String`, found `&str` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/deref-patterns/mir.rs b/src/test/ui/deref-patterns/mir.rs index 3be4a82d76c65..2e7d26d0dfd96 100644 --- a/src/test/ui/deref-patterns/mir.rs +++ b/src/test/ui/deref-patterns/mir.rs @@ -1,5 +1,7 @@ // compile-flags: -Z unpretty=mir // build-pass +#![feature(deref_patterns)] + fn main() { let s = Some(String::new()); let a; @@ -7,4 +9,4 @@ fn main() { Some("a") => a = 1234, s => a = 4321, } -} \ No newline at end of file +} diff --git a/src/test/ui/deref-patterns/mir.stdout b/src/test/ui/deref-patterns/mir.stdout index 211f50fa1a846..e73d37efb24a2 100644 --- a/src/test/ui/deref-patterns/mir.stdout +++ b/src/test/ui/deref-patterns/mir.stdout @@ -1,99 +1,99 @@ // WARNING: This output format is intended for human consumers only // and is subject to change without notice. Knock yourself out. fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/mir.rs:3:11: 3:11 - let _1: std::option::Option; // in scope 0 at $DIR/mir.rs:4:9: 4:10 - let mut _2: std::string::String; // in scope 0 at $DIR/mir.rs:4:18: 4:31 - let mut _4: &std::string::String; // in scope 0 at $DIR/mir.rs:7:14: 7:17 - let mut _5: &str; // in scope 0 at $DIR/mir.rs:7:14: 7:17 - let mut _6: bool; // in scope 0 at $DIR/mir.rs:7:14: 7:17 - let mut _7: isize; // in scope 0 at $DIR/mir.rs:7:9: 7:18 - let mut _9: bool; // in scope 0 at $DIR/mir.rs:10:1: 10:2 + let mut _0: (); // return place in scope 0 at $DIR/mir.rs:5:11: 5:11 + let _1: std::option::Option; // in scope 0 at $DIR/mir.rs:6:9: 6:10 + let mut _2: std::string::String; // in scope 0 at $DIR/mir.rs:6:18: 6:31 + let mut _4: &std::string::String; // in scope 0 at $DIR/mir.rs:9:14: 9:17 + let mut _5: &str; // in scope 0 at $DIR/mir.rs:9:14: 9:17 + let mut _6: bool; // in scope 0 at $DIR/mir.rs:9:14: 9:17 + let mut _7: isize; // in scope 0 at $DIR/mir.rs:9:9: 9:18 + let mut _9: bool; // in scope 0 at $DIR/mir.rs:12:1: 12:2 scope 1 { - debug s => _1; // in scope 1 at $DIR/mir.rs:4:9: 4:10 - let _3: i32; // in scope 1 at $DIR/mir.rs:5:9: 5:10 + debug s => _1; // in scope 1 at $DIR/mir.rs:6:9: 6:10 + let _3: i32; // in scope 1 at $DIR/mir.rs:7:9: 7:10 scope 2 { - debug a => _3; // in scope 2 at $DIR/mir.rs:5:9: 5:10 - let _8: std::option::Option; // in scope 2 at $DIR/mir.rs:8:9: 8:10 + debug a => _3; // in scope 2 at $DIR/mir.rs:7:9: 7:10 + let _8: std::option::Option; // in scope 2 at $DIR/mir.rs:10:9: 10:10 scope 3 { - debug s => _8; // in scope 3 at $DIR/mir.rs:8:9: 8:10 + debug s => _8; // in scope 3 at $DIR/mir.rs:10:9: 10:10 } } } bb0: { - _9 = const false; // scope 0 at $DIR/mir.rs:4:9: 4:10 - _2 = String::new() -> bb1; // scope 0 at $DIR/mir.rs:4:18: 4:31 + _9 = const false; // scope 0 at $DIR/mir.rs:6:9: 6:10 + _2 = String::new() -> bb1; // scope 0 at $DIR/mir.rs:6:18: 6:31 // mir::Constant - // + span: $DIR/mir.rs:4:18: 4:29 + // + span: $DIR/mir.rs:6:18: 6:29 // + literal: Const { ty: fn() -> String {String::new}, val: Value(Scalar()) } } bb1: { - _9 = const true; // scope 0 at $DIR/mir.rs:4:13: 4:32 - Deinit(_1); // scope 0 at $DIR/mir.rs:4:13: 4:32 - ((_1 as Some).0: std::string::String) = move _2; // scope 0 at $DIR/mir.rs:4:13: 4:32 - discriminant(_1) = 1; // scope 0 at $DIR/mir.rs:4:13: 4:32 - _7 = discriminant(_1); // scope 2 at $DIR/mir.rs:6:11: 6:12 - switchInt(move _7) -> [1_isize: bb3, otherwise: bb2]; // scope 2 at $DIR/mir.rs:6:5: 6:12 + _9 = const true; // scope 0 at $DIR/mir.rs:6:13: 6:32 + Deinit(_1); // scope 0 at $DIR/mir.rs:6:13: 6:32 + ((_1 as Some).0: std::string::String) = move _2; // scope 0 at $DIR/mir.rs:6:13: 6:32 + discriminant(_1) = 1; // scope 0 at $DIR/mir.rs:6:13: 6:32 + _7 = discriminant(_1); // scope 2 at $DIR/mir.rs:8:11: 8:12 + switchInt(move _7) -> [1_isize: bb3, otherwise: bb2]; // scope 2 at $DIR/mir.rs:8:5: 8:12 } bb2: { - _9 = const false; // scope 2 at $DIR/mir.rs:8:9: 8:10 - _8 = move _1; // scope 2 at $DIR/mir.rs:8:9: 8:10 - _3 = const 4321_i32; // scope 3 at $DIR/mir.rs:8:14: 8:22 - drop(_8) -> [return: bb7, unwind: bb12]; // scope 2 at $DIR/mir.rs:8:21: 8:22 + _9 = const false; // scope 2 at $DIR/mir.rs:10:9: 10:10 + _8 = move _1; // scope 2 at $DIR/mir.rs:10:9: 10:10 + _3 = const 4321_i32; // scope 3 at $DIR/mir.rs:10:14: 10:22 + drop(_8) -> [return: bb7, unwind: bb12]; // scope 2 at $DIR/mir.rs:10:21: 10:22 } bb3: { - _4 = &((_1 as Some).0: std::string::String); // scope 2 at $DIR/mir.rs:7:14: 7:17 - _5 = ::deref(move _4) -> bb4; // scope 2 at $DIR/mir.rs:7:14: 7:17 + _4 = &((_1 as Some).0: std::string::String); // scope 2 at $DIR/mir.rs:9:14: 9:17 + _5 = ::deref(move _4) -> bb4; // scope 2 at $DIR/mir.rs:9:14: 9:17 // mir::Constant - // + span: $DIR/mir.rs:7:14: 7:17 + // + span: $DIR/mir.rs:9:14: 9:17 // + literal: Const { ty: for<'r> fn(&'r String) -> &'r ::Target {::deref}, val: Value(Scalar()) } } bb4: { - _6 = ::eq(_5, const "a") -> [return: bb5, unwind: bb12]; // scope 2 at $DIR/mir.rs:7:14: 7:17 + _6 = ::eq(_5, const "a") -> [return: bb5, unwind: bb12]; // scope 2 at $DIR/mir.rs:9:14: 9:17 // mir::Constant - // + span: $DIR/mir.rs:7:14: 7:17 + // + span: $DIR/mir.rs:9:14: 9:17 // + literal: Const { ty: for<'r, 's> fn(&'r str, &'s str) -> bool {::eq}, val: Value(Scalar()) } // mir::Constant - // + span: $DIR/mir.rs:7:14: 7:17 + // + span: $DIR/mir.rs:9:14: 9:17 // + literal: Const { ty: &str, val: Value(Slice(..)) } } bb5: { - switchInt(move _6) -> [false: bb2, otherwise: bb6]; // scope 2 at $DIR/mir.rs:7:14: 7:17 + switchInt(move _6) -> [false: bb2, otherwise: bb6]; // scope 2 at $DIR/mir.rs:9:14: 9:17 } bb6: { - _3 = const 1234_i32; // scope 2 at $DIR/mir.rs:7:22: 7:30 - goto -> bb7; // scope 2 at $DIR/mir.rs:7:22: 7:30 + _3 = const 1234_i32; // scope 2 at $DIR/mir.rs:9:22: 9:30 + goto -> bb7; // scope 2 at $DIR/mir.rs:9:22: 9:30 } bb7: { - switchInt(_9) -> [false: bb8, otherwise: bb10]; // scope 0 at $DIR/mir.rs:10:1: 10:2 + switchInt(_9) -> [false: bb8, otherwise: bb10]; // scope 0 at $DIR/mir.rs:12:1: 12:2 } bb8: { - _9 = const false; // scope 0 at $DIR/mir.rs:10:1: 10:2 - return; // scope 0 at $DIR/mir.rs:10:2: 10:2 + _9 = const false; // scope 0 at $DIR/mir.rs:12:1: 12:2 + return; // scope 0 at $DIR/mir.rs:12:2: 12:2 } bb9 (cleanup): { - resume; // scope 0 at $DIR/mir.rs:3:1: 10:2 + resume; // scope 0 at $DIR/mir.rs:5:1: 12:2 } bb10: { - drop(_1) -> bb8; // scope 0 at $DIR/mir.rs:10:1: 10:2 + drop(_1) -> bb8; // scope 0 at $DIR/mir.rs:12:1: 12:2 } bb11 (cleanup): { - drop(_1) -> bb9; // scope 0 at $DIR/mir.rs:10:1: 10:2 + drop(_1) -> bb9; // scope 0 at $DIR/mir.rs:12:1: 12:2 } bb12 (cleanup): { - switchInt(_9) -> [false: bb9, otherwise: bb11]; // scope 0 at $DIR/mir.rs:10:1: 10:2 + switchInt(_9) -> [false: bb9, otherwise: bb11]; // scope 0 at $DIR/mir.rs:12:1: 12:2 } } From d1c6b797deafbc9d3311a1e02db9623e75419218 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Tue, 5 Jul 2022 07:46:57 +0000 Subject: [PATCH 3/6] Move a ui test to make space for new folder --- src/test/ui/{ => resolve}/blind-item-local-shadow.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{ => resolve}/blind-item-local-shadow.rs (100%) diff --git a/src/test/ui/blind-item-local-shadow.rs b/src/test/ui/resolve/blind-item-local-shadow.rs similarity index 100% rename from src/test/ui/blind-item-local-shadow.rs rename to src/test/ui/resolve/blind-item-local-shadow.rs From c74f155b24005790fdc1ddf787a47e2bda38e01c Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 13 Jul 2022 18:13:07 +0000 Subject: [PATCH 4/6] Adding more tests --- .../string.foo.PreCodegen.after.mir | 74 ++++++++++++++ src/test/mir-opt/deref-patterns/string.rs | 12 +++ src/test/ui/deref-patterns/default-infer.rs | 9 ++ src/test/ui/deref-patterns/gate.stderr | 2 +- src/test/ui/deref-patterns/mir.rs | 12 --- src/test/ui/deref-patterns/mir.stdout | 99 ------------------- src/test/ui/deref-patterns/refs.rs | 18 ++++ 7 files changed, 114 insertions(+), 112 deletions(-) create mode 100644 src/test/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir create mode 100644 src/test/mir-opt/deref-patterns/string.rs create mode 100644 src/test/ui/deref-patterns/default-infer.rs delete mode 100644 src/test/ui/deref-patterns/mir.rs delete mode 100644 src/test/ui/deref-patterns/mir.stdout create mode 100644 src/test/ui/deref-patterns/refs.rs diff --git a/src/test/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir b/src/test/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir new file mode 100644 index 0000000000000..5b185082d4d87 --- /dev/null +++ b/src/test/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir @@ -0,0 +1,74 @@ +// MIR for `foo` after PreCodegen + +fn foo(_1: Option) -> i32 { + debug s => _1; // in scope 0 at $DIR/string.rs:+0:12: +0:13 + let mut _0: i32; // return place in scope 0 at $DIR/string.rs:+0:34: +0:37 + let mut _2: &std::string::String; // in scope 0 at $DIR/string.rs:+2:14: +2:17 + let mut _3: &str; // in scope 0 at $DIR/string.rs:+2:14: +2:17 + let mut _4: bool; // in scope 0 at $DIR/string.rs:+2:14: +2:17 + let mut _5: isize; // in scope 0 at $DIR/string.rs:+2:9: +2:18 + let _6: std::option::Option; // in scope 0 at $DIR/string.rs:+3:9: +3:10 + let mut _7: bool; // in scope 0 at $DIR/string.rs:+5:1: +5:2 + scope 1 { + debug s => _6; // in scope 1 at $DIR/string.rs:+3:9: +3:10 + } + + bb0: { + _7 = const false; // scope 0 at $DIR/string.rs:+1:11: +1:12 + _7 = const true; // scope 0 at $DIR/string.rs:+1:11: +1:12 + _5 = discriminant(_1); // scope 0 at $DIR/string.rs:+1:11: +1:12 + switchInt(move _5) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/string.rs:+1:5: +1:12 + } + + bb1: { + StorageLive(_6); // scope 0 at $DIR/string.rs:+3:9: +3:10 + _7 = const false; // scope 0 at $DIR/string.rs:+3:9: +3:10 + _6 = move _1; // scope 0 at $DIR/string.rs:+3:9: +3:10 + _0 = const 4321_i32; // scope 1 at $DIR/string.rs:+3:14: +3:18 + drop(_6) -> bb6; // scope 0 at $DIR/string.rs:+3:17: +3:18 + } + + bb2: { + _2 = &((_1 as Some).0: std::string::String); // scope 0 at $DIR/string.rs:+2:14: +2:17 + _3 = ::deref(move _2) -> bb3; // scope 0 at $DIR/string.rs:+2:14: +2:17 + // mir::Constant + // + span: $DIR/string.rs:9:14: 9:17 + // + literal: Const { ty: for<'a> fn(&'a String) -> &'a ::Target {::deref}, val: Value() } + } + + bb3: { + _4 = ::eq(_3, const "a") -> bb4; // scope 0 at $DIR/string.rs:+2:14: +2:17 + // mir::Constant + // + span: $DIR/string.rs:9:14: 9:17 + // + literal: Const { ty: for<'a, 'b> fn(&'a str, &'b str) -> bool {::eq}, val: Value() } + // mir::Constant + // + span: $DIR/string.rs:9:14: 9:17 + // + literal: Const { ty: &str, val: Value(Slice(..)) } + } + + bb4: { + switchInt(move _4) -> [false: bb1, otherwise: bb5]; // scope 0 at $DIR/string.rs:+2:14: +2:17 + } + + bb5: { + _0 = const 1234_i32; // scope 0 at $DIR/string.rs:+2:22: +2:26 + goto -> bb9; // scope 0 at $DIR/string.rs:+2:22: +2:26 + } + + bb6: { + StorageDead(_6); // scope 0 at $DIR/string.rs:+3:17: +3:18 + goto -> bb9; // scope 0 at $DIR/string.rs:+3:17: +3:18 + } + + bb7: { + return; // scope 0 at $DIR/string.rs:+5:2: +5:2 + } + + bb8: { + drop(_1) -> bb7; // scope 0 at $DIR/string.rs:+5:1: +5:2 + } + + bb9: { + switchInt(_7) -> [false: bb7, otherwise: bb8]; // scope 0 at $DIR/string.rs:+5:1: +5:2 + } +} diff --git a/src/test/mir-opt/deref-patterns/string.rs b/src/test/mir-opt/deref-patterns/string.rs new file mode 100644 index 0000000000000..2557f75b267a6 --- /dev/null +++ b/src/test/mir-opt/deref-patterns/string.rs @@ -0,0 +1,12 @@ +// compile-flags: -Z mir-opt-level=0 -C panic=abort + +#![feature(deref_patterns)] +#![crate_type = "lib"] + +// EMIT_MIR string.foo.PreCodegen.after.mir +pub fn foo(s: Option) -> i32 { + match s { + Some("a") => 1234, + s => 4321, + } +} diff --git a/src/test/ui/deref-patterns/default-infer.rs b/src/test/ui/deref-patterns/default-infer.rs new file mode 100644 index 0000000000000..b7155b7efffee --- /dev/null +++ b/src/test/ui/deref-patterns/default-infer.rs @@ -0,0 +1,9 @@ +// check-pass +#![feature(deref_patterns)] + +fn main() { + match <_ as Default>::default() { + "" => (), + _ => unreachable!(), + } +} diff --git a/src/test/ui/deref-patterns/gate.stderr b/src/test/ui/deref-patterns/gate.stderr index 7ffd0eb7e6c03..993468b5e826b 100644 --- a/src/test/ui/deref-patterns/gate.stderr +++ b/src/test/ui/deref-patterns/gate.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/gate.rs:3:9 + --> $DIR/gate.rs:4:9 | LL | match String::new() { | ------------- this expression has type `String` diff --git a/src/test/ui/deref-patterns/mir.rs b/src/test/ui/deref-patterns/mir.rs deleted file mode 100644 index 2e7d26d0dfd96..0000000000000 --- a/src/test/ui/deref-patterns/mir.rs +++ /dev/null @@ -1,12 +0,0 @@ -// compile-flags: -Z unpretty=mir -// build-pass -#![feature(deref_patterns)] - -fn main() { - let s = Some(String::new()); - let a; - match s { - Some("a") => a = 1234, - s => a = 4321, - } -} diff --git a/src/test/ui/deref-patterns/mir.stdout b/src/test/ui/deref-patterns/mir.stdout deleted file mode 100644 index e73d37efb24a2..0000000000000 --- a/src/test/ui/deref-patterns/mir.stdout +++ /dev/null @@ -1,99 +0,0 @@ -// WARNING: This output format is intended for human consumers only -// and is subject to change without notice. Knock yourself out. -fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/mir.rs:5:11: 5:11 - let _1: std::option::Option; // in scope 0 at $DIR/mir.rs:6:9: 6:10 - let mut _2: std::string::String; // in scope 0 at $DIR/mir.rs:6:18: 6:31 - let mut _4: &std::string::String; // in scope 0 at $DIR/mir.rs:9:14: 9:17 - let mut _5: &str; // in scope 0 at $DIR/mir.rs:9:14: 9:17 - let mut _6: bool; // in scope 0 at $DIR/mir.rs:9:14: 9:17 - let mut _7: isize; // in scope 0 at $DIR/mir.rs:9:9: 9:18 - let mut _9: bool; // in scope 0 at $DIR/mir.rs:12:1: 12:2 - scope 1 { - debug s => _1; // in scope 1 at $DIR/mir.rs:6:9: 6:10 - let _3: i32; // in scope 1 at $DIR/mir.rs:7:9: 7:10 - scope 2 { - debug a => _3; // in scope 2 at $DIR/mir.rs:7:9: 7:10 - let _8: std::option::Option; // in scope 2 at $DIR/mir.rs:10:9: 10:10 - scope 3 { - debug s => _8; // in scope 3 at $DIR/mir.rs:10:9: 10:10 - } - } - } - - bb0: { - _9 = const false; // scope 0 at $DIR/mir.rs:6:9: 6:10 - _2 = String::new() -> bb1; // scope 0 at $DIR/mir.rs:6:18: 6:31 - // mir::Constant - // + span: $DIR/mir.rs:6:18: 6:29 - // + literal: Const { ty: fn() -> String {String::new}, val: Value(Scalar()) } - } - - bb1: { - _9 = const true; // scope 0 at $DIR/mir.rs:6:13: 6:32 - Deinit(_1); // scope 0 at $DIR/mir.rs:6:13: 6:32 - ((_1 as Some).0: std::string::String) = move _2; // scope 0 at $DIR/mir.rs:6:13: 6:32 - discriminant(_1) = 1; // scope 0 at $DIR/mir.rs:6:13: 6:32 - _7 = discriminant(_1); // scope 2 at $DIR/mir.rs:8:11: 8:12 - switchInt(move _7) -> [1_isize: bb3, otherwise: bb2]; // scope 2 at $DIR/mir.rs:8:5: 8:12 - } - - bb2: { - _9 = const false; // scope 2 at $DIR/mir.rs:10:9: 10:10 - _8 = move _1; // scope 2 at $DIR/mir.rs:10:9: 10:10 - _3 = const 4321_i32; // scope 3 at $DIR/mir.rs:10:14: 10:22 - drop(_8) -> [return: bb7, unwind: bb12]; // scope 2 at $DIR/mir.rs:10:21: 10:22 - } - - bb3: { - _4 = &((_1 as Some).0: std::string::String); // scope 2 at $DIR/mir.rs:9:14: 9:17 - _5 = ::deref(move _4) -> bb4; // scope 2 at $DIR/mir.rs:9:14: 9:17 - // mir::Constant - // + span: $DIR/mir.rs:9:14: 9:17 - // + literal: Const { ty: for<'r> fn(&'r String) -> &'r ::Target {::deref}, val: Value(Scalar()) } - } - - bb4: { - _6 = ::eq(_5, const "a") -> [return: bb5, unwind: bb12]; // scope 2 at $DIR/mir.rs:9:14: 9:17 - // mir::Constant - // + span: $DIR/mir.rs:9:14: 9:17 - // + literal: Const { ty: for<'r, 's> fn(&'r str, &'s str) -> bool {::eq}, val: Value(Scalar()) } - // mir::Constant - // + span: $DIR/mir.rs:9:14: 9:17 - // + literal: Const { ty: &str, val: Value(Slice(..)) } - } - - bb5: { - switchInt(move _6) -> [false: bb2, otherwise: bb6]; // scope 2 at $DIR/mir.rs:9:14: 9:17 - } - - bb6: { - _3 = const 1234_i32; // scope 2 at $DIR/mir.rs:9:22: 9:30 - goto -> bb7; // scope 2 at $DIR/mir.rs:9:22: 9:30 - } - - bb7: { - switchInt(_9) -> [false: bb8, otherwise: bb10]; // scope 0 at $DIR/mir.rs:12:1: 12:2 - } - - bb8: { - _9 = const false; // scope 0 at $DIR/mir.rs:12:1: 12:2 - return; // scope 0 at $DIR/mir.rs:12:2: 12:2 - } - - bb9 (cleanup): { - resume; // scope 0 at $DIR/mir.rs:5:1: 12:2 - } - - bb10: { - drop(_1) -> bb8; // scope 0 at $DIR/mir.rs:12:1: 12:2 - } - - bb11 (cleanup): { - drop(_1) -> bb9; // scope 0 at $DIR/mir.rs:12:1: 12:2 - } - - bb12 (cleanup): { - switchInt(_9) -> [false: bb9, otherwise: bb11]; // scope 0 at $DIR/mir.rs:12:1: 12:2 - } -} diff --git a/src/test/ui/deref-patterns/refs.rs b/src/test/ui/deref-patterns/refs.rs new file mode 100644 index 0000000000000..6dac46c05fd08 --- /dev/null +++ b/src/test/ui/deref-patterns/refs.rs @@ -0,0 +1,18 @@ +// check-pass +#![feature(deref_patterns)] + +fn foo(s: &String) -> i32 { + match *s { + "a" => 42, + _ => -1, + } +} + +fn bar(s: Option<&&&&String>) -> i32 { + match s { + Some(&&&&"&&&&") => 1, + _ => -1, + } +} + +fn main() {} From 64a17a09a87118fdb80dae8bf993692d18ea9fa2 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Tue, 5 Jul 2022 16:56:16 +0000 Subject: [PATCH 5/6] Rm diagnostic item, use lang item --- .../src/fn_ctxt/suggestions.rs | 2 +- .../rustc_hir_typeck/src/method/suggest.rs | 4 +-- compiler/rustc_hir_typeck/src/op.rs | 4 +-- compiler/rustc_lint/src/non_fmt_panic.rs | 2 +- .../src/traits/error_reporting/mod.rs | 2 +- library/alloc/src/string.rs | 3 +- src/tools/clippy/clippy_lints/src/format.rs | 2 +- .../clippy_lints/src/format_push_string.rs | 6 ++-- .../clippy_lints/src/from_str_radix_10.rs | 6 ++-- .../clippy_lints/src/inherent_to_string.rs | 6 ++-- .../clippy/clippy_lints/src/manual_retain.rs | 4 +-- .../clippy_lints/src/manual_string_new.rs | 2 +- .../src/matches/match_str_case_mismatch.rs | 8 ++--- .../src/methods/bytes_count_to_len.rs | 5 ++-- .../clippy_lints/src/methods/bytes_nth.rs | 7 ++--- ...se_sensitive_file_extension_comparisons.rs | 8 ++--- .../src/methods/expect_fun_call.rs | 6 ++-- .../src/methods/inefficient_to_string.rs | 6 ++-- .../src/methods/manual_str_repeat.rs | 6 ++-- .../src/methods/no_effect_replace.rs | 7 ++--- .../clippy_lints/src/methods/repeat_once.rs | 7 ++--- .../src/methods/search_is_some.rs | 4 +-- .../src/methods/string_extend_chars.rs | 7 ++--- .../src/methods/unnecessary_join.rs | 8 ++--- .../src/needless_pass_by_value.rs | 6 ++-- src/tools/clippy/clippy_lints/src/ptr.rs | 2 +- .../clippy_lints/src/redundant_clone.rs | 6 ++-- src/tools/clippy/clippy_lints/src/strings.rs | 8 ++--- .../clippy_lints/src/types/box_collection.rs | 29 ++++++++++--------- .../clippy_lints/src/types/rc_buffer.rs | 8 ++--- .../src/unnecessary_owned_empty_strings.rs | 7 ++--- src/tools/clippy/clippy_utils/src/lib.rs | 15 ++++++++-- 32 files changed, 103 insertions(+), 100 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 06e6e4350fcbc..dbb8b1bb4a026 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -464,7 +464,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ref_cnt += 1; } if let ty::Adt(adt, _) = peeled.kind() - && self.tcx.is_diagnostic_item(sym::String, adt.did()) + && Some(adt.did()) == self.tcx.lang_items().string() { err.span_suggestion_verbose( expr.span.shrink_to_hi(), diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 19f56c738239b..2d9d89f78c3e6 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -817,10 +817,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty.is_str() || matches!( ty.kind(), - ty::Adt(adt, _) if self.tcx.is_diagnostic_item(sym::String, adt.did()) + ty::Adt(adt, _) if Some(adt.did()) == self.tcx.lang_items().string() ) } - ty::Adt(adt, _) => self.tcx.is_diagnostic_item(sym::String, adt.did()), + ty::Adt(adt, _) => Some(adt.did()) == self.tcx.lang_items().string(), _ => false, }; if is_string_or_ref_str && item_name.name == sym::iter { diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 38b3dd218a971..adc7a21f265a8 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -556,9 +556,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let rm_borrow_msg = "remove the borrow to obtain an owned `String`"; let to_owned_msg = "create an owned `String` from a string reference"; + let string_type = self.tcx.lang_items().string(); let is_std_string = |ty: Ty<'tcx>| { - ty.ty_adt_def() - .map_or(false, |ty_def| self.tcx.is_diagnostic_item(sym::String, ty_def.did())) + ty.ty_adt_def().map_or(false, |ty_def| Some(ty_def.did()) == string_type) }; match (lhs_ty.kind(), rhs_ty.kind()) { diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index 6ad2e0294b9b0..83e6f4e33bed8 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -148,7 +148,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc ty::Ref(_, r, _) if *r.kind() == ty::Str, ) || matches!( ty.ty_adt_def(), - Some(ty_def) if cx.tcx.is_diagnostic_item(sym::String, ty_def.did()), + Some(ty_def) if Some(ty_def.did()) == cx.tcx.lang_items().string(), ); let infcx = cx.tcx.infer_ctxt().build(); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 786cadaa6cefc..6bb88db41bdc9 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1705,7 +1705,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ty::Bool => Some(0), ty::Char => Some(1), ty::Str => Some(2), - ty::Adt(def, _) if tcx.is_diagnostic_item(sym::String, def.did()) => Some(2), + ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().string() => Some(2), ty::Int(..) | ty::Uint(..) | ty::Float(..) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 5799ef778c4f6..7a8e6f088f3ac 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -362,9 +362,8 @@ use crate::vec::Vec; /// [`Deref`]: core::ops::Deref "ops::Deref" /// [`as_str()`]: String::as_str #[derive(PartialOrd, Eq, Ord)] -#[cfg_attr(not(test), rustc_diagnostic_item = "String")] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), lang = "String")] +#[cfg_attr(all(not(bootstrap), not(test)), lang = "String")] pub struct String { vec: Vec, } diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs index bc0c68f535a96..d0fab69496040 100644 --- a/src/tools/clippy/clippy_lints/src/format.rs +++ b/src/tools/clippy/clippy_lints/src/format.rs @@ -73,7 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { if format_args.format_string.parts == [kw::Empty]; if arg.format.is_default(); if match cx.typeck_results().expr_ty(value).peel_refs().kind() { - ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::String, adt.did()), + ty::Adt(adt, _) => Some(adt.did()) == cx.tcx.lang_items().string(), ty::Str => true, _ => false, }; diff --git a/src/tools/clippy/clippy_lints/src/format_push_string.rs b/src/tools/clippy/clippy_lints/src/format_push_string.rs index 9b9f1872bfc1d..68c5c3673fe15 100644 --- a/src/tools/clippy/clippy_lints/src/format_push_string.rs +++ b/src/tools/clippy/clippy_lints/src/format_push_string.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::is_type_lang_item; use clippy_utils::{match_def_path, paths, peel_hir_expr_refs}; -use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -41,7 +41,7 @@ declare_clippy_lint! { declare_lint_pass!(FormatPushString => [FORMAT_PUSH_STRING]); fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { - is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), sym::String) + is_type_lang_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), LangItem::String) } fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { if let Some(macro_def_id) = e.span.ctxt().outer_expn_data().macro_def_id { diff --git a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs index cf8b7acd66d22..74a60b6a0d24b 100644 --- a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs +++ b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_integer_literal; use clippy_utils::sugg::Sugg; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{def, Expr, ExprKind, PrimTy, QPath, TyKind}; +use rustc_hir::{def, Expr, ExprKind, LangItem, PrimTy, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -98,5 +98,5 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 { /// Checks if a Ty is `String` or `&str` fn is_ty_stringish(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - is_type_diagnostic_item(cx, ty, sym::String) || is_type_diagnostic_item(cx, ty, sym::str) + is_type_lang_item(cx, ty, LangItem::String) || is_type_diagnostic_item(cx, ty, sym::str) } diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs index 14a37f535b46c..aaecc4fa8f256 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::ty::{implements_trait, is_type_lang_item}; use clippy_utils::{return_ty, trait_ref_of_method}; use if_chain::if_chain; -use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind}; +use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString { if impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })); // Check if return type is String - if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::String); + if is_type_lang_item(cx, return_ty(cx, impl_item.hir_id()), LangItem::String); // Filters instances of to_string which are required by a trait if trait_ref_of_method(cx, impl_item.owner_id.def_id).is_none(); diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs index 6abbab278feb4..d6438ca7fec2a 100644 --- a/src/tools/clippy/clippy_lints/src/manual_retain.rs +++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::{get_parent_expr, match_def_path, paths, SpanlessEq}; use clippy_utils::{meets_msrv, msrvs}; use rustc_errors::Applicability; @@ -140,7 +140,7 @@ fn check_to_owned( && let Some(chars_expr_def_id) = cx.typeck_results().type_dependent_def_id(chars_expr.hir_id) && match_def_path(cx, chars_expr_def_id, &paths::STR_CHARS) && let ty = cx.typeck_results().expr_ty(str_expr).peel_refs() - && is_type_diagnostic_item(cx, ty, sym::String) + && is_type_lang_item(cx, ty, hir::LangItem::String) && SpanlessEq::new(cx).eq_expr(left_expr, str_expr) { suggest(cx, parent_expr, left_expr, filter_expr); } diff --git a/src/tools/clippy/clippy_lints/src/manual_string_new.rs b/src/tools/clippy/clippy_lints/src/manual_string_new.rs index 6acfb2ae3471c..c20d7959fc4a2 100644 --- a/src/tools/clippy/clippy_lints/src/manual_string_new.rs +++ b/src/tools/clippy/clippy_lints/src/manual_string_new.rs @@ -44,7 +44,7 @@ impl LateLintPass<'_> for ManualStringNew { let ty = cx.typeck_results().expr_ty(expr); match ty.kind() { ty::Adt(adt_def, _) if adt_def.is_struct() => { - if !cx.tcx.is_diagnostic_item(sym::String, adt_def.did()) { + if cx.tcx.lang_items().string() != Some(adt_def.did()) { return; } }, diff --git a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs index 6647322caa37a..675a85ae5553a 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::is_type_lang_item; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{Arm, Expr, ExprKind, PatKind}; +use rustc_hir::{Arm, Expr, ExprKind, LangItem, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::symbol::Symbol; -use rustc_span::{sym, Span}; +use rustc_span::Span; use super::MATCH_STR_CASE_MISMATCH; @@ -59,7 +59,7 @@ impl<'a, 'tcx> MatchExprVisitor<'a, 'tcx> { if let Some(case_method) = get_case_method(segment_ident) { let ty = self.cx.typeck_results().expr_ty(receiver).peel_refs(); - if is_type_diagnostic_item(self.cx, ty, sym::String) || ty.kind() == &ty::Str { + if is_type_lang_item(self.cx, ty, LangItem::String) || ty.kind() == &ty::Str { self.case_method = Some(case_method); return true; } diff --git a/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs b/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs index fcfc25b523dac..89aaad359d4ac 100644 --- a/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs +++ b/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs @@ -1,11 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::is_type_lang_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::sym; use super::BYTES_COUNT_TO_LEN; @@ -20,7 +19,7 @@ pub(super) fn check<'tcx>( if let Some(impl_id) = cx.tcx.impl_of_method(bytes_id); if cx.tcx.type_of(impl_id).is_str(); let ty = cx.typeck_results().expr_ty(bytes_recv).peel_refs(); - if ty.is_str() || is_type_diagnostic_item(cx, ty, sym::String); + if ty.is_str() || is_type_lang_item(cx, ty, hir::LangItem::String); then { let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs index 2e96346be977e..d512cc4eeae12 100644 --- a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs +++ b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs @@ -1,10 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::is_type_lang_item; use rustc_errors::Applicability; -use rustc_hir::Expr; +use rustc_hir::{Expr, LangItem}; use rustc_lint::LateContext; -use rustc_span::sym; use super::BYTES_NTH; @@ -12,7 +11,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E let ty = cx.typeck_results().expr_ty(recv).peel_refs(); let caller_type = if ty.is_str() { "str" - } else if is_type_diagnostic_item(cx, ty, sym::String) { + } else if is_type_lang_item(cx, ty, LangItem::String) { "String" } else { return; diff --git a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index b3c2c7c9a2dcc..d226c0bba6593 100644 --- a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::is_type_lang_item; use if_chain::if_chain; use rustc_ast::ast::LitKind; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::LateContext; -use rustc_span::{source_map::Spanned, symbol::sym, Span}; +use rustc_span::{source_map::Spanned, Span}; use super::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS; @@ -26,7 +26,7 @@ pub(super) fn check<'tcx>( if ext_str.chars().skip(1).all(|c| c.is_uppercase() || c.is_ascii_digit()) || ext_str.chars().skip(1).all(|c| c.is_lowercase() || c.is_ascii_digit()); let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs(); - if recv_ty.is_str() || is_type_diagnostic_item(cx, recv_ty, sym::String); + if recv_ty.is_str() || is_type_lang_item(cx, recv_ty, LangItem::String); then { span_lint_and_help( cx, diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs index d0cf411dfd34c..a9189b31c5710 100644 --- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -33,7 +33,7 @@ pub(super) fn check<'tcx>( if (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref) && { let arg_type = cx.typeck_results().expr_ty(receiver); let base_type = arg_type.peel_refs(); - *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::String) + *base_type.kind() == ty::Str || is_type_lang_item(cx, base_type, hir::LangItem::String) } { receiver } else { @@ -50,7 +50,7 @@ pub(super) fn check<'tcx>( // converted to string. fn requires_to_string(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool { let arg_ty = cx.typeck_results().expr_ty(arg); - if is_type_diagnostic_item(cx, arg_ty, sym::String) { + if is_type_lang_item(cx, arg_ty, hir::LangItem::String) { return false; } if let ty::Ref(_, ty, ..) = arg_ty.kind() { diff --git a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs index ede3b8bb74e97..4f4f543e8a912 100644 --- a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs +++ b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::{is_type_diagnostic_item, walk_ptrs_ty_depth}; +use clippy_utils::ty::{is_type_lang_item, walk_ptrs_ty_depth}; use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{Symbol, sym}; use super::INEFFICIENT_TO_STRING; @@ -60,7 +60,7 @@ fn specializes_tostring(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { return true; } - if is_type_diagnostic_item(cx, ty, sym::String) { + if is_type_lang_item(cx, ty, hir::LangItem::String) { return true; } diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs index 8b6b8f1bf16cb..13c47c03a80dd 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs @@ -36,14 +36,14 @@ fn parse_repeat_arg(cx: &LateContext<'_>, e: &Expr<'_>) -> Option { } } else { let ty = cx.typeck_results().expr_ty(e); - if is_type_diagnostic_item(cx, ty, sym::String) + if is_type_lang_item(cx, ty, LangItem::String) || (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).map_or(false, Ty::is_str)) || (is_type_diagnostic_item(cx, ty, sym::Cow) && get_ty_param(ty).map_or(false, Ty::is_str)) { Some(RepeatKind::String) } else { let ty = ty.peel_refs(); - (ty.is_str() || is_type_diagnostic_item(cx, ty, sym::String)).then_some(RepeatKind::String) + (ty.is_str() || is_type_lang_item(cx, ty, LangItem::String)).then_some(RepeatKind::String) } } } @@ -58,7 +58,7 @@ pub(super) fn check( if_chain! { if let ExprKind::Call(repeat_fn, [repeat_arg]) = take_self_arg.kind; if is_path_diagnostic_item(cx, repeat_fn, sym::iter_repeat); - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(collect_expr), sym::String); + if is_type_lang_item(cx, cx.typeck_results().expr_ty(collect_expr), LangItem::String); if let Some(collect_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id); if let Some(take_id) = cx.typeck_results().type_dependent_def_id(take_expr.hir_id); if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator); diff --git a/src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs b/src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs index a76341855b6db..01655e860c43f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs +++ b/src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs @@ -1,11 +1,10 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::is_type_lang_item; use clippy_utils::SpanlessEq; use if_chain::if_chain; use rustc_ast::LitKind; -use rustc_hir::ExprKind; +use rustc_hir::{ExprKind, LangItem}; use rustc_lint::LateContext; -use rustc_span::sym; use super::NO_EFFECT_REPLACE; @@ -16,7 +15,7 @@ pub(super) fn check<'tcx>( arg2: &'tcx rustc_hir::Expr<'_>, ) { let ty = cx.typeck_results().expr_ty(expr).peel_refs(); - if !(ty.is_str() || is_type_diagnostic_item(cx, ty, sym::String)) { + if !(ty.is_str() || is_type_lang_item(cx, ty, LangItem::String)) { return; } diff --git a/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs b/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs index 0a14f9216ab38..a345ec813ff50 100644 --- a/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs +++ b/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs @@ -1,11 +1,10 @@ use clippy_utils::consts::{constant_context, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::is_type_lang_item; use rustc_errors::Applicability; -use rustc_hir::Expr; +use rustc_hir::{Expr, LangItem}; use rustc_lint::LateContext; -use rustc_span::sym; use super::REPEAT_ONCE; @@ -37,7 +36,7 @@ pub(super) fn check<'tcx>( format!("{}.to_vec()", snippet(cx, recv.span, r#""...""#)), Applicability::MachineApplicable, ); - } else if is_type_diagnostic_item(cx, ty, sym::String) { + } else if is_type_lang_item(cx, ty, LangItem::String) { span_lint_and_sugg( cx, REPEAT_ONCE, diff --git a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs index 324c9c17b5a9a..1c031ad6acbaf 100644 --- a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs +++ b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::deref_closure_args; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::is_type_lang_item; use clippy_utils::{is_trait_method, strip_pat_refs}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -105,7 +105,7 @@ pub(super) fn check<'tcx>( else if search_method == "find" { let is_string_or_str_slice = |e| { let self_ty = cx.typeck_results().expr_ty(e).peel_refs(); - if is_type_diagnostic_item(cx, self_ty, sym::String) { + if is_type_lang_item(cx, self_ty, hir::LangItem::String) { true } else { *self_ty.kind() == ty::Str diff --git a/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs b/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs index 6974260f70dbd..6f4cec546e969 100644 --- a/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs +++ b/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs @@ -1,18 +1,17 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::method_chain_args; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::is_type_lang_item; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::symbol::sym; use super::STRING_EXTEND_CHARS; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) { let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); - if !is_type_diagnostic_item(cx, obj_ty, sym::String) { + if !is_type_lang_item(cx, obj_ty, hir::LangItem::String) { return; } if let Some(arglists) = method_chain_args(arg, &["chars"]) { @@ -20,7 +19,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr let self_ty = cx.typeck_results().expr_ty(target).peel_refs(); let ref_str = if *self_ty.kind() == ty::Str { "" - } else if is_type_diagnostic_item(cx, self_ty, sym::String) { + } else if is_type_lang_item(cx, self_ty, hir::LangItem::String) { "&" } else { return; diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs index 973b8a7e6bf6a..c9b87bc6bf29d 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs @@ -1,10 +1,10 @@ -use clippy_utils::{diagnostics::span_lint_and_sugg, ty::is_type_diagnostic_item}; +use clippy_utils::{diagnostics::span_lint_and_sugg, ty::is_type_lang_item}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::LateContext; use rustc_middle::ty::{Ref, Slice}; -use rustc_span::{sym, Span}; +use rustc_span::Span; use super::UNNECESSARY_JOIN; @@ -21,7 +21,7 @@ pub(super) fn check<'tcx>( // the turbofish for collect is ::> if let Ref(_, ref_type, _) = collect_output_adjusted_type.kind(); if let Slice(slice) = ref_type.kind(); - if is_type_diagnostic_item(cx, *slice, sym::String); + if is_type_lang_item(cx, *slice, LangItem::String); // the argument for join is "" if let ExprKind::Lit(spanned) = &join_arg.kind; if let LitKind::Str(symbol, _) = spanned.node; diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index b2e9ce5c94d65..79aa15b06ef4d 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::ptr::get_spans; use clippy_utils::source::{snippet, snippet_opt}; -use clippy_utils::ty::{implements_trait, is_copy, is_type_diagnostic_item}; +use clippy_utils::ty::{implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::{get_trait_def_id, is_self, paths}; use if_chain::if_chain; use rustc_ast::ast::Attribute; @@ -11,7 +11,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{ BindingAnnotation, Body, FnDecl, GenericArg, HirId, Impl, ItemKind, Mutability, Node, PatKind, QPath, TyKind, }; -use rustc_hir::{HirIdMap, HirIdSet}; +use rustc_hir::{HirIdMap, HirIdSet, LangItem}; use rustc_hir_typeck::expr_use_visitor as euv; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; @@ -249,7 +249,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { } } - if is_type_diagnostic_item(cx, ty, sym::String) { + if is_type_lang_item(cx, ty, LangItem::String) { if let Some(clone_spans) = get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")]) { diag.span_suggestion( diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 0d74c90a834f7..612ee8a55a66a 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -450,7 +450,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>( substs.type_at(0), ), ), - Some(sym::String) => ( + _ if Some(adt.did()) == cx.tcx.lang_items().string() => ( [("clone", ".to_owned()"), ("as_str", "")].as_slice(), DerefTy::Str, ), diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs index aedbe08e3e46e..c1677fb3da1c4 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; use clippy_utils::mir::{visit_local_usage, LocalUsage, PossibleBorrowerMap}; use clippy_utils::source::snippet_opt; -use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, walk_ptrs_ty_depth}; +use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, is_type_lang_item, walk_ptrs_ty_depth}; use clippy_utils::{fn_has_unsatisfiable_preds, match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; -use rustc_hir::{def_id, Body, FnDecl, HirId}; +use rustc_hir::{def_id, Body, FnDecl, HirId, LangItem}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir; use rustc_middle::ty::{self, Ty}; @@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { let from_borrow = match_def_path(cx, fn_def_id, &paths::CLONE_TRAIT_METHOD) || match_def_path(cx, fn_def_id, &paths::TO_OWNED_METHOD) || (match_def_path(cx, fn_def_id, &paths::TO_STRING_METHOD) - && is_type_diagnostic_item(cx, arg_ty, sym::String)); + && is_type_lang_item(cx, arg_ty, LangItem::String)); let from_deref = !from_borrow && (match_def_path(cx, fn_def_id, &paths::PATH_TO_PATH_BUF) diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index d356c99c8fc47..f4705481d4e69 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_with_applicability}; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::is_type_lang_item; use clippy_utils::{get_parent_expr, is_lint_allowed, match_function_call, method_calls, paths}; use clippy_utils::{peel_blocks, SpanlessEq}; use if_chain::if_chain; @@ -190,7 +190,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd { }, ExprKind::Index(target, _idx) => { let e_ty = cx.typeck_results().expr_ty(target).peel_refs(); - if matches!(e_ty.kind(), ty::Str) || is_type_diagnostic_item(cx, e_ty, sym::String) { + if matches!(e_ty.kind(), ty::Str) || is_type_lang_item(cx, e_ty, LangItem::String) { span_lint( cx, STRING_SLICE, @@ -205,7 +205,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd { } fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { - is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), sym::String) + is_type_lang_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), LangItem::String) } fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool { @@ -446,7 +446,7 @@ impl<'tcx> LateLintPass<'tcx> for StringToString { if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind; if path.ident.name == sym::to_string; let ty = cx.typeck_results().expr_ty(self_arg); - if is_type_diagnostic_item(cx, ty, sym::String); + if is_type_lang_item(cx, ty, LangItem::String); then { span_lint_and_help( cx, diff --git a/src/tools/clippy/clippy_lints/src/types/box_collection.rs b/src/tools/clippy/clippy_lints/src/types/box_collection.rs index 08020ce663817..802415e163df5 100644 --- a/src/tools/clippy/clippy_lints/src/types/box_collection.rs +++ b/src/tools/clippy/clippy_lints/src/types/box_collection.rs @@ -37,18 +37,19 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ fn get_std_collection(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option { let param = qpath_generic_tys(qpath).next()?; let id = path_def_id(cx, param)?; - cx.tcx.get_diagnostic_name(id).filter(|&name| { - matches!( - name, - sym::HashMap - | sym::String - | sym::Vec - | sym::HashSet - | sym::VecDeque - | sym::LinkedList - | sym::BTreeMap - | sym::BTreeSet - | sym::BinaryHeap - ) - }) + cx.tcx + .get_diagnostic_name(id) + .filter(|&name| matches!(name, sym::HashMap | sym::Vec | sym::HashSet + | sym::VecDeque + | sym::LinkedList + | sym::BTreeMap + | sym::BTreeSet + | sym::BinaryHeap)) + .or_else(|| { + cx.tcx + .lang_items() + .string() + .filter(|did| id == *did) + .map(|_| sym::String) + }) } diff --git a/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs b/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs index fa567b9b2d243..855137b14d84b 100644 --- a/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs +++ b/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs @@ -91,10 +91,10 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ fn match_buffer_type(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<&'static str> { let ty = qpath_generic_tys(qpath).next()?; let id = path_def_id(cx, ty)?; - let path = match cx.tcx.get_diagnostic_name(id)? { - sym::String => "str", - sym::OsString => "std::ffi::OsStr", - sym::PathBuf => "std::path::Path", + let path = match cx.tcx.get_diagnostic_name(id) { + Some(sym::OsString) => "std::ffi::OsStr", + Some(sym::PathBuf) => "std::path::Path", + _ if Some(id) == cx.tcx.lang_items().string() => "str", _ => return None, }; Some(path) diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs index ab73f0fc44f4e..9f207d32fcfff 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs @@ -1,13 +1,12 @@ -use clippy_utils::{diagnostics::span_lint_and_sugg, ty::is_type_diagnostic_item}; +use clippy_utils::{diagnostics::span_lint_and_sugg, ty::is_type_lang_item}; use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability}; +use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -61,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryOwnedEmptyStrings { if let LitKind::Str(symbol, _) = spanned.node; if symbol.is_empty(); let inner_expr_type = cx.typeck_results().expr_ty(inner_expr); - if is_type_diagnostic_item(cx, inner_expr_type, sym::String); + if is_type_lang_item(cx, inner_expr_type, LangItem::String); then { span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index d32cf1a793672..fac91dfdbda01 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -434,6 +434,16 @@ pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[ path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, segments)) } +/// If `maybe_path` is a path node which resolves to an item, resolves it to a `DefId` and checks if +/// it matches the given lang item. +pub fn is_path_lang_item<'tcx>( + cx: &LateContext<'_>, + maybe_path: &impl MaybePath<'tcx>, + lang_item: LangItem, +) -> bool { + path_def_id(cx, maybe_path).map_or(false, |id| cx.tcx.lang_items().get(lang_item) == Some(id)) +} + /// If `maybe_path` is a path node which resolves to an item, resolves it to a `DefId` and checks if /// it matches the given diagnostic item. pub fn is_path_diagnostic_item<'tcx>( @@ -760,7 +770,6 @@ pub fn can_mut_borrow_both(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>) - /// constructor from the std library fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<'_>) -> bool { let std_types_symbols = &[ - sym::String, sym::Vec, sym::VecDeque, sym::LinkedList, @@ -777,7 +786,7 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath< if let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def() { return std_types_symbols .iter() - .any(|&symbol| cx.tcx.is_diagnostic_item(symbol, adt.did())); + .any(|&symbol| cx.tcx.is_diagnostic_item(symbol, adt.did()) || Some(adt.did()) == cx.tcx.lang_items().string()); } } } @@ -834,7 +843,7 @@ fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: & ExprKind::Lit(hir::Lit { node: LitKind::Str(ref sym, _), .. - }) => return sym.is_empty() && is_path_diagnostic_item(cx, ty, sym::String), + }) => return sym.is_empty() && is_path_lang_item(cx, ty, LangItem::String), ExprKind::Array([]) => return is_path_diagnostic_item(cx, ty, sym::Vec), ExprKind::Repeat(_, ArrayLen::Body(len)) => { if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(len.body).value.kind && From bc51f8783cdbee5a1ed121f017ec7360d9be9124 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 11 Nov 2022 14:31:07 +0000 Subject: [PATCH 6/6] rename to `string_deref_patterns` --- compiler/rustc_feature/src/active.rs | 4 ++-- compiler/rustc_hir_typeck/src/pat.rs | 2 +- compiler/rustc_mir_build/src/build/matches/test.rs | 4 ++-- compiler/rustc_span/src/symbol.rs | 2 +- src/test/mir-opt/deref-patterns/string.rs | 2 +- src/test/ui/deref-patterns/basic.rs | 2 +- src/test/ui/deref-patterns/default-infer.rs | 2 +- src/test/ui/deref-patterns/gate.rs | 2 +- src/test/ui/deref-patterns/refs.rs | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 3a1db1193b3dd..ae49a76a08783 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -376,8 +376,6 @@ declare_features! ( (active, deprecated_safe, "1.61.0", Some(94978), None), /// Allows having using `suggestion` in the `#[deprecated]` attribute. (active, deprecated_suggestion, "1.61.0", Some(94785), None), - /// Allows patterns to dereference values to match them. - (active, deref_patterns, "1.64.0", Some(87121), None), /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. (active, doc_auto_cfg, "1.58.0", Some(43781), None), /// Allows `#[doc(cfg(...))]`. @@ -508,6 +506,8 @@ declare_features! ( (active, stmt_expr_attributes, "1.6.0", Some(15701), None), /// Allows lints part of the strict provenance effort. (active, strict_provenance, "1.61.0", Some(95228), None), + /// Allows string patterns to dereference values to match them. + (active, string_deref_patterns, "CURRENT_RUSTC_VERSION", Some(87121), None), /// Allows the use of `#[target_feature]` on safe functions. (active, target_feature_11, "1.45.0", Some(69098), None), /// Allows using `#[thread_local]` on `static` items. diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index b20949bcbd54a..4e3194501dc35 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -401,7 +401,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - if self.tcx.features().deref_patterns && let hir::ExprKind::Lit(Spanned { node: ast::LitKind::Str(..), .. }) = lt.kind { + if self.tcx.features().string_deref_patterns && let hir::ExprKind::Lit(Spanned { node: ast::LitKind::Str(..), .. }) = lt.kind { let tcx = self.tcx; let expected = self.resolve_vars_if_possible(expected); pat_ty = match expected.kind() { diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index e6c01b72b1bfe..af0d7879c576a 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -242,8 +242,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TestKind::Eq { value, ty } => { let tcx = self.tcx; if let ty::Adt(def, _) = ty.kind() && Some(def.did()) == tcx.lang_items().string() { - if !tcx.features().deref_patterns { - bug!("matching on `String` went through without enabling deref_patterns"); + if !tcx.features().string_deref_patterns { + bug!("matching on `String` went through without enabling string_deref_patterns"); } let re_erased = tcx.lifetimes.re_erased; let ref_string = self.temp(tcx.mk_imm_ref(re_erased, ty), test.span); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index a06e613b82f46..ec393ce5030fd 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -597,7 +597,6 @@ symbols! { deref, deref_method, deref_mut, - deref_patterns, deref_target, derive, derive_const, @@ -1406,6 +1405,7 @@ symbols! { str_trim_end, str_trim_start, strict_provenance, + string_deref_patterns, stringify, struct_field_attributes, struct_inherit, diff --git a/src/test/mir-opt/deref-patterns/string.rs b/src/test/mir-opt/deref-patterns/string.rs index 2557f75b267a6..3a99c44aa0e18 100644 --- a/src/test/mir-opt/deref-patterns/string.rs +++ b/src/test/mir-opt/deref-patterns/string.rs @@ -1,6 +1,6 @@ // compile-flags: -Z mir-opt-level=0 -C panic=abort -#![feature(deref_patterns)] +#![feature(string_deref_patterns)] #![crate_type = "lib"] // EMIT_MIR string.foo.PreCodegen.after.mir diff --git a/src/test/ui/deref-patterns/basic.rs b/src/test/ui/deref-patterns/basic.rs index e03f2455954f8..249716040a177 100644 --- a/src/test/ui/deref-patterns/basic.rs +++ b/src/test/ui/deref-patterns/basic.rs @@ -1,6 +1,6 @@ // run-pass // check-run-results -#![feature(deref_patterns)] +#![feature(string_deref_patterns)] fn main() { test(Some(String::from("42"))); diff --git a/src/test/ui/deref-patterns/default-infer.rs b/src/test/ui/deref-patterns/default-infer.rs index b7155b7efffee..050b847305b16 100644 --- a/src/test/ui/deref-patterns/default-infer.rs +++ b/src/test/ui/deref-patterns/default-infer.rs @@ -1,5 +1,5 @@ // check-pass -#![feature(deref_patterns)] +#![feature(string_deref_patterns)] fn main() { match <_ as Default>::default() { diff --git a/src/test/ui/deref-patterns/gate.rs b/src/test/ui/deref-patterns/gate.rs index 90d0448e94a5f..ff50e30dea8c8 100644 --- a/src/test/ui/deref-patterns/gate.rs +++ b/src/test/ui/deref-patterns/gate.rs @@ -1,4 +1,4 @@ -// gate-test-deref_patterns +// gate-test-string_deref_patterns fn main() { match String::new() { "" | _ => {} diff --git a/src/test/ui/deref-patterns/refs.rs b/src/test/ui/deref-patterns/refs.rs index 6dac46c05fd08..97e260d2752bb 100644 --- a/src/test/ui/deref-patterns/refs.rs +++ b/src/test/ui/deref-patterns/refs.rs @@ -1,5 +1,5 @@ // check-pass -#![feature(deref_patterns)] +#![feature(string_deref_patterns)] fn foo(s: &String) -> i32 { match *s {