|
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