Documentation and finishing touches
This commit is contained in:
parent
ba9f51b055
commit
8586cad77c
4 changed files with 215 additions and 79 deletions
|
@ -1270,6 +1270,25 @@ impl DesugaringKind {
|
||||||
DesugaringKind::PatTyRange => "pattern type",
|
DesugaringKind::PatTyRange => "pattern type",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// For use with `rustc_unimplemented` to support conditions
|
||||||
|
/// like `from_desugaring = "QuestionMark"`
|
||||||
|
pub fn matches(&self, value: &str) -> bool {
|
||||||
|
match self {
|
||||||
|
DesugaringKind::CondTemporary => value == "CondTemporary",
|
||||||
|
DesugaringKind::Async => value == "Async",
|
||||||
|
DesugaringKind::Await => value == "Await",
|
||||||
|
DesugaringKind::QuestionMark => value == "QuestionMark",
|
||||||
|
DesugaringKind::TryBlock => value == "TryBlock",
|
||||||
|
DesugaringKind::YeetExpr => value == "YeetExpr",
|
||||||
|
DesugaringKind::OpaqueTy => value == "OpaqueTy",
|
||||||
|
DesugaringKind::ForLoop => value == "ForLoop",
|
||||||
|
DesugaringKind::WhileLoop => value == "WhileLoop",
|
||||||
|
DesugaringKind::BoundModifier => value == "BoundModifier",
|
||||||
|
DesugaringKind::Contract => value == "Contract",
|
||||||
|
DesugaringKind::PatTyRange => value == "PatTyRange",
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
|
@ -6,6 +6,7 @@ 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_macros::LintDiagnostic;
|
||||||
use rustc_middle::bug;
|
use rustc_middle::bug;
|
||||||
use rustc_middle::ty::print::PrintTraitRefExt;
|
use rustc_middle::ty::print::PrintTraitRefExt;
|
||||||
use rustc_middle::ty::{self, GenericArgsRef, GenericParamDef, GenericParamDefKind, TyCtxt};
|
use rustc_middle::ty::{self, GenericArgsRef, GenericParamDef, GenericParamDefKind, TyCtxt};
|
||||||
|
@ -17,7 +18,6 @@ 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, ConditionOptions};
|
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::{Ctx, FormatArgs, FormatString};
|
use crate::error_reporting::traits::on_unimplemented_format::{Ctx, FormatArgs, FormatString};
|
||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented,
|
EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented,
|
||||||
|
@ -112,10 +112,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
// 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 item_context = self
|
let item_context = self.describe_enclosure(obligation.cause.body_id).unwrap_or("");
|
||||||
.describe_enclosure(obligation.cause.body_id)
|
|
||||||
.map(|t| t.to_owned())
|
|
||||||
.unwrap_or(String::new());
|
|
||||||
|
|
||||||
let direct = match obligation.cause.code() {
|
let direct = match obligation.cause.code() {
|
||||||
ObligationCauseCode::BuiltinDerived(..)
|
ObligationCauseCode::BuiltinDerived(..)
|
||||||
|
@ -128,7 +125,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let from_desugaring = obligation.cause.span.desugaring_kind().map(|k| format!("{k:?}"));
|
let from_desugaring = obligation.cause.span.desugaring_kind();
|
||||||
|
|
||||||
let cause = if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
|
let cause = if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
|
||||||
Some("MainFunctionType".to_string())
|
Some("MainFunctionType".to_string())
|
||||||
|
@ -253,8 +250,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let this = self.tcx.def_path_str(trait_pred.trait_ref.def_id).to_string();
|
let this = self.tcx.def_path_str(trait_pred.trait_ref.def_id);
|
||||||
let trait_sugared = trait_pred.trait_ref.print_trait_sugared().to_string();
|
let trait_sugared = trait_pred.trait_ref.print_trait_sugared();
|
||||||
|
|
||||||
let condition_options = ConditionOptions {
|
let condition_options = ConditionOptions {
|
||||||
self_types,
|
self_types,
|
||||||
|
@ -268,6 +265,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
// Unlike the generic_args earlier,
|
// Unlike the generic_args earlier,
|
||||||
// this one is *not* collected under `with_no_trimmed_paths!`
|
// this one is *not* collected under `with_no_trimmed_paths!`
|
||||||
// for printing the type to the user
|
// for printing the type to the user
|
||||||
|
//
|
||||||
|
// This includes `Self`, as it is the first parameter in `own_params`.
|
||||||
let generic_args = self
|
let generic_args = self
|
||||||
.tcx
|
.tcx
|
||||||
.generics_of(trait_pred.trait_ref.def_id)
|
.generics_of(trait_pred.trait_ref.def_id)
|
||||||
|
@ -341,6 +340,63 @@ pub enum AppendConstMessage {
|
||||||
Custom(Symbol, Span),
|
Custom(Symbol, Span),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(LintDiagnostic)]
|
||||||
|
#[diag(trait_selection_malformed_on_unimplemented_attr)]
|
||||||
|
#[help]
|
||||||
|
pub struct MalformedOnUnimplementedAttrLint {
|
||||||
|
#[label]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MalformedOnUnimplementedAttrLint {
|
||||||
|
pub fn new(span: Span) -> Self {
|
||||||
|
Self { span }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(LintDiagnostic)]
|
||||||
|
#[diag(trait_selection_missing_options_for_on_unimplemented_attr)]
|
||||||
|
#[help]
|
||||||
|
pub struct MissingOptionsForOnUnimplementedAttr;
|
||||||
|
|
||||||
|
#[derive(LintDiagnostic)]
|
||||||
|
#[diag(trait_selection_ignored_diagnostic_option)]
|
||||||
|
pub struct IgnoredDiagnosticOption {
|
||||||
|
pub option_name: &'static str,
|
||||||
|
#[label]
|
||||||
|
pub span: Span,
|
||||||
|
#[label(trait_selection_other_label)]
|
||||||
|
pub prev_span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IgnoredDiagnosticOption {
|
||||||
|
pub fn maybe_emit_warning<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
item_def_id: DefId,
|
||||||
|
new: Option<Span>,
|
||||||
|
old: Option<Span>,
|
||||||
|
option_name: &'static str,
|
||||||
|
) {
|
||||||
|
if let (Some(new_item), Some(old_item)) = (new, old) {
|
||||||
|
if let Some(item_def_id) = item_def_id.as_local() {
|
||||||
|
tcx.emit_node_span_lint(
|
||||||
|
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||||
|
tcx.local_def_id_to_hir_id(item_def_id),
|
||||||
|
new_item,
|
||||||
|
IgnoredDiagnosticOption { span: new_item, prev_span: old_item, option_name },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(LintDiagnostic)]
|
||||||
|
#[diag(trait_selection_wrapped_parser_error)]
|
||||||
|
pub struct WrappedParserError {
|
||||||
|
pub description: String,
|
||||||
|
pub label: String,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> OnUnimplementedDirective {
|
impl<'tcx> OnUnimplementedDirective {
|
||||||
fn parse(
|
fn parse(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
@ -664,7 +720,7 @@ impl<'tcx> OnUnimplementedDirective {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
trait_ref: ty::TraitRef<'tcx>,
|
trait_ref: ty::TraitRef<'tcx>,
|
||||||
condition_options: &ConditionOptions,
|
condition_options: &ConditionOptions,
|
||||||
args: &FormatArgs,
|
args: &FormatArgs<'tcx>,
|
||||||
) -> OnUnimplementedNote {
|
) -> OnUnimplementedNote {
|
||||||
let mut message = None;
|
let mut message = None;
|
||||||
let mut label = None;
|
let mut label = None;
|
||||||
|
@ -784,7 +840,7 @@ impl<'tcx> OnUnimplementedFormatString {
|
||||||
&self,
|
&self,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
trait_ref: ty::TraitRef<'tcx>,
|
trait_ref: ty::TraitRef<'tcx>,
|
||||||
args: &FormatArgs,
|
args: &FormatArgs<'tcx>,
|
||||||
) -> 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 {
|
||||||
|
|
|
@ -2,19 +2,10 @@ use rustc_ast::MetaItemInner;
|
||||||
use rustc_attr_parsing as attr;
|
use rustc_attr_parsing as attr;
|
||||||
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, kw, sym};
|
use rustc_span::{DesugaringKind, Span, Symbol, kw, sym};
|
||||||
|
|
||||||
pub static ALLOWED_CONDITION_SYMBOLS: &[Symbol] = &[
|
|
||||||
sym::from_desugaring,
|
|
||||||
sym::direct,
|
|
||||||
sym::cause,
|
|
||||||
sym::integral,
|
|
||||||
sym::integer_,
|
|
||||||
sym::float,
|
|
||||||
sym::_Self,
|
|
||||||
sym::crate_local,
|
|
||||||
];
|
|
||||||
|
|
||||||
|
/// A predicate in an attribute using on, all, any,
|
||||||
|
/// similar to a cfg predicate.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Condition {
|
pub struct Condition {
|
||||||
pub inner: MetaItemInner,
|
pub inner: MetaItemInner,
|
||||||
|
@ -31,8 +22,7 @@ impl Condition {
|
||||||
// `with_no_visible_paths` is also used when generating the options,
|
// `with_no_visible_paths` is also used when generating the options,
|
||||||
// so we need to match it here.
|
// so we need to match it here.
|
||||||
ty::print::with_no_visible_paths!({
|
ty::print::with_no_visible_paths!({
|
||||||
let mut parser = Parser::new(v.as_str(), None, None, false, ParseMode::Format);
|
Parser::new(v.as_str(), None, None, false, ParseMode::Format)
|
||||||
let constructed_message = (&mut parser)
|
|
||||||
.map(|p| match p {
|
.map(|p| match p {
|
||||||
Piece::Lit(s) => s.to_owned(),
|
Piece::Lit(s) => s.to_owned(),
|
||||||
Piece::NextArgument(a) => match a.position {
|
Piece::NextArgument(a) => match a.position {
|
||||||
|
@ -47,8 +37,7 @@ impl Condition {
|
||||||
Position::ArgumentIs(idx) => format!("{{{idx}}}"),
|
Position::ArgumentIs(idx) => format!("{{{idx}}}"),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.collect();
|
.collect()
|
||||||
constructed_message
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -57,13 +46,57 @@ impl Condition {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used with `Condition::matches_predicate` to test whether the condition applies
|
||||||
|
///
|
||||||
|
/// For example, given a
|
||||||
|
/// ```rust,ignore (just an example)
|
||||||
|
/// #[rustc_on_unimplemented(
|
||||||
|
/// on(all(from_desugaring = "QuestionMark"),
|
||||||
|
/// message = "the `?` operator can only be used in {ItemContext} \
|
||||||
|
/// that returns `Result` or `Option` \
|
||||||
|
/// (or another type that implements `{FromResidual}`)",
|
||||||
|
/// label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`",
|
||||||
|
/// parent_label = "this function should return `Result` or `Option` to accept `?`"
|
||||||
|
/// ),
|
||||||
|
/// )]
|
||||||
|
/// pub trait FromResidual<R = <Self as Try>::Residual> {
|
||||||
|
/// ...
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// async fn an_async_function() -> u32 {
|
||||||
|
/// let x: Option<u32> = None;
|
||||||
|
/// x?; //~ ERROR the `?` operator
|
||||||
|
/// 22
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
/// it will look like this:
|
||||||
|
///
|
||||||
|
/// ```rust,ignore (just an example)
|
||||||
|
/// ConditionOptions {
|
||||||
|
/// self_types: ["u32", "{integral}"],
|
||||||
|
/// from_desugaring: Some("QuestionMark"),
|
||||||
|
/// cause: None,
|
||||||
|
/// crate_local: false,
|
||||||
|
/// direct: true,
|
||||||
|
/// generic_args: [("Self","u32"),
|
||||||
|
/// ("R", "core::option::Option<core::convert::Infallible>"),
|
||||||
|
/// ("R", "core::option::Option<T>" ),
|
||||||
|
/// ],
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ConditionOptions {
|
pub struct ConditionOptions {
|
||||||
|
/// All the self types that may apply.
|
||||||
|
/// for example
|
||||||
pub self_types: Vec<String>,
|
pub self_types: Vec<String>,
|
||||||
pub from_desugaring: Option<String>,
|
// The kind of compiler desugaring.
|
||||||
|
pub from_desugaring: Option<DesugaringKind>,
|
||||||
|
/// Match on a variant of [rustc_infer::traits::ObligationCauseCode]
|
||||||
pub cause: Option<String>,
|
pub cause: Option<String>,
|
||||||
pub crate_local: bool,
|
pub crate_local: bool,
|
||||||
|
/// Is the obligation "directly" user-specified, rather than derived?
|
||||||
pub direct: bool,
|
pub direct: bool,
|
||||||
|
// A list of the generic arguments and their reified types
|
||||||
pub generic_args: Vec<(Symbol, String)>,
|
pub generic_args: Vec<(Symbol, String)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +107,7 @@ impl ConditionOptions {
|
||||||
// from_desugaring as a flag
|
// from_desugaring as a flag
|
||||||
(sym::from_desugaring, None) => self.from_desugaring.is_some(),
|
(sym::from_desugaring, None) => self.from_desugaring.is_some(),
|
||||||
// from_desugaring as key == value
|
// from_desugaring as key == value
|
||||||
(sym::from_desugaring, v) => *v == self.from_desugaring,
|
(sym::from_desugaring, Some(v)) if let Some(ds) = self.from_desugaring => ds.matches(v),
|
||||||
(sym::cause, Some(value)) => self.cause.as_deref() == Some(value),
|
(sym::cause, Some(value)) => self.cause.as_deref() == Some(value),
|
||||||
(sym::crate_local, None) => self.crate_local,
|
(sym::crate_local, None) => self.crate_local,
|
||||||
(sym::direct, None) => self.direct,
|
(sym::direct, None) => self.direct,
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
use errors::*;
|
use errors::*;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
|
use rustc_middle::ty::print::TraitRefPrintSugared;
|
||||||
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,
|
||||||
|
@ -8,28 +11,39 @@ 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)]
|
/// Like [std::fmt::Arguments] this is a string that has been parsed into "pieces",
|
||||||
|
/// either as string pieces or dynamic arguments.
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct FormatString {
|
pub struct FormatString {
|
||||||
|
#[allow(dead_code, reason = "Debug impl")]
|
||||||
input: Symbol,
|
input: Symbol,
|
||||||
input_span: Span,
|
span: Span,
|
||||||
pieces: Vec<Piece>,
|
pieces: Vec<Piece>,
|
||||||
// the formatting string was parsed succesfully but with warnings
|
/// The formatting string was parsed succesfully but with warnings
|
||||||
pub warnings: Vec<FormatWarning>,
|
pub warnings: Vec<FormatWarning>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
enum Piece {
|
enum Piece {
|
||||||
Lit(String),
|
Lit(String),
|
||||||
Arg(FormatArg),
|
Arg(FormatArg),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum FormatArg {
|
#[derive(Debug)]
|
||||||
|
enum FormatArg {
|
||||||
// A generic parameter, like `{T}` if we're on the `From<T>` trait.
|
// A generic parameter, like `{T}` if we're on the `From<T>` trait.
|
||||||
GenericParam { generic_param: Symbol, span: Span },
|
GenericParam {
|
||||||
|
generic_param: Symbol,
|
||||||
|
},
|
||||||
// `{Self}`
|
// `{Self}`
|
||||||
SelfUpper,
|
SelfUpper,
|
||||||
|
/// `{This}` or `{TraitName}`
|
||||||
This,
|
This,
|
||||||
|
/// The sugared form of the trait
|
||||||
Trait,
|
Trait,
|
||||||
|
/// what we're in, like a function, method, closure etc.
|
||||||
ItemContext,
|
ItemContext,
|
||||||
|
/// What the user typed, if it doesn't match anything we can use.
|
||||||
AsIs(String),
|
AsIs(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +54,7 @@ pub enum Ctx<'tcx> {
|
||||||
DiagnosticOnUnimplemented { tcx: TyCtxt<'tcx>, trait_def_id: DefId },
|
DiagnosticOnUnimplemented { tcx: TyCtxt<'tcx>, trait_def_id: DefId },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum FormatWarning {
|
pub enum FormatWarning {
|
||||||
UnknownParam { argument_name: Symbol, span: Span },
|
UnknownParam { argument_name: Symbol, span: Span },
|
||||||
PositionalArgument { span: Span, help: String },
|
PositionalArgument { span: Span, help: String },
|
||||||
|
@ -95,26 +110,58 @@ impl FormatWarning {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Arguments to fill a [FormatString] with.
|
||||||
|
///
|
||||||
|
/// For example, given a
|
||||||
|
/// ```rust,ignore (just an example)
|
||||||
|
///
|
||||||
|
/// #[rustc_on_unimplemented(
|
||||||
|
/// on(all(from_desugaring = "QuestionMark"),
|
||||||
|
/// message = "the `?` operator can only be used in {ItemContext} \
|
||||||
|
/// that returns `Result` or `Option` \
|
||||||
|
/// (or another type that implements `{FromResidual}`)",
|
||||||
|
/// label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`",
|
||||||
|
/// parent_label = "this function should return `Result` or `Option` to accept `?`"
|
||||||
|
/// ),
|
||||||
|
/// )]
|
||||||
|
/// pub trait FromResidual<R = <Self as Try>::Residual> {
|
||||||
|
/// ...
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// async fn an_async_function() -> u32 {
|
||||||
|
/// let x: Option<u32> = None;
|
||||||
|
/// x?; //~ ERROR the `?` operator
|
||||||
|
/// 22
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
/// it will look like this:
|
||||||
|
///
|
||||||
|
/// ```rust,ignore (just an example)
|
||||||
|
/// FormatArgs {
|
||||||
|
/// this: "FromResidual",
|
||||||
|
/// trait_sugared: "FromResidual<Option<Infallible>>",
|
||||||
|
/// item_context: "an async function",
|
||||||
|
/// generic_args: [("Self", "u32"), ("R", "Option<Infallible>")],
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ConditionOptions {
|
pub struct FormatArgs<'tcx> {
|
||||||
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 this: String,
|
||||||
pub trait_sugared: String,
|
pub trait_sugared: TraitRefPrintSugared<'tcx>,
|
||||||
pub item_context: String,
|
pub item_context: &'static str,
|
||||||
pub generic_args: Vec<(Symbol, 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 span(&self) -> Span {
|
||||||
|
self.span
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse<'tcx>(
|
||||||
|
input: Symbol,
|
||||||
|
span: Span,
|
||||||
|
ctx: &Ctx<'tcx>,
|
||||||
|
) -> Result<Self, Vec<ParseError>> {
|
||||||
let s = input.as_str();
|
let s = input.as_str();
|
||||||
let mut parser = Parser::new(s, None, None, false, ParseMode::Format);
|
let mut parser = Parser::new(s, None, None, false, ParseMode::Format);
|
||||||
let mut pieces = Vec::new();
|
let mut pieces = Vec::new();
|
||||||
|
@ -126,28 +173,28 @@ impl FormatString {
|
||||||
pieces.push(Piece::Lit(lit.into()));
|
pieces.push(Piece::Lit(lit.into()));
|
||||||
}
|
}
|
||||||
RpfPiece::NextArgument(arg) => {
|
RpfPiece::NextArgument(arg) => {
|
||||||
warn_on_format_spec(arg.format, &mut warnings, input_span);
|
warn_on_format_spec(arg.format, &mut warnings, span);
|
||||||
let arg = parse_arg(&arg, ctx, &mut warnings, input_span);
|
let arg = parse_arg(&arg, ctx, &mut warnings, span);
|
||||||
pieces.push(Piece::Arg(arg));
|
pieces.push(Piece::Arg(arg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if parser.errors.is_empty() {
|
if parser.errors.is_empty() {
|
||||||
Ok(FormatString { input, input_span, pieces, warnings })
|
Ok(FormatString { input, pieces, span, warnings })
|
||||||
} else {
|
} else {
|
||||||
Err(parser.errors)
|
Err(parser.errors)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format(&self, args: &FormatArgs) -> String {
|
pub fn format(&self, args: &FormatArgs<'_>) -> 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, .. }) => {
|
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
|
||||||
let value = match args.generic_args.iter().find(|(p, _)| p == generic_param) {
|
let value = match args.generic_args.iter().find(|(p, _)| p == generic_param) {
|
||||||
Some((_, val)) => val.to_string(),
|
Some((_, val)) => val.to_string(),
|
||||||
|
@ -166,17 +213,19 @@ impl FormatString {
|
||||||
|
|
||||||
// It's only `rustc_onunimplemented` from here
|
// It's only `rustc_onunimplemented` from here
|
||||||
Piece::Arg(FormatArg::This) => ret.push_str(&args.this),
|
Piece::Arg(FormatArg::This) => ret.push_str(&args.this),
|
||||||
Piece::Arg(FormatArg::Trait) => ret.push_str(&args.trait_sugared),
|
Piece::Arg(FormatArg::Trait) => {
|
||||||
Piece::Arg(FormatArg::ItemContext) => ret.push_str(&args.item_context),
|
let _ = fmt::write(&mut ret, format_args!("{}", &args.trait_sugared));
|
||||||
|
}
|
||||||
|
Piece::Arg(FormatArg::ItemContext) => ret.push_str(args.item_context),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_arg(
|
fn parse_arg<'tcx>(
|
||||||
arg: &Argument<'_>,
|
arg: &Argument<'_>,
|
||||||
ctx: &Ctx<'_>,
|
ctx: &Ctx<'tcx>,
|
||||||
warnings: &mut Vec<FormatWarning>,
|
warnings: &mut Vec<FormatWarning>,
|
||||||
input_span: Span,
|
input_span: Span,
|
||||||
) -> FormatArg {
|
) -> FormatArg {
|
||||||
|
@ -233,7 +282,7 @@ fn parse_arg(
|
||||||
Ctx::RustcOnUnimplemented { .. } | Ctx::DiagnosticOnUnimplemented { .. },
|
Ctx::RustcOnUnimplemented { .. } | Ctx::DiagnosticOnUnimplemented { .. },
|
||||||
generic_param,
|
generic_param,
|
||||||
) if generics.own_params.iter().any(|param| param.name == generic_param) => {
|
) if generics.own_params.iter().any(|param| param.name == generic_param) => {
|
||||||
FormatArg::GenericParam { generic_param, span }
|
FormatArg::GenericParam { generic_param }
|
||||||
}
|
}
|
||||||
|
|
||||||
(_, argument_name) => {
|
(_, argument_name) => {
|
||||||
|
@ -286,6 +335,7 @@ fn warn_on_format_spec(spec: FormatSpec<'_>, warnings: &mut Vec<FormatWarning>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper function because `Span` and `rustc_parse_format::InnerSpan` don't know about each other
|
||||||
fn slice_span(input: Span, inner: InnerSpan) -> Span {
|
fn slice_span(input: Span, inner: InnerSpan) -> Span {
|
||||||
let InnerSpan { start, end } = inner;
|
let InnerSpan { start, end } = inner;
|
||||||
let span = input.data();
|
let span = input.data();
|
||||||
|
@ -300,8 +350,6 @@ fn slice_span(input: Span, inner: InnerSpan) -> Span {
|
||||||
|
|
||||||
pub mod errors {
|
pub mod errors {
|
||||||
use rustc_macros::LintDiagnostic;
|
use rustc_macros::LintDiagnostic;
|
||||||
use rustc_middle::ty::TyCtxt;
|
|
||||||
use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
|
|
||||||
use rustc_span::Ident;
|
use rustc_span::Ident;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -324,26 +372,6 @@ pub mod errors {
|
||||||
#[help]
|
#[help]
|
||||||
pub struct InvalidFormatSpecifier;
|
pub struct InvalidFormatSpecifier;
|
||||||
|
|
||||||
#[derive(LintDiagnostic)]
|
|
||||||
#[diag(trait_selection_wrapped_parser_error)]
|
|
||||||
pub struct WrappedParserError {
|
|
||||||
pub description: String,
|
|
||||||
pub label: String,
|
|
||||||
}
|
|
||||||
#[derive(LintDiagnostic)]
|
|
||||||
#[diag(trait_selection_malformed_on_unimplemented_attr)]
|
|
||||||
#[help]
|
|
||||||
pub struct MalformedOnUnimplementedAttrLint {
|
|
||||||
#[label]
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MalformedOnUnimplementedAttrLint {
|
|
||||||
pub fn new(span: Span) -> Self {
|
|
||||||
Self { span }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(LintDiagnostic)]
|
#[derive(LintDiagnostic)]
|
||||||
#[diag(trait_selection_missing_options_for_on_unimplemented_attr)]
|
#[diag(trait_selection_missing_options_for_on_unimplemented_attr)]
|
||||||
#[help]
|
#[help]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue