Auto merge of #123468 - compiler-errors:precise-capturing, r=oli-obk
Implement syntax for `impl Trait` to specify its captures explicitly (`feature(precise_capturing)`) Implements `impl use<'a, 'b, T, U> Sized` syntax that allows users to explicitly list the captured parameters for an opaque, rather than inferring it from the opaque's bounds (or capturing *all* lifetimes under 2024-edition capture rules). This allows us to exclude some implicit captures, so this syntax may be used as a migration strategy for changes due to #117587. We represent this list of captured params as `PreciseCapturingArg` in AST and HIR, resolving them between `rustc_resolve` and `resolve_bound_vars`. Later on, we validate that the opaques only capture the parameters in this list. We artificially limit the feature to *require* mentioning all type and const parameters, since we don't currently have support for non-lifetime bivariant generics. This can be relaxed in the future. We also may need to limit this to require naming *all* lifetime parameters for RPITIT, since GATs have no variance. I have to investigate this. This can also be relaxed in the future. r? `@oli-obk` Tracking issue: - https://github.com/rust-lang/rust/issues/123432
This commit is contained in:
commit
4e1f5d90bc
55 changed files with 1033 additions and 71 deletions
|
@ -62,7 +62,7 @@ impl<'a> Parser<'a> {
|
|||
let snapshot = self.create_snapshot_for_diagnostic();
|
||||
match self.parse_ty() {
|
||||
Ok(p) => {
|
||||
if let TyKind::ImplTrait(_, bounds) = &p.kind {
|
||||
if let TyKind::ImplTrait(_, bounds, None) = &p.kind {
|
||||
let span = impl_span.to(self.token.span.shrink_to_lo());
|
||||
let mut err = self.dcx().struct_span_err(
|
||||
span,
|
||||
|
|
|
@ -625,7 +625,7 @@ impl<'a> Parser<'a> {
|
|||
// This notably includes paths passed through `ty` macro fragments (#46438).
|
||||
TyKind::Path(None, path) => path,
|
||||
other => {
|
||||
if let TyKind::ImplTrait(_, bounds) = other
|
||||
if let TyKind::ImplTrait(_, bounds, None) = other
|
||||
&& let [bound] = bounds.as_slice()
|
||||
{
|
||||
// Suggest removing extra `impl` keyword:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::{Parser, PathStyle, TokenType, Trailing};
|
||||
use super::{Parser, PathStyle, SeqSep, TokenType, Trailing};
|
||||
|
||||
use crate::errors::{
|
||||
self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType,
|
||||
|
@ -14,7 +14,7 @@ use rustc_ast::util::case::Case;
|
|||
use rustc_ast::{
|
||||
self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, FnRetTy, GenericBound,
|
||||
GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, PolyTraitRef,
|
||||
TraitBoundModifiers, TraitObjectSyntax, Ty, TyKind, DUMMY_NODE_ID,
|
||||
PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty, TyKind, DUMMY_NODE_ID,
|
||||
};
|
||||
use rustc_errors::{Applicability, PResult};
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
|
@ -316,7 +316,7 @@ impl<'a> Parser<'a> {
|
|||
TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn)
|
||||
}
|
||||
(TyKind::TraitObject(bounds, _), kw::Impl) => {
|
||||
TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds)
|
||||
TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds, None)
|
||||
}
|
||||
_ => return Err(err),
|
||||
};
|
||||
|
@ -655,7 +655,6 @@ impl<'a> Parser<'a> {
|
|||
|
||||
/// Parses an `impl B0 + ... + Bn` type.
|
||||
fn parse_impl_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> {
|
||||
// Always parse bounds greedily for better error recovery.
|
||||
if self.token.is_lifetime() {
|
||||
self.look_ahead(1, |t| {
|
||||
if let token::Ident(sym, _) = t.kind {
|
||||
|
@ -669,9 +668,53 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
// parse precise captures, if any. This is `use<'lt, 'lt, P, P>`; a list of
|
||||
// lifetimes and ident params (including SelfUpper). These are validated later
|
||||
// for order, duplication, and whether they actually reference params.
|
||||
let precise_capturing = if self.eat_keyword(kw::Use) {
|
||||
let use_span = self.prev_token.span;
|
||||
self.psess.gated_spans.gate(sym::precise_capturing, use_span);
|
||||
let args = self.parse_precise_capturing_args()?;
|
||||
Some(P((args, use_span)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Always parse bounds greedily for better error recovery.
|
||||
let bounds = self.parse_generic_bounds()?;
|
||||
|
||||
*impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus);
|
||||
Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds))
|
||||
|
||||
Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds, precise_capturing))
|
||||
}
|
||||
|
||||
fn parse_precise_capturing_args(&mut self) -> PResult<'a, ThinVec<PreciseCapturingArg>> {
|
||||
Ok(self
|
||||
.parse_unspanned_seq(
|
||||
&TokenKind::Lt,
|
||||
&TokenKind::Gt,
|
||||
SeqSep::trailing_allowed(token::Comma),
|
||||
|self_| {
|
||||
if self_.check_keyword(kw::SelfUpper) {
|
||||
self_.bump();
|
||||
Ok(PreciseCapturingArg::Arg(
|
||||
ast::Path::from_ident(self_.prev_token.ident().unwrap().0),
|
||||
DUMMY_NODE_ID,
|
||||
))
|
||||
} else if self_.check_ident() {
|
||||
Ok(PreciseCapturingArg::Arg(
|
||||
ast::Path::from_ident(self_.parse_ident()?),
|
||||
DUMMY_NODE_ID,
|
||||
))
|
||||
} else if self_.check_lifetime() {
|
||||
Ok(PreciseCapturingArg::Lifetime(self_.expect_lifetime()))
|
||||
} else {
|
||||
self_.unexpected_any()
|
||||
}
|
||||
},
|
||||
)?
|
||||
.0)
|
||||
}
|
||||
|
||||
/// Is a `dyn B0 + ... + Bn` type allowed here?
|
||||
|
@ -957,7 +1000,7 @@ impl<'a> Parser<'a> {
|
|||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
}
|
||||
TyKind::ImplTrait(_, bounds)
|
||||
TyKind::ImplTrait(_, bounds, None)
|
||||
if let [GenericBound::Trait(tr, ..), ..] = bounds.as_slice() =>
|
||||
{
|
||||
(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue