-
Notifications
You must be signed in to change notification settings - Fork 13.8k
Minimal implementation of implicit deref patterns for Strings #98914
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b2cb42d
0537d30
d1c6b79
c74f155
64a17a0
bc51f87
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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().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); | ||
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) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// MIR for `foo` after PreCodegen | ||
|
||
fn foo(_1: Option<String>) -> 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<std::string::String>; // 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 = <String as Deref>::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 <String as Deref>::Target {<String as Deref>::deref}, val: Value(<ZST>) } | ||
} | ||
|
||
bb3: { | ||
_4 = <str as PartialEq>::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 {<str as PartialEq>::eq}, val: Value(<ZST>) } | ||
// 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 | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// compile-flags: -Z mir-opt-level=0 -C panic=abort | ||
|
||
#![feature(string_deref_patterns)] | ||
#![crate_type = "lib"] | ||
|
||
// EMIT_MIR string.foo.PreCodegen.after.mir | ||
pub fn foo(s: Option<String>) -> i32 { | ||
match s { | ||
Some("a") => 1234, | ||
s => 4321, | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// run-pass | ||
// check-run-results | ||
#![feature(string_deref_patterns)] | ||
|
||
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"), | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
the answer | ||
something else? | ||
nil |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// check-pass | ||
#![feature(string_deref_patterns)] | ||
|
||
fn main() { | ||
match <_ as Default>::default() { | ||
"" => (), | ||
_ => unreachable!(), | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
// gate-test-string_deref_patterns | ||
fn main() { | ||
match String::new() { | ||
"" | _ => {} | ||
//~^ mismatched types | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
error[E0308]: mismatched types | ||
--> $DIR/gate.rs:4: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`. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// check-pass | ||
#![feature(string_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() {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you need to check the feature flag here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if it falls through to the statements below it would ICE anyways. I will add a
bug!
statement just to make sure that the feature flag is enabled.