|
1 |
| -// ignore-tidy-filelength :( |
2 |
| - |
3 | 1 | pub mod ambiguity;
|
| 2 | +mod fulfillment_errors; |
4 | 3 | mod infer_ctxt_ext;
|
5 | 4 | pub mod on_unimplemented;
|
| 5 | +mod overflow; |
6 | 6 | pub mod suggestions;
|
7 |
| -mod type_err_ctxt_ext; |
8 | 7 |
|
9 |
| -use rustc_data_structures::fx::FxIndexSet; |
10 |
| -use rustc_hir as hir; |
| 8 | +use std::iter; |
| 9 | + |
| 10 | +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; |
11 | 11 | use rustc_hir::def_id::DefId;
|
12 | 12 | use rustc_hir::intravisit::Visitor;
|
13 |
| -use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode, PredicateObligation}; |
| 13 | +use rustc_hir::{self as hir, LangItem}; |
| 14 | +use rustc_infer::infer::error_reporting::TypeErrCtxt; |
| 15 | +use rustc_infer::traits::{ |
| 16 | + Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, SelectionError, |
| 17 | +}; |
| 18 | +use rustc_macros::extension; |
14 | 19 | use rustc_middle::ty::print::PrintTraitRefExt as _;
|
15 | 20 | use rustc_middle::ty::{self, Ty, TyCtxt};
|
16 |
| -use rustc_span::Span; |
17 |
| -use std::ops::ControlFlow; |
| 21 | +use rustc_span::{ErrorGuaranteed, ExpnKind, Span}; |
| 22 | + |
| 23 | +use ambiguity::TypeErrCtxtAmbiguityExt as _; |
| 24 | +use fulfillment_errors::TypeErrCtxtExt as _; |
| 25 | +use suggestions::TypeErrCtxtExt as _; |
| 26 | + |
| 27 | +use crate::traits::{FulfillmentError, FulfillmentErrorCode}; |
18 | 28 |
|
| 29 | +pub use self::fulfillment_errors::*; |
19 | 30 | pub use self::infer_ctxt_ext::*;
|
20 |
| -pub use self::type_err_ctxt_ext::*; |
| 31 | +pub use self::overflow::*; |
21 | 32 |
|
22 | 33 | // When outputting impl candidates, prefer showing those that are more similar.
|
23 | 34 | //
|
@@ -89,49 +100,6 @@ impl<'v> Visitor<'v> for FindExprBySpan<'v> {
|
89 | 100 | }
|
90 | 101 | }
|
91 | 102 |
|
92 |
| -/// Look for type `param` in an ADT being used only through a reference to confirm that suggesting |
93 |
| -/// `param: ?Sized` would be a valid constraint. |
94 |
| -struct FindTypeParam { |
95 |
| - param: rustc_span::Symbol, |
96 |
| - invalid_spans: Vec<Span>, |
97 |
| - nested: bool, |
98 |
| -} |
99 |
| - |
100 |
| -impl<'v> Visitor<'v> for FindTypeParam { |
101 |
| - fn visit_where_predicate(&mut self, _: &'v hir::WherePredicate<'v>) { |
102 |
| - // Skip where-clauses, to avoid suggesting indirection for type parameters found there. |
103 |
| - } |
104 |
| - |
105 |
| - fn visit_ty(&mut self, ty: &hir::Ty<'_>) { |
106 |
| - // We collect the spans of all uses of the "bare" type param, like in `field: T` or |
107 |
| - // `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be |
108 |
| - // valid like `field: &'a T` or `field: *mut T` and cases that *might* have further `Sized` |
109 |
| - // obligations like `Box<T>` and `Vec<T>`, but we perform no extra analysis for those cases |
110 |
| - // and suggest `T: ?Sized` regardless of their obligations. This is fine because the errors |
111 |
| - // in that case should make what happened clear enough. |
112 |
| - match ty.kind { |
113 |
| - hir::TyKind::Ptr(_) | hir::TyKind::Ref(..) | hir::TyKind::TraitObject(..) => {} |
114 |
| - hir::TyKind::Path(hir::QPath::Resolved(None, path)) |
115 |
| - if path.segments.len() == 1 && path.segments[0].ident.name == self.param => |
116 |
| - { |
117 |
| - if !self.nested { |
118 |
| - debug!(?ty, "FindTypeParam::visit_ty"); |
119 |
| - self.invalid_spans.push(ty.span); |
120 |
| - } |
121 |
| - } |
122 |
| - hir::TyKind::Path(_) => { |
123 |
| - let prev = self.nested; |
124 |
| - self.nested = true; |
125 |
| - hir::intravisit::walk_ty(self, ty); |
126 |
| - self.nested = prev; |
127 |
| - } |
128 |
| - _ => { |
129 |
| - hir::intravisit::walk_ty(self, ty); |
130 |
| - } |
131 |
| - } |
132 |
| - } |
133 |
| -} |
134 |
| - |
135 | 103 | /// Summarizes information
|
136 | 104 | #[derive(Clone)]
|
137 | 105 | pub enum ArgKind {
|
@@ -163,24 +131,199 @@ impl ArgKind {
|
163 | 131 | }
|
164 | 132 | }
|
165 | 133 |
|
166 |
| -struct HasNumericInferVisitor; |
| 134 | +#[derive(Copy, Clone)] |
| 135 | +pub enum DefIdOrName { |
| 136 | + DefId(DefId), |
| 137 | + Name(&'static str), |
| 138 | +} |
167 | 139 |
|
168 |
| -impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for HasNumericInferVisitor { |
169 |
| - type Result = ControlFlow<()>; |
| 140 | +#[extension(pub trait TypeErrCtxtExt<'a, 'tcx>)] |
| 141 | +impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { |
| 142 | + fn report_fulfillment_errors( |
| 143 | + &self, |
| 144 | + mut errors: Vec<FulfillmentError<'tcx>>, |
| 145 | + ) -> ErrorGuaranteed { |
| 146 | + self.sub_relations |
| 147 | + .borrow_mut() |
| 148 | + .add_constraints(self, errors.iter().map(|e| e.obligation.predicate)); |
| 149 | + |
| 150 | + #[derive(Debug)] |
| 151 | + struct ErrorDescriptor<'tcx> { |
| 152 | + predicate: ty::Predicate<'tcx>, |
| 153 | + index: Option<usize>, // None if this is an old error |
| 154 | + } |
170 | 155 |
|
171 |
| - fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { |
172 |
| - if matches!(ty.kind(), ty::Infer(ty::FloatVar(_) | ty::IntVar(_))) { |
173 |
| - ControlFlow::Break(()) |
174 |
| - } else { |
175 |
| - ControlFlow::Continue(()) |
| 156 | + let mut error_map: FxIndexMap<_, Vec<_>> = self |
| 157 | + .reported_trait_errors |
| 158 | + .borrow() |
| 159 | + .iter() |
| 160 | + .map(|(&span, predicates)| { |
| 161 | + ( |
| 162 | + span, |
| 163 | + predicates |
| 164 | + .0 |
| 165 | + .iter() |
| 166 | + .map(|&predicate| ErrorDescriptor { predicate, index: None }) |
| 167 | + .collect(), |
| 168 | + ) |
| 169 | + }) |
| 170 | + .collect(); |
| 171 | + |
| 172 | + // Ensure `T: Sized` and `T: WF` obligations come last. This lets us display diagnostics |
| 173 | + // with more relevant type information and hide redundant E0282 errors. |
| 174 | + errors.sort_by_key(|e| match e.obligation.predicate.kind().skip_binder() { |
| 175 | + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) |
| 176 | + if self.tcx.is_lang_item(pred.def_id(), LangItem::Sized) => |
| 177 | + { |
| 178 | + 1 |
| 179 | + } |
| 180 | + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3, |
| 181 | + ty::PredicateKind::Coerce(_) => 2, |
| 182 | + _ => 0, |
| 183 | + }); |
| 184 | + |
| 185 | + for (index, error) in errors.iter().enumerate() { |
| 186 | + // We want to ignore desugarings here: spans are equivalent even |
| 187 | + // if one is the result of a desugaring and the other is not. |
| 188 | + let mut span = error.obligation.cause.span; |
| 189 | + let expn_data = span.ctxt().outer_expn_data(); |
| 190 | + if let ExpnKind::Desugaring(_) = expn_data.kind { |
| 191 | + span = expn_data.call_site; |
| 192 | + } |
| 193 | + |
| 194 | + error_map.entry(span).or_default().push(ErrorDescriptor { |
| 195 | + predicate: error.obligation.predicate, |
| 196 | + index: Some(index), |
| 197 | + }); |
176 | 198 | }
|
| 199 | + |
| 200 | + // We do this in 2 passes because we want to display errors in order, though |
| 201 | + // maybe it *is* better to sort errors by span or something. |
| 202 | + let mut is_suppressed = vec![false; errors.len()]; |
| 203 | + for (_, error_set) in error_map.iter() { |
| 204 | + // We want to suppress "duplicate" errors with the same span. |
| 205 | + for error in error_set { |
| 206 | + if let Some(index) = error.index { |
| 207 | + // Suppress errors that are either: |
| 208 | + // 1) strictly implied by another error. |
| 209 | + // 2) implied by an error with a smaller index. |
| 210 | + for error2 in error_set { |
| 211 | + if error2.index.is_some_and(|index2| is_suppressed[index2]) { |
| 212 | + // Avoid errors being suppressed by already-suppressed |
| 213 | + // errors, to prevent all errors from being suppressed |
| 214 | + // at once. |
| 215 | + continue; |
| 216 | + } |
| 217 | + |
| 218 | + if self.error_implies(error2.predicate, error.predicate) |
| 219 | + && !(error2.index >= error.index |
| 220 | + && self.error_implies(error.predicate, error2.predicate)) |
| 221 | + { |
| 222 | + info!("skipping {:?} (implied by {:?})", error, error2); |
| 223 | + is_suppressed[index] = true; |
| 224 | + break; |
| 225 | + } |
| 226 | + } |
| 227 | + } |
| 228 | + } |
| 229 | + } |
| 230 | + |
| 231 | + let mut reported = None; |
| 232 | + |
| 233 | + for from_expansion in [false, true] { |
| 234 | + for (error, suppressed) in iter::zip(&errors, &is_suppressed) { |
| 235 | + if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion { |
| 236 | + let guar = self.report_fulfillment_error(error); |
| 237 | + self.infcx.set_tainted_by_errors(guar); |
| 238 | + reported = Some(guar); |
| 239 | + // We want to ignore desugarings here: spans are equivalent even |
| 240 | + // if one is the result of a desugaring and the other is not. |
| 241 | + let mut span = error.obligation.cause.span; |
| 242 | + let expn_data = span.ctxt().outer_expn_data(); |
| 243 | + if let ExpnKind::Desugaring(_) = expn_data.kind { |
| 244 | + span = expn_data.call_site; |
| 245 | + } |
| 246 | + self.reported_trait_errors |
| 247 | + .borrow_mut() |
| 248 | + .entry(span) |
| 249 | + .or_insert_with(|| (vec![], guar)) |
| 250 | + .0 |
| 251 | + .push(error.obligation.predicate); |
| 252 | + } |
| 253 | + } |
| 254 | + } |
| 255 | + |
| 256 | + // It could be that we don't report an error because we have seen an `ErrorReported` from |
| 257 | + // another source. We should probably be able to fix most of these, but some are delayed |
| 258 | + // bugs that get a proper error after this function. |
| 259 | + reported.unwrap_or_else(|| self.dcx().delayed_bug("failed to report fulfillment errors")) |
177 | 260 | }
|
178 |
| -} |
179 | 261 |
|
180 |
| -#[derive(Copy, Clone)] |
181 |
| -pub enum DefIdOrName { |
182 |
| - DefId(DefId), |
183 |
| - Name(&'static str), |
| 262 | + #[instrument(skip(self), level = "debug")] |
| 263 | + fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed { |
| 264 | + let mut error = FulfillmentError { |
| 265 | + obligation: error.obligation.clone(), |
| 266 | + code: error.code.clone(), |
| 267 | + root_obligation: error.root_obligation.clone(), |
| 268 | + }; |
| 269 | + if matches!( |
| 270 | + error.code, |
| 271 | + FulfillmentErrorCode::Select(crate::traits::SelectionError::Unimplemented) |
| 272 | + | FulfillmentErrorCode::Project(_) |
| 273 | + ) && self.apply_do_not_recommend(&mut error.obligation) |
| 274 | + { |
| 275 | + error.code = FulfillmentErrorCode::Select(SelectionError::Unimplemented); |
| 276 | + } |
| 277 | + |
| 278 | + match error.code { |
| 279 | + FulfillmentErrorCode::Select(ref selection_error) => self.report_selection_error( |
| 280 | + error.obligation.clone(), |
| 281 | + &error.root_obligation, |
| 282 | + selection_error, |
| 283 | + ), |
| 284 | + FulfillmentErrorCode::Project(ref e) => { |
| 285 | + self.report_projection_error(&error.obligation, e) |
| 286 | + } |
| 287 | + FulfillmentErrorCode::Ambiguity { overflow: None } => { |
| 288 | + self.maybe_report_ambiguity(&error.obligation) |
| 289 | + } |
| 290 | + FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } => { |
| 291 | + self.report_overflow_no_abort(error.obligation.clone(), suggest_increasing_limit) |
| 292 | + } |
| 293 | + FulfillmentErrorCode::Subtype(ref expected_found, ref err) => self |
| 294 | + .report_mismatched_types( |
| 295 | + &error.obligation.cause, |
| 296 | + expected_found.expected, |
| 297 | + expected_found.found, |
| 298 | + *err, |
| 299 | + ) |
| 300 | + .emit(), |
| 301 | + FulfillmentErrorCode::ConstEquate(ref expected_found, ref err) => { |
| 302 | + let mut diag = self.report_mismatched_consts( |
| 303 | + &error.obligation.cause, |
| 304 | + expected_found.expected, |
| 305 | + expected_found.found, |
| 306 | + *err, |
| 307 | + ); |
| 308 | + let code = error.obligation.cause.code().peel_derives().peel_match_impls(); |
| 309 | + if let ObligationCauseCode::WhereClause(..) |
| 310 | + | ObligationCauseCode::WhereClauseInExpr(..) = code |
| 311 | + { |
| 312 | + self.note_obligation_cause_code( |
| 313 | + error.obligation.cause.body_id, |
| 314 | + &mut diag, |
| 315 | + error.obligation.predicate, |
| 316 | + error.obligation.param_env, |
| 317 | + code, |
| 318 | + &mut vec![], |
| 319 | + &mut Default::default(), |
| 320 | + ); |
| 321 | + } |
| 322 | + diag.emit() |
| 323 | + } |
| 324 | + FulfillmentErrorCode::Cycle(ref cycle) => self.report_overflow_obligation_cycle(cycle), |
| 325 | + } |
| 326 | + } |
184 | 327 | }
|
185 | 328 |
|
186 | 329 | /// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a
|
|
0 commit comments