|
1 | 1 | //! Borrow checker diagnostics. |
2 | 2 |
|
| 3 | +use itertools::Itertools; |
3 | 4 | use rustc_const_eval::util::{call_kind, CallDesugaringKind}; |
4 | 5 | use rustc_errors::{Applicability, Diagnostic}; |
5 | 6 | use rustc_hir as hir; |
@@ -161,158 +162,103 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { |
161 | 162 | } |
162 | 163 |
|
163 | 164 | /// End-user visible description of `place` if one can be found. |
164 | | - /// If the place is a temporary for instance, None will be returned. |
| 165 | + /// If the place is a temporary for instance, `None` will be returned. |
165 | 166 | pub(super) fn describe_place(&self, place_ref: PlaceRef<'tcx>) -> Option<String> { |
166 | 167 | self.describe_place_with_options(place_ref, IncludingDowncast(false)) |
167 | 168 | } |
168 | 169 |
|
169 | | - /// End-user visible description of `place` if one can be found. If the |
170 | | - /// place is a temporary for instance, None will be returned. |
171 | | - /// `IncludingDowncast` parameter makes the function return `Err` if `ProjectionElem` is |
| 170 | + /// End-user visible description of `place` if one can be found. If the place is a temporary |
| 171 | + /// for instance, `None` will be returned. |
| 172 | + /// `IncludingDowncast` parameter makes the function return `None` if `ProjectionElem` is |
172 | 173 | /// `Downcast` and `IncludingDowncast` is true |
173 | 174 | pub(super) fn describe_place_with_options( |
174 | 175 | &self, |
175 | 176 | place: PlaceRef<'tcx>, |
176 | 177 | including_downcast: IncludingDowncast, |
177 | 178 | ) -> Option<String> { |
| 179 | + let local = place.local; |
| 180 | + let mut autoderef_index = None; |
178 | 181 | let mut buf = String::new(); |
179 | | - match self.append_place_to_string(place, &mut buf, false, &including_downcast) { |
180 | | - Ok(()) => Some(buf), |
181 | | - Err(()) => None, |
182 | | - } |
183 | | - } |
184 | | - |
185 | | - /// Appends end-user visible description of `place` to `buf`. |
186 | | - fn append_place_to_string( |
187 | | - &self, |
188 | | - place: PlaceRef<'tcx>, |
189 | | - buf: &mut String, |
190 | | - mut autoderef: bool, |
191 | | - including_downcast: &IncludingDowncast, |
192 | | - ) -> Result<(), ()> { |
193 | | - match place { |
194 | | - PlaceRef { local, projection: [] } => { |
195 | | - self.append_local_to_string(local, buf)?; |
196 | | - } |
197 | | - PlaceRef { local, projection: [ProjectionElem::Deref] } |
198 | | - if self.body.local_decls[local].is_ref_for_guard() => |
199 | | - { |
200 | | - self.append_place_to_string( |
201 | | - PlaceRef { local, projection: &[] }, |
202 | | - buf, |
203 | | - autoderef, |
204 | | - &including_downcast, |
205 | | - )?; |
206 | | - } |
207 | | - PlaceRef { local, projection: [ProjectionElem::Deref] } |
208 | | - if self.body.local_decls[local].is_ref_to_static() => |
209 | | - { |
210 | | - let local_info = &self.body.local_decls[local].local_info; |
211 | | - if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info { |
212 | | - buf.push_str(self.infcx.tcx.item_name(def_id).as_str()); |
213 | | - } else { |
214 | | - unreachable!(); |
215 | | - } |
216 | | - } |
217 | | - PlaceRef { local, projection: [proj_base @ .., elem] } => { |
218 | | - match elem { |
219 | | - ProjectionElem::Deref => { |
220 | | - let upvar_field_projection = self.is_upvar_field_projection(place); |
221 | | - if let Some(field) = upvar_field_projection { |
222 | | - let var_index = field.index(); |
223 | | - let name = self.upvars[var_index].place.to_string(self.infcx.tcx); |
224 | | - if self.upvars[var_index].by_ref { |
225 | | - buf.push_str(&name); |
226 | | - } else { |
227 | | - buf.push('*'); |
228 | | - buf.push_str(&name); |
229 | | - } |
230 | | - } else { |
231 | | - if autoderef { |
232 | | - // FIXME turn this recursion into iteration |
233 | | - self.append_place_to_string( |
234 | | - PlaceRef { local, projection: proj_base }, |
235 | | - buf, |
236 | | - autoderef, |
237 | | - &including_downcast, |
238 | | - )?; |
239 | | - } else { |
240 | | - buf.push('*'); |
241 | | - self.append_place_to_string( |
242 | | - PlaceRef { local, projection: proj_base }, |
243 | | - buf, |
244 | | - autoderef, |
245 | | - &including_downcast, |
246 | | - )?; |
247 | | - } |
| 182 | + let mut ok = self.append_local_to_string(local, &mut buf); |
| 183 | + |
| 184 | + for (index, elem) in place.projection.into_iter().enumerate() { |
| 185 | + match elem { |
| 186 | + ProjectionElem::Deref => { |
| 187 | + if index == 0 { |
| 188 | + if self.body.local_decls[local].is_ref_for_guard() { |
| 189 | + continue; |
248 | 190 | } |
249 | | - } |
250 | | - ProjectionElem::Downcast(..) => { |
251 | | - self.append_place_to_string( |
252 | | - PlaceRef { local, projection: proj_base }, |
253 | | - buf, |
254 | | - autoderef, |
255 | | - &including_downcast, |
256 | | - )?; |
257 | | - if including_downcast.0 { |
258 | | - return Err(()); |
| 191 | + if let Some(box LocalInfo::StaticRef { def_id, .. }) = |
| 192 | + &self.body.local_decls[local].local_info |
| 193 | + { |
| 194 | + buf.push_str(self.infcx.tcx.item_name(*def_id).as_str()); |
| 195 | + ok = Ok(()); |
| 196 | + continue; |
259 | 197 | } |
260 | 198 | } |
261 | | - ProjectionElem::Field(field, _ty) => { |
262 | | - autoderef = true; |
263 | | - |
264 | | - // FIXME(project-rfc_2229#36): print capture precisely here. |
265 | | - let upvar_field_projection = self.is_upvar_field_projection(place); |
266 | | - if let Some(field) = upvar_field_projection { |
267 | | - let var_index = field.index(); |
268 | | - let name = self.upvars[var_index].place.to_string(self.infcx.tcx); |
269 | | - buf.push_str(&name); |
270 | | - } else { |
271 | | - let field_name = self |
272 | | - .describe_field(PlaceRef { local, projection: proj_base }, *field); |
273 | | - self.append_place_to_string( |
274 | | - PlaceRef { local, projection: proj_base }, |
275 | | - buf, |
276 | | - autoderef, |
277 | | - &including_downcast, |
278 | | - )?; |
279 | | - buf.push('.'); |
280 | | - buf.push_str(&field_name); |
| 199 | + if let Some(field) = self.is_upvar_field_projection(PlaceRef { |
| 200 | + local, |
| 201 | + projection: place.projection.split_at(index + 1).0, |
| 202 | + }) { |
| 203 | + let var_index = field.index(); |
| 204 | + buf = self.upvars[var_index].place.to_string(self.infcx.tcx); |
| 205 | + ok = Ok(()); |
| 206 | + if !self.upvars[var_index].by_ref { |
| 207 | + buf.insert(0, '*'); |
281 | 208 | } |
282 | | - } |
283 | | - ProjectionElem::Index(index) => { |
284 | | - autoderef = true; |
285 | | - |
286 | | - self.append_place_to_string( |
287 | | - PlaceRef { local, projection: proj_base }, |
288 | | - buf, |
289 | | - autoderef, |
290 | | - &including_downcast, |
291 | | - )?; |
292 | | - buf.push('['); |
293 | | - if self.append_local_to_string(*index, buf).is_err() { |
294 | | - buf.push('_'); |
| 209 | + } else { |
| 210 | + if autoderef_index.is_none() { |
| 211 | + autoderef_index = |
| 212 | + match place.projection.into_iter().rev().find_position(|elem| { |
| 213 | + !matches!( |
| 214 | + elem, |
| 215 | + ProjectionElem::Deref | ProjectionElem::Downcast(..) |
| 216 | + ) |
| 217 | + }) { |
| 218 | + Some((index, _)) => Some(place.projection.len() - index), |
| 219 | + None => Some(0), |
| 220 | + }; |
| 221 | + } |
| 222 | + if index >= autoderef_index.unwrap() { |
| 223 | + buf.insert(0, '*'); |
295 | 224 | } |
296 | | - buf.push(']'); |
297 | 225 | } |
298 | | - ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { |
299 | | - autoderef = true; |
300 | | - // Since it isn't possible to borrow an element on a particular index and |
301 | | - // then use another while the borrow is held, don't output indices details |
302 | | - // to avoid confusing the end-user |
303 | | - self.append_place_to_string( |
304 | | - PlaceRef { local, projection: proj_base }, |
305 | | - buf, |
306 | | - autoderef, |
307 | | - &including_downcast, |
308 | | - )?; |
309 | | - buf.push_str("[..]"); |
| 226 | + } |
| 227 | + ProjectionElem::Downcast(..) if including_downcast.0 => return None, |
| 228 | + ProjectionElem::Downcast(..) => (), |
| 229 | + ProjectionElem::Field(field, _ty) => { |
| 230 | + // FIXME(project-rfc_2229#36): print capture precisely here. |
| 231 | + if let Some(field) = self.is_upvar_field_projection(PlaceRef { |
| 232 | + local, |
| 233 | + projection: place.projection.split_at(index + 1).0, |
| 234 | + }) { |
| 235 | + buf = self.upvars[field.index()].place.to_string(self.infcx.tcx); |
| 236 | + ok = Ok(()); |
| 237 | + } else { |
| 238 | + let field_name = self.describe_field( |
| 239 | + PlaceRef { local, projection: place.projection.split_at(index).0 }, |
| 240 | + *field, |
| 241 | + ); |
| 242 | + buf.push('.'); |
| 243 | + buf.push_str(&field_name); |
310 | 244 | } |
311 | | - }; |
| 245 | + } |
| 246 | + ProjectionElem::Index(index) => { |
| 247 | + buf.push('['); |
| 248 | + if self.append_local_to_string(*index, &mut buf).is_err() { |
| 249 | + buf.push('_'); |
| 250 | + } |
| 251 | + buf.push(']'); |
| 252 | + } |
| 253 | + ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { |
| 254 | + // Since it isn't possible to borrow an element on a particular index and |
| 255 | + // then use another while the borrow is held, don't output indices details |
| 256 | + // to avoid confusing the end-user |
| 257 | + buf.push_str("[..]"); |
| 258 | + } |
312 | 259 | } |
313 | 260 | } |
314 | | - |
315 | | - Ok(()) |
| 261 | + ok.ok().map(|_| buf) |
316 | 262 | } |
317 | 263 |
|
318 | 264 | /// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have |
|
0 commit comments