rustc_trait_selection/error_reporting/traits/
on_unimplemented_condition.rs1use rustc_ast::{MetaItemInner, MetaItemKind, MetaItemLit};
2use rustc_parse_format::{ParseMode, Parser, Piece, Position};
3use rustc_span::{DesugaringKind, Ident, Span, Symbol, kw, sym};
4
5use crate::errors::InvalidOnClause;
6
7#[derive(Debug)]
9pub(crate) struct OnUnimplementedCondition {
10 span: Span,
11 pred: Predicate,
12}
13
14impl OnUnimplementedCondition {
15 pub(crate) fn span(&self) -> Span {
16 self.span
17 }
18
19 pub(crate) fn matches_predicate(&self, options: &ConditionOptions) -> bool {
20 self.pred.eval(&mut |p| match p {
21 FlagOrNv::Flag(b) => options.has_flag(*b),
22 FlagOrNv::NameValue(NameValue { name, value }) => {
23 let value = value.format(&options.generic_args);
24 options.contains(*name, value)
25 }
26 })
27 }
28
29 pub(crate) fn parse(
30 input: &MetaItemInner,
31 generics: &[Symbol],
32 ) -> Result<Self, InvalidOnClause> {
33 let span = input.span();
34 let pred = Predicate::parse(input, generics)?;
35 Ok(OnUnimplementedCondition { span, pred })
36 }
37}
38
39#[derive(Debug)]
44enum Predicate {
45 Flag(Flag),
47 Match(NameValue),
49 Not(Box<Predicate>),
51 All(Vec<Predicate>),
53 Any(Vec<Predicate>),
55}
56
57impl Predicate {
58 fn parse(input: &MetaItemInner, generics: &[Symbol]) -> Result<Self, InvalidOnClause> {
59 let meta_item = match input {
60 MetaItemInner::MetaItem(meta_item) => meta_item,
61 MetaItemInner::Lit(lit) => {
62 return Err(InvalidOnClause::UnsupportedLiteral { span: lit.span });
63 }
64 };
65
66 let Some(predicate) = meta_item.ident() else {
67 return Err(InvalidOnClause::ExpectedIdentifier {
68 span: meta_item.path.span,
69 path: meta_item.path.clone(),
70 });
71 };
72
73 match meta_item.kind {
74 MetaItemKind::List(ref mis) => match predicate.name {
75 sym::any => Ok(Predicate::Any(Predicate::parse_sequence(mis, generics)?)),
76 sym::all => Ok(Predicate::All(Predicate::parse_sequence(mis, generics)?)),
77 sym::not => match &**mis {
78 [one] => Ok(Predicate::Not(Box::new(Predicate::parse(one, generics)?))),
79 [first, .., last] => Err(InvalidOnClause::ExpectedOnePredInNot {
80 span: first.span().to(last.span()),
81 }),
82 [] => Err(InvalidOnClause::ExpectedOnePredInNot { span: meta_item.span }),
83 },
84 invalid_pred => {
85 Err(InvalidOnClause::InvalidPredicate { span: predicate.span, invalid_pred })
86 }
87 },
88 MetaItemKind::NameValue(MetaItemLit { symbol, .. }) => {
89 let name = Name::parse(predicate, generics)?;
90 let value = FilterFormatString::parse(symbol);
91 let kv = NameValue { name, value };
92 Ok(Predicate::Match(kv))
93 }
94 MetaItemKind::Word => {
95 let flag = Flag::parse(predicate)?;
96 Ok(Predicate::Flag(flag))
97 }
98 }
99 }
100
101 fn parse_sequence(
102 sequence: &[MetaItemInner],
103 generics: &[Symbol],
104 ) -> Result<Vec<Self>, InvalidOnClause> {
105 sequence.iter().map(|item| Predicate::parse(item, generics)).collect()
106 }
107
108 fn eval(&self, eval: &mut impl FnMut(FlagOrNv<'_>) -> bool) -> bool {
109 match self {
110 Predicate::Flag(flag) => eval(FlagOrNv::Flag(flag)),
111 Predicate::Match(nv) => eval(FlagOrNv::NameValue(nv)),
112 Predicate::Not(not) => !not.eval(eval),
113 Predicate::All(preds) => preds.into_iter().all(|pred| pred.eval(eval)),
114 Predicate::Any(preds) => preds.into_iter().any(|pred| pred.eval(eval)),
115 }
116 }
117}
118
119#[derive(Debug, Clone, Copy)]
121enum Flag {
122 CrateLocal,
125 Direct,
127 FromDesugaring,
130}
131
132impl Flag {
133 fn parse(Ident { name, span }: Ident) -> Result<Self, InvalidOnClause> {
134 match name {
135 sym::crate_local => Ok(Flag::CrateLocal),
136 sym::direct => Ok(Flag::Direct),
137 sym::from_desugaring => Ok(Flag::FromDesugaring),
138 invalid_flag => Err(InvalidOnClause::InvalidFlag { invalid_flag, span }),
139 }
140 }
141}
142
143#[derive(Debug, Clone)]
147struct NameValue {
148 name: Name,
149 value: FilterFormatString,
153}
154
155#[derive(Debug, Clone, Copy)]
157enum Name {
158 Cause,
159 FromDesugaring,
160 SelfUpper,
161 GenericArg(Symbol),
162}
163
164impl Name {
165 fn parse(Ident { name, span }: Ident, generics: &[Symbol]) -> Result<Self, InvalidOnClause> {
166 match name {
167 kw::SelfUpper => Ok(Name::SelfUpper),
168 sym::from_desugaring => Ok(Name::FromDesugaring),
169 sym::cause => Ok(Name::Cause),
170 generic if generics.contains(&generic) => Ok(Name::GenericArg(generic)),
171 invalid_name => Err(InvalidOnClause::InvalidName { invalid_name, span }),
172 }
173 }
174}
175
176#[derive(Debug, Clone)]
177enum FlagOrNv<'p> {
178 Flag(&'p Flag),
179 NameValue(&'p NameValue),
180}
181
182#[derive(Debug, Clone)]
189struct FilterFormatString {
190 pieces: Vec<LitOrArg>,
191}
192
193#[derive(Debug, Clone)]
194enum LitOrArg {
195 Lit(String),
196 Arg(String),
197}
198
199impl FilterFormatString {
200 fn parse(input: Symbol) -> Self {
201 let pieces = Parser::new(input.as_str(), None, None, false, ParseMode::Format)
202 .map(|p| match p {
203 Piece::Lit(s) => LitOrArg::Lit(s.to_owned()),
204 Piece::NextArgument(a) => match a.position {
206 Position::ArgumentNamed(arg @ "integer" | arg @ "integral" | arg @ "float") => {
213 LitOrArg::Lit(format!("{{{arg}}}"))
214 }
215
216 Position::ArgumentNamed(arg) => LitOrArg::Arg(arg.to_owned()),
218
219 Position::ArgumentImplicitlyIs(_) => LitOrArg::Lit(String::from("{}")),
221 Position::ArgumentIs(idx) => LitOrArg::Lit(format!("{{{idx}}}")),
222 },
223 })
224 .collect();
225 Self { pieces }
226 }
227
228 fn format(&self, generic_args: &[(Symbol, String)]) -> String {
229 let mut ret = String::new();
230
231 for piece in &self.pieces {
232 match piece {
233 LitOrArg::Lit(s) => ret.push_str(s),
234 LitOrArg::Arg(arg) => {
235 let s = Symbol::intern(arg);
236 match generic_args.iter().find(|(k, _)| *k == s) {
237 Some((_, val)) => ret.push_str(val),
238 None => {
239 let _ = std::fmt::write(&mut ret, format_args!("{{{s}}}"));
242 }
243 }
244 }
245 }
246 }
247
248 ret
249 }
250}
251
252#[derive(Debug)]
292pub(crate) struct ConditionOptions {
293 pub(crate) self_types: Vec<String>,
295 pub(crate) from_desugaring: Option<DesugaringKind>,
297 pub(crate) cause: Option<String>,
299 pub(crate) crate_local: bool,
300 pub(crate) direct: bool,
302 pub(crate) generic_args: Vec<(Symbol, String)>,
304}
305
306impl ConditionOptions {
307 fn has_flag(&self, name: Flag) -> bool {
308 match name {
309 Flag::CrateLocal => self.crate_local,
310 Flag::Direct => self.direct,
311 Flag::FromDesugaring => self.from_desugaring.is_some(),
312 }
313 }
314 fn contains(&self, name: Name, value: String) -> bool {
315 match name {
316 Name::SelfUpper => self.self_types.contains(&value),
317 Name::FromDesugaring => self.from_desugaring.is_some_and(|ds| ds.matches(&value)),
318 Name::Cause => self.cause == Some(value),
319 Name::GenericArg(arg) => self.generic_args.contains(&(arg, value)),
320 }
321 }
322}