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