diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 5b708cf4e1a..55a934c48a8 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2132,7 +2132,7 @@ pub enum TyKind { /// The `NodeId` exists to prevent lowering from having to /// generate `NodeId`s on the fly, which would complicate /// the generation of opaque `type Foo = impl Trait` items significantly. - ImplTrait(NodeId, GenericBounds), + ImplTrait(NodeId, GenericBounds, Option>), /// No-op; kept solely so that we can pretty-print faithfully. Paren(P), /// Unused for now. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index da57def263d..b8a5eeebf3a 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -518,9 +518,12 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { TyKind::TraitObject(bounds, _syntax) => { visit_vec(bounds, |bound| vis.visit_param_bound(bound)) } - TyKind::ImplTrait(id, bounds) => { + TyKind::ImplTrait(id, bounds, precise_capturing) => { vis.visit_id(id); 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::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => { diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 9e9ae52962d..91740021727 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -457,8 +457,9 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result { TyKind::TraitObject(bounds, ..) => { 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); + visit_opt!(visitor, visit_generic_args, precise_capturing); } TyKind::Typeof(expression) => try_visit!(visitor.visit_anon_const(expression)), TyKind::Infer | TyKind::ImplicitSelf | TyKind::Dummy | TyKind::Err(_) => {} diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 5005c22d4cc..a4470622972 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1398,7 +1398,8 @@ fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> }); 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; match itctx { ImplTraitContext::OpaqueTy { origin, fn_kind } => self.lower_opaque_impl_trait( diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index cb4dcf3ae75..495e90e967b 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -737,7 +737,7 @@ fn visit_ty_common(&mut self, ty: &'a Ty) { } } } - TyKind::ImplTrait(_, bounds) => { + TyKind::ImplTrait(_, bounds, _) => { if self.is_impl_trait_banned { self.dcx().emit_err(errors::ImplTraitPath { span: ty.span }); } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index d7cd3efe408..70a3ccb0f44 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -569,6 +569,7 @@ macro_rules! gate_all { gate_all!(fn_delegation, "functions delegation is not yet fully implemented"); gate_all!(postfix_match, "postfix match is 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 let Some(spans) = spans.get(&sym::never_patterns) { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 51ccfe89fbd..6553ed72532 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1150,7 +1150,8 @@ pub fn print_type(&mut self, ty: &ast::Ty) { } self.print_type_bounds(bounds); } - ast::TyKind::ImplTrait(_, bounds) => { + ast::TyKind::ImplTrait(_, bounds, _precise_capturing) => { + // TODO(precise_capturing): self.word_nbsp("impl"); self.print_type_bounds(bounds); } diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index e6b19817de3..792cc1066f5 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -535,6 +535,8 @@ pub fn internal(&self, feature: Symbol) -> bool { (unstable, must_not_suspend, "1.57.0", Some(83310)), /// Allows `mut ref` and `mut ref mut` identifier patterns. (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. (unstable, naked_functions, "1.9.0", Some(90957)), /// Allows specifying the as-needed link modifier diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 503caa35358..3fe1f21d56a 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1235,7 +1235,7 @@ fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) { ast::TyKind::TraitObject(..) => {} ast::TyKind::BareFn(b) 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() { r.span 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 @@ fn parse_ty_param(&mut self, preceding_attrs: AttrVec) -> PResult<'a, GenericPar 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 d54eb8dc4c9..fd72dca6e21 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -625,7 +625,7 @@ fn parse_item_impl( // 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 1cea32cb90f..5d6c4f39ae1 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -316,7 +316,7 @@ fn parse_ty_common( 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 @@ fn recover_fn_ptr_with_generics( /// 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,26 @@ fn parse_impl_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> { } }) } + + // 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()?; + *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? @@ -957,7 +973,7 @@ fn parse_generic_ty_bound( Applicability::MaybeIncorrect, ) } - TyKind::ImplTrait(_, bounds) + TyKind::ImplTrait(_, bounds, None) if let [GenericBound::Trait(tr, ..), ..] = bounds.as_slice() => { ( diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 33c9c7fcc62..9e881532311 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -793,7 +793,7 @@ fn visit_ty(&mut self, ty: &'ast Ty) { self.r.record_partial_res(ty.id, PartialRes::new(res)); visit::walk_ty(self, ty) } - TyKind::ImplTrait(node_id, _) => { + TyKind::ImplTrait(node_id, _, _) => { let candidates = self.lifetime_elision_candidates.take(); visit::walk_ty(self, ty); self.record_lifetime_params_for_impl_trait(*node_id); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index bb4294fbcfb..d79c638fa07 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -3121,7 +3121,7 @@ fn add_missing_lifetime_specifiers_label( .inputs .iter() .filter_map(|param| match ¶m.ty.kind { - TyKind::ImplTrait(_, bounds) => Some(bounds), + TyKind::ImplTrait(_, bounds, _) => Some(bounds), _ => None, }) .flat_map(|bounds| bounds.into_iter()) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index bfd0f77c237..19c3fc58943 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1375,6 +1375,7 @@ powif32, powif64, pre_dash_lto: "pre-lto", + precise_capturing, precise_pointer_size_matching, pref_align_of, prefetch_read_data,