Skip to content

Commit 87aef4b

Browse files
committed
Parse condition options into a struct
1 parent ca3f5ae commit 87aef4b

File tree

3 files changed

+168
-165
lines changed

3 files changed

+168
-165
lines changed

compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs

+101-77
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,23 @@ use std::iter;
22
use std::path::PathBuf;
33

44
use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit};
5-
use rustc_data_structures::fx::FxHashMap;
65
use rustc_errors::codes::*;
76
use rustc_errors::{ErrorGuaranteed, struct_span_code_err};
87
use rustc_hir::def_id::{DefId, LocalDefId};
98
use rustc_hir::{AttrArgs, Attribute};
109
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};
1312
use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
1413
use rustc_span::{Span, Symbol, sym};
1514
use tracing::{debug, info};
1615
use {rustc_attr_parsing as attr, rustc_hir as hir};
1716

1817
use super::{ObligationCauseCode, PredicateObligation};
1918
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};
2120
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};
2322
use 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

Comments
 (0)