Rework precise capturing syntax

This commit is contained in:
Michael Goulet 2024-06-05 16:18:52 -04:00
parent 68bd001c00
commit b1efe1ab5d
54 changed files with 406 additions and 350 deletions

View File

@ -307,6 +307,8 @@ impl TraitBoundModifiers {
pub enum GenericBound {
Trait(PolyTraitRef, TraitBoundModifiers),
Outlives(Lifetime),
/// Precise capturing syntax: `impl Sized + use<'a>`
Use(ThinVec<PreciseCapturingArg>, Span),
}
impl GenericBound {
@ -314,6 +316,7 @@ impl GenericBound {
match self {
GenericBound::Trait(t, ..) => t.span,
GenericBound::Outlives(l) => l.ident.span,
GenericBound::Use(_, span) => *span,
}
}
}
@ -2162,7 +2165,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, Option<P<(ThinVec<PreciseCapturingArg>, Span)>>),
ImplTrait(NodeId, GenericBounds),
/// No-op; kept solely so that we can pretty-print faithfully.
Paren(P<Ty>),
/// Unused for now.

View File

@ -523,14 +523,9 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
TyKind::TraitObject(bounds, _syntax) => {
visit_vec(bounds, |bound| vis.visit_param_bound(bound))
}
TyKind::ImplTrait(id, bounds, precise_capturing) => {
TyKind::ImplTrait(id, bounds) => {
vis.visit_id(id);
visit_vec(bounds, |bound| vis.visit_param_bound(bound));
if let Some((precise_capturing, _span)) = precise_capturing.as_deref_mut() {
for arg in precise_capturing {
vis.visit_precise_capturing_arg(arg);
}
}
}
TyKind::MacCall(mac) => vis.visit_mac_call(mac),
TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => {
@ -923,6 +918,11 @@ fn noop_visit_param_bound<T: MutVisitor>(pb: &mut GenericBound, vis: &mut T) {
match pb {
GenericBound::Trait(ty, _modifier) => vis.visit_poly_trait_ref(ty),
GenericBound::Outlives(lifetime) => noop_visit_lifetime(lifetime, vis),
GenericBound::Use(args, _) => {
for arg in args {
vis.visit_precise_capturing_arg(arg);
}
}
}
}

View File

@ -184,7 +184,7 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
None => break None,
},
ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds, _) => {
ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds) => {
match bounds.last() {
Some(ast::GenericBound::Trait(bound, _)) => {
match path_return_type(&bound.trait_ref.path) {
@ -192,7 +192,9 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
None => break None,
}
}
Some(ast::GenericBound::Outlives(_)) | None => break None,
Some(ast::GenericBound::Outlives(_) | ast::GenericBound::Use(..)) | None => {
break None;
}
}
}

View File

@ -52,6 +52,16 @@ pub enum BoundKind {
/// E.g., `trait A: B`
SuperTraits,
}
impl BoundKind {
pub fn descr(self) -> &'static str {
match self {
BoundKind::Bound => "bounds",
BoundKind::Impl => "`impl Trait`",
BoundKind::TraitObject => "`dyn` trait object bounds",
BoundKind::SuperTraits => "supertrait bounds",
}
}
}
#[derive(Copy, Clone, Debug)]
pub enum FnKind<'a> {
@ -497,13 +507,8 @@ 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, precise_capturing) => {
TyKind::ImplTrait(_, bounds) => {
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Impl);
if let Some((precise_capturing, _span)) = precise_capturing.as_deref() {
for arg in precise_capturing {
try_visit!(visitor.visit_precise_capturing_arg(arg));
}
}
}
TyKind::Typeof(expression) => try_visit!(visitor.visit_anon_const(expression)),
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Dummy | TyKind::Err(_) => {}
@ -688,6 +693,10 @@ pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericB
match bound {
GenericBound::Trait(typ, _modifier) => visitor.visit_poly_trait_ref(typ),
GenericBound::Outlives(lifetime) => visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound),
GenericBound::Use(args, _) => {
walk_list!(visitor, visit_precise_capturing_arg, args);
V::Result::output()
}
}
}

View File

@ -51,9 +51,9 @@ use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::Lrc;
use rustc_errors::{DiagArgFromDisplay, DiagCtxt, StashKey};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
use rustc_hir::def_id::{LocalDefId, LocalDefIdMap, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::{self as hir};
use rustc_hir::{
ConstArg, GenericArg, HirId, ItemLocalMap, MissingLifetimeKind, ParamName, TraitCandidate,
};
@ -1384,6 +1384,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
None
}
// Ignore `use` syntax since that is not valid in objects.
GenericBound::Use(..) => None,
}));
let lifetime_bound =
lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span));
@ -1391,7 +1393,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
});
hir::TyKind::TraitObject(bounds, lifetime_bound, *kind)
}
TyKind::ImplTrait(def_node_id, bounds, precise_capturing) => {
TyKind::ImplTrait(def_node_id, bounds) => {
let span = t.span;
match itctx {
ImplTraitContext::OpaqueTy { origin, fn_kind } => self.lower_opaque_impl_trait(
@ -1401,12 +1403,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
bounds,
fn_kind,
itctx,
precise_capturing.as_deref().map(|(args, span)| (args.as_slice(), *span)),
),
ImplTraitContext::Universal => {
if let Some(&(_, span)) = precise_capturing.as_deref() {
if let Some(span) = bounds.iter().find_map(|bound| match *bound {
ast::GenericBound::Use(_, span) => Some(span),
_ => None,
}) {
self.tcx.dcx().emit_err(errors::NoPreciseCapturesOnApit { span });
};
}
let span = t.span;
// HACK: pprust breaks strings with newlines when the type
@ -1517,7 +1522,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
bounds: &GenericBounds,
fn_kind: Option<FnDeclKind>,
itctx: ImplTraitContext,
precise_capturing_args: Option<(&[PreciseCapturingArg], Span)>,
) -> hir::TyKind<'hir> {
// Make sure we know that some funky desugaring has been going on here.
// This is a first: there is code in other places like for loop
@ -1526,59 +1530,61 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// frequently opened issues show.
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
let captured_lifetimes_to_duplicate =
if let Some((precise_capturing, _)) = precise_capturing_args {
// We'll actually validate these later on; all we need is the list of
// lifetimes to duplicate during this portion of lowering.
precise_capturing
.iter()
.filter_map(|arg| match arg {
PreciseCapturingArg::Lifetime(lt) => Some(*lt),
PreciseCapturingArg::Arg(..) => None,
})
// Add in all the lifetimes mentioned in the bounds. We will error
// them out later, but capturing them here is important to make sure
// they actually get resolved in resolve_bound_vars.
.chain(lifetime_collector::lifetimes_in_bounds(self.resolver, bounds))
.collect()
} else {
match origin {
hir::OpaqueTyOrigin::TyAlias { .. } => {
// type alias impl trait and associated type position impl trait were
// decided to capture all in-scope lifetimes, which we collect for
// all opaques during resolution.
let captured_lifetimes_to_duplicate = if let Some(args) =
bounds.iter().find_map(|bound| match bound {
ast::GenericBound::Use(a, _) => Some(a),
_ => None,
}) {
// We'll actually validate these later on; all we need is the list of
// lifetimes to duplicate during this portion of lowering.
args.iter()
.filter_map(|arg| match arg {
PreciseCapturingArg::Lifetime(lt) => Some(*lt),
PreciseCapturingArg::Arg(..) => None,
})
// Add in all the lifetimes mentioned in the bounds. We will error
// them out later, but capturing them here is important to make sure
// they actually get resolved in resolve_bound_vars.
.chain(lifetime_collector::lifetimes_in_bounds(self.resolver, bounds))
.collect()
} else {
match origin {
hir::OpaqueTyOrigin::TyAlias { .. } => {
// type alias impl trait and associated type position impl trait were
// decided to capture all in-scope lifetimes, which we collect for
// all opaques during resolution.
self.resolver
.take_extra_lifetime_params(opaque_ty_node_id)
.into_iter()
.map(|(ident, id, _)| Lifetime { id, ident })
.collect()
}
hir::OpaqueTyOrigin::FnReturn(..) => {
if matches!(
fn_kind.expect("expected RPITs to be lowered with a FnKind"),
FnDeclKind::Impl | FnDeclKind::Trait
) || self.tcx.features().lifetime_capture_rules_2024
|| span.at_least_rust_2024()
{
// return-position impl trait in trait was decided to capture all
// in-scope lifetimes, which we collect for all opaques during resolution.
self.resolver
.take_extra_lifetime_params(opaque_ty_node_id)
.into_iter()
.map(|(ident, id, _)| Lifetime { id, ident })
.collect()
}
hir::OpaqueTyOrigin::FnReturn(..) => {
if matches!(
fn_kind.expect("expected RPITs to be lowered with a FnKind"),
FnDeclKind::Impl | FnDeclKind::Trait
) || self.tcx.features().lifetime_capture_rules_2024
|| span.at_least_rust_2024()
{
// return-position impl trait in trait was decided to capture all
// in-scope lifetimes, which we collect for all opaques during resolution.
self.resolver
.take_extra_lifetime_params(opaque_ty_node_id)
.into_iter()
.map(|(ident, id, _)| Lifetime { id, ident })
.collect()
} else {
// in fn return position, like the `fn test<'a>() -> impl Debug + 'a`
// example, we only need to duplicate lifetimes that appear in the
// bounds, since those are the only ones that are captured by the opaque.
lifetime_collector::lifetimes_in_bounds(self.resolver, bounds)
}
}
hir::OpaqueTyOrigin::AsyncFn(..) => {
unreachable!("should be using `lower_async_fn_ret_ty`")
} else {
// in fn return position, like the `fn test<'a>() -> impl Debug + 'a`
// example, we only need to duplicate lifetimes that appear in the
// bounds, since those are the only ones that are captured by the opaque.
lifetime_collector::lifetimes_in_bounds(self.resolver, bounds)
}
}
};
hir::OpaqueTyOrigin::AsyncFn(..) => {
unreachable!("should be using `lower_async_fn_ret_ty`")
}
}
};
debug!(?captured_lifetimes_to_duplicate);
self.lower_opaque_inner(
@ -1588,7 +1594,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
captured_lifetimes_to_duplicate,
span,
opaque_ty_span,
precise_capturing_args,
|this| this.lower_param_bounds(bounds, itctx),
)
}
@ -1601,7 +1606,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
captured_lifetimes_to_duplicate: FxIndexSet<Lifetime>,
span: Span,
opaque_ty_span: Span,
precise_capturing_args: Option<(&[PreciseCapturingArg], Span)>,
lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>],
) -> hir::TyKind<'hir> {
let opaque_ty_def_id = self.create_def(
@ -1688,18 +1692,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// Install the remapping from old to new (if any). This makes sure that
// any lifetimes that would have resolved to the def-id of captured
// lifetimes are remapped to the new *synthetic* lifetimes of the opaque.
let (bounds, precise_capturing_args) =
this.with_remapping(captured_to_synthesized_mapping, |this| {
(
lower_item_bounds(this),
precise_capturing_args.map(|(precise_capturing, span)| {
(
this.lower_precise_capturing_args(precise_capturing),
this.lower_span(span),
)
}),
)
});
let bounds = this
.with_remapping(captured_to_synthesized_mapping, |this| lower_item_bounds(this));
let generic_params =
this.arena.alloc_from_iter(synthesized_lifetime_definitions.iter().map(
@ -1744,7 +1738,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
origin,
lifetime_mapping,
in_trait,
precise_capturing_args,
};
// Generate an `type Foo = impl Trait;` declaration.
@ -1955,7 +1948,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
captured_lifetimes,
span,
opaque_ty_span,
None,
|this| {
let bound = this.lower_coroutine_fn_output_type_to_bound(
output,
@ -2038,6 +2030,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
GenericBound::Outlives(lifetime) => {
hir::GenericBound::Outlives(self.lower_lifetime(lifetime))
}
GenericBound::Use(args, span) => hir::GenericBound::Use(
self.lower_precise_capturing_args(args),
self.lower_span(*span),
),
}
}

View File

@ -14,6 +14,8 @@ ast_passes_assoc_type_without_body =
associated type in `impl` without body
.suggestion = provide a definition for the type
ast_passes_precise_capturing_not_allowed_here = `use<...>` precise capturing syntax is not allowed in {$loc}
ast_passes_at_least_one_trait = at least one trait must be specified
ast_passes_auto_generic = auto traits cannot have generic parameters

View File

@ -751,7 +751,7 @@ impl<'a> AstValidator<'a> {
}
}
}
TyKind::ImplTrait(_, bounds, _) => {
TyKind::ImplTrait(_, bounds) => {
if self.is_impl_trait_banned {
self.dcx().emit_err(errors::ImplTraitPath { span: ty.span });
}
@ -1304,6 +1304,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
}
GenericBound::Outlives(_) => {}
GenericBound::Use(..) => {}
}
}
}
@ -1322,95 +1323,110 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
if let GenericBound::Trait(poly, modifiers) = bound {
match (ctxt, modifiers.constness, modifiers.polarity) {
(BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
self.dcx().emit_err(errors::OptionalTraitSupertrait {
span: poly.span,
path_str: pprust::path_to_string(&poly.trait_ref.path),
});
match bound {
GenericBound::Trait(trait_ref, modifiers) => {
match (ctxt, modifiers.constness, modifiers.polarity) {
(BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
self.dcx().emit_err(errors::OptionalTraitSupertrait {
span: trait_ref.span,
path_str: pprust::path_to_string(&trait_ref.trait_ref.path),
});
}
(BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
self.dcx().emit_err(errors::OptionalTraitObject { span: trait_ref.span });
}
(
BoundKind::TraitObject,
BoundConstness::Always(_),
BoundPolarity::Positive,
) => {
self.dcx().emit_err(errors::ConstBoundTraitObject { span: trait_ref.span });
}
(_, BoundConstness::Maybe(span), BoundPolarity::Positive)
if let Some(reason) = &self.disallow_tilde_const =>
{
let reason = match reason {
DisallowTildeConstContext::Fn(FnKind::Closure(..)) => {
errors::TildeConstReason::Closure
}
DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => {
errors::TildeConstReason::Function { ident: ident.span }
}
&DisallowTildeConstContext::Trait(span) => {
errors::TildeConstReason::Trait { span }
}
&DisallowTildeConstContext::TraitImpl(span) => {
errors::TildeConstReason::TraitImpl { span }
}
&DisallowTildeConstContext::Impl(span) => {
// FIXME(effects): Consider providing a help message or even a structured
// suggestion for moving such bounds to the assoc const fns if available.
errors::TildeConstReason::Impl { span }
}
&DisallowTildeConstContext::TraitAssocTy(span) => {
errors::TildeConstReason::TraitAssocTy { span }
}
&DisallowTildeConstContext::TraitImplAssocTy(span) => {
errors::TildeConstReason::TraitImplAssocTy { span }
}
&DisallowTildeConstContext::InherentAssocTy(span) => {
errors::TildeConstReason::InherentAssocTy { span }
}
DisallowTildeConstContext::TraitObject => {
errors::TildeConstReason::TraitObject
}
DisallowTildeConstContext::Item => errors::TildeConstReason::Item,
};
self.dcx().emit_err(errors::TildeConstDisallowed { span, reason });
}
(
_,
BoundConstness::Always(_) | BoundConstness::Maybe(_),
BoundPolarity::Negative(_) | BoundPolarity::Maybe(_),
) => {
self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers {
span: bound.span(),
left: modifiers.constness.as_str(),
right: modifiers.polarity.as_str(),
});
}
_ => {}
}
(BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
self.dcx().emit_err(errors::OptionalTraitObject { span: poly.span });
}
(BoundKind::TraitObject, BoundConstness::Always(_), BoundPolarity::Positive) => {
self.dcx().emit_err(errors::ConstBoundTraitObject { span: poly.span });
}
(_, BoundConstness::Maybe(span), BoundPolarity::Positive)
if let Some(reason) = &self.disallow_tilde_const =>
{
let reason = match reason {
DisallowTildeConstContext::Fn(FnKind::Closure(..)) => {
errors::TildeConstReason::Closure
}
DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => {
errors::TildeConstReason::Function { ident: ident.span }
}
&DisallowTildeConstContext::Trait(span) => {
errors::TildeConstReason::Trait { span }
}
&DisallowTildeConstContext::TraitImpl(span) => {
errors::TildeConstReason::TraitImpl { span }
}
&DisallowTildeConstContext::Impl(span) => {
// FIXME(effects): Consider providing a help message or even a structured
// suggestion for moving such bounds to the assoc const fns if available.
errors::TildeConstReason::Impl { span }
}
&DisallowTildeConstContext::TraitAssocTy(span) => {
errors::TildeConstReason::TraitAssocTy { span }
}
&DisallowTildeConstContext::TraitImplAssocTy(span) => {
errors::TildeConstReason::TraitImplAssocTy { span }
}
&DisallowTildeConstContext::InherentAssocTy(span) => {
errors::TildeConstReason::InherentAssocTy { span }
}
DisallowTildeConstContext::TraitObject => {
errors::TildeConstReason::TraitObject
}
DisallowTildeConstContext::Item => errors::TildeConstReason::Item,
};
self.dcx().emit_err(errors::TildeConstDisallowed { span, reason });
}
(
_,
BoundConstness::Always(_) | BoundConstness::Maybe(_),
BoundPolarity::Negative(_) | BoundPolarity::Maybe(_),
) => {
self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers {
span: bound.span(),
left: modifiers.constness.as_str(),
right: modifiers.polarity.as_str(),
});
}
_ => {}
}
}
// Negative trait bounds are not allowed to have associated constraints
if let GenericBound::Trait(trait_ref, modifiers) = bound
&& let BoundPolarity::Negative(_) = modifiers.polarity
&& let Some(segment) = trait_ref.trait_ref.path.segments.last()
{
match segment.args.as_deref() {
Some(ast::GenericArgs::AngleBracketed(args)) => {
for arg in &args.args {
if let ast::AngleBracketedArg::Constraint(constraint) = arg {
self.dcx().emit_err(errors::ConstraintOnNegativeBound {
span: constraint.span,
// Negative trait bounds are not allowed to have associated constraints
if let BoundPolarity::Negative(_) = modifiers.polarity
&& let Some(segment) = trait_ref.trait_ref.path.segments.last()
{
match segment.args.as_deref() {
Some(ast::GenericArgs::AngleBracketed(args)) => {
for arg in &args.args {
if let ast::AngleBracketedArg::Constraint(constraint) = arg {
self.dcx().emit_err(errors::ConstraintOnNegativeBound {
span: constraint.span,
});
}
}
}
// The lowered form of parenthesized generic args contains an associated type binding.
Some(ast::GenericArgs::Parenthesized(args)) => {
self.dcx().emit_err(errors::NegativeBoundWithParentheticalNotation {
span: args.span,
});
}
None => {}
}
}
// The lowered form of parenthesized generic args contains an associated type binding.
Some(ast::GenericArgs::Parenthesized(args)) => {
self.dcx().emit_err(errors::NegativeBoundWithParentheticalNotation {
span: args.span,
});
}
None => {}
}
GenericBound::Outlives(_) => {}
GenericBound::Use(_, span) => match ctxt {
BoundKind::Impl => {}
BoundKind::Bound | BoundKind::TraitObject | BoundKind::SuperTraits => {
self.dcx().emit_err(errors::PreciseCapturingNotAllowedHere {
loc: ctxt.descr(),
span: *span,
})
}
},
}
visit::walk_param_bound(self, bound)

View File

@ -844,3 +844,11 @@ pub struct MatchArmWithNoBody {
#[suggestion(code = " => todo!(),", applicability = "has-placeholders")]
pub suggestion: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_precise_capturing_not_allowed_here)]
pub struct PreciseCapturingNotAllowedHere {
#[primary_span]
pub span: Span,
pub loc: &'static str,
}

View File

@ -1187,17 +1187,8 @@ impl<'a> State<'a> {
}
self.print_type_bounds(bounds);
}
ast::TyKind::ImplTrait(_, bounds, precise_capturing_args) => {
ast::TyKind::ImplTrait(_, bounds) => {
self.word_nbsp("impl");
if let Some((precise_capturing_args, ..)) = precise_capturing_args.as_deref() {
self.word("use");
self.word("<");
self.commasep(Inconsistent, precise_capturing_args, |s, arg| match arg {
ast::PreciseCapturingArg::Arg(p, _) => s.print_path(p, false, 0),
ast::PreciseCapturingArg::Lifetime(lt) => s.print_lifetime(*lt),
});
self.word(">")
}
self.print_type_bounds(bounds);
}
ast::TyKind::Array(ty, length) => {
@ -1800,6 +1791,15 @@ impl<'a> State<'a> {
self.print_poly_trait_ref(tref);
}
GenericBound::Outlives(lt) => self.print_lifetime(*lt),
GenericBound::Use(args, _) => {
self.word("use");
self.word("<");
self.commasep(Inconsistent, args, |s, arg| match arg {
ast::PreciseCapturingArg::Arg(p, _) => s.print_path(p, false, 0),
ast::PreciseCapturingArg::Lifetime(lt) => s.print_lifetime(*lt),
});
self.word(">")
}
}
}
}

View File

@ -567,7 +567,7 @@ declare_features! (
(unstable, optimize_attribute, "1.34.0", Some(54882)),
/// Allows postfix match `expr.match { ... }`
(unstable, postfix_match, "1.79.0", Some(121618)),
/// Allows `use<'a, 'b, A, B>` in `impl use<...> Trait` for precise capture of generic args.
/// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args.
(incomplete, precise_capturing, "1.79.0", Some(123432)),
/// Allows macro attributes on expressions, statements and non-inline modules.
(unstable, proc_macro_hygiene, "1.30.0", Some(54727)),

View File

@ -463,6 +463,7 @@ pub enum TraitBoundModifier {
pub enum GenericBound<'hir> {
Trait(PolyTraitRef<'hir>, TraitBoundModifier),
Outlives(&'hir Lifetime),
Use(&'hir [PreciseCapturingArg<'hir>], Span),
}
impl GenericBound<'_> {
@ -477,6 +478,7 @@ impl GenericBound<'_> {
match self {
GenericBound::Trait(t, ..) => t.span,
GenericBound::Outlives(l) => l.ident.span,
GenericBound::Use(_, span) => *span,
}
}
}
@ -2689,8 +2691,6 @@ pub struct OpaqueTy<'hir> {
/// originating from a trait method. This makes it so that the opaque is
/// lowered as an associated type.
pub in_trait: bool,
/// List of arguments captured via `impl use<'a, P, ...> Trait` syntax.
pub precise_capturing_args: Option<(&'hir [PreciseCapturingArg<'hir>], Span)>,
}
#[derive(Debug, Clone, Copy, HashStable_Generic)]

View File

@ -532,15 +532,10 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
try_visit!(visitor.visit_ty(ty));
try_visit!(visitor.visit_generics(generics));
}
ItemKind::OpaqueTy(&OpaqueTy { generics, bounds, precise_capturing_args, .. }) => {
ItemKind::OpaqueTy(&OpaqueTy { generics, bounds, .. }) => {
try_visit!(visitor.visit_id(item.hir_id()));
try_visit!(walk_generics(visitor, generics));
walk_list!(visitor, visit_param_bound, bounds);
if let Some((precise_capturing_args, _)) = precise_capturing_args {
for arg in precise_capturing_args {
try_visit!(visitor.visit_precise_capturing_arg(arg));
}
}
}
ItemKind::Enum(ref enum_definition, ref generics) => {
try_visit!(visitor.visit_generics(generics));
@ -1147,6 +1142,10 @@ pub fn walk_param_bound<'v, V: Visitor<'v>>(
match *bound {
GenericBound::Trait(ref typ, _modifier) => visitor.visit_poly_trait_ref(typ),
GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime),
GenericBound::Use(args, _) => {
walk_list!(visitor, visit_precise_capturing_arg, args);
V::Result::output()
}
}
}

View File

@ -481,9 +481,12 @@ fn sanity_check_found_hidden_type<'tcx>(
/// 2. Checking that all lifetimes that are implicitly captured are mentioned.
/// 3. Asserting that all parameters mentioned in the captures list are invariant.
fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDefId) {
let hir::OpaqueTy { precise_capturing_args, .. } =
let hir::OpaqueTy { bounds, .. } =
*tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty();
let Some((precise_capturing_args, _)) = precise_capturing_args else {
let Some(precise_capturing_args) = bounds.iter().find_map(|bound| match *bound {
hir::GenericBound::Use(bounds, ..) => Some(bounds),
_ => None,
}) else {
// No precise capturing args; nothing to validate
return;
};

View File

@ -178,6 +178,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
lifetime.ident.span,
);
}
hir::GenericBound::Use(..) => {
// We don't actually lower `use` into the type layer.
}
}
}
}

View File

@ -13,7 +13,7 @@ use rustc_ast_pretty::pprust::{Comments, PrintState};
use rustc_hir as hir;
use rustc_hir::{
BindingMode, ByRef, GenericArg, GenericBound, GenericParam, GenericParamKind, HirId,
LifetimeParamKind, Node, PatKind, RangeEnd, Term, TraitBoundModifier,
LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, TraitBoundModifier,
};
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{kw, Ident, Symbol};
@ -2100,10 +2100,24 @@ impl<'a> State<'a> {
GenericBound::Outlives(lt) => {
self.print_lifetime(lt);
}
GenericBound::Use(args, _) => {
self.word("use <");
self.commasep(Inconsistent, args, |s, arg| s.print_precise_capturing_arg(*arg));
self.word(">");
}
}
}
}
fn print_precise_capturing_arg(&mut self, arg: PreciseCapturingArg<'_>) {
match arg {
PreciseCapturingArg::Lifetime(lt) => self.print_lifetime(lt),
PreciseCapturingArg::Param(arg) => self.print_ident(arg.ident),
}
}
fn print_generic_params(&mut self, generic_params: &[GenericParam<'_>]) {
if !generic_params.is_empty() {
self.word("<");

View File

@ -11,7 +11,7 @@ use rustc_middle::ty::{
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
};
use rustc_session::{declare_lint, declare_lint_pass};
use rustc_span::{sym, BytePos, Span};
use rustc_span::{sym, Span};
use crate::fluent_generated as fluent;
use crate::{LateContext, LateLintPass};
@ -53,7 +53,7 @@ declare_lint! {
/// while the `impl Display` is live.
///
/// To fix this, we can explicitly state that the `impl Display` doesn't
/// capture any lifetimes, using `impl use<> Display`.
/// capture any lifetimes, using `impl Display + use<>`.
pub IMPL_TRAIT_OVERCAPTURES,
Allow,
"`impl Trait` will capture more lifetimes than possibly intended in edition 2024",
@ -79,7 +79,7 @@ declare_lint! {
/// # #![feature(precise_capturing, lifetime_capture_rules_2024)]
/// # #![allow(incomplete_features)]
/// # #![deny(impl_trait_redundant_captures)]
/// fn test<'a>(x: &'a i32) -> impl use<'a> Sized { x }
/// fn test<'a>(x: &'a i32) -> impl Sized + use<'a> { x }
/// ```
///
/// {{produces}}
@ -249,7 +249,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
// If we have uncaptured args, and if the opaque doesn't already have
// `use<>` syntax on it, and we're < edition 2024, then warn the user.
if !new_capture_rules
&& opaque.precise_capturing_args.is_none()
&& !opaque.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Use(..)))
&& !uncaptured_spans.is_empty()
{
let suggestion = if let Ok(snippet) =
@ -268,8 +268,8 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
// Make sure that we're not trying to name any APITs
if generics.iter().all(|name| !name.starts_with("impl ")) {
Some((
format!(" use<{}>", generics.join(", ")),
opaque_span.with_lo(opaque_span.lo() + BytePos(4)).shrink_to_lo(),
format!(" + use<{}>", generics.join(", ")),
opaque_span.shrink_to_hi(),
))
} else {
None
@ -294,7 +294,11 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
// have no uncaptured args, then we should warn to the user that
// it's redundant to capture all args explicitly.
else if new_capture_rules
&& let Some((captured_args, capturing_span)) = opaque.precise_capturing_args
&& let Some((captured_args, capturing_span)) =
opaque.bounds.iter().find_map(|bound| match *bound {
hir::GenericBound::Use(a, s) => Some((a, s)),
_ => None,
})
{
let mut explicitly_captured = UnordSet::default();
for arg in captured_args {

View File

@ -1268,7 +1268,7 @@ impl EarlyLintPass for UnusedParens {
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

View File

@ -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, None) = &p.kind {
if let TyKind::ImplTrait(_, bounds) = &p.kind {
let span = impl_span.to(self.token.span.shrink_to_lo());
let mut err = self.dcx().struct_span_err(
span,

View File

@ -633,7 +633,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, None) = other
if let TyKind::ImplTrait(_, bounds) = other
&& let [bound] = bounds.as_slice()
{
// Suggest removing extra `impl` keyword:

View File

@ -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, None)
TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds)
}
_ => return Err(err),
};
@ -670,24 +670,12 @@ 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, args_span) = self.parse_precise_capturing_args()?;
Some(P((args, use_span.to(args_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, precise_capturing))
Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds))
}
fn parse_precise_capturing_args(
@ -834,6 +822,7 @@ impl<'a> Parser<'a> {
|| self.check(&token::OpenDelim(Delimiter::Parenthesis))
|| self.check_keyword(kw::Const)
|| self.check_keyword(kw::Async)
|| self.check_keyword(kw::Use)
}
/// Parses a bound according to the grammar:
@ -850,6 +839,14 @@ impl<'a> Parser<'a> {
let bound = if self.token.is_lifetime() {
self.error_lt_bound_with_modifiers(modifiers);
self.parse_generic_lt_bound(lo, inner_lo, has_parens)?
} else if self.eat_keyword(kw::Use) {
// 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 use_span = self.prev_token.span;
self.psess.gated_spans.gate(sym::precise_capturing, use_span);
let (args, args_span) = self.parse_precise_capturing_args()?;
GenericBound::Use(args, use_span.to(args_span))
} else {
self.parse_generic_ty_bound(lo, has_parens, modifiers, &leading_token)?
};
@ -1009,7 +1006,7 @@ impl<'a> Parser<'a> {
Applicability::MaybeIncorrect,
)
}
TyKind::ImplTrait(_, bounds, None)
TyKind::ImplTrait(_, bounds)
if let [GenericBound::Trait(tr, ..), ..] = bounds.as_slice() =>
{
(

View File

@ -429,7 +429,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
fn visit_param_bound(&mut self, b: &'v hir::GenericBound<'v>) {
record_variants!(
(self, b, b, Id::None, hir, GenericBound, GenericBound),
[Trait, Outlives]
[Trait, Outlives, Use]
);
hir_visit::walk_param_bound(self, b)
}
@ -659,7 +659,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
fn visit_param_bound(&mut self, b: &'v ast::GenericBound, _ctxt: BoundKind) {
record_variants!(
(self, b, b, Id::None, ast, GenericBound, GenericBound),
[Trait, Outlives]
[Trait, Outlives, Use]
);
ast_visit::walk_param_bound(self, b)
}

View File

@ -799,7 +799,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
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);

View File

@ -829,7 +829,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
auto-traits; structs and enums can't be bound in that way",
);
if bounds.iter().all(|bound| match bound {
ast::GenericBound::Outlives(_) => true,
ast::GenericBound::Outlives(_) | ast::GenericBound::Use(..) => true,
ast::GenericBound::Trait(tr, _) => tr.span == base_error.span,
}) {
let mut sugg = vec![];
@ -3210,7 +3210,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
.inputs
.iter()
.filter_map(|param| match &param.ty.kind {
TyKind::ImplTrait(_, bounds, _) => Some(bounds),
TyKind::ImplTrait(_, bounds) => Some(bounds),
_ => None,
})
.flat_map(|bounds| bounds.into_iter())

View File

@ -73,7 +73,7 @@ fn type_param_bounds<'tcx>(generics: &'tcx Generics<'tcx>) -> impl Iterator<Item
predicate_pos,
bound_pos,
}),
GenericBound::Outlives(_) => None,
GenericBound::Outlives(_) | GenericBound::Use(..) => None,
})
.filter(|bound| !bound.trait_bound.span.from_expansion()),
)

View File

@ -1,4 +1,4 @@
fn hello() -> impl use<> Sized {}
fn hello() -> impl Sized + use<> {}
//~^ ERROR precise captures on `impl Trait` are experimental
fn main() {}

View File

@ -1,8 +1,8 @@
error[E0658]: precise captures on `impl Trait` are experimental
--> $DIR/feature-gate-precise-capturing.rs:1:20
--> $DIR/feature-gate-precise-capturing.rs:1:28
|
LL | fn hello() -> impl use<> Sized {}
| ^^^
LL | fn hello() -> impl Sized + use<> {}
| ^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= help: add `#![feature(precise_capturing)]` to the crate attributes to enable

View File

@ -1,7 +1,7 @@
#![feature(precise_capturing)]
//~^ WARN the feature `precise_capturing` is incomplete
fn hello(_: impl use<> Sized) {}
fn hello(_: impl Sized + use<>) {}
//~^ ERROR `use<...>` precise capturing syntax not allowed on argument-position `impl Trait`
fn main() {}

View File

@ -8,10 +8,10 @@ LL | #![feature(precise_capturing)]
= note: `#[warn(incomplete_features)]` on by default
error: `use<...>` precise capturing syntax not allowed on argument-position `impl Trait`
--> $DIR/apit.rs:4:18
--> $DIR/apit.rs:4:26
|
LL | fn hello(_: impl use<> Sized) {}
| ^^^^^
LL | fn hello(_: impl Sized + use<>) {}
| ^^^^^
error: aborting due to 1 previous error; 1 warning emitted

View File

@ -1,14 +1,14 @@
#![feature(precise_capturing)]
//~^ WARN the feature `precise_capturing` is incomplete
fn no_elided_lt() -> impl use<'_> Sized {}
fn no_elided_lt() -> impl Sized + use<'_> {}
//~^ ERROR missing lifetime specifier
//~| ERROR expected lifetime parameter in `use<...>` precise captures list, found `'_`
fn static_lt() -> impl use<'static> Sized {}
fn static_lt() -> impl Sized + use<'static> {}
//~^ ERROR expected lifetime parameter in `use<...>` precise captures list, found `'static`
fn missing_lt() -> impl use<'missing> Sized {}
fn missing_lt() -> impl Sized + use<'missing> {}
//~^ ERROR use of undeclared lifetime name `'missing`
fn main() {}

View File

@ -1,20 +1,20 @@
error[E0106]: missing lifetime specifier
--> $DIR/bad-lifetimes.rs:4:31
--> $DIR/bad-lifetimes.rs:4:39
|
LL | fn no_elided_lt() -> impl use<'_> Sized {}
| ^^ expected named lifetime parameter
LL | fn no_elided_lt() -> impl Sized + use<'_> {}
| ^^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values
|
LL | fn no_elided_lt() -> impl use<'static> Sized {}
| ~~~~~~~
LL | fn no_elided_lt() -> impl Sized + use<'static> {}
| ~~~~~~~
error[E0261]: use of undeclared lifetime name `'missing`
--> $DIR/bad-lifetimes.rs:11:29
--> $DIR/bad-lifetimes.rs:11:37
|
LL | fn missing_lt() -> impl use<'missing> Sized {}
| - ^^^^^^^^ undeclared lifetime
LL | fn missing_lt() -> impl Sized + use<'missing> {}
| - ^^^^^^^^ undeclared lifetime
| |
| help: consider introducing lifetime `'missing` here: `<'missing>`
@ -28,16 +28,16 @@ LL | #![feature(precise_capturing)]
= note: `#[warn(incomplete_features)]` on by default
error: expected lifetime parameter in `use<...>` precise captures list, found `'_`
--> $DIR/bad-lifetimes.rs:4:31
--> $DIR/bad-lifetimes.rs:4:39
|
LL | fn no_elided_lt() -> impl use<'_> Sized {}
| ^^
LL | fn no_elided_lt() -> impl Sized + use<'_> {}
| ^^
error: expected lifetime parameter in `use<...>` precise captures list, found `'static`
--> $DIR/bad-lifetimes.rs:8:28
--> $DIR/bad-lifetimes.rs:8:36
|
LL | fn static_lt() -> impl use<'static> Sized {}
| ^^^^^^^
LL | fn static_lt() -> impl Sized + use<'static> {}
| ^^^^^^^
error: aborting due to 4 previous errors; 1 warning emitted

View File

@ -1,19 +1,19 @@
#![feature(precise_capturing)]
//~^ WARN the feature `precise_capturing` is incomplete
fn missing() -> impl use<T> Sized {}
fn missing() -> impl Sized + use<T> {}
//~^ ERROR cannot find type `T` in this scope
fn missing_self() -> impl use<Self> Sized {}
fn missing_self() -> impl Sized + use<Self> {}
//~^ ERROR cannot find type `Self` in this scope
struct MyType;
impl MyType {
fn self_is_not_param() -> impl use<Self> Sized {}
fn self_is_not_param() -> impl Sized + use<Self> {}
//~^ ERROR `Self` can't be captured in `use<...>` precise captures list, since it is an alias
}
fn hello() -> impl use<hello> Sized {}
fn hello() -> impl Sized + use<hello> {}
//~^ ERROR expected type or const parameter in `use<...>` precise captures list, found function
fn main() {}

View File

@ -1,19 +1,19 @@
error[E0412]: cannot find type `T` in this scope
--> $DIR/bad-params.rs:4:26
--> $DIR/bad-params.rs:4:34
|
LL | fn missing() -> impl use<T> Sized {}
| ^ not found in this scope
LL | fn missing() -> impl Sized + use<T> {}
| ^ not found in this scope
|
help: you might be missing a type parameter
|
LL | fn missing<T>() -> impl use<T> Sized {}
LL | fn missing<T>() -> impl Sized + use<T> {}
| +++
error[E0411]: cannot find type `Self` in this scope
--> $DIR/bad-params.rs:7:31
--> $DIR/bad-params.rs:7:39
|
LL | fn missing_self() -> impl use<Self> Sized {}
| ------------ ^^^^ `Self` is only available in impls, traits, and type definitions
LL | fn missing_self() -> impl Sized + use<Self> {}
| ------------ ^^^^ `Self` is only available in impls, traits, and type definitions
| |
| `Self` not allowed in a function
@ -27,18 +27,18 @@ LL | #![feature(precise_capturing)]
= note: `#[warn(incomplete_features)]` on by default
error: `Self` can't be captured in `use<...>` precise captures list, since it is an alias
--> $DIR/bad-params.rs:12:40
--> $DIR/bad-params.rs:12:48
|
LL | impl MyType {
| ----------- `Self` is not a generic argument, but an alias to the type of the implementation
LL | fn self_is_not_param() -> impl use<Self> Sized {}
| ^^^^
LL | fn self_is_not_param() -> impl Sized + use<Self> {}
| ^^^^
error: expected type or const parameter in `use<...>` precise captures list, found function
--> $DIR/bad-params.rs:16:24
--> $DIR/bad-params.rs:16:32
|
LL | fn hello() -> impl use<hello> Sized {}
| ^^^^^
LL | fn hello() -> impl Sized + use<hello> {}
| ^^^^^
error: aborting due to 4 previous errors; 1 warning emitted

View File

@ -13,25 +13,25 @@ impl Tr for W<'_> {
// The normal way of capturing `'a`...
impl<'a> W<'a> {
fn good1() -> impl use<'a> Into<<W<'a> as Tr>::Assoc> {}
fn good1() -> impl Into<<W<'a> as Tr>::Assoc> + use<'a> {}
}
// This ensures that we don't error when we capture the *parent* copy of `'a`,
// since the opaque captures that rather than the duplicated `'a` lifetime
// synthesized from mentioning `'a` directly in the bounds.
impl<'a> W<'a> {
fn good2() -> impl use<'a> Into<<Self as Tr>::Assoc> {}
fn good2() -> impl Into<<Self as Tr>::Assoc> + use<'a> {}
}
// The normal way of capturing `'a`... but not mentioned in the bounds.
impl<'a> W<'a> {
fn bad1() -> impl use<> Into<<W<'a> as Tr>::Assoc> {}
fn bad1() -> impl Into<<W<'a> as Tr>::Assoc> + use<> {}
//~^ ERROR `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
}
// But also make sure that we error here...
impl<'a> W<'a> {
fn bad2() -> impl use<> Into<<Self as Tr>::Assoc> {}
fn bad2() -> impl Into<<Self as Tr>::Assoc> + use<> {}
//~^ ERROR `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
}

View File

@ -8,20 +8,20 @@ LL | #![feature(precise_capturing)]
= note: `#[warn(incomplete_features)]` on by default
error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
--> $DIR/capture-parent-arg.rs:28:37
--> $DIR/capture-parent-arg.rs:28:31
|
LL | impl<'a> W<'a> {
| -- this lifetime parameter is captured
LL | fn bad1() -> impl use<> Into<<W<'a> as Tr>::Assoc> {}
| -------------------^^---------------- lifetime captured due to being mentioned in the bounds of the `impl Trait`
LL | fn bad1() -> impl Into<<W<'a> as Tr>::Assoc> + use<> {}
| -------------^^------------------------ lifetime captured due to being mentioned in the bounds of the `impl Trait`
error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
--> $DIR/capture-parent-arg.rs:34:18
|
LL | impl<'a> W<'a> {
| -- this lifetime parameter is captured
LL | fn bad2() -> impl use<> Into<<Self as Tr>::Assoc> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime captured due to being mentioned in the bounds of the `impl Trait`
LL | fn bad2() -> impl Into<<Self as Tr>::Assoc> + use<> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime captured due to being mentioned in the bounds of the `impl Trait`
error: aborting due to 2 previous errors; 1 warning emitted

View File

@ -3,6 +3,6 @@
#![feature(precise_capturing)]
//~^ WARN the feature `precise_capturing` is incomplete
fn elided(x: &()) -> impl use<'_> Sized { x }
fn elided(x: &()) -> impl Sized + use<'_> { x }
fn main() {}

View File

@ -1,7 +1,7 @@
#![feature(precise_capturing)]
//~^ WARN the feature `precise_capturing` is incomplete
fn constant<const C: usize>() -> impl use<> Sized {}
fn constant<const C: usize>() -> impl Sized + use<> {}
//~^ ERROR `impl Trait` must mention all const parameters in scope
fn main() {}

View File

@ -10,8 +10,8 @@ LL | #![feature(precise_capturing)]
error: `impl Trait` must mention all const parameters in scope in `use<...>`
--> $DIR/forgot-to-capture-const.rs:4:34
|
LL | fn constant<const C: usize>() -> impl use<> Sized {}
| -------------- ^^^^^^^^^^^^^^^^
LL | fn constant<const C: usize>() -> impl Sized + use<> {}
| -------------- ^^^^^^^^^^^^^^^^^^
| |
| const parameter is implicitly captured by this `impl Trait`
|

View File

@ -1,10 +1,10 @@
#![feature(precise_capturing)]
//~^ WARN the feature `precise_capturing` is incomplete
fn lifetime_in_bounds<'a>(x: &'a ()) -> impl use<> Into<&'a ()> { x }
fn lifetime_in_bounds<'a>(x: &'a ()) -> impl Into<&'a ()> + use<> { x }
//~^ ERROR `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
fn lifetime_in_hidden<'a>(x: &'a ()) -> impl use<> Sized { x }
fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<> { x }
//~^ ERROR hidden type for `impl Sized` captures lifetime that does not appear in bounds
fn main() {}

View File

@ -8,27 +8,27 @@ LL | #![feature(precise_capturing)]
= note: `#[warn(incomplete_features)]` on by default
error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
--> $DIR/forgot-to-capture-lifetime.rs:4:58
--> $DIR/forgot-to-capture-lifetime.rs:4:52
|
LL | fn lifetime_in_bounds<'a>(x: &'a ()) -> impl use<> Into<&'a ()> { x }
| -- -----------------^^----
LL | fn lifetime_in_bounds<'a>(x: &'a ()) -> impl Into<&'a ()> + use<> { x }
| -- -----------^^------------
| | |
| | lifetime captured due to being mentioned in the bounds of the `impl Trait`
| this lifetime parameter is captured
error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds
--> $DIR/forgot-to-capture-lifetime.rs:7:60
--> $DIR/forgot-to-capture-lifetime.rs:7:62
|
LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl use<> Sized { x }
| -- ---------------- ^
LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<> { x }
| -- ------------------ ^
| | |
| | opaque type defined here
| hidden type `&'a ()` captures the lifetime `'a` as defined here
|
help: to declare that `impl Sized` captures `'a`, you can add an explicit `'a` lifetime bound
|
LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl use<> Sized + 'a { x }
| ++++
LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<> + 'a { x }
| ++++
error: aborting due to 2 previous errors; 1 warning emitted

View File

@ -1,11 +1,11 @@
#![feature(precise_capturing)]
//~^ WARN the feature `precise_capturing` is incomplete
fn type_param<T>() -> impl use<> Sized {}
fn type_param<T>() -> impl Sized + use<> {}
//~^ ERROR `impl Trait` must mention all type parameters in scope
trait Foo {
fn bar() -> impl use<> Sized;
fn bar() -> impl Sized + use<>;
//~^ ERROR `impl Trait` must mention the `Self` type of the trait
}

View File

@ -10,8 +10,8 @@ LL | #![feature(precise_capturing)]
error: `impl Trait` must mention all type parameters in scope in `use<...>`
--> $DIR/forgot-to-capture-type.rs:4:23
|
LL | fn type_param<T>() -> impl use<> Sized {}
| - ^^^^^^^^^^^^^^^^
LL | fn type_param<T>() -> impl Sized + use<> {}
| - ^^^^^^^^^^^^^^^^^^
| |
| type parameter is implicitly captured by this `impl Trait`
|
@ -22,8 +22,8 @@ error: `impl Trait` must mention the `Self` type of the trait in `use<...>`
|
LL | trait Foo {
| --------- `Self` type parameter is implicitly captured by this `impl Trait`
LL | fn bar() -> impl use<> Sized;
| ^^^^^^^^^^^^^^^^
LL | fn bar() -> impl Sized + use<>;
| ^^^^^^^^^^^^^^^^^^
|
= note: currently, all type parameters are required to be mentioned in the precise captures list

View File

@ -13,6 +13,6 @@ impl Trait<'_> for () {
type Item = Vec<()>;
}
fn hello() -> impl for<'a> Trait<'a, Item = impl use<> IntoIterator> {}
fn hello() -> impl for<'a> Trait<'a, Item = impl IntoIterator + use<>> {}
fn main() {}

View File

@ -1,16 +1,16 @@
#![feature(precise_capturing)]
//~^ WARN the feature `precise_capturing` is incomplete
fn lt<'a>() -> impl use<'a, 'a> Sized {}
fn lt<'a>() -> impl Sized + use<'a, 'a> {}
//~^ ERROR cannot capture parameter `'a` twice
fn ty<T>() -> impl use<T, T> Sized {}
fn ty<T>() -> impl Sized + use<T, T> {}
//~^ ERROR cannot capture parameter `T` twice
fn ct<const N: usize>() -> impl use<N, N> Sized {}
fn ct<const N: usize>() -> impl Sized + use<N, N> {}
//~^ ERROR cannot capture parameter `N` twice
fn ordering<'a, T>() -> impl use<T, 'a> Sized {}
fn ordering<'a, T>() -> impl Sized + use<T, 'a> {}
//~^ ERROR lifetime parameter `'a` must be listed before non-lifetime parameters
fn main() {}

View File

@ -8,30 +8,30 @@ LL | #![feature(precise_capturing)]
= note: `#[warn(incomplete_features)]` on by default
error: cannot capture parameter `'a` twice
--> $DIR/ordering.rs:4:25
--> $DIR/ordering.rs:4:33
|
LL | fn lt<'a>() -> impl use<'a, 'a> Sized {}
| ^^ -- parameter captured again here
LL | fn lt<'a>() -> impl Sized + use<'a, 'a> {}
| ^^ -- parameter captured again here
error: cannot capture parameter `T` twice
--> $DIR/ordering.rs:7:24
--> $DIR/ordering.rs:7:32
|
LL | fn ty<T>() -> impl use<T, T> Sized {}
| ^ - parameter captured again here
LL | fn ty<T>() -> impl Sized + use<T, T> {}
| ^ - parameter captured again here
error: cannot capture parameter `N` twice
--> $DIR/ordering.rs:10:37
--> $DIR/ordering.rs:10:45
|
LL | fn ct<const N: usize>() -> impl use<N, N> Sized {}
| ^ - parameter captured again here
LL | fn ct<const N: usize>() -> impl Sized + use<N, N> {}
| ^ - parameter captured again here
error: lifetime parameter `'a` must be listed before non-lifetime parameters
--> $DIR/ordering.rs:13:37
--> $DIR/ordering.rs:13:45
|
LL | fn ordering<'a, T>() -> impl use<T, 'a> Sized {}
| - ^^
| |
| move the lifetime before this parameter
LL | fn ordering<'a, T>() -> impl Sized + use<T, 'a> {}
| - ^^
| |
| move the lifetime before this parameter
error: aborting due to 4 previous errors; 1 warning emitted

View File

@ -5,7 +5,7 @@
#![feature(lifetime_capture_rules_2024, precise_capturing)]
//~^ WARN the feature `precise_capturing` is incomplete
fn hello<'a: 'a, 'b: 'b>() -> impl use<'a> Sized { }
fn hello<'a: 'a, 'b: 'b>() -> impl Sized + use<'a> { }
fn outlives<'a, T: 'a>(_: T) {}

View File

@ -4,15 +4,15 @@
#![allow(unused, incomplete_features)]
#![deny(impl_trait_overcaptures)]
fn named<'a>(x: &'a i32) -> impl use<> Sized { *x }
fn named<'a>(x: &'a i32) -> impl Sized + use<> { *x }
//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
fn implicit(x: &i32) -> impl use<> Sized { *x }
fn implicit(x: &i32) -> impl Sized + use<> { *x }
//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
struct W;
impl W {
fn hello(&self, x: &i32) -> impl use<'_> Sized + '_ { self }
fn hello(&self, x: &i32) -> impl Sized + '_ + use<'_> { self }
//~^ ERROR `impl Sized + '_` will capture more lifetimes than possibly intended in edition 2024
}
@ -23,7 +23,7 @@ impl Higher<'_> for () {
type Output = ();
}
fn hrtb() -> impl for<'a> Higher<'a, Output = impl use<> Sized> {}
fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized + use<>> {}
//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
fn main() {}

View File

@ -17,8 +17,8 @@ LL | #![deny(impl_trait_overcaptures)]
| ^^^^^^^^^^^^^^^^^^^^^^^
help: use the precise capturing `use<...>` syntax to make the captures explicit
|
LL | fn named<'a>(x: &'a i32) -> impl use<> Sized { *x }
| +++++
LL | fn named<'a>(x: &'a i32) -> impl Sized + use<> { *x }
| +++++++
error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024
--> $DIR/overcaptures-2024.rs:10:25
@ -34,8 +34,8 @@ LL | fn implicit(x: &i32) -> impl Sized { *x }
= note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
help: use the precise capturing `use<...>` syntax to make the captures explicit
|
LL | fn implicit(x: &i32) -> impl use<> Sized { *x }
| +++++
LL | fn implicit(x: &i32) -> impl Sized + use<> { *x }
| +++++++
error: `impl Sized + '_` will capture more lifetimes than possibly intended in edition 2024
--> $DIR/overcaptures-2024.rs:15:33
@ -51,8 +51,8 @@ LL | fn hello(&self, x: &i32) -> impl Sized + '_ { self }
= note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
help: use the precise capturing `use<...>` syntax to make the captures explicit
|
LL | fn hello(&self, x: &i32) -> impl use<'_> Sized + '_ { self }
| +++++++
LL | fn hello(&self, x: &i32) -> impl Sized + '_ + use<'_> { self }
| +++++++++
error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024
--> $DIR/overcaptures-2024.rs:26:47
@ -68,8 +68,8 @@ LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {}
= note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
help: use the precise capturing `use<...>` syntax to make the captures explicit
|
LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl use<> Sized> {}
| +++++
LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized + use<>> {}
| +++++++
error: aborting due to 4 previous errors

View File

@ -4,21 +4,21 @@
#![feature(precise_capturing)]
//~^ WARN the feature `precise_capturing` is incomplete
fn hello<'a>() -> impl use<'a> Sized {}
fn hello<'a>() -> impl Sized + use<'a> {}
//~^ WARN all possible in-scope parameters are already captured
struct Inherent;
impl Inherent {
fn inherent(&self) -> impl use<'_> Sized {}
fn inherent(&self) -> impl Sized + use<'_> {}
//~^ WARN all possible in-scope parameters are already captured
}
trait Test<'a> {
fn in_trait() -> impl use<'a, Self> Sized;
fn in_trait() -> impl Sized + use<'a, Self>;
//~^ WARN all possible in-scope parameters are already captured
}
impl<'a> Test<'a> for () {
fn in_trait() -> impl use<'a> Sized {}
fn in_trait() -> impl Sized + use<'a> {}
//~^ WARN all possible in-scope parameters are already captured
}

View File

@ -10,36 +10,36 @@ LL | #![feature(precise_capturing)]
warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
--> $DIR/redundant.rs:7:19
|
LL | fn hello<'a>() -> impl use<'a> Sized {}
| ^^^^^-------^^^^^^
| |
| help: remove the `use<...>` syntax
LL | fn hello<'a>() -> impl Sized + use<'a> {}
| ^^^^^^^^^^^^^-------
| |
| help: remove the `use<...>` syntax
|
= note: `#[warn(impl_trait_redundant_captures)]` on by default
warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
--> $DIR/redundant.rs:12:27
|
LL | fn inherent(&self) -> impl use<'_> Sized {}
| ^^^^^-------^^^^^^
| |
| help: remove the `use<...>` syntax
LL | fn inherent(&self) -> impl Sized + use<'_> {}
| ^^^^^^^^^^^^^-------
| |
| help: remove the `use<...>` syntax
warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
--> $DIR/redundant.rs:17:22
|
LL | fn in_trait() -> impl use<'a, Self> Sized;
| ^^^^^-------------^^^^^^
| |
| help: remove the `use<...>` syntax
LL | fn in_trait() -> impl Sized + use<'a, Self>;
| ^^^^^^^^^^^^^-------------
| |
| help: remove the `use<...>` syntax
warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
--> $DIR/redundant.rs:21:22
|
LL | fn in_trait() -> impl use<'a> Sized {}
| ^^^^^-------^^^^^^
| |
| help: remove the `use<...>` syntax
LL | fn in_trait() -> impl Sized + use<'a> {}
| ^^^^^^^^^^^^^-------
| |
| help: remove the `use<...>` syntax
warning: 5 warnings emitted

View File

@ -4,7 +4,7 @@
//~^ WARN the feature `precise_capturing` is incomplete
trait Foo {
fn bar<'a>() -> impl use<Self> Sized;
fn bar<'a>() -> impl Sized + use<Self>;
}
fn main() {}

View File

@ -2,7 +2,7 @@
// token due to a strange interaction between the sequence parsing code and the
// param/lifetime parsing code.
fn hello() -> impl use<'a {}> Sized {}
fn hello() -> impl Sized + use<'a {}> {}
//~^ ERROR expected one of `,` or `>`, found `{`
fn main() {}

View File

@ -1,8 +1,8 @@
error: expected one of `,` or `>`, found `{`
--> $DIR/unexpected-token.rs:5:27
--> $DIR/unexpected-token.rs:5:35
|
LL | fn hello() -> impl use<'a {}> Sized {}
| ^ expected one of `,` or `>`
LL | fn hello() -> impl Sized + use<'a {}> {}
| ^ expected one of `,` or `>`
error: aborting due to 1 previous error

View File

@ -8,7 +8,7 @@ fn foo2(_: &dyn (Drop + AsRef<str>)) {} //~ ERROR incorrect parentheses around t
fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {} //~ ERROR incorrect parentheses around trait bounds
fn foo3(_: &dyn {Drop + AsRef<str>}) {} //~ ERROR expected parameter name, found `{`
//~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `async`, `const`, `for`, `~`, lifetime, or path, found `{`
//~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `async`, `const`, `for`, `use`, `~`, lifetime, or path, found `{`
//~| ERROR at least one trait is required for an object type
fn foo4(_: &dyn <Drop + AsRef<str>>) {} //~ ERROR expected identifier, found `<`

View File

@ -34,11 +34,11 @@ error: expected parameter name, found `{`
LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
| ^ expected parameter name
error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `async`, `const`, `for`, `~`, lifetime, or path, found `{`
error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `async`, `const`, `for`, `use`, `~`, lifetime, or path, found `{`
--> $DIR/trait-object-delimiters.rs:10:17
|
LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
| -^ expected one of 12 possible tokens
| -^ expected one of 13 possible tokens
| |
| help: missing `,`