1
Fork 0

Parse condition options into a struct

This commit is contained in:
mejrs 2025-03-27 23:09:44 +01:00
parent 2007c8994d
commit ba9f51b055
3 changed files with 168 additions and 165 deletions

View file

@ -2,14 +2,13 @@ use std::iter;
use std::path::PathBuf; use std::path::PathBuf;
use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit}; use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::codes::*; use rustc_errors::codes::*;
use rustc_errors::{ErrorGuaranteed, struct_span_code_err}; use rustc_errors::{ErrorGuaranteed, struct_span_code_err};
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{AttrArgs, Attribute}; use rustc_hir::{AttrArgs, Attribute};
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::print::PrintTraitRefExt;
use rustc_middle::ty::{self, GenericArgsRef, GenericParamDefKind, TyCtxt}; use rustc_middle::ty::{self, GenericArgsRef, GenericParamDef, GenericParamDefKind, TyCtxt};
use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
use rustc_span::{Span, Symbol, sym}; use rustc_span::{Span, Symbol, sym};
use tracing::{debug, info}; use tracing::{debug, info};
@ -17,9 +16,9 @@ use {rustc_attr_parsing as attr, rustc_hir as hir};
use super::{ObligationCauseCode, PredicateObligation}; use super::{ObligationCauseCode, PredicateObligation};
use crate::error_reporting::TypeErrCtxt; use crate::error_reporting::TypeErrCtxt;
use crate::error_reporting::traits::on_unimplemented_condition::Condition; use crate::error_reporting::traits::on_unimplemented_condition::{Condition, ConditionOptions};
use crate::error_reporting::traits::on_unimplemented_format::errors::*; use crate::error_reporting::traits::on_unimplemented_format::errors::*;
use crate::error_reporting::traits::on_unimplemented_format::{Ctx, FormatString}; use crate::error_reporting::traits::on_unimplemented_format::{Ctx, FormatArgs, FormatString};
use crate::errors::{ use crate::errors::{
EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented, EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented,
}; };
@ -107,86 +106,81 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
.unwrap_or_else(|| (trait_pred.def_id(), trait_pred.skip_binder().trait_ref.args)); .unwrap_or_else(|| (trait_pred.def_id(), trait_pred.skip_binder().trait_ref.args));
let trait_pred = trait_pred.skip_binder(); let trait_pred = trait_pred.skip_binder();
let mut flags = vec![]; let mut self_types = vec![];
let mut generic_args: Vec<(Symbol, String)> = vec![];
let mut crate_local = false;
// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): HIR is not present for RPITITs, // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): HIR is not present for RPITITs,
// but I guess we could synthesize one here. We don't see any errors that rely on // but I guess we could synthesize one here. We don't see any errors that rely on
// that yet, though. // that yet, though.
let enclosure = self.describe_enclosure(obligation.cause.body_id).map(|t| t.to_owned()); let item_context = self
flags.push((sym::ItemContext, enclosure)); .describe_enclosure(obligation.cause.body_id)
.map(|t| t.to_owned())
.unwrap_or(String::new());
match obligation.cause.code() { let direct = match obligation.cause.code() {
ObligationCauseCode::BuiltinDerived(..) ObligationCauseCode::BuiltinDerived(..)
| ObligationCauseCode::ImplDerived(..) | ObligationCauseCode::ImplDerived(..)
| ObligationCauseCode::WellFormedDerived(..) => {} | ObligationCauseCode::WellFormedDerived(..) => false,
_ => { _ => {
// this is a "direct", user-specified, rather than derived, // this is a "direct", user-specified, rather than derived,
// obligation. // obligation.
flags.push((sym::direct, None)); true
} }
} };
if let Some(k) = obligation.cause.span.desugaring_kind() { let from_desugaring = obligation.cause.span.desugaring_kind().map(|k| format!("{k:?}"));
flags.push((sym::from_desugaring, None));
flags.push((sym::from_desugaring, Some(format!("{k:?}"))));
}
if let ObligationCauseCode::MainFunctionType = obligation.cause.code() { let cause = if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
flags.push((sym::cause, Some("MainFunctionType".to_string()))); Some("MainFunctionType".to_string())
} } else {
None
flags.push((sym::Trait, Some(trait_pred.trait_ref.print_trait_sugared().to_string()))); };
// Add all types without trimmed paths or visible paths, ensuring they end up with // Add all types without trimmed paths or visible paths, ensuring they end up with
// their "canonical" def path. // their "canonical" def path.
ty::print::with_no_trimmed_paths!(ty::print::with_no_visible_paths!({ ty::print::with_no_trimmed_paths!(ty::print::with_no_visible_paths!({
let generics = self.tcx.generics_of(def_id); let generics = self.tcx.generics_of(def_id);
let self_ty = trait_pred.self_ty(); let self_ty = trait_pred.self_ty();
// This is also included through the generics list as `Self`, self_types.push(self_ty.to_string());
// but the parser won't allow you to use it
flags.push((sym::_Self, Some(self_ty.to_string())));
if let Some(def) = self_ty.ty_adt_def() { if let Some(def) = self_ty.ty_adt_def() {
// We also want to be able to select self's original // We also want to be able to select self's original
// signature with no type arguments resolved // signature with no type arguments resolved
flags.push(( self_types.push(self.tcx.type_of(def.did()).instantiate_identity().to_string());
sym::_Self,
Some(self.tcx.type_of(def.did()).instantiate_identity().to_string()),
));
} }
for param in generics.own_params.iter() { for GenericParamDef { name, kind, index, .. } in generics.own_params.iter() {
let value = match param.kind { let value = match kind {
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
args[param.index as usize].to_string() args[*index as usize].to_string()
} }
GenericParamDefKind::Lifetime => continue, GenericParamDefKind::Lifetime => continue,
}; };
let name = param.name; generic_args.push((*name, value));
flags.push((name, Some(value)));
if let GenericParamDefKind::Type { .. } = param.kind { if let GenericParamDefKind::Type { .. } = kind {
let param_ty = args[param.index as usize].expect_ty(); let param_ty = args[*index as usize].expect_ty();
if let Some(def) = param_ty.ty_adt_def() { if let Some(def) = param_ty.ty_adt_def() {
// We also want to be able to select the parameter's // We also want to be able to select the parameter's
// original signature with no type arguments resolved // original signature with no type arguments resolved
flags.push(( generic_args.push((
name, *name,
Some(self.tcx.type_of(def.did()).instantiate_identity().to_string()), self.tcx.type_of(def.did()).instantiate_identity().to_string(),
)); ));
} }
} }
} }
if let Some(true) = self_ty.ty_adt_def().map(|def| def.did().is_local()) { if let Some(true) = self_ty.ty_adt_def().map(|def| def.did().is_local()) {
flags.push((sym::crate_local, None)); crate_local = true;
} }
// Allow targeting all integers using `{integral}`, even if the exact type was resolved // Allow targeting all integers using `{integral}`, even if the exact type was resolved
if self_ty.is_integral() { if self_ty.is_integral() {
flags.push((sym::_Self, Some("{integral}".to_owned()))); self_types.push("{integral}".to_owned());
} }
if self_ty.is_array_slice() { if self_ty.is_array_slice() {
flags.push((sym::_Self, Some("&[]".to_owned()))); self_types.push("&[]".to_owned());
} }
if self_ty.is_fn() { if self_ty.is_fn() {
@ -201,53 +195,51 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
hir::Safety::Unsafe => "unsafe fn", hir::Safety::Unsafe => "unsafe fn",
} }
}; };
flags.push((sym::_Self, Some(shortname.to_owned()))); self_types.push(shortname.to_owned());
} }
// Slices give us `[]`, `[{ty}]` // Slices give us `[]`, `[{ty}]`
if let ty::Slice(aty) = self_ty.kind() { if let ty::Slice(aty) = self_ty.kind() {
flags.push((sym::_Self, Some("[]".to_string()))); self_types.push("[]".to_owned());
if let Some(def) = aty.ty_adt_def() { if let Some(def) = aty.ty_adt_def() {
// We also want to be able to select the slice's type's original // We also want to be able to select the slice's type's original
// signature with no type arguments resolved // signature with no type arguments resolved
flags.push(( self_types
sym::_Self, .push(format!("[{}]", self.tcx.type_of(def.did()).instantiate_identity()));
Some(format!("[{}]", self.tcx.type_of(def.did()).instantiate_identity())),
));
} }
if aty.is_integral() { if aty.is_integral() {
flags.push((sym::_Self, Some("[{integral}]".to_string()))); self_types.push("[{integral}]".to_string());
} }
} }
// Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]` // Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]`
if let ty::Array(aty, len) = self_ty.kind() { if let ty::Array(aty, len) = self_ty.kind() {
flags.push((sym::_Self, Some("[]".to_string()))); self_types.push("[]".to_string());
let len = len.try_to_target_usize(self.tcx); let len = len.try_to_target_usize(self.tcx);
flags.push((sym::_Self, Some(format!("[{aty}; _]")))); self_types.push(format!("[{aty}; _]"));
if let Some(n) = len { if let Some(n) = len {
flags.push((sym::_Self, Some(format!("[{aty}; {n}]")))); self_types.push(format!("[{aty}; {n}]"));
} }
if let Some(def) = aty.ty_adt_def() { if let Some(def) = aty.ty_adt_def() {
// We also want to be able to select the array's type's original // We also want to be able to select the array's type's original
// signature with no type arguments resolved // signature with no type arguments resolved
let def_ty = self.tcx.type_of(def.did()).instantiate_identity(); let def_ty = self.tcx.type_of(def.did()).instantiate_identity();
flags.push((sym::_Self, Some(format!("[{def_ty}; _]")))); self_types.push(format!("[{def_ty}; _]"));
if let Some(n) = len { if let Some(n) = len {
flags.push((sym::_Self, Some(format!("[{def_ty}; {n}]")))); self_types.push(format!("[{def_ty}; {n}]"));
} }
} }
if aty.is_integral() { if aty.is_integral() {
flags.push((sym::_Self, Some("[{integral}; _]".to_string()))); self_types.push("[{integral}; _]".to_string());
if let Some(n) = len { if let Some(n) = len {
flags.push((sym::_Self, Some(format!("[{{integral}}; {n}]")))); self_types.push(format!("[{{integral}}; {n}]"));
} }
} }
} }
if let ty::Dynamic(traits, _, _) = self_ty.kind() { if let ty::Dynamic(traits, _, _) = self_ty.kind() {
for t in traits.iter() { for t in traits.iter() {
if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() { if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() {
flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id)))) self_types.push(self.tcx.def_path_str(trait_ref.def_id));
} }
} }
} }
@ -257,14 +249,51 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
&& let ty::Slice(sty) = ref_ty.kind() && let ty::Slice(sty) = ref_ty.kind()
&& sty.is_integral() && sty.is_integral()
{ {
flags.push((sym::_Self, Some("&[{integral}]".to_owned()))); self_types.push("&[{integral}]".to_owned());
} }
})); }));
flags.push((sym::This, Some(self.tcx.def_path_str(trait_pred.trait_ref.def_id)))); let this = self.tcx.def_path_str(trait_pred.trait_ref.def_id).to_string();
let trait_sugared = trait_pred.trait_ref.print_trait_sugared().to_string();
let condition_options = ConditionOptions {
self_types,
from_desugaring,
cause,
crate_local,
direct,
generic_args,
};
// Unlike the generic_args earlier,
// this one is *not* collected under `with_no_trimmed_paths!`
// for printing the type to the user
let generic_args = self
.tcx
.generics_of(trait_pred.trait_ref.def_id)
.own_params
.iter()
.filter_map(|param| {
let value = match param.kind {
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
if let Some(ty) = trait_pred.trait_ref.args[param.index as usize].as_type()
{
self.tcx.short_string(ty, long_ty_file)
} else {
trait_pred.trait_ref.args[param.index as usize].to_string()
}
}
GenericParamDefKind::Lifetime => return None,
};
let name = param.name;
Some((name, value))
})
.collect();
let format_args = FormatArgs { this, trait_sugared, generic_args, item_context };
if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) { if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) {
command.evaluate(self.tcx, trait_pred.trait_ref, &flags, long_ty_file) command.evaluate(self.tcx, trait_pred.trait_ref, &condition_options, &format_args)
} else { } else {
OnUnimplementedNote::default() OnUnimplementedNote::default()
} }
@ -634,23 +663,23 @@ impl<'tcx> OnUnimplementedDirective {
&self, &self,
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
trait_ref: ty::TraitRef<'tcx>, trait_ref: ty::TraitRef<'tcx>,
options: &[(Symbol, Option<String>)], condition_options: &ConditionOptions,
long_ty_file: &mut Option<PathBuf>, args: &FormatArgs,
) -> OnUnimplementedNote { ) -> OnUnimplementedNote {
let mut message = None; let mut message = None;
let mut label = None; let mut label = None;
let mut notes = Vec::new(); let mut notes = Vec::new();
let mut parent_label = None; let mut parent_label = None;
let mut append_const_msg = None; let mut append_const_msg = None;
info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options); info!(
"evaluate({:?}, trait_ref={:?}, options={:?}, args ={:?})",
let options_map: FxHashMap<Symbol, String> = self, trait_ref, condition_options, args
options.iter().filter_map(|(k, v)| v.clone().map(|v| (*k, v))).collect(); );
for command in self.subcommands.iter().chain(Some(self)).rev() { for command in self.subcommands.iter().chain(Some(self)).rev() {
debug!(?command); debug!(?command);
if let Some(ref condition) = command.condition if let Some(ref condition) = command.condition
&& !condition.matches_predicate(tcx, options, &options_map) && !condition.matches_predicate(tcx, condition_options)
{ {
debug!("evaluate: skipping {:?} due to condition", command); debug!("evaluate: skipping {:?} due to condition", command);
continue; continue;
@ -674,14 +703,10 @@ impl<'tcx> OnUnimplementedDirective {
} }
OnUnimplementedNote { OnUnimplementedNote {
label: label.map(|l| l.1.format(tcx, trait_ref, &options_map, long_ty_file)), label: label.map(|l| l.1.format(tcx, trait_ref, args)),
message: message.map(|m| m.1.format(tcx, trait_ref, &options_map, long_ty_file)), message: message.map(|m| m.1.format(tcx, trait_ref, args)),
notes: notes notes: notes.into_iter().map(|n| n.format(tcx, trait_ref, args)).collect(),
.into_iter() parent_label: parent_label.map(|e_s| e_s.format(tcx, trait_ref, args)),
.map(|n| n.format(tcx, trait_ref, &options_map, long_ty_file))
.collect(),
parent_label: parent_label
.map(|e_s| e_s.format(tcx, trait_ref, &options_map, long_ty_file)),
append_const_msg, append_const_msg,
} }
} }
@ -759,8 +784,7 @@ impl<'tcx> OnUnimplementedFormatString {
&self, &self,
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
trait_ref: ty::TraitRef<'tcx>, trait_ref: ty::TraitRef<'tcx>,
options: &FxHashMap<Symbol, String>, args: &FormatArgs,
long_ty_file: &mut Option<PathBuf>,
) -> String { ) -> String {
let trait_def_id = trait_ref.def_id; let trait_def_id = trait_ref.def_id;
let ctx = if self.is_diagnostic_namespace_variant { let ctx = if self.is_diagnostic_namespace_variant {
@ -770,7 +794,7 @@ impl<'tcx> OnUnimplementedFormatString {
}; };
if let Ok(s) = FormatString::parse(self.symbol, self.span, &ctx) { if let Ok(s) = FormatString::parse(self.symbol, self.span, &ctx) {
s.format(tcx, trait_ref, options, long_ty_file) s.format(args)
} else { } else {
// we cannot return errors from processing the format string as hard error here // we cannot return errors from processing the format string as hard error here
// as the diagnostic namespace guarantees that malformed input cannot cause an error // as the diagnostic namespace guarantees that malformed input cannot cause an error

View file

@ -1,9 +1,8 @@
use rustc_ast::MetaItemInner; use rustc_ast::MetaItemInner;
use rustc_attr_parsing as attr; use rustc_attr_parsing as attr;
use rustc_data_structures::fx::FxHashMap;
use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::ty::{self, TyCtxt};
use rustc_parse_format::{ParseMode, Parser, Piece, Position}; use rustc_parse_format::{ParseMode, Parser, Piece, Position};
use rustc_span::{Span, Symbol, sym}; use rustc_span::{Span, Symbol, kw, sym};
pub static ALLOWED_CONDITION_SYMBOLS: &[Symbol] = &[ pub static ALLOWED_CONDITION_SYMBOLS: &[Symbol] = &[
sym::from_desugaring, sym::from_desugaring,
@ -26,12 +25,7 @@ impl Condition {
self.inner.span() self.inner.span()
} }
pub fn matches_predicate<'tcx>( pub fn matches_predicate<'tcx>(&self, tcx: TyCtxt<'tcx>, options: &ConditionOptions) -> bool {
&self,
tcx: TyCtxt<'tcx>,
options: &[(Symbol, Option<String>)],
options_map: &FxHashMap<Symbol, String>,
) -> bool {
attr::eval_condition(&self.inner, tcx.sess, Some(tcx.features()), &mut |cfg| { attr::eval_condition(&self.inner, tcx.sess, Some(tcx.features()), &mut |cfg| {
let value = cfg.value.map(|v| { let value = cfg.value.map(|v| {
// `with_no_visible_paths` is also used when generating the options, // `with_no_visible_paths` is also used when generating the options,
@ -44,8 +38,8 @@ impl Condition {
Piece::NextArgument(a) => match a.position { Piece::NextArgument(a) => match a.position {
Position::ArgumentNamed(arg) => { Position::ArgumentNamed(arg) => {
let s = Symbol::intern(arg); let s = Symbol::intern(arg);
match options_map.get(&s) { match options.generic_args.iter().find(|(k, _)| *k == s) {
Some(val) => val.to_string(), Some((_, val)) => val.to_string(),
None => format!("{{{arg}}}"), None => format!("{{{arg}}}"),
} }
} }
@ -58,7 +52,36 @@ impl Condition {
}) })
}); });
options.contains(&(cfg.name, value)) options.contains(cfg.name, &value)
}) })
} }
} }
#[derive(Debug)]
pub struct ConditionOptions {
pub self_types: Vec<String>,
pub from_desugaring: Option<String>,
pub cause: Option<String>,
pub crate_local: bool,
pub direct: bool,
pub generic_args: Vec<(Symbol, String)>,
}
impl ConditionOptions {
pub fn contains(&self, key: Symbol, value: &Option<String>) -> bool {
match (key, value) {
(sym::_Self | kw::SelfUpper, Some(value)) => self.self_types.contains(&value),
// from_desugaring as a flag
(sym::from_desugaring, None) => self.from_desugaring.is_some(),
// from_desugaring as key == value
(sym::from_desugaring, v) => *v == self.from_desugaring,
(sym::cause, Some(value)) => self.cause.as_deref() == Some(value),
(sym::crate_local, None) => self.crate_local,
(sym::direct, None) => self.direct,
(other, Some(value)) => {
self.generic_args.iter().any(|(k, v)| *k == other && v == value)
}
_ => false,
}
}
}

View file

@ -1,10 +1,5 @@
use std::fmt::Write;
use std::path::PathBuf;
use errors::*; use errors::*;
use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::TyCtxt;
use rustc_middle::span_bug;
use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
use rustc_parse_format::{ use rustc_parse_format::{
Alignment, Argument, Count, FormatSpec, InnerSpan, ParseError, ParseMode, Parser, Alignment, Argument, Count, FormatSpec, InnerSpan, ParseError, ParseMode, Parser,
Piece as RpfPiece, Position, Piece as RpfPiece, Position,
@ -13,6 +8,7 @@ use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
use rustc_span::def_id::DefId; use rustc_span::def_id::DefId;
use rustc_span::{BytePos, Pos, Span, Symbol, kw, sym}; use rustc_span::{BytePos, Pos, Span, Symbol, kw, sym};
#[allow(dead_code)]
pub struct FormatString { pub struct FormatString {
input: Symbol, input: Symbol,
input_span: Span, input_span: Span,
@ -99,6 +95,24 @@ impl FormatWarning {
} }
} }
#[derive(Debug)]
pub struct ConditionOptions {
pub self_types: Vec<String>,
pub from_desugaring: Option<String>,
pub cause: Option<String>,
pub crate_local: bool,
pub direct: bool,
pub generic_args: Vec<(Symbol, String)>,
}
#[derive(Debug)]
pub struct FormatArgs {
pub this: String,
pub trait_sugared: String,
pub item_context: String,
pub generic_args: Vec<(Symbol, String)>,
}
impl FormatString { impl FormatString {
pub fn parse(input: Symbol, input_span: Span, ctx: &Ctx<'_>) -> Result<Self, Vec<ParseError>> { pub fn parse(input: Symbol, input_span: Span, ctx: &Ctx<'_>) -> Result<Self, Vec<ParseError>> {
let s = input.as_str(); let s = input.as_str();
@ -126,92 +140,34 @@ impl FormatString {
} }
} }
pub fn format<'tcx>( pub fn format(&self, args: &FormatArgs) -> String {
&self,
tcx: TyCtxt<'tcx>,
trait_ref: ty::TraitRef<'tcx>,
options: &FxHashMap<Symbol, String>,
long_ty_file: &mut Option<PathBuf>,
) -> String {
let generics = tcx.generics_of(trait_ref.def_id);
let generic_map = generics
.own_params
.iter()
.filter_map(|param| {
let value = match param.kind {
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
if let Some(ty) = trait_ref.args[param.index as usize].as_type() {
tcx.short_string(ty, long_ty_file)
} else {
trait_ref.args[param.index as usize].to_string()
}
}
GenericParamDefKind::Lifetime => return None,
};
let name = param.name;
Some((name, value))
})
.collect::<FxHashMap<Symbol, String>>();
let mut ret = String::new(); let mut ret = String::new();
for piece in &self.pieces { for piece in &self.pieces {
match piece { match piece {
Piece::Lit(s) | Piece::Arg(FormatArg::AsIs(s)) => ret.push_str(&s), Piece::Lit(s) | Piece::Arg(FormatArg::AsIs(s)) => ret.push_str(&s),
// `A` if we have `trait Trait<A> {}` and `note = "i'm the actual type of {A}"` // `A` if we have `trait Trait<A> {}` and `note = "i'm the actual type of {A}"`
Piece::Arg(FormatArg::GenericParam { generic_param, span }) => { Piece::Arg(FormatArg::GenericParam { generic_param, .. }) => {
// Should always be some but we can't raise errors here // Should always be some but we can't raise errors here
if let Some(value) = generic_map.get(&generic_param) { let value = match args.generic_args.iter().find(|(p, _)| p == generic_param) {
ret.push_str(value); Some((_, val)) => val.to_string(),
} else if cfg!(debug_assertions) { None => generic_param.to_string(),
span_bug!(*span, "invalid generic parameter"); };
} else { ret.push_str(&value);
let _ = ret.write_fmt(format_args!("{{{}}}", generic_param.as_str()));
}
} }
// `{Self}` // `{Self}`
Piece::Arg(FormatArg::SelfUpper) => { Piece::Arg(FormatArg::SelfUpper) => {
let Some(slf) = generic_map.get(&kw::SelfUpper) else { let slf = match args.generic_args.iter().find(|(p, _)| *p == kw::SelfUpper) {
span_bug!( Some((_, val)) => val.to_string(),
self.input_span, None => "Self".to_string(),
"broken format string {:?} for {:?}: \
no argument matching `Self`",
self.input,
trait_ref,
)
}; };
ret.push_str(&slf); ret.push_str(&slf);
} }
// It's only `rustc_onunimplemented` from here // It's only `rustc_onunimplemented` from here
Piece::Arg(FormatArg::This) => { Piece::Arg(FormatArg::This) => ret.push_str(&args.this),
let Some(this) = options.get(&sym::This) else { Piece::Arg(FormatArg::Trait) => ret.push_str(&args.trait_sugared),
span_bug!( Piece::Arg(FormatArg::ItemContext) => ret.push_str(&args.item_context),
self.input_span,
"broken format string {:?} for {:?}: \
no argument matching This",
self.input,
trait_ref,
)
};
ret.push_str(this);
}
Piece::Arg(FormatArg::Trait) => {
let Some(this) = options.get(&sym::Trait) else {
span_bug!(
self.input_span,
"broken format string {:?} for {:?}: \
no argument matching Trait",
self.input,
trait_ref,
)
};
ret.push_str(this);
}
Piece::Arg(FormatArg::ItemContext) => {
let itemcontext = options.get(&sym::ItemContext);
ret.push_str(itemcontext.unwrap_or(&String::new()));
}
} }
} }
ret ret