@@ -2,24 +2,23 @@ use std::iter;
2
2
use std:: path:: PathBuf ;
3
3
4
4
use rustc_ast:: { LitKind , MetaItem , MetaItemInner , MetaItemKind , MetaItemLit } ;
5
- use rustc_data_structures:: fx:: FxHashMap ;
6
5
use rustc_errors:: codes:: * ;
7
6
use rustc_errors:: { ErrorGuaranteed , struct_span_code_err} ;
8
7
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
9
8
use rustc_hir:: { AttrArgs , Attribute } ;
10
9
use rustc_middle:: bug;
11
- use rustc_middle:: ty:: print:: PrintTraitRefExt as _ ;
12
- use rustc_middle:: ty:: { self , GenericArgsRef , GenericParamDefKind , TyCtxt } ;
10
+ use rustc_middle:: ty:: print:: PrintTraitRefExt ;
11
+ use rustc_middle:: ty:: { self , GenericArgsRef , GenericParamDef , GenericParamDefKind , TyCtxt } ;
13
12
use rustc_session:: lint:: builtin:: UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES ;
14
13
use rustc_span:: { Span , Symbol , sym} ;
15
14
use tracing:: { debug, info} ;
16
15
use { rustc_attr_parsing as attr, rustc_hir as hir} ;
17
16
18
17
use super :: { ObligationCauseCode , PredicateObligation } ;
19
18
use crate :: error_reporting:: TypeErrCtxt ;
20
- use crate :: error_reporting:: traits:: on_unimplemented_condition:: Condition ;
19
+ use crate :: error_reporting:: traits:: on_unimplemented_condition:: { Condition , ConditionOptions } ;
21
20
use crate :: error_reporting:: traits:: on_unimplemented_format:: errors:: * ;
22
- use crate :: error_reporting:: traits:: on_unimplemented_format:: { Ctx , FormatString } ;
21
+ use crate :: error_reporting:: traits:: on_unimplemented_format:: { Ctx , FormatArgs , FormatString } ;
23
22
use crate :: errors:: {
24
23
EmptyOnClauseInOnUnimplemented , InvalidOnClauseInOnUnimplemented , NoValueInOnUnimplemented ,
25
24
} ;
@@ -107,86 +106,81 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
107
106
. unwrap_or_else ( || ( trait_pred. def_id ( ) , trait_pred. skip_binder ( ) . trait_ref . args ) ) ;
108
107
let trait_pred = trait_pred. skip_binder ( ) ;
109
108
110
- let mut flags = vec ! [ ] ;
109
+ let mut self_types = vec ! [ ] ;
110
+ let mut generic_args: Vec < ( Symbol , String ) > = vec ! [ ] ;
111
+ let mut crate_local = false ;
111
112
// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): HIR is not present for RPITITs,
112
113
// but I guess we could synthesize one here. We don't see any errors that rely on
113
114
// that yet, though.
114
- let enclosure = self . describe_enclosure ( obligation. cause . body_id ) . map ( |t| t. to_owned ( ) ) ;
115
- flags. push ( ( sym:: ItemContext , enclosure) ) ;
115
+ let item_context = self
116
+ . describe_enclosure ( obligation. cause . body_id )
117
+ . map ( |t| t. to_owned ( ) )
118
+ . unwrap_or ( String :: new ( ) ) ;
116
119
117
- match obligation. cause . code ( ) {
120
+ let direct = match obligation. cause . code ( ) {
118
121
ObligationCauseCode :: BuiltinDerived ( ..)
119
122
| ObligationCauseCode :: ImplDerived ( ..)
120
- | ObligationCauseCode :: WellFormedDerived ( ..) => { }
123
+ | ObligationCauseCode :: WellFormedDerived ( ..) => false ,
121
124
_ => {
122
125
// this is a "direct", user-specified, rather than derived,
123
126
// obligation.
124
- flags . push ( ( sym :: direct , None ) ) ;
127
+ true
125
128
}
126
- }
127
-
128
- if let Some ( k) = obligation. cause . span . desugaring_kind ( ) {
129
- flags. push ( ( sym:: from_desugaring, None ) ) ;
130
- flags. push ( ( sym:: from_desugaring, Some ( format ! ( "{k:?}" ) ) ) ) ;
131
- }
129
+ } ;
132
130
133
- if let ObligationCauseCode :: MainFunctionType = obligation. cause . code ( ) {
134
- flags. push ( ( sym:: cause, Some ( "MainFunctionType" . to_string ( ) ) ) ) ;
135
- }
131
+ let from_desugaring = obligation. cause . span . desugaring_kind ( ) . map ( |k| format ! ( "{k:?}" ) ) ;
136
132
137
- flags. push ( ( sym:: Trait , Some ( trait_pred. trait_ref . print_trait_sugared ( ) . to_string ( ) ) ) ) ;
133
+ let cause = if let ObligationCauseCode :: MainFunctionType = obligation. cause . code ( ) {
134
+ Some ( "MainFunctionType" . to_string ( ) )
135
+ } else {
136
+ None
137
+ } ;
138
138
139
139
// Add all types without trimmed paths or visible paths, ensuring they end up with
140
140
// their "canonical" def path.
141
141
ty:: print:: with_no_trimmed_paths!( ty:: print:: with_no_visible_paths!( {
142
142
let generics = self . tcx. generics_of( def_id) ;
143
143
let self_ty = trait_pred. self_ty( ) ;
144
- // This is also included through the generics list as `Self`,
145
- // but the parser won't allow you to use it
146
- flags. push( ( sym:: _Self, Some ( self_ty. to_string( ) ) ) ) ;
144
+ self_types. push( self_ty. to_string( ) ) ;
147
145
if let Some ( def) = self_ty. ty_adt_def( ) {
148
146
// We also want to be able to select self's original
149
147
// signature with no type arguments resolved
150
- flags. push( (
151
- sym:: _Self,
152
- Some ( self . tcx. type_of( def. did( ) ) . instantiate_identity( ) . to_string( ) ) ,
153
- ) ) ;
148
+ self_types. push( self . tcx. type_of( def. did( ) ) . instantiate_identity( ) . to_string( ) ) ;
154
149
}
155
150
156
- for param in generics. own_params. iter( ) {
157
- let value = match param . kind {
151
+ for GenericParamDef { name , kind , index , .. } in generics. own_params. iter( ) {
152
+ let value = match kind {
158
153
GenericParamDefKind :: Type { .. } | GenericParamDefKind :: Const { .. } => {
159
- args[ param . index as usize ] . to_string( )
154
+ args[ * index as usize ] . to_string( )
160
155
}
161
156
GenericParamDefKind :: Lifetime => continue ,
162
157
} ;
163
- let name = param. name;
164
- flags. push( ( name, Some ( value) ) ) ;
158
+ generic_args. push( ( * name, value) ) ;
165
159
166
- if let GenericParamDefKind :: Type { .. } = param . kind {
167
- let param_ty = args[ param . index as usize ] . expect_ty( ) ;
160
+ if let GenericParamDefKind :: Type { .. } = kind {
161
+ let param_ty = args[ * index as usize ] . expect_ty( ) ;
168
162
if let Some ( def) = param_ty. ty_adt_def( ) {
169
163
// We also want to be able to select the parameter's
170
164
// original signature with no type arguments resolved
171
- flags . push( (
172
- name,
173
- Some ( self . tcx. type_of( def. did( ) ) . instantiate_identity( ) . to_string( ) ) ,
165
+ generic_args . push( (
166
+ * name,
167
+ self . tcx. type_of( def. did( ) ) . instantiate_identity( ) . to_string( ) ,
174
168
) ) ;
175
169
}
176
170
}
177
171
}
178
172
179
173
if let Some ( true ) = self_ty. ty_adt_def( ) . map( |def| def. did( ) . is_local( ) ) {
180
- flags . push ( ( sym :: crate_local, None ) ) ;
174
+ crate_local = true ;
181
175
}
182
176
183
177
// Allow targeting all integers using `{integral}`, even if the exact type was resolved
184
178
if self_ty. is_integral( ) {
185
- flags . push( ( sym :: _Self , Some ( "{integral}" . to_owned( ) ) ) ) ;
179
+ self_types . push( "{integral}" . to_owned( ) ) ;
186
180
}
187
181
188
182
if self_ty. is_array_slice( ) {
189
- flags . push( ( sym :: _Self , Some ( "&[]" . to_owned( ) ) ) ) ;
183
+ self_types . push( "&[]" . to_owned( ) ) ;
190
184
}
191
185
192
186
if self_ty. is_fn( ) {
@@ -201,53 +195,51 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
201
195
hir:: Safety :: Unsafe => "unsafe fn" ,
202
196
}
203
197
} ;
204
- flags . push( ( sym :: _Self , Some ( shortname. to_owned( ) ) ) ) ;
198
+ self_types . push( shortname. to_owned( ) ) ;
205
199
}
206
200
207
201
// Slices give us `[]`, `[{ty}]`
208
202
if let ty:: Slice ( aty) = self_ty. kind( ) {
209
- flags . push( ( sym :: _Self , Some ( "[]" . to_string ( ) ) ) ) ;
203
+ self_types . push( "[]" . to_owned ( ) ) ;
210
204
if let Some ( def) = aty. ty_adt_def( ) {
211
205
// We also want to be able to select the slice's type's original
212
206
// signature with no type arguments resolved
213
- flags. push( (
214
- sym:: _Self,
215
- Some ( format!( "[{}]" , self . tcx. type_of( def. did( ) ) . instantiate_identity( ) ) ) ,
216
- ) ) ;
207
+ self_types
208
+ . push( format!( "[{}]" , self . tcx. type_of( def. did( ) ) . instantiate_identity( ) ) ) ;
217
209
}
218
210
if aty. is_integral( ) {
219
- flags . push( ( sym :: _Self , Some ( "[{integral}]" . to_string( ) ) ) ) ;
211
+ self_types . push( "[{integral}]" . to_string( ) ) ;
220
212
}
221
213
}
222
214
223
215
// Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]`
224
216
if let ty:: Array ( aty, len) = self_ty. kind( ) {
225
- flags . push( ( sym :: _Self , Some ( "[]" . to_string( ) ) ) ) ;
217
+ self_types . push( "[]" . to_string( ) ) ;
226
218
let len = len. try_to_target_usize( self . tcx) ;
227
- flags . push( ( sym :: _Self , Some ( format!( "[{aty}; _]" ) ) ) ) ;
219
+ self_types . push( format!( "[{aty}; _]" ) ) ;
228
220
if let Some ( n) = len {
229
- flags . push( ( sym :: _Self , Some ( format!( "[{aty}; {n}]" ) ) ) ) ;
221
+ self_types . push( format!( "[{aty}; {n}]" ) ) ;
230
222
}
231
223
if let Some ( def) = aty. ty_adt_def( ) {
232
224
// We also want to be able to select the array's type's original
233
225
// signature with no type arguments resolved
234
226
let def_ty = self . tcx. type_of( def. did( ) ) . instantiate_identity( ) ;
235
- flags . push( ( sym :: _Self , Some ( format!( "[{def_ty}; _]" ) ) ) ) ;
227
+ self_types . push( format!( "[{def_ty}; _]" ) ) ;
236
228
if let Some ( n) = len {
237
- flags . push( ( sym :: _Self , Some ( format!( "[{def_ty}; {n}]" ) ) ) ) ;
229
+ self_types . push( format!( "[{def_ty}; {n}]" ) ) ;
238
230
}
239
231
}
240
232
if aty. is_integral( ) {
241
- flags . push( ( sym :: _Self , Some ( "[{integral}; _]" . to_string( ) ) ) ) ;
233
+ self_types . push( "[{integral}; _]" . to_string( ) ) ;
242
234
if let Some ( n) = len {
243
- flags . push( ( sym :: _Self , Some ( format!( "[{{integral}}; {n}]" ) ) ) ) ;
235
+ self_types . push( format!( "[{{integral}}; {n}]" ) ) ;
244
236
}
245
237
}
246
238
}
247
239
if let ty:: Dynamic ( traits, _, _) = self_ty. kind( ) {
248
240
for t in traits. iter( ) {
249
241
if let ty:: ExistentialPredicate :: Trait ( trait_ref) = t. skip_binder( ) {
250
- flags . push( ( sym :: _Self , Some ( self . tcx. def_path_str( trait_ref. def_id) ) ) )
242
+ self_types . push( self . tcx. def_path_str( trait_ref. def_id) ) ;
251
243
}
252
244
}
253
245
}
@@ -257,14 +249,51 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
257
249
&& let ty:: Slice ( sty) = ref_ty. kind( )
258
250
&& sty. is_integral( )
259
251
{
260
- flags . push( ( sym :: _Self , Some ( "&[{integral}]" . to_owned( ) ) ) ) ;
252
+ self_types . push( "&[{integral}]" . to_owned( ) ) ;
261
253
}
262
254
} ) ) ;
263
255
264
- flags. push ( ( sym:: This , Some ( self . tcx . def_path_str ( trait_pred. trait_ref . def_id ) ) ) ) ;
256
+ let this = self . tcx . def_path_str ( trait_pred. trait_ref . def_id ) . to_string ( ) ;
257
+ let trait_sugared = trait_pred. trait_ref . print_trait_sugared ( ) . to_string ( ) ;
258
+
259
+ let condition_options = ConditionOptions {
260
+ self_types,
261
+ from_desugaring,
262
+ cause,
263
+ crate_local,
264
+ direct,
265
+ generic_args,
266
+ } ;
267
+
268
+ // Unlike the generic_args earlier,
269
+ // this one is *not* collected under `with_no_trimmed_paths!`
270
+ // for printing the type to the user
271
+ let generic_args = self
272
+ . tcx
273
+ . generics_of ( trait_pred. trait_ref . def_id )
274
+ . own_params
275
+ . iter ( )
276
+ . filter_map ( |param| {
277
+ let value = match param. kind {
278
+ GenericParamDefKind :: Type { .. } | GenericParamDefKind :: Const { .. } => {
279
+ if let Some ( ty) = trait_pred. trait_ref . args [ param. index as usize ] . as_type ( )
280
+ {
281
+ self . tcx . short_string ( ty, long_ty_file)
282
+ } else {
283
+ trait_pred. trait_ref . args [ param. index as usize ] . to_string ( )
284
+ }
285
+ }
286
+ GenericParamDefKind :: Lifetime => return None ,
287
+ } ;
288
+ let name = param. name ;
289
+ Some ( ( name, value) )
290
+ } )
291
+ . collect ( ) ;
292
+
293
+ let format_args = FormatArgs { this, trait_sugared, generic_args, item_context } ;
265
294
266
295
if let Ok ( Some ( command) ) = OnUnimplementedDirective :: of_item ( self . tcx , def_id) {
267
- command. evaluate ( self . tcx , trait_pred. trait_ref , & flags , long_ty_file )
296
+ command. evaluate ( self . tcx , trait_pred. trait_ref , & condition_options , & format_args )
268
297
} else {
269
298
OnUnimplementedNote :: default ( )
270
299
}
@@ -634,23 +663,23 @@ impl<'tcx> OnUnimplementedDirective {
634
663
& self ,
635
664
tcx : TyCtxt < ' tcx > ,
636
665
trait_ref : ty:: TraitRef < ' tcx > ,
637
- options : & [ ( Symbol , Option < String > ) ] ,
638
- long_ty_file : & mut Option < PathBuf > ,
666
+ condition_options : & ConditionOptions ,
667
+ args : & FormatArgs ,
639
668
) -> OnUnimplementedNote {
640
669
let mut message = None ;
641
670
let mut label = None ;
642
671
let mut notes = Vec :: new ( ) ;
643
672
let mut parent_label = None ;
644
673
let mut append_const_msg = None ;
645
- info ! ( "evaluate({:?}, trait_ref={:?}, options={:?})" , self , trait_ref , options ) ;
646
-
647
- let options_map : FxHashMap < Symbol , String > =
648
- options . iter ( ) . filter_map ( | ( k , v ) | v . clone ( ) . map ( |v| ( * k , v ) ) ) . collect ( ) ;
674
+ info ! (
675
+ "evaluate({:?}, trait_ref={:?}, options={:?}, args ={:?})" ,
676
+ self , trait_ref , condition_options , args
677
+ ) ;
649
678
650
679
for command in self . subcommands . iter ( ) . chain ( Some ( self ) ) . rev ( ) {
651
680
debug ! ( ?command) ;
652
681
if let Some ( ref condition) = command. condition
653
- && !condition. matches_predicate ( tcx, options , & options_map )
682
+ && !condition. matches_predicate ( tcx, condition_options )
654
683
{
655
684
debug ! ( "evaluate: skipping {:?} due to condition" , command) ;
656
685
continue ;
@@ -674,14 +703,10 @@ impl<'tcx> OnUnimplementedDirective {
674
703
}
675
704
676
705
OnUnimplementedNote {
677
- label : label. map ( |l| l. 1 . format ( tcx, trait_ref, & options_map, long_ty_file) ) ,
678
- message : message. map ( |m| m. 1 . format ( tcx, trait_ref, & options_map, long_ty_file) ) ,
679
- notes : notes
680
- . into_iter ( )
681
- . map ( |n| n. format ( tcx, trait_ref, & options_map, long_ty_file) )
682
- . collect ( ) ,
683
- parent_label : parent_label
684
- . map ( |e_s| e_s. format ( tcx, trait_ref, & options_map, long_ty_file) ) ,
706
+ label : label. map ( |l| l. 1 . format ( tcx, trait_ref, args) ) ,
707
+ message : message. map ( |m| m. 1 . format ( tcx, trait_ref, args) ) ,
708
+ notes : notes. into_iter ( ) . map ( |n| n. format ( tcx, trait_ref, args) ) . collect ( ) ,
709
+ parent_label : parent_label. map ( |e_s| e_s. format ( tcx, trait_ref, args) ) ,
685
710
append_const_msg,
686
711
}
687
712
}
@@ -759,8 +784,7 @@ impl<'tcx> OnUnimplementedFormatString {
759
784
& self ,
760
785
tcx : TyCtxt < ' tcx > ,
761
786
trait_ref : ty:: TraitRef < ' tcx > ,
762
- options : & FxHashMap < Symbol , String > ,
763
- long_ty_file : & mut Option < PathBuf > ,
787
+ args : & FormatArgs ,
764
788
) -> String {
765
789
let trait_def_id = trait_ref. def_id ;
766
790
let ctx = if self . is_diagnostic_namespace_variant {
@@ -770,7 +794,7 @@ impl<'tcx> OnUnimplementedFormatString {
770
794
} ;
771
795
772
796
if let Ok ( s) = FormatString :: parse ( self . symbol , self . span , & ctx) {
773
- s. format ( tcx , trait_ref , options , long_ty_file )
797
+ s. format ( args )
774
798
} else {
775
799
// we cannot return errors from processing the format string as hard error here
776
800
// as the diagnostic namespace guarantees that malformed input cannot cause an error
0 commit comments