@@ -2,24 +2,23 @@ use std::iter;
22use std:: path:: PathBuf ;
33
44use rustc_ast:: { LitKind , MetaItem , MetaItemInner , MetaItemKind , MetaItemLit } ;
5- use rustc_data_structures:: fx:: FxHashMap ;
65use rustc_errors:: codes:: * ;
76use rustc_errors:: { ErrorGuaranteed , struct_span_code_err} ;
87use rustc_hir:: def_id:: { DefId , LocalDefId } ;
98use rustc_hir:: { AttrArgs , Attribute } ;
109use 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 } ;
1312use rustc_session:: lint:: builtin:: UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES ;
1413use rustc_span:: { Span , Symbol , sym} ;
1514use tracing:: { debug, info} ;
1615use { rustc_attr_parsing as attr, rustc_hir as hir} ;
1716
1817use super :: { ObligationCauseCode , PredicateObligation } ;
1918use 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 } ;
2120use 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 } ;
2322use crate :: errors:: {
2423 EmptyOnClauseInOnUnimplemented , InvalidOnClauseInOnUnimplemented , NoValueInOnUnimplemented ,
2524} ;
@@ -107,86 +106,81 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
107106 . unwrap_or_else ( || ( trait_pred. def_id ( ) , trait_pred. skip_binder ( ) . trait_ref . args ) ) ;
108107 let trait_pred = trait_pred. skip_binder ( ) ;
109108
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 ;
111112 // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): HIR is not present for RPITITs,
112113 // but I guess we could synthesize one here. We don't see any errors that rely on
113114 // 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 ( ) ) ;
116119
117- match obligation. cause . code ( ) {
120+ let direct = match obligation. cause . code ( ) {
118121 ObligationCauseCode :: BuiltinDerived ( ..)
119122 | ObligationCauseCode :: ImplDerived ( ..)
120- | ObligationCauseCode :: WellFormedDerived ( ..) => { }
123+ | ObligationCauseCode :: WellFormedDerived ( ..) => false ,
121124 _ => {
122125 // this is a "direct", user-specified, rather than derived,
123126 // obligation.
124- flags . push ( ( sym :: direct , None ) ) ;
127+ true
125128 }
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+ } ;
132130
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:?}" ) ) ;
136132
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+ } ;
138138
139139 // Add all types without trimmed paths or visible paths, ensuring they end up with
140140 // their "canonical" def path.
141141 ty:: print:: with_no_trimmed_paths!( ty:: print:: with_no_visible_paths!( {
142142 let generics = self . tcx. generics_of( def_id) ;
143143 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( ) ) ;
147145 if let Some ( def) = self_ty. ty_adt_def( ) {
148146 // We also want to be able to select self's original
149147 // 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( ) ) ;
154149 }
155150
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 {
158153 GenericParamDefKind :: Type { .. } | GenericParamDefKind :: Const { .. } => {
159- args[ param . index as usize ] . to_string( )
154+ args[ * index as usize ] . to_string( )
160155 }
161156 GenericParamDefKind :: Lifetime => continue ,
162157 } ;
163- let name = param. name;
164- flags. push( ( name, Some ( value) ) ) ;
158+ generic_args. push( ( * name, value) ) ;
165159
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( ) ;
168162 if let Some ( def) = param_ty. ty_adt_def( ) {
169163 // We also want to be able to select the parameter's
170164 // 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( ) ,
174168 ) ) ;
175169 }
176170 }
177171 }
178172
179173 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 ;
181175 }
182176
183177 // Allow targeting all integers using `{integral}`, even if the exact type was resolved
184178 if self_ty. is_integral( ) {
185- flags . push( ( sym :: _Self , Some ( "{integral}" . to_owned( ) ) ) ) ;
179+ self_types . push( "{integral}" . to_owned( ) ) ;
186180 }
187181
188182 if self_ty. is_array_slice( ) {
189- flags . push( ( sym :: _Self , Some ( "&[]" . to_owned( ) ) ) ) ;
183+ self_types . push( "&[]" . to_owned( ) ) ;
190184 }
191185
192186 if self_ty. is_fn( ) {
@@ -201,53 +195,51 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
201195 hir:: Safety :: Unsafe => "unsafe fn" ,
202196 }
203197 } ;
204- flags . push( ( sym :: _Self , Some ( shortname. to_owned( ) ) ) ) ;
198+ self_types . push( shortname. to_owned( ) ) ;
205199 }
206200
207201 // Slices give us `[]`, `[{ty}]`
208202 if let ty:: Slice ( aty) = self_ty. kind( ) {
209- flags . push( ( sym :: _Self , Some ( "[]" . to_string ( ) ) ) ) ;
203+ self_types . push( "[]" . to_owned ( ) ) ;
210204 if let Some ( def) = aty. ty_adt_def( ) {
211205 // We also want to be able to select the slice's type's original
212206 // 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( ) ) ) ;
217209 }
218210 if aty. is_integral( ) {
219- flags . push( ( sym :: _Self , Some ( "[{integral}]" . to_string( ) ) ) ) ;
211+ self_types . push( "[{integral}]" . to_string( ) ) ;
220212 }
221213 }
222214
223215 // Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]`
224216 if let ty:: Array ( aty, len) = self_ty. kind( ) {
225- flags . push( ( sym :: _Self , Some ( "[]" . to_string( ) ) ) ) ;
217+ self_types . push( "[]" . to_string( ) ) ;
226218 let len = len. try_to_target_usize( self . tcx) ;
227- flags . push( ( sym :: _Self , Some ( format!( "[{aty}; _]" ) ) ) ) ;
219+ self_types . push( format!( "[{aty}; _]" ) ) ;
228220 if let Some ( n) = len {
229- flags . push( ( sym :: _Self , Some ( format!( "[{aty}; {n}]" ) ) ) ) ;
221+ self_types . push( format!( "[{aty}; {n}]" ) ) ;
230222 }
231223 if let Some ( def) = aty. ty_adt_def( ) {
232224 // We also want to be able to select the array's type's original
233225 // signature with no type arguments resolved
234226 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}; _]" ) ) ;
236228 if let Some ( n) = len {
237- flags . push( ( sym :: _Self , Some ( format!( "[{def_ty}; {n}]" ) ) ) ) ;
229+ self_types . push( format!( "[{def_ty}; {n}]" ) ) ;
238230 }
239231 }
240232 if aty. is_integral( ) {
241- flags . push( ( sym :: _Self , Some ( "[{integral}; _]" . to_string( ) ) ) ) ;
233+ self_types . push( "[{integral}; _]" . to_string( ) ) ;
242234 if let Some ( n) = len {
243- flags . push( ( sym :: _Self , Some ( format!( "[{{integral}}; {n}]" ) ) ) ) ;
235+ self_types . push( format!( "[{{integral}}; {n}]" ) ) ;
244236 }
245237 }
246238 }
247239 if let ty:: Dynamic ( traits, _, _) = self_ty. kind( ) {
248240 for t in traits. iter( ) {
249241 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) ) ;
251243 }
252244 }
253245 }
@@ -257,14 +249,51 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
257249 && let ty:: Slice ( sty) = ref_ty. kind( )
258250 && sty. is_integral( )
259251 {
260- flags . push( ( sym :: _Self , Some ( "&[{integral}]" . to_owned( ) ) ) ) ;
252+ self_types . push( "&[{integral}]" . to_owned( ) ) ;
261253 }
262254 } ) ) ;
263255
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 } ;
265294
266295 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 )
268297 } else {
269298 OnUnimplementedNote :: default ( )
270299 }
@@ -634,23 +663,23 @@ impl<'tcx> OnUnimplementedDirective {
634663 & self ,
635664 tcx : TyCtxt < ' tcx > ,
636665 trait_ref : ty:: TraitRef < ' tcx > ,
637- options : & [ ( Symbol , Option < String > ) ] ,
638- long_ty_file : & mut Option < PathBuf > ,
666+ condition_options : & ConditionOptions ,
667+ args : & FormatArgs ,
639668 ) -> OnUnimplementedNote {
640669 let mut message = None ;
641670 let mut label = None ;
642671 let mut notes = Vec :: new ( ) ;
643672 let mut parent_label = None ;
644673 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+ ) ;
649678
650679 for command in self . subcommands . iter ( ) . chain ( Some ( self ) ) . rev ( ) {
651680 debug ! ( ?command) ;
652681 if let Some ( ref condition) = command. condition
653- && !condition. matches_predicate ( tcx, options , & options_map )
682+ && !condition. matches_predicate ( tcx, condition_options )
654683 {
655684 debug ! ( "evaluate: skipping {:?} due to condition" , command) ;
656685 continue ;
@@ -674,14 +703,10 @@ impl<'tcx> OnUnimplementedDirective {
674703 }
675704
676705 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) ) ,
685710 append_const_msg,
686711 }
687712 }
@@ -759,8 +784,7 @@ impl<'tcx> OnUnimplementedFormatString {
759784 & self ,
760785 tcx : TyCtxt < ' tcx > ,
761786 trait_ref : ty:: TraitRef < ' tcx > ,
762- options : & FxHashMap < Symbol , String > ,
763- long_ty_file : & mut Option < PathBuf > ,
787+ args : & FormatArgs ,
764788 ) -> String {
765789 let trait_def_id = trait_ref. def_id ;
766790 let ctx = if self . is_diagnostic_namespace_variant {
@@ -770,7 +794,7 @@ impl<'tcx> OnUnimplementedFormatString {
770794 } ;
771795
772796 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 )
774798 } else {
775799 // we cannot return errors from processing the format string as hard error here
776800 // as the diagnostic namespace guarantees that malformed input cannot cause an error
0 commit comments