Parse condition options into a struct
This commit is contained in:
parent
2007c8994d
commit
ba9f51b055
3 changed files with 168 additions and 165 deletions
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue