Auto merge of #126049 - compiler-errors:rework-use, r=oli-obk

Rework `feature(precise_capturing)` to represent `use<...>` as a syntactical bound

Reworks `precise_capturing` for a recent lang-team consensus.

Specifically:

> The conclusion of the team is that we'll make use<..> a bound. That is, we'll support impl use<..> + Trait, impl Trait + use<..>, etc.

> For now, we will support at most one such bound in a list of bounds, and semantically we'll only support these bounds in the item bounds of RPIT-like impl Trait opaque types (i.e., in the places discussed in the RFC).

Lang decision in favor of this approach:

- https://github.com/rust-lang/rust/issues/125836#issuecomment-2151351849

Tracking:

- https://github.com/rust-lang/rust/issues/123432
This commit is contained in:
bors 2024-06-18 09:30:38 +00:00
commit c1f62a7c35
76 changed files with 629 additions and 575 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

@ -128,7 +128,7 @@ ast_lowering_never_pattern_with_guard =
a guard on a never pattern will never be run
.suggestion = remove this guard
ast_lowering_no_precise_captures_on_apit = `use<...>` precise capturing syntax not allowed on argument-position `impl Trait`
ast_lowering_no_precise_captures_on_apit = `use<...>` precise capturing syntax not allowed in argument-position `impl Trait`
ast_lowering_previously_used_here = previously used here

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,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
None
}
// Ignore `use` syntax since that is not valid in objects.
GenericBound::Use(_, span) => {
this.dcx()
.span_delayed_bug(*span, "use<> not allowed in dyn types");
None
}
}));
let lifetime_bound =
lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span));
@ -1391,7 +1397,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 +1407,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 +1526,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 +1534,64 @@ 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) =
// We only look for one `use<...>` syntax since we syntactially reject more than one.
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 +1601,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 +1613,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 +1699,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 +1745,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
origin,
lifetime_mapping,
in_trait,
precise_capturing_args,
};
// Generate an `type Foo = impl Trait;` declaration.
@ -1955,7 +1955,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 +2037,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

@ -215,6 +215,11 @@ ast_passes_pattern_in_fn_pointer = patterns aren't allowed in function pointer t
ast_passes_pattern_in_foreign = patterns aren't allowed in foreign function declarations
.label = pattern not allowed in foreign function
ast_passes_precise_capturing_duplicated = duplicate `use<...>` precise capturing syntax
.label = second `use<...>` here
ast_passes_precise_capturing_not_allowed_here = `use<...>` precise capturing syntax not allowed in {$loc}
ast_passes_show_span = {$msg}
ast_passes_stability_outside_std = stability attributes may not be used outside of the standard library

View File

@ -193,8 +193,24 @@ impl<'a> AstValidator<'a> {
// Mirrors `visit::walk_ty`, but tracks relevant state.
fn walk_ty(&mut self, t: &'a Ty) {
match &t.kind {
TyKind::ImplTrait(..) => {
self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
TyKind::ImplTrait(_, bounds) => {
self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t));
// FIXME(precise_capturing): If we were to allow `use` in other positions
// (e.g. GATs), then we must validate those as well. However, we don't have
// a good way of doing this with the current `Visitor` structure.
let mut use_bounds = bounds
.iter()
.filter_map(|bound| match bound {
GenericBound::Use(_, span) => Some(span),
_ => None,
})
.copied();
if let Some(bound1) = use_bounds.next()
&& let Some(bound2) = use_bounds.next()
{
self.dcx().emit_err(errors::DuplicatePreciseCapturing { bound1, bound2 });
}
}
TyKind::TraitObject(..) => self
.with_tilde_const(Some(DisallowTildeConstContext::TraitObject), |this| {
@ -751,7 +767,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 +1320,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
}
GenericBound::Outlives(_) => {}
GenericBound::Use(..) => {}
}
}
}
@ -1322,95 +1339,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,
}
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,
});
}
None => {}
}
},
}
visit::walk_param_bound(self, bound)

View File

@ -844,3 +844,20 @@ 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,
}
#[derive(Diagnostic)]
#[diag(ast_passes_precise_capturing_duplicated)]
pub struct DuplicatePreciseCapturing {
#[primary_span]
pub bound1: Span,
#[label]
pub bound2: Span,
}

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,8 +567,8 @@ 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.
(incomplete, precise_capturing, "1.79.0", Some(123432)),
/// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args.
(unstable, 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)),
/// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.

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

@ -1,7 +1,6 @@
use super::pat::Expected;
use super::{
BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep,
TokenExpectType, TokenType,
BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenType,
};
use crate::errors::{
AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, BadQPathStage2, BadTypePlus,
@ -1045,9 +1044,7 @@ impl<'a> Parser<'a> {
/// passes through any errors encountered. Used for error recovery.
pub(super) fn eat_to_tokens(&mut self, kets: &[&TokenKind]) {
if let Err(err) =
self.parse_seq_to_before_tokens(kets, SeqSep::none(), TokenExpectType::Expect, |p| {
Ok(p.parse_token_tree())
})
self.parse_seq_to_before_tokens(kets, &[], SeqSep::none(), |p| Ok(p.parse_token_tree()))
{
err.cancel();
}

View File

@ -4,7 +4,7 @@ use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma};
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{
AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions,
SemiColonMode, SeqSep, TokenExpectType, TokenType, Trailing, TrailingToken,
SemiColonMode, SeqSep, TokenType, Trailing, TrailingToken,
};
use crate::errors;
@ -2456,9 +2456,9 @@ impl<'a> Parser<'a> {
self.expect(&token::BinOp(token::Or))?;
let args = self
.parse_seq_to_before_tokens(
&[&token::BinOp(token::Or), &token::OrOr],
&[&token::BinOp(token::Or)],
&[&token::OrOr],
SeqSep::trailing_allowed(token::Comma),
TokenExpectType::NoExpect,
|p| p.parse_fn_block_param(),
)?
.0;

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

@ -335,18 +335,6 @@ impl TokenType {
}
}
/// Used by [`Parser::expect_any_with_type`].
#[derive(Copy, Clone, Debug)]
enum TokenExpectType {
/// Unencountered tokens are inserted into [`Parser::expected_tokens`].
/// See [`Parser::check`].
Expect,
/// Unencountered tokens are not inserted into [`Parser::expected_tokens`].
/// See [`Parser::check_noexpect`].
NoExpect,
}
/// A sequence separator.
#[derive(Debug)]
struct SeqSep {
@ -807,11 +795,13 @@ impl<'a> Parser<'a> {
}
/// Checks if the next token is contained within `kets`, and returns `true` if so.
fn expect_any_with_type(&mut self, kets: &[&TokenKind], expect: TokenExpectType) -> bool {
kets.iter().any(|k| match expect {
TokenExpectType::Expect => self.check(k),
TokenExpectType::NoExpect => self.check_noexpect(k),
})
fn expect_any_with_type(
&mut self,
kets_expected: &[&TokenKind],
kets_not_expected: &[&TokenKind],
) -> bool {
kets_expected.iter().any(|k| self.check(k))
|| kets_not_expected.iter().any(|k| self.check_noexpect(k))
}
/// Parses a sequence until the specified delimiters. The function
@ -819,9 +809,9 @@ impl<'a> Parser<'a> {
/// closing bracket.
fn parse_seq_to_before_tokens<T>(
&mut self,
kets: &[&TokenKind],
kets_expected: &[&TokenKind],
kets_not_expected: &[&TokenKind],
sep: SeqSep,
expect: TokenExpectType,
mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
) -> PResult<'a, (ThinVec<T>, Trailing, Recovered)> {
let mut first = true;
@ -829,7 +819,7 @@ impl<'a> Parser<'a> {
let mut trailing = Trailing::No;
let mut v = ThinVec::new();
while !self.expect_any_with_type(kets, expect) {
while !self.expect_any_with_type(kets_expected, kets_not_expected) {
if let token::CloseDelim(..) | token::Eof = self.token.kind {
break;
}
@ -927,7 +917,8 @@ impl<'a> Parser<'a> {
if self.token == token::Colon {
// we will try to recover in `maybe_recover_struct_lit_bad_delims`
return Err(expect_err);
} else if let [token::CloseDelim(Delimiter::Parenthesis)] = kets
} else if let [token::CloseDelim(Delimiter::Parenthesis)] =
kets_expected
{
return Err(expect_err);
} else {
@ -940,7 +931,9 @@ impl<'a> Parser<'a> {
}
}
}
if sep.trailing_sep_allowed && self.expect_any_with_type(kets, expect) {
if sep.trailing_sep_allowed
&& self.expect_any_with_type(kets_expected, kets_not_expected)
{
trailing = Trailing::Yes;
break;
}
@ -1020,7 +1013,7 @@ impl<'a> Parser<'a> {
sep: SeqSep,
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
) -> PResult<'a, (ThinVec<T>, Trailing, Recovered)> {
self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f)
self.parse_seq_to_before_tokens(&[ket], &[], sep, f)
}
/// Parses a sequence, including only the closing delimiter. The function

View File

@ -9,7 +9,7 @@ use crate::errors::{
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
use rustc_ast::token::{self, BinOpToken, Delimiter, Token, TokenKind};
use rustc_ast::util::case::Case;
use rustc_ast::{
self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, FnRetTy, GenericBound,
@ -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,33 +670,26 @@ 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(
&mut self,
) -> PResult<'a, (ThinVec<PreciseCapturingArg>, Span)> {
let lo = self.token.span;
let (args, _) = self.parse_unspanned_seq(
&TokenKind::Lt,
&TokenKind::Gt,
self.expect_lt()?;
let (args, _, _) = self.parse_seq_to_before_tokens(
&[&TokenKind::Gt],
&[
&TokenKind::Ge,
&TokenKind::BinOp(BinOpToken::Shr),
&TokenKind::BinOpEq(BinOpToken::Shr),
],
SeqSep::trailing_allowed(token::Comma),
|self_| {
if self_.check_keyword(kw::SelfUpper) {
@ -717,6 +710,7 @@ impl<'a> Parser<'a> {
}
},
)?;
self.expect_gt()?;
Ok((args, lo.to(self.prev_token.span)))
}
@ -828,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:
@ -844,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)?
};
@ -1003,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

@ -228,6 +228,8 @@ fn clean_generic_bound<'tcx>(
GenericBound::TraitBound(clean_poly_trait_ref(t, cx), modifier)
}
// FIXME(precise_capturing): Implement rustdoc support
hir::GenericBound::Use(..) => return None,
})
}

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

@ -724,11 +724,8 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool {
(Tup(l), Tup(r)) => over(l, r, |l, r| eq_ty(l, r)),
(Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp),
(TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, eq_generic_bound),
(ImplTrait(_, lg, lc), ImplTrait(_, rg, rc)) => {
(ImplTrait(_, lg), ImplTrait(_, rg)) => {
over(lg, rg, eq_generic_bound)
&& both(lc, rc, |lc, rc| {
over(lc.0.as_slice(), rc.0.as_slice(), eq_precise_capture)
})
},
(Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value),
(MacCall(l), MacCall(r)) => eq_mac_call(l, r),

View File

@ -181,6 +181,7 @@ impl Spanned for ast::GenericBound {
match *self {
ast::GenericBound::Trait(ref ptr, _) => ptr.span,
ast::GenericBound::Outlives(ref l) => l.ident.span,
ast::GenericBound::Use(_, span) => span,
}
}
}

View File

@ -563,6 +563,8 @@ impl Rewrite for ast::GenericBound {
.map(|s| if has_paren { format!("({})", s) } else { s })
}
ast::GenericBound::Outlives(ref lifetime) => lifetime.rewrite(context, shape),
// FIXME(precise_capturing): Should implement formatting before stabilization.
ast::GenericBound::Use(..) => None,
}
}
}
@ -843,11 +845,7 @@ impl Rewrite for ast::Ty {
rewrite_macro(mac, None, context, shape, MacroPosition::Expression)
}
ast::TyKind::ImplicitSelf => Some(String::from("")),
ast::TyKind::ImplTrait(_, ref it, ref captures) => {
// FIXME(precise_capturing): Implement formatting.
if captures.is_some() {
return None;
}
ast::TyKind::ImplTrait(_, ref it) => {
// Empty trait is not a parser error.
if it.is_empty() {
return Some("impl".to_owned());
@ -932,6 +930,8 @@ fn is_generic_bounds_in_order(generic_bounds: &[ast::GenericBound]) -> bool {
let is_trait = |b: &ast::GenericBound| match b {
ast::GenericBound::Outlives(..) => false,
ast::GenericBound::Trait(..) => true,
// FIXME(precise_capturing): This ordering fn should be reworked.
ast::GenericBound::Use(..) => false,
};
let is_lifetime = |b: &ast::GenericBound| !is_trait(b);
let last_trait_index = generic_bounds.iter().rposition(is_trait);
@ -966,6 +966,8 @@ fn join_bounds_inner(
let is_bound_extendable = |s: &str, b: &ast::GenericBound| match b {
ast::GenericBound::Outlives(..) => true,
ast::GenericBound::Trait(..) => last_line_extendable(s),
// FIXME(precise_capturing): This ordering fn should be reworked.
ast::GenericBound::Use(..) => true,
};
// Whether a GenericBound item is a PathSegment segment that includes internal array
@ -1110,8 +1112,7 @@ fn join_bounds_inner(
pub(crate) fn opaque_ty(ty: &Option<ptr::P<ast::Ty>>) -> Option<&ast::GenericBounds> {
ty.as_ref().and_then(|t| match &t.kind {
// FIXME(precise_capturing): Implement support here
ast::TyKind::ImplTrait(_, bounds, _) => Some(bounds),
ast::TyKind::ImplTrait(_, bounds) => Some(bounds),
_ => None,
})
}

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,5 +1,5 @@
error[E0282]: type annotations needed
--> $DIR/call_method_ambiguous.rs:29:13
--> $DIR/call_method_ambiguous.rs:28:13
|
LL | let mut iter = foo(n - 1, m);
| ^^^^^^^^

View File

@ -3,7 +3,6 @@
//@[current] run-pass
#![feature(precise_capturing)]
#![allow(incomplete_features)]
trait Get {
fn get(&mut self) -> u32;
@ -24,7 +23,7 @@ where
}
}
fn foo(n: usize, m: &mut ()) -> impl use<'_> Get {
fn foo(n: usize, m: &mut ()) -> impl Get + use<'_> {
if n > 0 {
let mut iter = foo(n - 1, m);
//[next]~^ type annotations needed

View File

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

View File

@ -1,17 +1,8 @@
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/apit.rs:1:12
error: `use<...>` precise capturing syntax not allowed in argument-position `impl Trait`
--> $DIR/apit.rs:3:26
|
LL | #![feature(precise_capturing)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= note: `#[warn(incomplete_features)]` on by default
LL | fn hello(_: impl Sized + use<>) {}
| ^^^^^
error: `use<...>` precise capturing syntax not allowed on argument-position `impl Trait`
--> $DIR/apit.rs:4:18
|
LL | fn hello(_: impl use<> Sized) {}
| ^^^^^
error: aborting due to 1 previous error; 1 warning emitted
error: aborting due to 1 previous error

View File

@ -1,14 +1,13 @@
#![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,45 +1,36 @@
error[E0106]: missing lifetime specifier
--> $DIR/bad-lifetimes.rs:4:31
--> $DIR/bad-lifetimes.rs:3: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:10: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>`
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/bad-lifetimes.rs:1:12
|
LL | #![feature(precise_capturing)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= 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:3: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:7: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
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0106, E0261.
For more information about an error, try `rustc --explain E0106`.

View File

@ -1,19 +1,18 @@
#![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,46 +1,37 @@
error[E0412]: cannot find type `T` in this scope
--> $DIR/bad-params.rs:4:26
--> $DIR/bad-params.rs:3: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:6: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
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/bad-params.rs:1:12
|
LL | #![feature(precise_capturing)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= 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:11: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:15: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
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0411, E0412.
For more information about an error, try `rustc --explain E0411`.

View File

@ -1,5 +1,4 @@
#![feature(precise_capturing)]
//~^ WARN the feature `precise_capturing` is incomplete
trait Tr {
type Assoc;
@ -13,25 +12,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

@ -1,27 +1,18 @@
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/capture-parent-arg.rs:1:12
|
LL | #![feature(precise_capturing)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= 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:27: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
--> $DIR/capture-parent-arg.rs:33: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
error: aborting due to 2 previous errors

View File

@ -0,0 +1,8 @@
error: duplicate `use<...>` precise capturing syntax
--> $DIR/duplicated-use.rs:7:32
|
LL | fn hello<'a>() -> impl Sized + use<'a> + use<'a> {}
| ^^^^^^^ ------- second `use<...>` here
error: aborting due to 1 previous error

View File

@ -0,0 +1,10 @@
//@ revisions: real pre_expansion
//@[pre_expansion] check-pass
#![feature(precise_capturing)]
#[cfg(real)]
fn hello<'a>() -> impl Sized + use<'a> + use<'a> {}
//[real]~^ ERROR duplicate `use<...>` precise capturing syntax
fn main() {}

View File

@ -0,0 +1,4 @@
#![feature(precise_capturing)]
fn dyn() -> &'static dyn use<> { &() }
//~^ ERROR expected one of `!`, `(`, `::`, `<`, `where`, or `{`, found keyword `use`

View File

@ -0,0 +1,8 @@
error: expected one of `!`, `(`, `::`, `<`, `where`, or `{`, found keyword `use`
--> $DIR/dyn-use.rs:3:26
|
LL | fn dyn() -> &'static dyn use<> { &() }
| ^^^ expected one of `!`, `(`, `::`, `<`, `where`, or `{`
error: aborting due to 1 previous error

View File

@ -1,8 +1,7 @@
//@ check-pass
#![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,11 +0,0 @@
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/elided.rs:3:12
|
LL | #![feature(precise_capturing)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted

View File

@ -1,7 +1,6 @@
#![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

@ -1,21 +1,12 @@
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/forgot-to-capture-const.rs:1:12
|
LL | #![feature(precise_capturing)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= note: `#[warn(incomplete_features)]` on by default
error: `impl Trait` must mention all const parameters in scope in `use<...>`
--> $DIR/forgot-to-capture-const.rs:4:34
--> $DIR/forgot-to-capture-const.rs:3: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`
|
= note: currently, all const parameters are required to be mentioned in the precise captures list
error: aborting due to 1 previous error; 1 warning emitted
error: aborting due to 1 previous error

View File

@ -1,10 +1,9 @@
#![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

@ -1,35 +1,26 @@
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/forgot-to-capture-lifetime.rs:1:12
|
LL | #![feature(precise_capturing)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= 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:3: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:6: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
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0700`.

View File

@ -1,11 +1,10 @@
#![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

@ -1,31 +1,22 @@
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/forgot-to-capture-type.rs:1:12
|
LL | #![feature(precise_capturing)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= note: `#[warn(incomplete_features)]` on by default
error: `impl Trait` must mention all type parameters in scope in `use<...>`
--> $DIR/forgot-to-capture-type.rs:4:23
--> $DIR/forgot-to-capture-type.rs:3: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`
|
= note: currently, all type parameters are required to be mentioned in the precise captures list
error: `impl Trait` must mention the `Self` type of the trait in `use<...>`
--> $DIR/forgot-to-capture-type.rs:8:17
--> $DIR/forgot-to-capture-type.rs:7:17
|
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
error: aborting due to 2 previous errors; 1 warning emitted
error: aborting due to 2 previous errors

View File

@ -3,7 +3,6 @@
// Show how precise captures allow us to skip capturing a higher-ranked lifetime
#![feature(lifetime_capture_rules_2024, precise_capturing)]
//~^ WARN the feature `precise_capturing` is incomplete
trait Trait<'a> {
type Item;
@ -13,6 +12,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,11 +0,0 @@
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/higher-ranked.rs:5:41
|
LL | #![feature(lifetime_capture_rules_2024, precise_capturing)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted

View File

@ -0,0 +1,57 @@
error: `use<...>` precise capturing syntax not allowed in supertrait bounds
--> $DIR/illegal-positions.rs:8:12
|
LL | trait Foo: use<> {
| ^^^^^
error: `use<...>` precise capturing syntax not allowed in bounds
--> $DIR/illegal-positions.rs:10:33
|
LL | type Assoc: use<> where (): use<>;
| ^^^^^
error: `use<...>` precise capturing syntax not allowed in bounds
--> $DIR/illegal-positions.rs:10:17
|
LL | type Assoc: use<> where (): use<>;
| ^^^^^
error: `use<...>` precise capturing syntax not allowed in bounds
--> $DIR/illegal-positions.rs:16:11
|
LL | fn fun<T: use<>>(_: impl use<>) where (): use<> {}
| ^^^^^
error: `use<...>` precise capturing syntax not allowed in bounds
--> $DIR/illegal-positions.rs:16:43
|
LL | fn fun<T: use<>>(_: impl use<>) where (): use<> {}
| ^^^^^
error: at least one trait must be specified
--> $DIR/illegal-positions.rs:16:21
|
LL | fn fun<T: use<>>(_: impl use<>) where (): use<> {}
| ^^^^^^^^^^
error: `use<...>` precise capturing syntax not allowed in `dyn` trait object bounds
--> $DIR/illegal-positions.rs:23:25
|
LL | fn dynamic() -> Box<dyn use<>> {}
| ^^^^^
error: `use<...>` precise capturing syntax not allowed in argument-position `impl Trait`
--> $DIR/illegal-positions.rs:16:26
|
LL | fn fun<T: use<>>(_: impl use<>) where (): use<> {}
| ^^^^^
error[E0224]: at least one trait is required for an object type
--> $DIR/illegal-positions.rs:23:21
|
LL | fn dynamic() -> Box<dyn use<>> {}
| ^^^^^^^^^
error: aborting due to 9 previous errors
For more information about this error, try `rustc --explain E0224`.

View File

@ -0,0 +1,27 @@
//@ revisions: real pre_expansion
//@[pre_expansion] check-pass
//@ edition: 2021
#![feature(precise_capturing)]
#[cfg(real)]
trait Foo: use<> {
//[real]~^ ERROR `use<...>` precise capturing syntax not allowed
type Assoc: use<> where (): use<>;
//[real]~^ ERROR `use<...>` precise capturing syntax not allowed
//[real]~| ERROR `use<...>` precise capturing syntax not allowed
}
#[cfg(real)]
fn fun<T: use<>>(_: impl use<>) where (): use<> {}
//[real]~^ ERROR `use<...>` precise capturing syntax not allowed
//[real]~| ERROR `use<...>` precise capturing syntax not allowed
//[real]~| ERROR `use<...>` precise capturing syntax not allowed
//[real]~| ERROR at least one trait must be specified
#[cfg(real)]
fn dynamic() -> Box<dyn use<>> {}
//[real]~^ ERROR `use<...>` precise capturing syntax not allowed in `dyn` trait object bounds
//[real]~| ERROR at least one trait is required for an object type [E0224]
fn main() {}

View File

@ -1,16 +1,15 @@
#![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

@ -1,37 +1,28 @@
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/ordering.rs:1:12
|
LL | #![feature(precise_capturing)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= note: `#[warn(incomplete_features)]` on by default
error: cannot capture parameter `'a` twice
--> $DIR/ordering.rs:4:25
--> $DIR/ordering.rs:3: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:6: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:9: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:12: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
error: aborting due to 4 previous errors

View File

@ -3,9 +3,8 @@
// Show that precise captures allow us to skip a lifetime param for outlives
#![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

@ -1,11 +0,0 @@
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/outlives.rs:5:41
|
LL | #![feature(lifetime_capture_rules_2024, precise_capturing)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted

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

@ -2,23 +2,22 @@
//@ check-pass
#![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

@ -1,45 +1,36 @@
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/redundant.rs:4:12
|
LL | #![feature(precise_capturing)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
--> $DIR/redundant.rs:7:19
--> $DIR/redundant.rs:6: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
--> $DIR/redundant.rs:11: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
--> $DIR/redundant.rs:16: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
--> $DIR/redundant.rs:20: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
warning: 4 warnings emitted

View File

@ -1,10 +1,9 @@
//@ check-pass
#![feature(precise_capturing)]
//~^ 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

@ -1,11 +0,0 @@
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/self-capture.rs:3:12
|
LL | #![feature(precise_capturing)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted

View File

@ -2,8 +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 `{`
//~| ERROR expected item, found `>`
fn main() {}

View File

@ -1,16 +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: expected item, found `>`
--> $DIR/unexpected-token.rs:5:29
|
LL | fn hello() -> impl use<'a {}> Sized {}
| ^ expected item
|
= note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
error: aborting due to 2 previous errors
error: aborting due to 1 previous error

View File

@ -1,6 +1,6 @@
fn a() {
[0; [|_: _ &_| ()].len()]
//~^ ERROR expected `,`, found `&`
//~^ ERROR expected one of `,` or `|`, found `&`
//~| ERROR type annotations needed
}
@ -11,7 +11,7 @@ fn b() {
fn c() {
[0; [|&_: _ &_| {}; 0 ].len()]
//~^ ERROR expected `,`, found `&`
//~^ ERROR expected one of `,` or `|`, found `&`
//~| ERROR type annotations needed
}

View File

@ -1,8 +1,8 @@
error: expected `,`, found `&`
error: expected one of `,` or `|`, found `&`
--> $DIR/issue-66706.rs:2:16
|
LL | [0; [|_: _ &_| ()].len()]
| -^ expected `,`
| -^ expected one of `,` or `|`
| |
| help: missing `,`
@ -12,11 +12,11 @@ error: expected identifier, found reserved identifier `_`
LL | [0; [|f @ &ref _| {} ; 0 ].len() ];
| ^ expected identifier, found reserved identifier
error: expected `,`, found `&`
error: expected one of `,` or `|`, found `&`
--> $DIR/issue-66706.rs:13:17
|
LL | [0; [|&_: _ &_| {}; 0 ].len()]
| -^ expected `,`
| -^ expected one of `,` or `|`
| |
| help: missing `,`

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 `,`