mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Auto merge of #123468 - compiler-errors:precise-capturing, r=oli-obk
Implement syntax for `impl Trait` to specify its captures explicitly (`feature(precise_capturing)`) Implements `impl use<'a, 'b, T, U> Sized` syntax that allows users to explicitly list the captured parameters for an opaque, rather than inferring it from the opaque's bounds (or capturing *all* lifetimes under 2024-edition capture rules). This allows us to exclude some implicit captures, so this syntax may be used as a migration strategy for changes due to #117587. We represent this list of captured params as `PreciseCapturingArg` in AST and HIR, resolving them between `rustc_resolve` and `resolve_bound_vars`. Later on, we validate that the opaques only capture the parameters in this list. We artificially limit the feature to *require* mentioning all type and const parameters, since we don't currently have support for non-lifetime bivariant generics. This can be relaxed in the future. We also may need to limit this to require naming *all* lifetime parameters for RPITIT, since GATs have no variance. I have to investigate this. This can also be relaxed in the future. r? `@oli-obk` Tracking issue: - https://github.com/rust-lang/rust/issues/123432
This commit is contained in:
commit
4e1f5d90bc
@ -63,7 +63,7 @@ impl fmt::Debug for Label {
|
||||
|
||||
/// A "Lifetime" is an annotation of the scope in which variable
|
||||
/// can be used, e.g. `'a` in `&'a i32`.
|
||||
#[derive(Clone, Encodable, Decodable, Copy, PartialEq, Eq)]
|
||||
#[derive(Clone, Encodable, Decodable, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct Lifetime {
|
||||
pub id: NodeId,
|
||||
pub ident: Ident,
|
||||
@ -2132,7 +2132,7 @@ pub enum TyKind {
|
||||
/// The `NodeId` exists to prevent lowering from having to
|
||||
/// generate `NodeId`s on the fly, which would complicate
|
||||
/// the generation of opaque `type Foo = impl Trait` items significantly.
|
||||
ImplTrait(NodeId, GenericBounds),
|
||||
ImplTrait(NodeId, GenericBounds, Option<P<(ThinVec<PreciseCapturingArg>, Span)>>),
|
||||
/// No-op; kept solely so that we can pretty-print faithfully.
|
||||
Paren(P<Ty>),
|
||||
/// Unused for now.
|
||||
@ -2188,6 +2188,14 @@ pub enum TraitObjectSyntax {
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum PreciseCapturingArg {
|
||||
/// Lifetime parameter
|
||||
Lifetime(Lifetime),
|
||||
/// Type or const parameter
|
||||
Arg(Path, NodeId),
|
||||
}
|
||||
|
||||
/// Inline assembly operand explicit register or register class.
|
||||
///
|
||||
/// E.g., `"eax"` as in `asm!("mov eax, 2", out("eax") result)`.
|
||||
|
@ -259,6 +259,10 @@ pub trait MutVisitor: Sized {
|
||||
noop_visit_param_bound(tpb, self);
|
||||
}
|
||||
|
||||
fn visit_precise_capturing_arg(&mut self, arg: &mut PreciseCapturingArg) {
|
||||
noop_visit_precise_capturing_arg(arg, self);
|
||||
}
|
||||
|
||||
fn visit_mt(&mut self, mt: &mut MutTy) {
|
||||
noop_visit_mt(mt, self);
|
||||
}
|
||||
@ -518,9 +522,14 @@ 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) => {
|
||||
TyKind::ImplTrait(id, bounds, precise_capturing) => {
|
||||
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) => {
|
||||
@ -914,6 +923,18 @@ pub fn noop_visit_param_bound<T: MutVisitor>(pb: &mut GenericBound, vis: &mut T)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn noop_visit_precise_capturing_arg<T: MutVisitor>(arg: &mut PreciseCapturingArg, vis: &mut T) {
|
||||
match arg {
|
||||
PreciseCapturingArg::Lifetime(lt) => {
|
||||
vis.visit_lifetime(lt);
|
||||
}
|
||||
PreciseCapturingArg::Arg(path, id) => {
|
||||
vis.visit_path(path);
|
||||
vis.visit_id(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn noop_flat_map_generic_param<T: MutVisitor>(
|
||||
mut param: GenericParam,
|
||||
vis: &mut T,
|
||||
|
@ -184,6 +184,9 @@ pub trait Visitor<'ast>: Sized {
|
||||
fn visit_param_bound(&mut self, bounds: &'ast GenericBound, _ctxt: BoundKind) -> Self::Result {
|
||||
walk_param_bound(self, bounds)
|
||||
}
|
||||
fn visit_precise_capturing_arg(&mut self, arg: &'ast PreciseCapturingArg) {
|
||||
walk_precise_capturing_arg(self, arg);
|
||||
}
|
||||
fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) -> Self::Result {
|
||||
walk_poly_trait_ref(self, t)
|
||||
}
|
||||
@ -457,8 +460,13 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result {
|
||||
TyKind::TraitObject(bounds, ..) => {
|
||||
walk_list!(visitor, visit_param_bound, bounds, BoundKind::TraitObject);
|
||||
}
|
||||
TyKind::ImplTrait(_, bounds) => {
|
||||
TyKind::ImplTrait(_, bounds, precise_capturing) => {
|
||||
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Impl);
|
||||
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(_) => {}
|
||||
@ -637,6 +645,20 @@ pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericB
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_precise_capturing_arg<'a, V: Visitor<'a>>(
|
||||
visitor: &mut V,
|
||||
arg: &'a PreciseCapturingArg,
|
||||
) {
|
||||
match arg {
|
||||
PreciseCapturingArg::Lifetime(lt) => {
|
||||
visitor.visit_lifetime(lt, LifetimeCtxt::GenericArg);
|
||||
}
|
||||
PreciseCapturingArg::Arg(path, id) => {
|
||||
visitor.visit_path(path, *id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_generic_param<'a, V: Visitor<'a>>(
|
||||
visitor: &mut V,
|
||||
param: &'a GenericParam,
|
||||
|
@ -127,6 +127,8 @@ 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_previously_used_here = previously used here
|
||||
|
||||
ast_lowering_register1 = register `{$reg1_name}`
|
||||
|
@ -414,3 +414,10 @@ pub(crate) struct AsyncBoundOnlyForFnTraits {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_no_precise_captures_on_apit)]
|
||||
pub(crate) struct NoPreciseCapturesOnApit {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
@ -385,4 +385,21 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||
fn visit_pattern_type_pattern(&mut self, p: &'hir hir::Pat<'hir>) {
|
||||
self.visit_pat(p)
|
||||
}
|
||||
|
||||
fn visit_precise_capturing_arg(
|
||||
&mut self,
|
||||
arg: &'hir PreciseCapturingArg<'hir>,
|
||||
) -> Self::Result {
|
||||
match arg {
|
||||
PreciseCapturingArg::Lifetime(_) => {
|
||||
// This is represented as a `Node::Lifetime`, intravisit will get to it below.
|
||||
}
|
||||
PreciseCapturingArg::Param(param) => self.insert(
|
||||
param.ident.span,
|
||||
param.hir_id,
|
||||
Node::PreciseCapturingNonLifetimeArg(param),
|
||||
),
|
||||
}
|
||||
intravisit::walk_precise_capturing_arg(self, arg);
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ use rustc_ast::{self as ast, *};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
@ -1398,7 +1399,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
});
|
||||
hir::TyKind::TraitObject(bounds, lifetime_bound, *kind)
|
||||
}
|
||||
TyKind::ImplTrait(def_node_id, bounds) => {
|
||||
TyKind::ImplTrait(def_node_id, bounds, precise_capturing) => {
|
||||
let span = t.span;
|
||||
match itctx {
|
||||
ImplTraitContext::OpaqueTy { origin, fn_kind } => self.lower_opaque_impl_trait(
|
||||
@ -1408,8 +1409,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
bounds,
|
||||
fn_kind,
|
||||
itctx,
|
||||
precise_capturing.as_deref().map(|(args, _)| args.as_slice()),
|
||||
),
|
||||
ImplTraitContext::Universal => {
|
||||
if let Some(&(_, span)) = precise_capturing.as_deref() {
|
||||
self.tcx.dcx().emit_err(errors::NoPreciseCapturesOnApit { span });
|
||||
};
|
||||
let span = t.span;
|
||||
|
||||
// HACK: pprust breaks strings with newlines when the type
|
||||
@ -1520,6 +1525,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
bounds: &GenericBounds,
|
||||
fn_kind: Option<FnDeclKind>,
|
||||
itctx: ImplTraitContext,
|
||||
precise_capturing_args: Option<&[PreciseCapturingArg]>,
|
||||
) -> 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
|
||||
@ -1528,42 +1534,59 @@ 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 = 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 })
|
||||
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()
|
||||
}
|
||||
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)
|
||||
} 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()
|
||||
} 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`")
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::OpaqueTyOrigin::AsyncFn(..) => {
|
||||
unreachable!("should be using `lower_async_fn_ret_ty`")
|
||||
}
|
||||
};
|
||||
};
|
||||
debug!(?captured_lifetimes_to_duplicate);
|
||||
|
||||
self.lower_opaque_inner(
|
||||
@ -1573,6 +1596,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
captured_lifetimes_to_duplicate,
|
||||
span,
|
||||
opaque_ty_span,
|
||||
precise_capturing_args,
|
||||
|this| this.lower_param_bounds(bounds, itctx),
|
||||
)
|
||||
}
|
||||
@ -1582,9 +1606,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
opaque_ty_node_id: NodeId,
|
||||
origin: hir::OpaqueTyOrigin,
|
||||
in_trait: bool,
|
||||
captured_lifetimes_to_duplicate: Vec<Lifetime>,
|
||||
captured_lifetimes_to_duplicate: FxIndexSet<Lifetime>,
|
||||
span: Span,
|
||||
opaque_ty_span: Span,
|
||||
precise_capturing_args: Option<&[PreciseCapturingArg]>,
|
||||
lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>],
|
||||
) -> hir::TyKind<'hir> {
|
||||
let opaque_ty_def_id = self.create_def(
|
||||
@ -1671,8 +1696,15 @@ 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 = this
|
||||
.with_remapping(captured_to_synthesized_mapping, |this| lower_item_bounds(this));
|
||||
let (bounds, precise_capturing_args) =
|
||||
this.with_remapping(captured_to_synthesized_mapping, |this| {
|
||||
(
|
||||
lower_item_bounds(this),
|
||||
precise_capturing_args.map(|precise_capturing| {
|
||||
this.lower_precise_capturing_args(precise_capturing)
|
||||
}),
|
||||
)
|
||||
});
|
||||
|
||||
let generic_params =
|
||||
this.arena.alloc_from_iter(synthesized_lifetime_definitions.iter().map(
|
||||
@ -1717,6 +1749,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
origin,
|
||||
lifetime_mapping,
|
||||
in_trait,
|
||||
precise_capturing_args,
|
||||
};
|
||||
|
||||
// Generate an `type Foo = impl Trait;` declaration.
|
||||
@ -1749,6 +1782,30 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
)
|
||||
}
|
||||
|
||||
fn lower_precise_capturing_args(
|
||||
&mut self,
|
||||
precise_capturing_args: &[PreciseCapturingArg],
|
||||
) -> &'hir [hir::PreciseCapturingArg<'hir>] {
|
||||
self.arena.alloc_from_iter(precise_capturing_args.iter().map(|arg| match arg {
|
||||
PreciseCapturingArg::Lifetime(lt) => {
|
||||
hir::PreciseCapturingArg::Lifetime(self.lower_lifetime(lt))
|
||||
}
|
||||
PreciseCapturingArg::Arg(path, id) => {
|
||||
let [segment] = path.segments.as_slice() else {
|
||||
panic!();
|
||||
};
|
||||
let res = self.resolver.get_partial_res(*id).map_or(Res::Err, |partial_res| {
|
||||
partial_res.full_res().expect("no partial res expected for precise capture arg")
|
||||
});
|
||||
hir::PreciseCapturingArg::Param(hir::PreciseCapturingNonLifetimeArg {
|
||||
hir_id: self.lower_node_id(*id),
|
||||
ident: self.lower_ident(segment.ident),
|
||||
res: self.lower_res(res),
|
||||
})
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
|
||||
self.arena.alloc_from_iter(decl.inputs.iter().map(|param| match param.pat.kind {
|
||||
PatKind::Ident(_, ident, _) => self.lower_ident(ident),
|
||||
@ -1889,7 +1946,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let opaque_ty_span =
|
||||
self.mark_span_with_reason(DesugaringKind::Async, span, allowed_features);
|
||||
|
||||
let captured_lifetimes: Vec<_> = self
|
||||
let captured_lifetimes = self
|
||||
.resolver
|
||||
.take_extra_lifetime_params(opaque_ty_node_id)
|
||||
.into_iter()
|
||||
@ -1903,6 +1960,7 @@ 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,
|
||||
|
@ -1,6 +1,7 @@
|
||||
use super::ResolverAstLoweringExt;
|
||||
use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor};
|
||||
use rustc_ast::{GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind};
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_hir::def::{DefKind, LifetimeRes, Res};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::ResolverAstLowering;
|
||||
@ -10,27 +11,23 @@ use rustc_span::Span;
|
||||
struct LifetimeCollectVisitor<'ast> {
|
||||
resolver: &'ast ResolverAstLowering,
|
||||
current_binders: Vec<NodeId>,
|
||||
collected_lifetimes: Vec<Lifetime>,
|
||||
collected_lifetimes: FxIndexSet<Lifetime>,
|
||||
}
|
||||
|
||||
impl<'ast> LifetimeCollectVisitor<'ast> {
|
||||
fn new(resolver: &'ast ResolverAstLowering) -> Self {
|
||||
Self { resolver, current_binders: Vec::new(), collected_lifetimes: Vec::new() }
|
||||
Self { resolver, current_binders: Vec::new(), collected_lifetimes: FxIndexSet::default() }
|
||||
}
|
||||
|
||||
fn record_lifetime_use(&mut self, lifetime: Lifetime) {
|
||||
match self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error) {
|
||||
LifetimeRes::Param { binder, .. } | LifetimeRes::Fresh { binder, .. } => {
|
||||
if !self.current_binders.contains(&binder) {
|
||||
if !self.collected_lifetimes.contains(&lifetime) {
|
||||
self.collected_lifetimes.push(lifetime);
|
||||
}
|
||||
self.collected_lifetimes.insert(lifetime);
|
||||
}
|
||||
}
|
||||
LifetimeRes::Static | LifetimeRes::Error => {
|
||||
if !self.collected_lifetimes.contains(&lifetime) {
|
||||
self.collected_lifetimes.push(lifetime);
|
||||
}
|
||||
self.collected_lifetimes.insert(lifetime);
|
||||
}
|
||||
LifetimeRes::Infer => {}
|
||||
res => {
|
||||
@ -111,7 +108,7 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
|
||||
pub(crate) fn lifetimes_in_bounds(
|
||||
resolver: &ResolverAstLowering,
|
||||
bounds: &GenericBounds,
|
||||
) -> Vec<Lifetime> {
|
||||
) -> FxIndexSet<Lifetime> {
|
||||
let mut visitor = LifetimeCollectVisitor::new(resolver);
|
||||
for bound in bounds {
|
||||
visitor.visit_param_bound(bound, BoundKind::Bound);
|
||||
|
@ -737,7 +737,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 });
|
||||
}
|
||||
|
@ -569,6 +569,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||
gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
|
||||
gate_all!(postfix_match, "postfix match is experimental");
|
||||
gate_all!(mut_ref, "mutable by-reference bindings are experimental");
|
||||
gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental");
|
||||
|
||||
if !visitor.features.never_patterns {
|
||||
if let Some(spans) = spans.get(&sym::never_patterns) {
|
||||
|
@ -1150,8 +1150,17 @@ impl<'a> State<'a> {
|
||||
}
|
||||
self.print_type_bounds(bounds);
|
||||
}
|
||||
ast::TyKind::ImplTrait(_, bounds) => {
|
||||
ast::TyKind::ImplTrait(_, bounds, precise_capturing_args) => {
|
||||
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) => {
|
||||
|
@ -567,6 +567,8 @@ declare_features! (
|
||||
(unstable, optimize_attribute, "1.34.0", Some(54882)),
|
||||
/// Allows postfix match `expr.match { ... }`
|
||||
(unstable, postfix_match, "CURRENT_RUSTC_VERSION", Some(121618)),
|
||||
/// Allows `use<'a, 'b, A, B>` in `impl use<...> Trait` for precise capture of generic args.
|
||||
(incomplete, precise_capturing, "CURRENT_RUSTC_VERSION", Some(123432)),
|
||||
/// Allows 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.
|
||||
|
@ -2557,6 +2557,27 @@ 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>]>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub enum PreciseCapturingArg<'hir> {
|
||||
Lifetime(&'hir Lifetime),
|
||||
/// Non-lifetime argument (type or const)
|
||||
Param(PreciseCapturingNonLifetimeArg),
|
||||
}
|
||||
|
||||
/// We need to have a [`Node`] for the [`HirId`] that we attach the type/const param
|
||||
/// resolution to. Lifetimes don't have this problem, and for them, it's actually
|
||||
/// kind of detrimental to use a custom node type versus just using [`Lifetime`],
|
||||
/// since resolve_bound_vars operates on `Lifetime`s.
|
||||
// FIXME(precise_capturing): Investigate storing this as a path instead?
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub struct PreciseCapturingNonLifetimeArg {
|
||||
pub hir_id: HirId,
|
||||
pub ident: Ident,
|
||||
pub res: Res,
|
||||
}
|
||||
|
||||
/// From whence the opaque type came.
|
||||
@ -3535,6 +3556,7 @@ pub enum Node<'hir> {
|
||||
WhereBoundPredicate(&'hir WhereBoundPredicate<'hir>),
|
||||
// FIXME: Merge into `Node::Infer`.
|
||||
ArrayLenInfer(&'hir InferArg),
|
||||
PreciseCapturingNonLifetimeArg(&'hir PreciseCapturingNonLifetimeArg),
|
||||
// Created by query feeding
|
||||
Synthetic,
|
||||
// Span by reference to minimize `Node`'s size
|
||||
@ -3571,6 +3593,7 @@ impl<'hir> Node<'hir> {
|
||||
Node::TypeBinding(b) => Some(b.ident),
|
||||
Node::PatField(f) => Some(f.ident),
|
||||
Node::ExprField(f) => Some(f.ident),
|
||||
Node::PreciseCapturingNonLifetimeArg(a) => Some(a.ident),
|
||||
Node::Param(..)
|
||||
| Node::AnonConst(..)
|
||||
| Node::ConstBlock(..)
|
||||
|
@ -413,6 +413,9 @@ pub trait Visitor<'v>: Sized {
|
||||
fn visit_param_bound(&mut self, bounds: &'v GenericBound<'v>) -> Self::Result {
|
||||
walk_param_bound(self, bounds)
|
||||
}
|
||||
fn visit_precise_capturing_arg(&mut self, arg: &'v PreciseCapturingArg<'v>) -> Self::Result {
|
||||
walk_precise_capturing_arg(self, arg)
|
||||
}
|
||||
fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef<'v>) -> Self::Result {
|
||||
walk_poly_trait_ref(self, t)
|
||||
}
|
||||
@ -526,10 +529,15 @@ 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, .. }) => {
|
||||
ItemKind::OpaqueTy(&OpaqueTy { generics, bounds, precise_capturing_args, .. }) => {
|
||||
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));
|
||||
@ -1137,6 +1145,16 @@ pub fn walk_param_bound<'v, V: Visitor<'v>>(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_precise_capturing_arg<'v, V: Visitor<'v>>(
|
||||
visitor: &mut V,
|
||||
arg: &'v PreciseCapturingArg<'v>,
|
||||
) -> V::Result {
|
||||
match *arg {
|
||||
PreciseCapturingArg::Lifetime(lt) => visitor.visit_lifetime(lt),
|
||||
PreciseCapturingArg::Param(param) => visitor.visit_id(param.hir_id),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>(
|
||||
visitor: &mut V,
|
||||
trait_ref: &'v PolyTraitRef<'v>,
|
||||
|
@ -37,6 +37,8 @@ hir_analysis_auto_deref_reached_recursion_limit = reached the recursion limit wh
|
||||
.label = deref recursion limit reached
|
||||
.help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)
|
||||
|
||||
hir_analysis_bad_precise_capture = expected {$kind} parameter in `use<...>` precise captures list, found {$found}
|
||||
|
||||
hir_analysis_cannot_capture_late_bound_const =
|
||||
cannot capture late-bound const parameter in {$what}
|
||||
.label = parameter defined here
|
||||
@ -111,6 +113,9 @@ hir_analysis_drop_impl_on_wrong_item =
|
||||
|
||||
hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported
|
||||
|
||||
hir_analysis_duplicate_precise_capture = cannot capture parameter `{$name}` twice
|
||||
.label = parameter captured again here
|
||||
|
||||
hir_analysis_empty_specialization = specialization impl does not specialize any associated items
|
||||
.note = impl is a specialization of this impl
|
||||
|
||||
@ -214,6 +219,13 @@ hir_analysis_late_bound_lifetime_in_apit = `impl Trait` can only mention lifetim
|
||||
hir_analysis_late_bound_type_in_apit = `impl Trait` can only mention type parameters from an fn or impl
|
||||
.label = type parameter declared here
|
||||
|
||||
hir_analysis_lifetime_must_be_first = lifetime parameter `{$name}` must be listed before non-lifetime parameters
|
||||
.label = move the lifetime before this parameter
|
||||
|
||||
hir_analysis_lifetime_not_captured = `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
|
||||
.label = lifetime captured due to being mentioned in the bounds of the `impl Trait`
|
||||
.param_label = this lifetime parameter is captured
|
||||
|
||||
hir_analysis_lifetimes_or_bounds_mismatch_on_trait =
|
||||
lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration
|
||||
.label = lifetimes do not match {$item_kind} in trait
|
||||
@ -339,6 +351,10 @@ hir_analysis_param_in_ty_of_assoc_const_binding =
|
||||
*[normal] the {$param_def_kind} `{$param_name}` is defined here
|
||||
}
|
||||
|
||||
hir_analysis_param_not_captured = `impl Trait` must mention all {$kind} parameters in scope
|
||||
.label = {$kind} parameter is implicitly captured by this `impl Trait`
|
||||
.note = currently, all {$kind} parameters are required to be mentioned in the precise captures list
|
||||
|
||||
hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation
|
||||
.help = add `#![feature(unboxed_closures)]` to the crate attributes to use it
|
||||
|
||||
@ -355,6 +371,9 @@ hir_analysis_pattern_type_wild_pat = "wildcard patterns are not permitted for pa
|
||||
hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
|
||||
.label = not allowed in type signatures
|
||||
|
||||
hir_analysis_precise_capture_self_alias = `Self` can't be captured in `use<...>` precise captures list, since it is an alias
|
||||
.label = `Self` is not a generic argument, but an alias to the type of the {$what}
|
||||
|
||||
hir_analysis_redundant_lifetime_args = unnecessary lifetime parameter `{$victim}`
|
||||
.note = you can use the `{$candidate}` lifetime directly, in place of `{$victim}`
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
use crate::check::intrinsicck::InlineAsmCtxt;
|
||||
use crate::errors::LinkageType;
|
||||
|
||||
use super::compare_impl_item::check_type_bounds;
|
||||
use super::compare_impl_item::{compare_impl_method, compare_impl_ty};
|
||||
use super::*;
|
||||
use rustc_attr as attr;
|
||||
use rustc_data_structures::unord::{UnordMap, UnordSet};
|
||||
use rustc_errors::{codes::*, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorKind, DefKind};
|
||||
@ -12,6 +12,7 @@ use rustc_hir::Node;
|
||||
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
|
||||
use rustc_infer::traits::{Obligation, TraitEngineExt as _};
|
||||
use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
|
||||
use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
|
||||
use rustc_middle::middle::stability::EvalResult;
|
||||
use rustc_middle::traits::ObligationCauseCode;
|
||||
use rustc_middle::ty::fold::BottomUpFolder;
|
||||
@ -474,6 +475,133 @@ fn sanity_check_found_hidden_type<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
/// Check that the opaque's precise captures list is valid (if present).
|
||||
/// We check this for regular `impl Trait`s and also RPITITs, even though the latter
|
||||
/// are technically GATs.
|
||||
///
|
||||
/// This function is responsible for:
|
||||
/// 1. Checking that all type/const params are mention in the captures list.
|
||||
/// 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, .. } =
|
||||
*tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty();
|
||||
let Some(precise_capturing_args) = precise_capturing_args else {
|
||||
// No precise capturing args; nothing to validate
|
||||
return;
|
||||
};
|
||||
|
||||
let mut expected_captures = UnordSet::default();
|
||||
let mut seen_params = UnordMap::default();
|
||||
let mut prev_non_lifetime_param = None;
|
||||
for arg in precise_capturing_args {
|
||||
let (hir_id, ident) = match *arg {
|
||||
hir::PreciseCapturingArg::Param(hir::PreciseCapturingNonLifetimeArg {
|
||||
hir_id,
|
||||
ident,
|
||||
..
|
||||
}) => {
|
||||
if prev_non_lifetime_param.is_none() {
|
||||
prev_non_lifetime_param = Some(ident);
|
||||
}
|
||||
(hir_id, ident)
|
||||
}
|
||||
hir::PreciseCapturingArg::Lifetime(&hir::Lifetime { hir_id, ident, .. }) => {
|
||||
if let Some(prev_non_lifetime_param) = prev_non_lifetime_param {
|
||||
tcx.dcx().emit_err(errors::LifetimesMustBeFirst {
|
||||
lifetime_span: ident.span,
|
||||
name: ident.name,
|
||||
other_span: prev_non_lifetime_param.span,
|
||||
});
|
||||
}
|
||||
(hir_id, ident)
|
||||
}
|
||||
};
|
||||
|
||||
let ident = ident.normalize_to_macros_2_0();
|
||||
if let Some(span) = seen_params.insert(ident, ident.span) {
|
||||
tcx.dcx().emit_err(errors::DuplicatePreciseCapture {
|
||||
name: ident.name,
|
||||
first_span: span,
|
||||
second_span: ident.span,
|
||||
});
|
||||
}
|
||||
|
||||
match tcx.named_bound_var(hir_id) {
|
||||
Some(ResolvedArg::EarlyBound(def_id)) => {
|
||||
expected_captures.insert(def_id);
|
||||
}
|
||||
_ => {
|
||||
tcx.dcx().span_delayed_bug(
|
||||
tcx.hir().span(hir_id),
|
||||
"parameter should have been resolved",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let variances = tcx.variances_of(opaque_def_id);
|
||||
let mut def_id = Some(opaque_def_id.to_def_id());
|
||||
while let Some(generics) = def_id {
|
||||
let generics = tcx.generics_of(generics);
|
||||
def_id = generics.parent;
|
||||
|
||||
for param in &generics.params {
|
||||
if expected_captures.contains(¶m.def_id) {
|
||||
assert_eq!(
|
||||
variances[param.index as usize],
|
||||
ty::Invariant,
|
||||
"precise captured param should be invariant"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
match param.kind {
|
||||
ty::GenericParamDefKind::Lifetime => {
|
||||
// Check if the lifetime param was captured but isn't named in the precise captures list.
|
||||
if variances[param.index as usize] == ty::Invariant {
|
||||
let param_span =
|
||||
if let ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. })
|
||||
| ty::ReLateParam(ty::LateParamRegion {
|
||||
bound_region: ty::BoundRegionKind::BrNamed(def_id, _),
|
||||
..
|
||||
}) = *tcx
|
||||
.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local())
|
||||
{
|
||||
Some(tcx.def_span(def_id))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
// FIXME(precise_capturing): Structured suggestion for this would be useful
|
||||
tcx.dcx().emit_err(errors::LifetimeNotCaptured {
|
||||
use_span: tcx.def_span(param.def_id),
|
||||
param_span,
|
||||
opaque_span: tcx.def_span(opaque_def_id),
|
||||
});
|
||||
continue;
|
||||
}
|
||||
}
|
||||
ty::GenericParamDefKind::Type { .. } => {
|
||||
// FIXME(precise_capturing): Structured suggestion for this would be useful
|
||||
tcx.dcx().emit_err(errors::ParamNotCaptured {
|
||||
param_span: tcx.def_span(param.def_id),
|
||||
opaque_span: tcx.def_span(opaque_def_id),
|
||||
kind: "type",
|
||||
});
|
||||
}
|
||||
ty::GenericParamDefKind::Const { .. } => {
|
||||
// FIXME(precise_capturing): Structured suggestion for this would be useful
|
||||
tcx.dcx().emit_err(errors::ParamNotCaptured {
|
||||
param_span: tcx.def_span(param.def_id),
|
||||
opaque_span: tcx.def_span(opaque_def_id),
|
||||
kind: "const",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_enum_of_nonnullable_ptr<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
adt_def: AdtDef<'tcx>,
|
||||
@ -499,7 +627,7 @@ fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
ty::Adt(adt_def, args) => !is_enum_of_nonnullable_ptr(tcx, *adt_def, *args),
|
||||
_ => true,
|
||||
} {
|
||||
tcx.dcx().emit_err(LinkageType { span: tcx.def_span(def_id) });
|
||||
tcx.dcx().emit_err(errors::LinkageType { span: tcx.def_span(def_id) });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -566,6 +694,8 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
check_union(tcx, def_id);
|
||||
}
|
||||
DefKind::OpaqueTy => {
|
||||
check_opaque_precise_captures(tcx, def_id);
|
||||
|
||||
let origin = tcx.opaque_type_origin(def_id);
|
||||
if let hir::OpaqueTyOrigin::FnReturn(fn_def_id)
|
||||
| hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin
|
||||
|
@ -557,6 +557,50 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_precise_capturing_arg(
|
||||
&mut self,
|
||||
arg: &'tcx hir::PreciseCapturingArg<'tcx>,
|
||||
) -> Self::Result {
|
||||
match *arg {
|
||||
hir::PreciseCapturingArg::Lifetime(lt) => match lt.res {
|
||||
LifetimeName::Param(def_id) => {
|
||||
self.resolve_lifetime_ref(def_id, lt);
|
||||
}
|
||||
LifetimeName::Error => {}
|
||||
LifetimeName::ImplicitObjectLifetimeDefault
|
||||
| LifetimeName::Infer
|
||||
| LifetimeName::Static => {
|
||||
self.tcx.dcx().emit_err(errors::BadPreciseCapture {
|
||||
span: lt.ident.span,
|
||||
kind: "lifetime",
|
||||
found: format!("`{}`", lt.ident.name),
|
||||
});
|
||||
}
|
||||
},
|
||||
hir::PreciseCapturingArg::Param(param) => match param.res {
|
||||
Res::Def(DefKind::TyParam | DefKind::ConstParam, def_id)
|
||||
| Res::SelfTyParam { trait_: def_id } => {
|
||||
self.resolve_type_ref(def_id.expect_local(), param.hir_id);
|
||||
}
|
||||
Res::Err => {}
|
||||
Res::SelfTyAlias { alias_to, .. } => {
|
||||
self.tcx.dcx().emit_err(errors::PreciseCaptureSelfAlias {
|
||||
span: param.ident.span,
|
||||
self_span: self.tcx.def_span(alias_to),
|
||||
what: self.tcx.def_descr(alias_to),
|
||||
});
|
||||
}
|
||||
res => {
|
||||
self.tcx.dcx().emit_err(errors::BadPreciseCapture {
|
||||
span: param.ident.span,
|
||||
kind: "type or const",
|
||||
found: res.descr().to_string(),
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
|
||||
match item.kind {
|
||||
hir::ForeignItemKind::Fn(_, _, generics) => {
|
||||
|
@ -10,6 +10,9 @@ use rustc_span::{symbol::Ident, Span, Symbol};
|
||||
mod pattern_types;
|
||||
pub use pattern_types::*;
|
||||
|
||||
mod precise_captures;
|
||||
pub(crate) use precise_captures::*;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_ambiguous_assoc_item)]
|
||||
pub struct AmbiguousAssocItem<'a> {
|
||||
|
63
compiler/rustc_hir_analysis/src/errors/precise_captures.rs
Normal file
63
compiler/rustc_hir_analysis/src/errors/precise_captures.rs
Normal file
@ -0,0 +1,63 @@
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_param_not_captured)]
|
||||
#[note]
|
||||
pub struct ParamNotCaptured {
|
||||
#[primary_span]
|
||||
pub param_span: Span,
|
||||
#[label]
|
||||
pub opaque_span: Span,
|
||||
pub kind: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_lifetime_not_captured)]
|
||||
pub struct LifetimeNotCaptured {
|
||||
#[primary_span]
|
||||
pub use_span: Span,
|
||||
#[label(hir_analysis_param_label)]
|
||||
pub param_span: Option<Span>,
|
||||
#[label]
|
||||
pub opaque_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_bad_precise_capture)]
|
||||
pub struct BadPreciseCapture {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub kind: &'static str,
|
||||
pub found: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_precise_capture_self_alias)]
|
||||
pub struct PreciseCaptureSelfAlias {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label]
|
||||
pub self_span: Span,
|
||||
pub what: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_duplicate_precise_capture)]
|
||||
pub struct DuplicatePreciseCapture {
|
||||
#[primary_span]
|
||||
pub first_span: Span,
|
||||
pub name: Symbol,
|
||||
#[label]
|
||||
pub second_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_lifetime_must_be_first)]
|
||||
pub struct LifetimesMustBeFirst {
|
||||
#[primary_span]
|
||||
pub lifetime_span: Span,
|
||||
pub name: Symbol,
|
||||
#[label]
|
||||
pub other_span: Span,
|
||||
}
|
@ -95,6 +95,7 @@ impl<'a> State<'a> {
|
||||
Node::PatField(a) => self.print_patfield(a),
|
||||
Node::Arm(a) => self.print_arm(a),
|
||||
Node::Infer(_) => self.word("_"),
|
||||
Node::PreciseCapturingNonLifetimeArg(param) => self.print_ident(param.ident),
|
||||
Node::Block(a) => {
|
||||
// Containing cbox, will be closed by print-block at `}`.
|
||||
self.cbox(INDENT_UNIT);
|
||||
|
@ -283,6 +283,7 @@ pub fn suggest_new_region_bound(
|
||||
continue;
|
||||
}
|
||||
match fn_return.kind {
|
||||
// FIXME(precise_captures): Suggest adding to `use<...>` list instead.
|
||||
TyKind::OpaqueDef(item_id, _, _) => {
|
||||
let item = tcx.hir().item(item_id);
|
||||
let ItemKind::OpaqueTy(opaque) = &item.kind else {
|
||||
|
@ -1235,7 +1235,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
|
||||
|
@ -910,6 +910,7 @@ impl<'hir> Map<'hir> {
|
||||
Node::Crate(item) => item.spans.inner_span,
|
||||
Node::WhereBoundPredicate(pred) => pred.span,
|
||||
Node::ArrayLenInfer(inf) => inf.span,
|
||||
Node::PreciseCapturingNonLifetimeArg(param) => param.ident.span,
|
||||
Node::Synthetic => unreachable!(),
|
||||
Node::Err(span) => *span,
|
||||
}
|
||||
@ -1183,6 +1184,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
|
||||
Node::ArrayLenInfer(_) => node_str("array len infer"),
|
||||
Node::Synthetic => unreachable!(),
|
||||
Node::Err(_) => node_str("error"),
|
||||
Node::PreciseCapturingNonLifetimeArg(_param) => node_str("parameter"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ impl<'a> Parser<'a> {
|
||||
let snapshot = self.create_snapshot_for_diagnostic();
|
||||
match self.parse_ty() {
|
||||
Ok(p) => {
|
||||
if let TyKind::ImplTrait(_, bounds) = &p.kind {
|
||||
if let TyKind::ImplTrait(_, bounds, None) = &p.kind {
|
||||
let span = impl_span.to(self.token.span.shrink_to_lo());
|
||||
let mut err = self.dcx().struct_span_err(
|
||||
span,
|
||||
|
@ -625,7 +625,7 @@ impl<'a> Parser<'a> {
|
||||
// This notably includes paths passed through `ty` macro fragments (#46438).
|
||||
TyKind::Path(None, path) => path,
|
||||
other => {
|
||||
if let TyKind::ImplTrait(_, bounds) = other
|
||||
if let TyKind::ImplTrait(_, bounds, None) = other
|
||||
&& let [bound] = bounds.as_slice()
|
||||
{
|
||||
// Suggest removing extra `impl` keyword:
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::{Parser, PathStyle, TokenType, Trailing};
|
||||
use super::{Parser, PathStyle, SeqSep, TokenType, Trailing};
|
||||
|
||||
use crate::errors::{
|
||||
self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType,
|
||||
@ -14,7 +14,7 @@ use rustc_ast::util::case::Case;
|
||||
use rustc_ast::{
|
||||
self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, FnRetTy, GenericBound,
|
||||
GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, PolyTraitRef,
|
||||
TraitBoundModifiers, TraitObjectSyntax, Ty, TyKind, DUMMY_NODE_ID,
|
||||
PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty, TyKind, DUMMY_NODE_ID,
|
||||
};
|
||||
use rustc_errors::{Applicability, PResult};
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
@ -316,7 +316,7 @@ impl<'a> Parser<'a> {
|
||||
TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn)
|
||||
}
|
||||
(TyKind::TraitObject(bounds, _), kw::Impl) => {
|
||||
TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds)
|
||||
TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds, None)
|
||||
}
|
||||
_ => return Err(err),
|
||||
};
|
||||
@ -655,7 +655,6 @@ impl<'a> Parser<'a> {
|
||||
|
||||
/// Parses an `impl B0 + ... + Bn` type.
|
||||
fn parse_impl_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> {
|
||||
// Always parse bounds greedily for better error recovery.
|
||||
if self.token.is_lifetime() {
|
||||
self.look_ahead(1, |t| {
|
||||
if let token::Ident(sym, _) = t.kind {
|
||||
@ -669,9 +668,53 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// parse precise captures, if any. This is `use<'lt, 'lt, P, P>`; a list of
|
||||
// lifetimes and ident params (including SelfUpper). These are validated later
|
||||
// for order, duplication, and whether they actually reference params.
|
||||
let precise_capturing = if self.eat_keyword(kw::Use) {
|
||||
let use_span = self.prev_token.span;
|
||||
self.psess.gated_spans.gate(sym::precise_capturing, use_span);
|
||||
let args = self.parse_precise_capturing_args()?;
|
||||
Some(P((args, use_span)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Always parse bounds greedily for better error recovery.
|
||||
let bounds = self.parse_generic_bounds()?;
|
||||
|
||||
*impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus);
|
||||
Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds))
|
||||
|
||||
Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds, precise_capturing))
|
||||
}
|
||||
|
||||
fn parse_precise_capturing_args(&mut self) -> PResult<'a, ThinVec<PreciseCapturingArg>> {
|
||||
Ok(self
|
||||
.parse_unspanned_seq(
|
||||
&TokenKind::Lt,
|
||||
&TokenKind::Gt,
|
||||
SeqSep::trailing_allowed(token::Comma),
|
||||
|self_| {
|
||||
if self_.check_keyword(kw::SelfUpper) {
|
||||
self_.bump();
|
||||
Ok(PreciseCapturingArg::Arg(
|
||||
ast::Path::from_ident(self_.prev_token.ident().unwrap().0),
|
||||
DUMMY_NODE_ID,
|
||||
))
|
||||
} else if self_.check_ident() {
|
||||
Ok(PreciseCapturingArg::Arg(
|
||||
ast::Path::from_ident(self_.parse_ident()?),
|
||||
DUMMY_NODE_ID,
|
||||
))
|
||||
} else if self_.check_lifetime() {
|
||||
Ok(PreciseCapturingArg::Lifetime(self_.expect_lifetime()))
|
||||
} else {
|
||||
self_.unexpected_any()
|
||||
}
|
||||
},
|
||||
)?
|
||||
.0)
|
||||
}
|
||||
|
||||
/// Is a `dyn B0 + ... + Bn` type allowed here?
|
||||
@ -957,7 +1000,7 @@ impl<'a> Parser<'a> {
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
}
|
||||
TyKind::ImplTrait(_, bounds)
|
||||
TyKind::ImplTrait(_, bounds, None)
|
||||
if let [GenericBound::Trait(tr, ..), ..] = bounds.as_slice() =>
|
||||
{
|
||||
(
|
||||
|
@ -793,7 +793,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
|
||||
self.r.record_partial_res(ty.id, PartialRes::new(res));
|
||||
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);
|
||||
@ -1047,10 +1047,39 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
|
||||
});
|
||||
self.diag_metadata.current_function = previous_value;
|
||||
}
|
||||
|
||||
fn visit_lifetime(&mut self, lifetime: &'ast Lifetime, use_ctxt: visit::LifetimeCtxt) {
|
||||
self.resolve_lifetime(lifetime, use_ctxt)
|
||||
}
|
||||
|
||||
fn visit_precise_capturing_arg(&mut self, arg: &'ast PreciseCapturingArg) {
|
||||
match arg {
|
||||
// Lower the lifetime regularly; we'll resolve the lifetime and check
|
||||
// it's a parameter later on in HIR lowering.
|
||||
PreciseCapturingArg::Lifetime(_) => {}
|
||||
|
||||
PreciseCapturingArg::Arg(path, id) => {
|
||||
// we want `impl use<C>` to try to resolve `C` as both a type parameter or
|
||||
// a const parameter. Since the resolver specifically doesn't allow having
|
||||
// two generic params with the same name, even if they're a different namespace,
|
||||
// it doesn't really matter which we try resolving first, but just like
|
||||
// `Ty::Param` we just fall back to the value namespace only if it's missing
|
||||
// from the type namespace.
|
||||
let mut check_ns = |ns| {
|
||||
self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns).is_some()
|
||||
};
|
||||
// Like `Ty::Param`, we try resolving this as both a const and a type.
|
||||
if !check_ns(TypeNS) && check_ns(ValueNS) {
|
||||
self.smart_resolve_path(*id, &None, path, PathSource::Expr(None));
|
||||
} else {
|
||||
self.smart_resolve_path(*id, &None, path, PathSource::Type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
visit::walk_precise_capturing_arg(self, arg)
|
||||
}
|
||||
|
||||
fn visit_generics(&mut self, generics: &'ast Generics) {
|
||||
self.visit_generic_params(&generics.params, self.diag_metadata.current_self_item.is_some());
|
||||
for p in &generics.where_clause.predicates {
|
||||
|
@ -3121,7 +3121,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||
.inputs
|
||||
.iter()
|
||||
.filter_map(|param| match ¶m.ty.kind {
|
||||
TyKind::ImplTrait(_, bounds) => Some(bounds),
|
||||
TyKind::ImplTrait(_, bounds, _) => Some(bounds),
|
||||
_ => None,
|
||||
})
|
||||
.flat_map(|bounds| bounds.into_iter())
|
||||
|
@ -1375,6 +1375,7 @@ symbols! {
|
||||
powif32,
|
||||
powif64,
|
||||
pre_dash_lto: "pre-lto",
|
||||
precise_capturing,
|
||||
precise_pointer_size_matching,
|
||||
pref_align_of,
|
||||
prefetch_read_data,
|
||||
|
@ -709,7 +709,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), ImplTrait(_, rg)) => over(lg, rg, eq_generic_bound),
|
||||
(ImplTrait(_, lg, lc), ImplTrait(_, rg, rc)) =>
|
||||
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),
|
||||
_ => false,
|
||||
@ -770,6 +771,14 @@ pub fn eq_generic_bound(l: &GenericBound, r: &GenericBound) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eq_precise_capture(l: &PreciseCapturingArg, r: &PreciseCapturingArg) -> bool {
|
||||
match (l, r) {
|
||||
(PreciseCapturingArg::Lifetime(l), PreciseCapturingArg::Lifetime(r)) => l.ident == r.ident,
|
||||
(PreciseCapturingArg::Arg(l, _), PreciseCapturingArg::Arg(r, _)) => l.segments[0].ident == r.segments[0].ident,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn eq_term(l: &Term, r: &Term) -> bool {
|
||||
match (l, r) {
|
||||
(Term::Ty(l), Term::Ty(r)) => eq_ty(l, r),
|
||||
|
@ -843,7 +843,11 @@ impl Rewrite for ast::Ty {
|
||||
rewrite_macro(mac, None, context, shape, MacroPosition::Expression)
|
||||
}
|
||||
ast::TyKind::ImplicitSelf => Some(String::from("")),
|
||||
ast::TyKind::ImplTrait(_, ref it) => {
|
||||
ast::TyKind::ImplTrait(_, ref it, ref captures) => {
|
||||
// FIXME(precise_capturing): Implement formatting.
|
||||
if captures.is_some() {
|
||||
return None;
|
||||
}
|
||||
// Empty trait is not a parser error.
|
||||
if it.is_empty() {
|
||||
return Some("impl".to_owned());
|
||||
@ -1106,7 +1110,8 @@ 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 {
|
||||
ast::TyKind::ImplTrait(_, bounds) => Some(bounds),
|
||||
// FIXME(precise_capturing): Implement support here
|
||||
ast::TyKind::ImplTrait(_, bounds, _) => Some(bounds),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
4
tests/ui/feature-gates/feature-gate-precise-capturing.rs
Normal file
4
tests/ui/feature-gates/feature-gate-precise-capturing.rs
Normal file
@ -0,0 +1,4 @@
|
||||
fn hello() -> impl use<> Sized {}
|
||||
//~^ ERROR precise captures on `impl Trait` are experimental
|
||||
|
||||
fn main() {}
|
13
tests/ui/feature-gates/feature-gate-precise-capturing.stderr
Normal file
13
tests/ui/feature-gates/feature-gate-precise-capturing.stderr
Normal file
@ -0,0 +1,13 @@
|
||||
error[E0658]: precise captures on `impl Trait` are experimental
|
||||
--> $DIR/feature-gate-precise-capturing.rs:1:20
|
||||
|
|
||||
LL | fn hello() -> impl use<> Sized {}
|
||||
| ^^^
|
||||
|
|
||||
= 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
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
7
tests/ui/impl-trait/precise-capturing/apit.rs
Normal file
7
tests/ui/impl-trait/precise-capturing/apit.rs
Normal file
@ -0,0 +1,7 @@
|
||||
#![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 main() {}
|
17
tests/ui/impl-trait/precise-capturing/apit.stderr
Normal file
17
tests/ui/impl-trait/precise-capturing/apit.stderr
Normal file
@ -0,0 +1,17 @@
|
||||
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/apit.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: `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
|
||||
|
14
tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs
Normal file
14
tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs
Normal file
@ -0,0 +1,14 @@
|
||||
#![feature(precise_capturing)]
|
||||
//~^ WARN the feature `precise_capturing` is incomplete
|
||||
|
||||
fn no_elided_lt() -> impl use<'_> Sized {}
|
||||
//~^ ERROR missing lifetime specifier
|
||||
//~| ERROR expected lifetime parameter in `use<...>` precise captures list, found `'_`
|
||||
|
||||
fn static_lt() -> impl use<'static> Sized {}
|
||||
//~^ ERROR expected lifetime parameter in `use<...>` precise captures list, found `'static`
|
||||
|
||||
fn missing_lt() -> impl use<'missing> Sized {}
|
||||
//~^ ERROR use of undeclared lifetime name `'missing`
|
||||
|
||||
fn main() {}
|
45
tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr
Normal file
45
tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr
Normal file
@ -0,0 +1,45 @@
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/bad-lifetimes.rs:4:31
|
||||
|
|
||||
LL | fn no_elided_lt() -> impl use<'_> Sized {}
|
||||
| ^^ 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 {}
|
||||
| ~~~~~~~
|
||||
|
||||
error[E0261]: use of undeclared lifetime name `'missing`
|
||||
--> $DIR/bad-lifetimes.rs:11:29
|
||||
|
|
||||
LL | fn missing_lt() -> impl use<'missing> Sized {}
|
||||
| - ^^^^^^^^ 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
|
||||
|
|
||||
LL | fn no_elided_lt() -> impl use<'_> Sized {}
|
||||
| ^^
|
||||
|
||||
error: expected lifetime parameter in `use<...>` precise captures list, found `'static`
|
||||
--> $DIR/bad-lifetimes.rs:8:28
|
||||
|
|
||||
LL | fn static_lt() -> impl use<'static> Sized {}
|
||||
| ^^^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors; 1 warning emitted
|
||||
|
||||
Some errors have detailed explanations: E0106, E0261.
|
||||
For more information about an error, try `rustc --explain E0106`.
|
19
tests/ui/impl-trait/precise-capturing/bad-params.rs
Normal file
19
tests/ui/impl-trait/precise-capturing/bad-params.rs
Normal file
@ -0,0 +1,19 @@
|
||||
#![feature(precise_capturing)]
|
||||
//~^ WARN the feature `precise_capturing` is incomplete
|
||||
|
||||
fn missing() -> impl use<T> Sized {}
|
||||
//~^ ERROR cannot find type `T` in this scope
|
||||
|
||||
fn missing_self() -> impl use<Self> Sized {}
|
||||
//~^ ERROR cannot find type `Self` in this scope
|
||||
|
||||
struct MyType;
|
||||
impl MyType {
|
||||
fn self_is_not_param() -> impl use<Self> Sized {}
|
||||
//~^ ERROR `Self` can't be captured in `use<...>` precise captures list, since it is an alias
|
||||
}
|
||||
|
||||
fn hello() -> impl use<hello> Sized {}
|
||||
//~^ ERROR expected type or const parameter in `use<...>` precise captures list, found function
|
||||
|
||||
fn main() {}
|
46
tests/ui/impl-trait/precise-capturing/bad-params.stderr
Normal file
46
tests/ui/impl-trait/precise-capturing/bad-params.stderr
Normal file
@ -0,0 +1,46 @@
|
||||
error[E0412]: cannot find type `T` in this scope
|
||||
--> $DIR/bad-params.rs:4:26
|
||||
|
|
||||
LL | fn missing() -> impl use<T> Sized {}
|
||||
| ^ not found in this scope
|
||||
|
|
||||
help: you might be missing a type parameter
|
||||
|
|
||||
LL | fn missing<T>() -> impl use<T> Sized {}
|
||||
| +++
|
||||
|
||||
error[E0411]: cannot find type `Self` in this scope
|
||||
--> $DIR/bad-params.rs:7:31
|
||||
|
|
||||
LL | fn missing_self() -> impl use<Self> Sized {}
|
||||
| ------------ ^^^^ `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
|
||||
|
|
||||
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 {}
|
||||
| ^^^^
|
||||
|
||||
error: expected type or const parameter in `use<...>` precise captures list, found function
|
||||
--> $DIR/bad-params.rs:16:24
|
||||
|
|
||||
LL | fn hello() -> impl use<hello> Sized {}
|
||||
| ^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors; 1 warning emitted
|
||||
|
||||
Some errors have detailed explanations: E0411, E0412.
|
||||
For more information about an error, try `rustc --explain E0411`.
|
8
tests/ui/impl-trait/precise-capturing/elided.rs
Normal file
8
tests/ui/impl-trait/precise-capturing/elided.rs
Normal file
@ -0,0 +1,8 @@
|
||||
//@ check-pass
|
||||
|
||||
#![feature(precise_capturing)]
|
||||
//~^ WARN the feature `precise_capturing` is incomplete
|
||||
|
||||
fn elided(x: &()) -> impl use<'_> Sized { x }
|
||||
|
||||
fn main() {}
|
11
tests/ui/impl-trait/precise-capturing/elided.stderr
Normal file
11
tests/ui/impl-trait/precise-capturing/elided.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
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
|
||||
|
@ -0,0 +1,7 @@
|
||||
#![feature(precise_capturing)]
|
||||
//~^ WARN the feature `precise_capturing` is incomplete
|
||||
|
||||
fn constant<const C: usize>() -> impl use<> Sized {}
|
||||
//~^ ERROR `impl Trait` must mention all const parameters in scope
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,19 @@
|
||||
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
|
||||
--> $DIR/forgot-to-capture-const.rs:4:13
|
||||
|
|
||||
LL | fn constant<const C: usize>() -> impl use<> Sized {}
|
||||
| ^^^^^^^^^^^^^^ ---------------- 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
|
||||
|
@ -0,0 +1,10 @@
|
||||
#![feature(precise_capturing)]
|
||||
//~^ WARN the feature `precise_capturing` is incomplete
|
||||
|
||||
fn lifetime_in_bounds<'a>(x: &'a ()) -> impl use<> Into<&'a ()> { 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 }
|
||||
//~^ ERROR hidden type for `impl Sized` captures lifetime that does not appear in bounds
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,35 @@
|
||||
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
|
||||
|
|
||||
LL | fn lifetime_in_bounds<'a>(x: &'a ()) -> impl use<> Into<&'a ()> { 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
|
||||
|
|
||||
LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl use<> Sized { 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 }
|
||||
| ++++
|
||||
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0700`.
|
@ -0,0 +1,12 @@
|
||||
#![feature(precise_capturing)]
|
||||
//~^ WARN the feature `precise_capturing` is incomplete
|
||||
|
||||
fn type_param<T>() -> impl use<> Sized {}
|
||||
//~^ ERROR `impl Trait` must mention all type parameters in scope
|
||||
|
||||
trait Foo {
|
||||
//~^ ERROR `impl Trait` must mention all type parameters in scope
|
||||
fn bar() -> impl use<> Sized;
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,30 @@
|
||||
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
|
||||
--> $DIR/forgot-to-capture-type.rs:4:15
|
||||
|
|
||||
LL | fn type_param<T>() -> impl use<> Sized {}
|
||||
| ^ ---------------- 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 all type parameters in scope
|
||||
--> $DIR/forgot-to-capture-type.rs:7:1
|
||||
|
|
||||
LL | trait Foo {
|
||||
| ^^^^^^^^^
|
||||
LL |
|
||||
LL | fn bar() -> impl use<> Sized;
|
||||
| ---------------- 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: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
18
tests/ui/impl-trait/precise-capturing/higher-ranked.rs
Normal file
18
tests/ui/impl-trait/precise-capturing/higher-ranked.rs
Normal file
@ -0,0 +1,18 @@
|
||||
//@ check-pass
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
impl Trait<'_> for () {
|
||||
type Item = Vec<()>;
|
||||
}
|
||||
|
||||
fn hello() -> impl for<'a> Trait<'a, Item = impl use<> IntoIterator> {}
|
||||
|
||||
fn main() {}
|
11
tests/ui/impl-trait/precise-capturing/higher-ranked.stderr
Normal file
11
tests/ui/impl-trait/precise-capturing/higher-ranked.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
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
|
||||
|
16
tests/ui/impl-trait/precise-capturing/ordering.rs
Normal file
16
tests/ui/impl-trait/precise-capturing/ordering.rs
Normal file
@ -0,0 +1,16 @@
|
||||
#![feature(precise_capturing)]
|
||||
//~^ WARN the feature `precise_capturing` is incomplete
|
||||
|
||||
fn lt<'a>() -> impl use<'a, 'a> Sized {}
|
||||
//~^ ERROR cannot capture parameter `'a` twice
|
||||
|
||||
fn ty<T>() -> impl use<T, T> Sized {}
|
||||
//~^ ERROR cannot capture parameter `T` twice
|
||||
|
||||
fn ct<const N: usize>() -> impl use<N, N> Sized {}
|
||||
//~^ ERROR cannot capture parameter `N` twice
|
||||
|
||||
fn ordering<'a, T>() -> impl use<T, 'a> Sized {}
|
||||
//~^ ERROR lifetime parameter `'a` must be listed before non-lifetime parameters
|
||||
|
||||
fn main() {}
|
37
tests/ui/impl-trait/precise-capturing/ordering.stderr
Normal file
37
tests/ui/impl-trait/precise-capturing/ordering.stderr
Normal file
@ -0,0 +1,37 @@
|
||||
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
|
||||
|
|
||||
LL | fn lt<'a>() -> impl use<'a, 'a> Sized {}
|
||||
| ^^ -- parameter captured again here
|
||||
|
||||
error: cannot capture parameter `T` twice
|
||||
--> $DIR/ordering.rs:7:24
|
||||
|
|
||||
LL | fn ty<T>() -> impl use<T, T> Sized {}
|
||||
| ^ - parameter captured again here
|
||||
|
||||
error: cannot capture parameter `N` twice
|
||||
--> $DIR/ordering.rs:10:37
|
||||
|
|
||||
LL | fn ct<const N: usize>() -> impl use<N, N> Sized {}
|
||||
| ^ - parameter captured again here
|
||||
|
||||
error: lifetime parameter `'a` must be listed before non-lifetime parameters
|
||||
--> $DIR/ordering.rs:13:37
|
||||
|
|
||||
LL | fn ordering<'a, T>() -> impl use<T, 'a> Sized {}
|
||||
| - ^^
|
||||
| |
|
||||
| move the lifetime before this parameter
|
||||
|
||||
error: aborting due to 4 previous errors; 1 warning emitted
|
||||
|
16
tests/ui/impl-trait/precise-capturing/outlives.rs
Normal file
16
tests/ui/impl-trait/precise-capturing/outlives.rs
Normal file
@ -0,0 +1,16 @@
|
||||
//@ check-pass
|
||||
|
||||
// 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 outlives<'a, T: 'a>(_: T) {}
|
||||
|
||||
fn test<'a, 'b>() {
|
||||
outlives::<'a, _>(hello::<'a, 'b>());
|
||||
}
|
||||
|
||||
fn main() {}
|
11
tests/ui/impl-trait/precise-capturing/outlives.stderr
Normal file
11
tests/ui/impl-trait/precise-capturing/outlives.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
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
|
||||
|
10
tests/ui/impl-trait/precise-capturing/self-capture.rs
Normal file
10
tests/ui/impl-trait/precise-capturing/self-capture.rs
Normal file
@ -0,0 +1,10 @@
|
||||
//@ check-pass
|
||||
|
||||
#![feature(precise_capturing)]
|
||||
//~^ WARN the feature `precise_capturing` is incomplete
|
||||
|
||||
trait Foo {
|
||||
fn bar<'a>() -> impl use<Self> Sized;
|
||||
}
|
||||
|
||||
fn main() {}
|
11
tests/ui/impl-trait/precise-capturing/self-capture.stderr
Normal file
11
tests/ui/impl-trait/precise-capturing/self-capture.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user