Parsing , pre-lowering support for precise captures

This commit is contained in:
Michael Goulet 2024-04-03 19:58:50 -04:00
parent 99d0186b1d
commit a076eae0d2
15 changed files with 41 additions and 15 deletions

View File

@ -2132,7 +2132,7 @@ pub enum TyKind {
/// The `NodeId` exists to prevent lowering from having to /// The `NodeId` exists to prevent lowering from having to
/// generate `NodeId`s on the fly, which would complicate /// generate `NodeId`s on the fly, which would complicate
/// the generation of opaque `type Foo = impl Trait` items significantly. /// the generation of opaque `type Foo = impl Trait` items significantly.
ImplTrait(NodeId, GenericBounds), ImplTrait(NodeId, GenericBounds, Option<P<GenericArgs>>),
/// No-op; kept solely so that we can pretty-print faithfully. /// No-op; kept solely so that we can pretty-print faithfully.
Paren(P<Ty>), Paren(P<Ty>),
/// Unused for now. /// Unused for now.

View File

@ -518,9 +518,12 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
TyKind::TraitObject(bounds, _syntax) => { TyKind::TraitObject(bounds, _syntax) => {
visit_vec(bounds, |bound| vis.visit_param_bound(bound)) visit_vec(bounds, |bound| vis.visit_param_bound(bound))
} }
TyKind::ImplTrait(id, bounds) => { TyKind::ImplTrait(id, bounds, precise_capturing) => {
vis.visit_id(id); vis.visit_id(id);
visit_vec(bounds, |bound| vis.visit_param_bound(bound)); visit_vec(bounds, |bound| vis.visit_param_bound(bound));
visit_opt(precise_capturing, |precise_capturing| {
vis.visit_generic_args(precise_capturing);
});
} }
TyKind::MacCall(mac) => vis.visit_mac_call(mac), TyKind::MacCall(mac) => vis.visit_mac_call(mac),
TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => { TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => {

View File

@ -457,8 +457,9 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result {
TyKind::TraitObject(bounds, ..) => { TyKind::TraitObject(bounds, ..) => {
walk_list!(visitor, visit_param_bound, bounds, BoundKind::TraitObject); walk_list!(visitor, visit_param_bound, bounds, BoundKind::TraitObject);
} }
TyKind::ImplTrait(_, bounds) => { TyKind::ImplTrait(_, bounds, precise_capturing) => {
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Impl); walk_list!(visitor, visit_param_bound, bounds, BoundKind::Impl);
visit_opt!(visitor, visit_generic_args, precise_capturing);
} }
TyKind::Typeof(expression) => try_visit!(visitor.visit_anon_const(expression)), TyKind::Typeof(expression) => try_visit!(visitor.visit_anon_const(expression)),
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Dummy | TyKind::Err(_) => {} TyKind::Infer | TyKind::ImplicitSelf | TyKind::Dummy | TyKind::Err(_) => {}

View File

@ -1398,7 +1398,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}); });
hir::TyKind::TraitObject(bounds, lifetime_bound, *kind) hir::TyKind::TraitObject(bounds, lifetime_bound, *kind)
} }
TyKind::ImplTrait(def_node_id, bounds) => { TyKind::ImplTrait(def_node_id, bounds, precise_capturing) => {
assert!(precise_capturing.is_none(), "precise captures not supported yet!");
let span = t.span; let span = t.span;
match itctx { match itctx {
ImplTraitContext::OpaqueTy { origin, fn_kind } => self.lower_opaque_impl_trait( ImplTraitContext::OpaqueTy { origin, fn_kind } => self.lower_opaque_impl_trait(

View File

@ -737,7 +737,7 @@ impl<'a> AstValidator<'a> {
} }
} }
} }
TyKind::ImplTrait(_, bounds) => { TyKind::ImplTrait(_, bounds, _) => {
if self.is_impl_trait_banned { if self.is_impl_trait_banned {
self.dcx().emit_err(errors::ImplTraitPath { span: ty.span }); self.dcx().emit_err(errors::ImplTraitPath { span: ty.span });
} }

View File

@ -569,6 +569,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
gate_all!(fn_delegation, "functions delegation is not yet fully implemented"); gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
gate_all!(postfix_match, "postfix match is experimental"); gate_all!(postfix_match, "postfix match is experimental");
gate_all!(mut_ref, "mutable by-reference bindings are experimental"); gate_all!(mut_ref, "mutable by-reference bindings are experimental");
gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental");
if !visitor.features.never_patterns { if !visitor.features.never_patterns {
if let Some(spans) = spans.get(&sym::never_patterns) { if let Some(spans) = spans.get(&sym::never_patterns) {

View File

@ -1150,7 +1150,8 @@ impl<'a> State<'a> {
} }
self.print_type_bounds(bounds); self.print_type_bounds(bounds);
} }
ast::TyKind::ImplTrait(_, bounds) => { ast::TyKind::ImplTrait(_, bounds, _precise_capturing) => {
// TODO(precise_capturing):
self.word_nbsp("impl"); self.word_nbsp("impl");
self.print_type_bounds(bounds); self.print_type_bounds(bounds);
} }

View File

@ -535,6 +535,8 @@ declare_features! (
(unstable, must_not_suspend, "1.57.0", Some(83310)), (unstable, must_not_suspend, "1.57.0", Some(83310)),
/// Allows `mut ref` and `mut ref mut` identifier patterns. /// Allows `mut ref` and `mut ref mut` identifier patterns.
(incomplete, mut_ref, "CURRENT_RUSTC_VERSION", Some(123076)), (incomplete, mut_ref, "CURRENT_RUSTC_VERSION", Some(123076)),
/// Allows `use<'a, 'b, A, B>` in `impl use<...> Trait` for precise capture of generic args.
(incomplete, precise_capturing, "CURRENT_RUSTC_VERSION", Some(123432)),
/// Allows using `#[naked]` on functions. /// Allows using `#[naked]` on functions.
(unstable, naked_functions, "1.9.0", Some(90957)), (unstable, naked_functions, "1.9.0", Some(90957)),
/// Allows specifying the as-needed link modifier /// Allows specifying the as-needed link modifier

View File

@ -1235,7 +1235,7 @@ impl EarlyLintPass for UnusedParens {
ast::TyKind::TraitObject(..) => {} ast::TyKind::TraitObject(..) => {}
ast::TyKind::BareFn(b) ast::TyKind::BareFn(b)
if self.with_self_ty_parens && b.generic_params.len() > 0 => {} if self.with_self_ty_parens && b.generic_params.len() > 0 => {}
ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {} ast::TyKind::ImplTrait(_, bounds, _) if bounds.len() > 1 => {}
_ => { _ => {
let spans = if !ty.span.from_expansion() { let spans = if !ty.span.from_expansion() {
r.span r.span

View File

@ -62,7 +62,7 @@ impl<'a> Parser<'a> {
let snapshot = self.create_snapshot_for_diagnostic(); let snapshot = self.create_snapshot_for_diagnostic();
match self.parse_ty() { match self.parse_ty() {
Ok(p) => { 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 span = impl_span.to(self.token.span.shrink_to_lo());
let mut err = self.dcx().struct_span_err( let mut err = self.dcx().struct_span_err(
span, span,

View File

@ -625,7 +625,7 @@ impl<'a> Parser<'a> {
// This notably includes paths passed through `ty` macro fragments (#46438). // This notably includes paths passed through `ty` macro fragments (#46438).
TyKind::Path(None, path) => path, TyKind::Path(None, path) => path,
other => { other => {
if let TyKind::ImplTrait(_, bounds) = other if let TyKind::ImplTrait(_, bounds, None) = other
&& let [bound] = bounds.as_slice() && let [bound] = bounds.as_slice()
{ {
// Suggest removing extra `impl` keyword: // Suggest removing extra `impl` keyword:

View File

@ -316,7 +316,7 @@ impl<'a> Parser<'a> {
TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn) TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn)
} }
(TyKind::TraitObject(bounds, _), kw::Impl) => { (TyKind::TraitObject(bounds, _), kw::Impl) => {
TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds) TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds, None)
} }
_ => return Err(err), _ => return Err(err),
}; };
@ -655,7 +655,6 @@ impl<'a> Parser<'a> {
/// Parses an `impl B0 + ... + Bn` type. /// Parses an `impl B0 + ... + Bn` type.
fn parse_impl_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> { 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() { if self.token.is_lifetime() {
self.look_ahead(1, |t| { self.look_ahead(1, |t| {
if let token::Ident(sym, _) = t.kind { if let token::Ident(sym, _) = t.kind {
@ -669,9 +668,26 @@ impl<'a> Parser<'a> {
} }
}) })
} }
// parse precise captures, if any.
let precise_capturing = if self.eat_keyword(kw::Use) {
self.expect_lt()?;
let use_span = self.prev_token.span;
self.psess.gated_spans.gate(sym::precise_capturing, use_span);
let lo = self.token.span;
let args = self.parse_angle_args(None)?;
self.expect_gt()?;
Some(ast::AngleBracketedArgs { args, span: lo.to(self.prev_token.span) }.into())
} else {
None
};
// Always parse bounds greedily for better error recovery.
let bounds = self.parse_generic_bounds()?; let bounds = self.parse_generic_bounds()?;
*impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus); *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))
} }
/// Is a `dyn B0 + ... + Bn` type allowed here? /// Is a `dyn B0 + ... + Bn` type allowed here?
@ -957,7 +973,7 @@ impl<'a> Parser<'a> {
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
) )
} }
TyKind::ImplTrait(_, bounds) TyKind::ImplTrait(_, bounds, None)
if let [GenericBound::Trait(tr, ..), ..] = bounds.as_slice() => if let [GenericBound::Trait(tr, ..), ..] = bounds.as_slice() =>
{ {
( (

View File

@ -793,7 +793,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
self.r.record_partial_res(ty.id, PartialRes::new(res)); self.r.record_partial_res(ty.id, PartialRes::new(res));
visit::walk_ty(self, ty) visit::walk_ty(self, ty)
} }
TyKind::ImplTrait(node_id, _) => { TyKind::ImplTrait(node_id, _, _) => {
let candidates = self.lifetime_elision_candidates.take(); let candidates = self.lifetime_elision_candidates.take();
visit::walk_ty(self, ty); visit::walk_ty(self, ty);
self.record_lifetime_params_for_impl_trait(*node_id); self.record_lifetime_params_for_impl_trait(*node_id);

View File

@ -3121,7 +3121,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
.inputs .inputs
.iter() .iter()
.filter_map(|param| match &param.ty.kind { .filter_map(|param| match &param.ty.kind {
TyKind::ImplTrait(_, bounds) => Some(bounds), TyKind::ImplTrait(_, bounds, _) => Some(bounds),
_ => None, _ => None,
}) })
.flat_map(|bounds| bounds.into_iter()) .flat_map(|bounds| bounds.into_iter())

View File

@ -1375,6 +1375,7 @@ symbols! {
powif32, powif32,
powif64, powif64,
pre_dash_lto: "pre-lto", pre_dash_lto: "pre-lto",
precise_capturing,
precise_pointer_size_matching, precise_pointer_size_matching,
pref_align_of, pref_align_of,
prefetch_read_data, prefetch_read_data,