register DerefMut
bounds for implicit mutable derefs
This commit is contained in:
parent
e4b7b3d820
commit
91d0b579f0
6 changed files with 100 additions and 18 deletions
|
@ -344,6 +344,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let ty = self.check_pat_inner(pat, opt_path_res, adjust_mode, expected, pat_info);
|
let ty = self.check_pat_inner(pat, opt_path_res, adjust_mode, expected, pat_info);
|
||||||
self.write_ty(pat.hir_id, ty);
|
self.write_ty(pat.hir_id, ty);
|
||||||
|
|
||||||
|
// If we implicitly inserted overloaded dereferences before matching, check the pattern to
|
||||||
|
// see if the dereferenced types need `DerefMut` bounds.
|
||||||
|
if let Some(derefed_tys) = self.typeck_results.borrow().pat_adjustments().get(pat.hir_id)
|
||||||
|
&& derefed_tys.iter().any(|adjust| adjust.kind == PatAdjust::OverloadedDeref)
|
||||||
|
{
|
||||||
|
self.register_deref_mut_bounds_if_needed(
|
||||||
|
pat.span,
|
||||||
|
pat,
|
||||||
|
derefed_tys.iter().filter_map(|adjust| match adjust.kind {
|
||||||
|
PatAdjust::OverloadedDeref => Some(adjust.source),
|
||||||
|
PatAdjust::BuiltinDeref => None,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// (note_1): In most of the cases where (note_1) is referenced
|
// (note_1): In most of the cases where (note_1) is referenced
|
||||||
// (literals and constants being the exception), we relate types
|
// (literals and constants being the exception), we relate types
|
||||||
// using strict equality, even though subtyping would be sufficient.
|
// using strict equality, even though subtyping would be sufficient.
|
||||||
|
@ -483,7 +498,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// requirement that `expected: DerefPure`.
|
// requirement that `expected: DerefPure`.
|
||||||
let inner_ty = self.deref_pat_target(pat.span, expected);
|
let inner_ty = self.deref_pat_target(pat.span, expected);
|
||||||
// Once we've checked `pat`, we'll add a `DerefMut` bound if it contains any
|
// Once we've checked `pat`, we'll add a `DerefMut` bound if it contains any
|
||||||
// `ref mut` bindings. TODO: implement that, then reference here.
|
// `ref mut` bindings. See `Self::register_deref_mut_bounds_if_needed`.
|
||||||
|
|
||||||
// Preserve the smart pointer type for THIR lowering and upvar analysis.
|
// Preserve the smart pointer type for THIR lowering and upvar analysis.
|
||||||
self.typeck_results
|
self.typeck_results
|
||||||
|
@ -2315,20 +2330,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
let target_ty = self.deref_pat_target(span, expected);
|
let target_ty = self.deref_pat_target(span, expected);
|
||||||
self.check_pat(inner, target_ty, pat_info);
|
self.check_pat(inner, target_ty, pat_info);
|
||||||
|
self.register_deref_mut_bounds_if_needed(span, inner, [expected]);
|
||||||
// Check if the pattern has any `ref mut` bindings, which would require
|
|
||||||
// `DerefMut` to be emitted in MIR building instead of just `Deref`.
|
|
||||||
// We do this *after* checking the inner pattern, since we want to make
|
|
||||||
// sure to apply any match-ergonomics adjustments.
|
|
||||||
// TODO: move this to a separate definition to share it with implicit deref pats
|
|
||||||
if self.typeck_results.borrow().pat_has_ref_mut_binding(inner) {
|
|
||||||
self.register_bound(
|
|
||||||
expected,
|
|
||||||
self.tcx.require_lang_item(hir::LangItem::DerefMut, Some(span)),
|
|
||||||
self.misc(span),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
expected
|
expected
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2350,6 +2352,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
self.try_structurally_resolve_type(span, target_ty)
|
self.try_structurally_resolve_type(span, target_ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if the interior of a deref pattern (either explicit or implicit) has any `ref mut`
|
||||||
|
/// bindings, which would require `DerefMut` to be emitted in MIR building instead of just
|
||||||
|
/// `Deref`. We do this *after* checking the inner pattern, since we want to make sure to
|
||||||
|
/// account for `ref mut` binding modes inherited from implicitly dereferencing `&mut` refs.
|
||||||
|
fn register_deref_mut_bounds_if_needed(
|
||||||
|
&self,
|
||||||
|
span: Span,
|
||||||
|
inner: &'tcx Pat<'tcx>,
|
||||||
|
derefed_tys: impl IntoIterator<Item = Ty<'tcx>>,
|
||||||
|
) {
|
||||||
|
if self.typeck_results.borrow().pat_has_ref_mut_binding(inner) {
|
||||||
|
for mutably_derefed_ty in derefed_tys {
|
||||||
|
self.register_bound(
|
||||||
|
mutably_derefed_ty,
|
||||||
|
self.tcx.require_lang_item(hir::LangItem::DerefMut, Some(span)),
|
||||||
|
self.misc(span),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Precondition: Pat is Ref(inner)
|
// Precondition: Pat is Ref(inner)
|
||||||
fn check_pat_ref(
|
fn check_pat_ref(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -51,6 +51,7 @@ fn nested_vec(vecvec: Vec<Vec<u32>>) -> u32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(explicit)]
|
||||||
fn ref_mut(val: u32) -> u32 {
|
fn ref_mut(val: u32) -> u32 {
|
||||||
let mut b = Box::new(0u32);
|
let mut b = Box::new(0u32);
|
||||||
match &mut b {
|
match &mut b {
|
||||||
|
@ -64,6 +65,21 @@ fn ref_mut(val: u32) -> u32 {
|
||||||
*x
|
*x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(implicit)]
|
||||||
|
fn ref_mut(val: u32) -> u32 {
|
||||||
|
let mut b = Box::new((0u32,));
|
||||||
|
match &mut b {
|
||||||
|
(_x,) if false => unreachable!(),
|
||||||
|
(x,) => {
|
||||||
|
*x = val;
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
let (x,) = &b else { unreachable!() };
|
||||||
|
*x
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(explicit)]
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
fn or_and_guard(tuple: (u32, u32)) -> u32 {
|
fn or_and_guard(tuple: (u32, u32)) -> u32 {
|
||||||
let mut sum = 0;
|
let mut sum = 0;
|
||||||
|
@ -75,6 +91,18 @@ fn or_and_guard(tuple: (u32, u32)) -> u32 {
|
||||||
sum
|
sum
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(implicit)]
|
||||||
|
#[rustfmt::skip]
|
||||||
|
fn or_and_guard(tuple: (u32, u32)) -> u32 {
|
||||||
|
let mut sum = 0;
|
||||||
|
let b = Box::new(tuple);
|
||||||
|
match b {
|
||||||
|
(x, _) | (_, x) if { sum += x; false } => {},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
sum
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
assert_eq!(simple_vec(vec![1]), 1);
|
assert_eq!(simple_vec(vec![1]), 1);
|
||||||
assert_eq!(simple_vec(vec![1, 2]), 202);
|
assert_eq!(simple_vec(vec![1, 2]), 202);
|
||||||
|
|
|
@ -11,4 +11,11 @@ fn main() {
|
||||||
deref!(false) => {}
|
deref!(false) => {}
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
|
match b {
|
||||||
|
true => {}
|
||||||
|
_ if { *b = true; false } => {}
|
||||||
|
//~^ ERROR cannot assign `*b` in match guard
|
||||||
|
false => {}
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,15 @@ LL | deref!(true) => {}
|
||||||
LL | _ if { *b = true; false } => {}
|
LL | _ if { *b = true; false } => {}
|
||||||
| ^^^^^^^^^ cannot assign
|
| ^^^^^^^^^ cannot assign
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error[E0510]: cannot assign `*b` in match guard
|
||||||
|
--> $DIR/fake_borrows.rs:16:16
|
||||||
|
|
|
||||||
|
LL | match b {
|
||||||
|
| - value is immutable in match guard
|
||||||
|
LL | true => {}
|
||||||
|
LL | _ if { *b = true; false } => {}
|
||||||
|
| ^^^^^^^^^ cannot assign
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0510`.
|
For more information about this error, try `rustc --explain E0510`.
|
||||||
|
|
|
@ -8,10 +8,19 @@ fn main() {
|
||||||
deref!(x) => {}
|
deref!(x) => {}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
match &mut vec![1] {
|
||||||
|
[x] => {}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
match &mut Rc::new(1) {
|
match &mut Rc::new(1) {
|
||||||
deref!(x) => {}
|
deref!(x) => {}
|
||||||
//~^ ERROR the trait bound `Rc<{integer}>: DerefMut` is not satisfied
|
//~^ ERROR the trait bound `Rc<{integer}>: DerefMut` is not satisfied
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
match &mut Rc::new((1,)) {
|
||||||
|
(x,) => {}
|
||||||
|
//~^ ERROR the trait bound `Rc<({integer},)>: DerefMut` is not satisfied
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,19 @@ LL | #![feature(deref_patterns)]
|
||||||
= note: `#[warn(incomplete_features)]` on by default
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
|
|
||||||
error[E0277]: the trait bound `Rc<{integer}>: DerefMut` is not satisfied
|
error[E0277]: the trait bound `Rc<{integer}>: DerefMut` is not satisfied
|
||||||
--> $DIR/ref-mut.rs:13:9
|
--> $DIR/ref-mut.rs:17:9
|
||||||
|
|
|
|
||||||
LL | deref!(x) => {}
|
LL | deref!(x) => {}
|
||||||
| ^^^^^^^^^ the trait `DerefMut` is not implemented for `Rc<{integer}>`
|
| ^^^^^^^^^ the trait `DerefMut` is not implemented for `Rc<{integer}>`
|
||||||
|
|
|
|
||||||
= note: this error originates in the macro `deref` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `deref` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: aborting due to 1 previous error; 1 warning emitted
|
error[E0277]: the trait bound `Rc<({integer},)>: DerefMut` is not satisfied
|
||||||
|
--> $DIR/ref-mut.rs:22:9
|
||||||
|
|
|
||||||
|
LL | (x,) => {}
|
||||||
|
| ^^^^ the trait `DerefMut` is not implemented for `Rc<({integer},)>`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors; 1 warning emitted
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0277`.
|
For more information about this error, try `rustc --explain E0277`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue