diff options
| author | bors <bors@rust-lang.org> | 2024-04-16 11:22:35 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-04-16 11:22:35 +0000 |
| commit | 4e1f5d90bca45207605a88e39b1f76abcdb85d2f (patch) | |
| tree | c927952718135627a6c5e5bc68886e81b9f38f60 /compiler/rustc_parse/src | |
| parent | ad18fe08de03fbb459c05475bddee22707b4f0ec (diff) | |
| parent | 8ddd2805de6ad8200868befc6ae703243fac3a46 (diff) | |
| download | rust-4e1f5d90bca45207605a88e39b1f76abcdb85d2f.tar.gz rust-4e1f5d90bca45207605a88e39b1f76abcdb85d2f.zip | |
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
Diffstat (limited to 'compiler/rustc_parse/src')
| -rw-r--r-- | compiler/rustc_parse/src/parser/generics.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/item.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/ty.rs | 55 |
3 files changed, 51 insertions, 8 deletions
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index fde16ac957d..93a15c938ec 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -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, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 003479b9d8e..b711ee9a8ee 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -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: diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 1eeb11a09fe..7096b201f84 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -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() => { ( |
