]> git.lizzy.rs Git - rust.git/blob - tests/ui/borrowck/two-phase-nonrecv-autoref.rs
Rollup merge of #106726 - cmorin6:fix-comment-typos, r=Nilstrieb
[rust.git] / tests / ui / borrowck / two-phase-nonrecv-autoref.rs
1 // revisions: base
2
3 //[g2p]compile-flags: -Z two-phase-beyond-autoref
4 // the above revision is disabled until two-phase-beyond-autoref support is better
5
6 // This is a test checking that when we limit two-phase borrows to
7 // method receivers, we do not let other kinds of auto-ref to leak
8 // through.
9 //
10 // The g2p revision illustrates the "undesirable" behavior you would
11 // otherwise observe without limiting the phasing to autoref on method
12 // receivers (namely, in many cases demonstrated below, the error
13 // would not arise).
14
15 use std::ops::{Index, IndexMut};
16
17 fn foo(x: &mut u32, y: u32) {
18     *x += y;
19 }
20
21 fn deref_coercion(x: &mut u32) {
22     foo(x, *x);
23     // Above error is a known limitation of AST borrowck
24 }
25
26 // While adding a flag to adjustments (indicating whether they
27 // should support two-phase borrows, here are the cases I
28 // encountered:
29 //
30 // - [x] Resolving overloaded_call_traits (call, call_mut, call_once)
31 // - [x] deref_coercion (shown above)
32 // - [x] coerce_unsized e.g., `&[T; n]`, `&mut [T; n] -> &[T]`,
33 //                      `&mut [T; n] -> &mut [T]`, `&Concrete -> &Trait`
34 // - [x] Method Call Receivers (the case we want to support!)
35 // - [x] ExprKind::Index and ExprKind::Unary Deref; only need to handle coerce_index_op
36 // - [x] overloaded_binops
37
38 fn overloaded_call_traits() {
39     // Regarding overloaded call traits, note that there is no
40     // scenario where adding two-phase borrows should "fix" these
41     // cases, because either we will resolve both invocations to
42     // `call_mut` (in which case the inner call requires a mutable
43     // borrow which will conflict with the outer reservation), or we
44     // will resolve both to `call` (which will just work, regardless
45     // of two-phase borrow support), or we will resolve both to
46     // `call_once` (in which case the inner call requires moving the
47     // receiver, invalidating the outer call).
48
49     fn twice_ten_sm<F: FnMut(i32) -> i32>(f: &mut F) {
50         f(f(10));
51         //~^ ERROR cannot borrow `*f` as mutable more than once at a time
52     }
53     fn twice_ten_si<F: Fn(i32) -> i32>(f: &mut F) {
54         f(f(10));
55     }
56     fn twice_ten_so<F: FnOnce(i32) -> i32>(f: Box<F>) {
57         f(f(10));
58         //~^ ERROR use of moved value: `f`
59     }
60
61     fn twice_ten_om(f: &mut dyn FnMut(i32) -> i32) {
62         f(f(10));
63         //~^ ERROR cannot borrow `*f` as mutable more than once at a time
64     }
65     fn twice_ten_oi(f: &mut dyn Fn(i32) -> i32) {
66         f(f(10));
67     }
68     fn twice_ten_oo(f: Box<dyn FnOnce(i32) -> i32>) {
69         f(f(10));
70         //~^ ERROR use of moved value: `f`
71     }
72
73     twice_ten_sm(&mut |x| x + 1);
74     twice_ten_si(&mut |x| x + 1);
75     twice_ten_so(Box::new(|x| x + 1));
76     twice_ten_om(&mut |x| x + 1);
77     twice_ten_oi(&mut |x| x + 1);
78     twice_ten_oo(Box::new(|x| x + 1));
79 }
80
81 trait TwoMethods {
82     fn m(&mut self, x: i32) -> i32 { x + 1 }
83     fn i(&self, x: i32) -> i32 { x + 1 }
84 }
85
86 struct T;
87
88 impl TwoMethods for T { }
89
90 struct S;
91
92 impl S {
93     fn m(&mut self, x: i32) -> i32 { x + 1 }
94     fn i(&self, x: i32) -> i32 { x + 1 }
95 }
96
97 impl TwoMethods for [i32; 3] { }
98
99 fn double_access<X: Copy>(m: &mut [X], s: &[X]) {
100     m[0] = s[1];
101 }
102
103 fn coerce_unsized() {
104     let mut a = [1, 2, 3];
105
106     // This is not okay.
107     double_access(&mut a, &a);
108     //~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
109
110     // But this is okay.
111     a.m(a.i(10));
112     // Above error is an expected limitation of AST borrowck
113 }
114
115 struct I(i32);
116
117 impl Index<i32> for I {
118     type Output = i32;
119     fn index(&self, _: i32) -> &i32 {
120         &self.0
121     }
122 }
123
124 impl IndexMut<i32> for I {
125     fn index_mut(&mut self, _: i32) -> &mut i32 {
126         &mut self.0
127     }
128 }
129
130 fn coerce_index_op() {
131     let mut i = I(10);
132     i[i[3]] = 4;
133     //~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
134     // Should be accepted with g2p
135
136     i[3] = i[4];
137
138     i[i[3]] = i[4];
139     //~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
140     // Should be accepted with g2p
141 }
142
143 fn main() {
144
145     // As a reminder, this is the basic case we want to ensure we handle.
146     let mut v = vec![1, 2, 3];
147     v.push(v.len());
148     // Error above is an expected limitation of AST borrowck
149
150     // (as a rule, pnkfelix does not like to write tests with dead code.)
151
152     deref_coercion(&mut 5);
153     overloaded_call_traits();
154
155
156     let mut s = S;
157     s.m(s.i(10));
158     // Error above is an expected limitation of AST borrowck
159
160     let mut t = T;
161     t.m(t.i(10));
162     // Error above is an expected limitation of AST borrowck
163
164     coerce_unsized();
165     coerce_index_op();
166 }