@@ -80,61 +80,81 @@ pub fn suggest_new_overflow_limit<'tcx, G: EmissionGuarantee>(
80
80
81
81
#[ extension( pub trait TypeErrCtxtExt <' tcx>) ]
82
82
impl < ' tcx > TypeErrCtxt < ' _ , ' tcx > {
83
+ #[ instrument( skip( self ) , level = "debug" ) ]
83
84
fn report_fulfillment_errors (
84
85
& self ,
85
86
mut errors : Vec < FulfillmentError < ' tcx > > ,
86
87
) -> ErrorGuaranteed {
88
+ if errors. is_empty ( ) {
89
+ bug ! ( "attempted to report fulfillment errors, but there we no errors" ) ;
90
+ }
91
+
87
92
self . sub_relations
88
93
. borrow_mut ( )
89
94
. add_constraints ( self , errors. iter ( ) . map ( |e| e. obligation . predicate ) ) ;
90
95
96
+ let mut reported = None ;
97
+
98
+ // We want to ignore desugarings when filtering errors: spans are equivalent even
99
+ // if one is the result of a desugaring and the other is not.
100
+ let strip_desugaring = |span : Span | {
101
+ let expn_data = span. ctxt ( ) . outer_expn_data ( ) ;
102
+ if let ExpnKind :: Desugaring ( _) = expn_data. kind { expn_data. call_site } else { span }
103
+ } ;
104
+
91
105
#[ derive( Debug ) ]
92
- struct ErrorDescriptor < ' tcx > {
106
+ struct ErrorDescriptor < ' tcx , ' err > {
93
107
predicate : ty:: Predicate < ' tcx > ,
94
- index : Option < usize > , // None if this is an old error
108
+ source : Option < ( usize , & ' err FulfillmentError < ' tcx > ) > , // None if this is an old error
95
109
}
96
110
97
111
let mut error_map: FxIndexMap < _ , Vec < _ > > = self
98
112
. reported_trait_errors
99
113
. borrow ( )
100
114
. iter ( )
101
- . map ( |( & span, predicates) | {
102
- (
103
- span,
104
- predicates
105
- . 0
106
- . iter ( )
107
- . map ( |& predicate| ErrorDescriptor { predicate, index : None } )
108
- . collect ( ) ,
109
- )
115
+ . map ( |( & span, & ( ref predicates, guar) ) | {
116
+ reported = Some ( guar) ;
117
+ let span = strip_desugaring ( span) ;
118
+ let reported_errors = predicates
119
+ . iter ( )
120
+ . map ( |& predicate| ErrorDescriptor { predicate, source : None } )
121
+ . collect ( ) ;
122
+ ( span, reported_errors)
110
123
} )
111
124
. collect ( ) ;
112
125
126
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , PartialOrd , Ord ) ]
127
+ enum ErrorOrd {
128
+ Default ,
129
+ Sized ,
130
+ Metadata ,
131
+ Coerce ,
132
+ WellFormed ,
133
+ }
134
+
113
135
// Ensure `T: Sized` and `T: WF` obligations come last. This lets us display diagnostics
114
- // with more relevant type information and hide redundant E0282 errors.
136
+ // with more relevant type information and hide redundant E0282 ("type annotations needed") errors.
115
137
errors. sort_by_key ( |e| match e. obligation . predicate . kind ( ) . skip_binder ( ) {
116
138
ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Trait ( pred) )
117
139
if Some ( pred. def_id ( ) ) == self . tcx . lang_items ( ) . sized_trait ( ) =>
118
140
{
119
- 1
141
+ ErrorOrd :: Sized
142
+ }
143
+ ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Projection ( pred) )
144
+ if Some ( pred. def_id ( ) ) == self . tcx . lang_items ( ) . metadata_type ( ) =>
145
+ {
146
+ ErrorOrd :: Metadata
120
147
}
121
- ty:: PredicateKind :: Clause ( ty :: ClauseKind :: WellFormed ( _ ) ) => 3 ,
122
- ty:: PredicateKind :: Coerce ( _ ) => 2 ,
123
- _ => 0 ,
148
+ ty:: PredicateKind :: Coerce ( _ ) => ErrorOrd :: Coerce ,
149
+ ty:: PredicateKind :: Clause ( ty :: ClauseKind :: WellFormed ( _ ) ) => ErrorOrd :: WellFormed ,
150
+ _ => ErrorOrd :: Default ,
124
151
} ) ;
125
152
126
153
for ( index, error) in errors. iter ( ) . enumerate ( ) {
127
- // We want to ignore desugarings here: spans are equivalent even
128
- // if one is the result of a desugaring and the other is not.
129
- let mut span = error. obligation . cause . span ;
130
- let expn_data = span. ctxt ( ) . outer_expn_data ( ) ;
131
- if let ExpnKind :: Desugaring ( _) = expn_data. kind {
132
- span = expn_data. call_site ;
133
- }
134
-
154
+ let span = strip_desugaring ( error. obligation . cause . span ) ;
135
155
error_map. entry ( span) . or_default ( ) . push ( ErrorDescriptor {
136
156
predicate : error. obligation . predicate ,
137
- index : Some ( index) ,
157
+ source : Some ( ( index, error ) ) ,
138
158
} ) ;
139
159
}
140
160
@@ -144,59 +164,63 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
144
164
for ( _, error_set) in error_map. iter ( ) {
145
165
// We want to suppress "duplicate" errors with the same span.
146
166
for error in error_set {
147
- if let Some ( index) = error. index {
167
+ let Some ( ( index, error_source) ) = error. source else {
168
+ continue ;
169
+ } ;
170
+
171
+ for error2 in error_set {
148
172
// Suppress errors that are either:
149
173
// 1) strictly implied by another error.
150
174
// 2) implied by an error with a smaller index.
151
- for error2 in error_set {
152
- if error2. index . is_some_and ( |index2| is_suppressed[ index2] ) {
153
- // Avoid errors being suppressed by already-suppressed
154
- // errors, to prevent all errors from being suppressed
155
- // at once.
156
- continue ;
157
- }
175
+ if self . error_implied_by ( error. predicate , error2. predicate )
176
+ && ( !error2. source . is_some_and ( |( index2, _) | index2 >= index)
177
+ || !self . error_implied_by ( error2. predicate , error. predicate ) )
178
+ {
179
+ info ! ( "skipping `{}` (implied by `{}`)" , error. predicate, error2. predicate) ;
180
+ is_suppressed[ index] = true ;
181
+ break ;
182
+ }
158
183
159
- if self . error_implies ( error2. predicate , error. predicate )
160
- && !( error2. index >= error. index
161
- && self . error_implies ( error. predicate , error2. predicate ) )
162
- {
163
- info ! ( "skipping {:?} (implied by {:?})" , error, error2) ;
164
- is_suppressed[ index] = true ;
165
- break ;
166
- }
184
+ // Also suppress the error if we are absolutely certain that a different
185
+ // error is the one that the user should fix. This will suppress errors
186
+ // about `<T as Pointee>::Metadata == ()` that can be fixed by `T: Sized`.
187
+ if error. predicate . to_opt_poly_projection_pred ( ) . is_some ( )
188
+ && error2. predicate . to_opt_poly_trait_pred ( ) . is_some ( )
189
+ && self . error_fixed_by (
190
+ error_source. obligation . clone ( ) ,
191
+ error2. predicate . expect_clause ( ) ,
192
+ )
193
+ {
194
+ info ! ( "skipping `{}` (fixed by `{}`)" , error. predicate, error2. predicate) ;
195
+ is_suppressed[ index] = true ;
196
+ break ;
167
197
}
168
198
}
169
199
}
170
200
}
171
201
172
- let mut reported = None ;
173
-
174
202
for from_expansion in [ false , true ] {
175
- for ( error, suppressed) in iter:: zip ( & errors, & is_suppressed) {
176
- if !suppressed && error. obligation . cause . span . from_expansion ( ) == from_expansion {
177
- let guar = self . report_fulfillment_error ( error) ;
178
- reported = Some ( guar) ;
179
- // We want to ignore desugarings here: spans are equivalent even
180
- // if one is the result of a desugaring and the other is not.
181
- let mut span = error. obligation . cause . span ;
182
- let expn_data = span. ctxt ( ) . outer_expn_data ( ) ;
183
- if let ExpnKind :: Desugaring ( _) = expn_data. kind {
184
- span = expn_data. call_site ;
185
- }
186
- self . reported_trait_errors
187
- . borrow_mut ( )
188
- . entry ( span)
189
- . or_insert_with ( || ( vec ! [ ] , guar) )
190
- . 0
191
- . push ( error. obligation . predicate ) ;
203
+ for ( error, & suppressed) in iter:: zip ( & errors, & is_suppressed) {
204
+ let span = error. obligation . cause . span ;
205
+ if suppressed || span. from_expansion ( ) != from_expansion {
206
+ continue ;
192
207
}
208
+
209
+ let guar = self . report_fulfillment_error ( error) ;
210
+ reported = Some ( guar) ;
211
+
212
+ self . reported_trait_errors
213
+ . borrow_mut ( )
214
+ . entry ( span)
215
+ . or_insert_with ( || ( vec ! [ ] , guar) )
216
+ . 0
217
+ . push ( error. obligation . predicate ) ;
193
218
}
194
219
}
195
220
196
- // It could be that we don't report an error because we have seen an `ErrorReported` from
197
- // another source. We should probably be able to fix most of these, but some are delayed
198
- // bugs that get a proper error after this function.
199
- reported. unwrap_or_else ( || self . dcx ( ) . delayed_bug ( "failed to report fulfillment errors" ) )
221
+ // If all errors are suppressed, then we must have reported at least one error
222
+ // from a previous call to this function.
223
+ reported. unwrap_or_else ( || bug ! ( "failed to report fulfillment errors" ) )
200
224
}
201
225
202
226
/// Reports that an overflow has occurred and halts compilation. We
@@ -1465,10 +1489,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
1465
1489
&& self . can_eq ( param_env, goal. term , assumption. term )
1466
1490
}
1467
1491
1468
- // returns if `cond` not occurring implies that `error` does not occur - i.e., that
1469
- // `error` occurring implies that `cond` occurs.
1492
+ /// Returns whether `cond` not occurring implies that `error` does not occur - i.e., that
1493
+ /// `error` occurring implies that `cond` occurs.
1470
1494
#[ instrument( level = "debug" , skip( self ) , ret) ]
1471
- fn error_implies ( & self , cond : ty:: Predicate < ' tcx > , error : ty:: Predicate < ' tcx > ) -> bool {
1495
+ fn error_implied_by ( & self , error : ty:: Predicate < ' tcx > , cond : ty:: Predicate < ' tcx > ) -> bool {
1472
1496
if cond == error {
1473
1497
return true ;
1474
1498
}
@@ -1490,6 +1514,29 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
1490
1514
}
1491
1515
}
1492
1516
1517
+ /// Returns whether fixing `cond` will also fix `error`.
1518
+ #[ instrument( level = "debug" , skip( self ) , ret) ]
1519
+ fn error_fixed_by ( & self , mut error : PredicateObligation < ' tcx > , cond : ty:: Clause < ' tcx > ) -> bool {
1520
+ self . probe ( |_| {
1521
+ let ocx = ObligationCtxt :: new ( self ) ;
1522
+
1523
+ let clauses = elaborate ( self . tcx , std:: iter:: once ( cond) ) . collect :: < Vec < _ > > ( ) ;
1524
+ let clauses = ocx. normalize ( & error. cause , error. param_env , clauses) ;
1525
+ let mut clauses = self . resolve_vars_if_possible ( clauses) ;
1526
+
1527
+ if clauses. has_infer ( ) {
1528
+ return false ;
1529
+ }
1530
+
1531
+ clauses. extend ( error. param_env . caller_bounds ( ) ) ;
1532
+ let clauses = self . tcx . mk_clauses ( & clauses) ;
1533
+ error. param_env = ty:: ParamEnv :: new ( clauses, error. param_env . reveal ( ) ) ;
1534
+
1535
+ ocx. register_obligation ( error) ;
1536
+ ocx. select_all_or_error ( ) . is_empty ( )
1537
+ } )
1538
+ }
1539
+
1493
1540
#[ instrument( skip( self ) , level = "debug" ) ]
1494
1541
fn report_fulfillment_error ( & self , error : & FulfillmentError < ' tcx > ) -> ErrorGuaranteed {
1495
1542
if self . tcx . sess . opts . unstable_opts . next_solver . map ( |c| c. dump_tree ) . unwrap_or_default ( )
0 commit comments