Minimal implementation of implicit deref patterns
This commit is contained in:
parent
7c75fe4c85
commit
b2cb42d6a7
@ -302,6 +302,8 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
|
||||
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 {
|
||||
|
@ -401,6 +401,16 @@ fn check_pat_lit(
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -240,6 +240,39 @@ pub(super) fn perform_test(
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -364,6 +364,7 @@
|
||||
#[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<u8>,
|
||||
}
|
||||
|
16
src/test/ui/deref-patterns/basic.rs
Normal file
16
src/test/ui/deref-patterns/basic.rs
Normal file
@ -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<String>) {
|
||||
match o {
|
||||
Some("42") => println!("the answer"),
|
||||
Some(_) => println!("something else?"),
|
||||
None => println!("nil"),
|
||||
}
|
||||
}
|
3
src/test/ui/deref-patterns/basic.run.stdout
Normal file
3
src/test/ui/deref-patterns/basic.run.stdout
Normal file
@ -0,0 +1,3 @@
|
||||
the answer
|
||||
something else?
|
||||
nil
|
10
src/test/ui/deref-patterns/mir.rs
Normal file
10
src/test/ui/deref-patterns/mir.rs
Normal file
@ -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,
|
||||
}
|
||||
}
|
99
src/test/ui/deref-patterns/mir.stdout
Normal file
99
src/test/ui/deref-patterns/mir.stdout
Normal file
@ -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<std::string::String>; // 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<std::string::String>; // 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(<ZST>)) }
|
||||
}
|
||||
|
||||
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 = <String as Deref>::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 <String as Deref>::Target {<String as Deref>::deref}, val: Value(Scalar(<ZST>)) }
|
||||
}
|
||||
|
||||
bb4: {
|
||||
_6 = <str as PartialEq>::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 {<str as PartialEq>::eq}, val: Value(Scalar(<ZST>)) }
|
||||
// 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
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user