|
1 | 1 | //! Error reporting machinery for lifetime errors.
|
2 | 2 |
|
3 |
| -use rustc::infer::{error_reporting::nice_region_error::NiceRegionError, NLLRegionVariableOrigin}; |
| 3 | +use rustc::infer::{ |
| 4 | + error_reporting::nice_region_error::NiceRegionError, opaque_types, NLLRegionVariableOrigin, |
| 5 | +}; |
4 | 6 | use rustc::mir::ConstraintCategory;
|
5 | 7 | use rustc::ty::{self, RegionVid, Ty};
|
6 | 8 | use rustc_errors::{Applicability, DiagnosticBuilder};
|
@@ -109,8 +111,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
109 | 111 | /// existentially bound, then we check its inferred value and try
|
110 | 112 | /// to find a good name from that. Returns `None` if we can't find
|
111 | 113 | /// one (e.g., this is just some random part of the CFG).
|
112 |
| - // TODO(mark-i-m): make this private when we move report_region_errors here... |
113 |
| - crate fn to_error_region(&self, r: RegionVid) -> Option<ty::Region<'tcx>> { |
| 114 | + pub(super) fn to_error_region(&self, r: RegionVid) -> Option<ty::Region<'tcx>> { |
114 | 115 | self.to_error_region_vid(r)
|
115 | 116 | .and_then(|r| self.nonlexical_regioncx.definitions[r].external_name)
|
116 | 117 | }
|
@@ -147,6 +148,125 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
147 | 148 | false
|
148 | 149 | }
|
149 | 150 |
|
| 151 | + /// Produces nice borrowck error diagnostics for all the errors collected in `nll_errors`. |
| 152 | + pub(in crate::borrow_check) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) { |
| 153 | + // Iterate through all the errors, producing a diagnostic for each one. The diagnostics are |
| 154 | + // buffered in the `MirBorrowckCtxt`. |
| 155 | + |
| 156 | + // TODO(mark-i-m): Would be great to get rid of the naming context. |
| 157 | + let mut region_naming = RegionErrorNamingCtx::new(); |
| 158 | + let mut outlives_suggestion = OutlivesSuggestionBuilder::default(); |
| 159 | + |
| 160 | + for nll_error in nll_errors.into_iter() { |
| 161 | + match nll_error { |
| 162 | + RegionErrorKind::TypeTestError { type_test } => { |
| 163 | + // Try to convert the lower-bound region into something named we can print for the user. |
| 164 | + let lower_bound_region = self.to_error_region(type_test.lower_bound); |
| 165 | + |
| 166 | + // Skip duplicate-ish errors. |
| 167 | + let type_test_span = type_test.locations.span(&self.body); |
| 168 | + |
| 169 | + if let Some(lower_bound_region) = lower_bound_region { |
| 170 | + let region_scope_tree = &self.infcx.tcx.region_scope_tree(self.mir_def_id); |
| 171 | + self.infcx |
| 172 | + .construct_generic_bound_failure( |
| 173 | + region_scope_tree, |
| 174 | + type_test_span, |
| 175 | + None, |
| 176 | + type_test.generic_kind, |
| 177 | + lower_bound_region, |
| 178 | + ) |
| 179 | + .buffer(&mut self.errors_buffer); |
| 180 | + } else { |
| 181 | + // FIXME. We should handle this case better. It |
| 182 | + // indicates that we have e.g., some region variable |
| 183 | + // whose value is like `'a+'b` where `'a` and `'b` are |
| 184 | + // distinct unrelated univesal regions that are not |
| 185 | + // known to outlive one another. It'd be nice to have |
| 186 | + // some examples where this arises to decide how best |
| 187 | + // to report it; we could probably handle it by |
| 188 | + // iterating over the universal regions and reporting |
| 189 | + // an error that multiple bounds are required. |
| 190 | + self.infcx |
| 191 | + .tcx |
| 192 | + .sess |
| 193 | + .struct_span_err( |
| 194 | + type_test_span, |
| 195 | + &format!("`{}` does not live long enough", type_test.generic_kind), |
| 196 | + ) |
| 197 | + .buffer(&mut self.errors_buffer); |
| 198 | + } |
| 199 | + } |
| 200 | + |
| 201 | + RegionErrorKind::UnexpectedHiddenRegion { |
| 202 | + opaque_type_def_id, |
| 203 | + hidden_ty, |
| 204 | + member_region, |
| 205 | + } => { |
| 206 | + let region_scope_tree = &self.infcx.tcx.region_scope_tree(self.mir_def_id); |
| 207 | + opaque_types::unexpected_hidden_region_diagnostic( |
| 208 | + self.infcx.tcx, |
| 209 | + Some(region_scope_tree), |
| 210 | + opaque_type_def_id, |
| 211 | + hidden_ty, |
| 212 | + member_region, |
| 213 | + ) |
| 214 | + .buffer(&mut self.errors_buffer); |
| 215 | + } |
| 216 | + |
| 217 | + RegionErrorKind::BoundUniversalRegionError { |
| 218 | + longer_fr, |
| 219 | + fr_origin, |
| 220 | + error_element, |
| 221 | + } => { |
| 222 | + let error_region = |
| 223 | + self.nonlexical_regioncx.region_from_element(longer_fr, error_element); |
| 224 | + |
| 225 | + // Find the code to blame for the fact that `longer_fr` outlives `error_fr`. |
| 226 | + let (_, span) = self.nonlexical_regioncx.find_outlives_blame_span( |
| 227 | + &self.body, |
| 228 | + longer_fr, |
| 229 | + fr_origin, |
| 230 | + error_region, |
| 231 | + ); |
| 232 | + |
| 233 | + // FIXME: improve this error message |
| 234 | + self.infcx |
| 235 | + .tcx |
| 236 | + .sess |
| 237 | + .struct_span_err(span, "higher-ranked subtype error") |
| 238 | + .buffer(&mut self.errors_buffer); |
| 239 | + } |
| 240 | + |
| 241 | + RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => { |
| 242 | + if is_reported { |
| 243 | + self.report_error( |
| 244 | + longer_fr, |
| 245 | + fr_origin, |
| 246 | + shorter_fr, |
| 247 | + &mut outlives_suggestion, |
| 248 | + &mut region_naming, |
| 249 | + ); |
| 250 | + } else { |
| 251 | + // We only report the first error, so as not to overwhelm the user. See |
| 252 | + // `RegRegionErrorKind` docs. |
| 253 | + // |
| 254 | + // FIXME: currently we do nothing with these, but perhaps we can do better? |
| 255 | + // FIXME: try collecting these constraints on the outlives suggestion |
| 256 | + // builder. Does it make the suggestions any better? |
| 257 | + debug!( |
| 258 | + "Unreported region error: can't prove that {:?}: {:?}", |
| 259 | + longer_fr, shorter_fr |
| 260 | + ); |
| 261 | + } |
| 262 | + } |
| 263 | + } |
| 264 | + } |
| 265 | + |
| 266 | + // Emit one outlives suggestions for each MIR def we borrowck |
| 267 | + outlives_suggestion.add_suggestion(self, &mut region_naming); |
| 268 | + } |
| 269 | + |
150 | 270 | /// Report an error because the universal region `fr` was required to outlive
|
151 | 271 | /// `outlived_fr` but it is not known to do so. For example:
|
152 | 272 | ///
|
|
0 commit comments