Change:
} } <ins> /// Recover from `Fn`-family traits (Fn, FnMut, FnOnce) with lifetime arguments /// (e.g. `FnOnce<'a>(&'a str) -> bool`). Up to generic arguments have already /// been eaten. fn recover_fn_trait_with_lifetime_params( &mut self, fn_path: &mut ast::Path, lifetime_defs: &mut Vec<GenericParam>, ) -> PResult<'a, ()> { let fn_path_segment = fn_path.segments.last_mut().unwrap(); let generic_args = if let Some(p_args) = &fn_path_segment.args { p_args.clone().into_inner() } else { // Normally it wouldn't come here because the upstream should have parsed // generic parameters (otherwise it's impossible to call this function). return Ok(()); }; let lifetimes = if let ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs { span: _, args }) = &generic_args { args.into_iter() .filter_map(|arg| { if let ast::AngleBracketedArg::Arg(generic_arg) = arg && let ast::GenericArg::Lifetime(lifetime) = generic_arg { Some(lifetime) } else { None } }) .collect() } else { Vec::new() }; // Only try to recover if the trait has lifetime params. if lifetimes.is_empty() { return Ok(()); } // Parse `(T, U) -> R`. let inputs_lo = self.token.span; let inputs: Vec<_> = self.parse_fn_params(|_| false)?.into_iter().map(|input| input.ty).collect(); let inputs_span = inputs_lo.to(self.prev_token.span); let output = self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No)?; let args = ast::ParenthesizedArgs { span: fn_path_segment.span().to(self.prev_token.span), inputs, inputs_span, output, } .into(); *fn_path_segment = ast::PathSegment { ident: fn_path_segment.ident, args, id: ast::DUMMY_NODE_ID }; // Convert parsed `<'a>` in `Fn<'a>` into `for<'a>`. let mut generic_params = lifetimes .iter() .map(|lt| GenericParam { id: lt.id, ident: lt.ident, attrs: ast::AttrVec::new(), bounds: Vec::new(), is_placeholder: false, kind: ast::GenericParamKind::Lifetime, colon_span: None, }) .collect::<Vec<GenericParam>>(); lifetime_defs.append(&mut generic_params); let generic_args_span = generic_args.span(); let mut err = self.struct_span_err(generic_args_span, "`Fn` traits cannot take lifetime parameters"); let snippet = format!( "for<{}> ", lifetimes.iter().map(|lt| lt.ident.as_str()).intersperse(", ").collect::<String>(), ); let before_fn_path = fn_path.span.shrink_to_lo(); err.multipart_suggestion( "consider using a higher-ranked trait bound instead", vec![(generic_args_span, "".to_owned()), (before_fn_path, snippet)], Applicability::MaybeIncorrect, ) .emit(); Ok(()) } </ins> pub(super) fn check_lifetime(&mut self) -> bool { self.expected_tokens.push(TokenType::Lifetime); self.token.is_lifetime()

Discussion:
The following code: currently produces a heap of semi-helpful diagnostics: <details<summary<bstderr (7 errors)</b</summary</detailswhen instead we could special-case this and emit a single (or at least fewer) diagnostic that suggests the following: If the bound in not inside , like in: we currently emit the following: which is less verbose for sure but still, we should provide the same suggestion I propose above. Related issue: . label A-parser A-suggestion-diagnostics D-newcomer-roadblock <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
Error: Parsing ping command in failed: ...'stbot ping' ''... Please file an issue on GitHub at if there's a problem with this bot, or reach out on on Zulip.
I'd like to take a look. claim
I'm wondering if taking an approach that suggests using higher-rank trait bounds () for an Fn-family trait with a lifetime parameter. Is it appropriate? I'm concerned that it may not a comprehensive solution because HRTB can be used outside of the Fn-family traits (as I understand). Or is it okay only for the Fn-family traits for now?
I am not sure I fully understand what you mean. As you probably know, none of , , take a lifetime parameter and probably never will. Of course, you could define such a trait with unstable features but there is no way to use them, so it's not relevant: Yes, I'd say so. I wouldn't look for names however (like , , …) but just look for an opening parenthesis after a generic parameter list. This way, we can emit the same suggestion for the following case (where the name is ):
Ah, definitely. Thank you!