Skip to content

Commit

Permalink
Allow use<> syntax in RPITIT, fix test example
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Jun 28, 2024
1 parent b56a74f commit 9b53b64
Show file tree
Hide file tree
Showing 19 changed files with 165 additions and 128 deletions.
3 changes: 0 additions & 3 deletions compiler/rustc_ast_lowering/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,6 @@ ast_lowering_never_pattern_with_guard =
ast_lowering_no_precise_captures_on_apit = `use<...>` precise capturing syntax not allowed in argument-position `impl Trait`
ast_lowering_no_precise_captures_on_rpitit = `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits
.note = currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope
ast_lowering_previously_used_here = previously used here
ast_lowering_register1 = register `{$reg1_name}`
Expand Down
8 changes: 0 additions & 8 deletions compiler/rustc_ast_lowering/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,14 +424,6 @@ pub(crate) struct NoPreciseCapturesOnApit {
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(ast_lowering_no_precise_captures_on_rpitit)]
#[note]
pub(crate) struct NoPreciseCapturesOnRpitit {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(ast_lowering_yield_in_closure)]
pub(crate) struct YieldInClosure {
Expand Down
20 changes: 0 additions & 20 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1594,26 +1594,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
};
debug!(?captured_lifetimes_to_duplicate);

match fn_kind {
// Deny `use<>` on RPITIT in trait/trait-impl for now.
Some(FnDeclKind::Trait | FnDeclKind::Impl) => {
if let Some(span) = bounds.iter().find_map(|bound| match *bound {
ast::GenericBound::Use(_, span) => Some(span),
_ => None,
}) {
self.tcx.dcx().emit_err(errors::NoPreciseCapturesOnRpitit { span });
}
}
None
| Some(
FnDeclKind::Fn
| FnDeclKind::Inherent
| FnDeclKind::ExternFn
| FnDeclKind::Closure
| FnDeclKind::Pointer,
) => {}
}

self.lower_opaque_inner(
opaque_ty_node_id,
origin,
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,9 @@ 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_implicitly_captured = `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
.param_label = all lifetime parameters originating from a trait are captured implicitly
hir_analysis_lifetime_must_be_first = lifetime parameter `{$name}` must be listed before non-lifetime parameters
.label = move the lifetime before this parameter
Expand Down
25 changes: 16 additions & 9 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -593,15 +593,22 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe
param_span: tcx.def_span(def_id),
});
} else {
// If the `use_span` is actually just the param itself, then we must
// have not duplicated the lifetime but captured the original.
// The "effective" `use_span` will be the span of the opaque itself,
// and the param span will be the def span of the param.
tcx.dcx().emit_err(errors::LifetimeNotCaptured {
opaque_span,
use_span: opaque_span,
param_span: use_span,
});
if tcx.def_kind(tcx.parent(param.def_id)) == DefKind::Trait {
tcx.dcx().emit_err(errors::LifetimeImplicitlyCaptured {
opaque_span,
param_span: tcx.def_span(param.def_id),
});
} else {
// If the `use_span` is actually just the param itself, then we must
// have not duplicated the lifetime but captured the original.
// The "effective" `use_span` will be the span of the opaque itself,
// and the param span will be the def span of the param.
tcx.dcx().emit_err(errors::LifetimeNotCaptured {
opaque_span,
use_span: opaque_span,
param_span: use_span,
});
}
}
continue;
}
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_hir_analysis/src/errors/precise_captures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ pub struct LifetimeNotCaptured {
pub opaque_span: Span,
}

#[derive(Diagnostic)]
#[diag(hir_analysis_lifetime_implicitly_captured)]
pub struct LifetimeImplicitlyCaptured {
#[primary_span]
pub opaque_span: Span,
#[label(hir_analysis_param_label)]
pub param_span: Span,
}

#[derive(Diagnostic)]
#[diag(hir_analysis_bad_precise_capture)]
pub struct BadPreciseCapture {
Expand Down
48 changes: 40 additions & 8 deletions compiler/rustc_hir_analysis/src/variance/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use itertools::Itertools;
use rustc_arena::DroplessArena;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::query::Providers;
Expand Down Expand Up @@ -63,13 +64,27 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] {
}
DefKind::AssocTy => match tcx.opt_rpitit_info(item_def_id.to_def_id()) {
Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => {
return variance_of_opaque(tcx, opaque_def_id.expect_local());
return variance_of_opaque(
tcx,
opaque_def_id.expect_local(),
ForceCaptureTraitArgs::Yes,
);
}
None => {}
Some(ty::ImplTraitInTraitData::Impl { .. }) => {}
None | Some(ty::ImplTraitInTraitData::Impl { .. }) => {}
},
DefKind::OpaqueTy => {
return variance_of_opaque(tcx, item_def_id);
let force_capture_trait_args = if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) =
tcx.hir_node_by_def_id(item_def_id).expect_item().expect_opaque_ty().origin
&& let Some(ty::AssocItem {
container: ty::AssocItemContainer::TraitContainer, ..
}) = tcx.opt_associated_item(fn_def_id.to_def_id())
{
ForceCaptureTraitArgs::Yes
} else {
ForceCaptureTraitArgs::No
};

return variance_of_opaque(tcx, item_def_id, force_capture_trait_args);
}
_ => {}
}
Expand All @@ -78,8 +93,18 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] {
span_bug!(tcx.def_span(item_def_id), "asked to compute variance for wrong kind of item");
}

#[derive(Debug, Copy, Clone)]
enum ForceCaptureTraitArgs {
Yes,
No,
}

#[instrument(level = "trace", skip(tcx), ret)]
fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] {
fn variance_of_opaque(
tcx: TyCtxt<'_>,
item_def_id: LocalDefId,
force_capture_trait_args: ForceCaptureTraitArgs,
) -> &[ty::Variance] {
let generics = tcx.generics_of(item_def_id);

// Opaque types may only use regions that are bound. So for
Expand Down Expand Up @@ -120,9 +145,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
#[instrument(level = "trace", skip(self), ret)]
fn visit_ty(&mut self, t: Ty<'tcx>) {
match t.kind() {
ty::Alias(_, ty::AliasTy { def_id, args, .. })
if matches!(self.tcx.def_kind(*def_id), DefKind::OpaqueTy) =>
{
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
self.visit_opaque(*def_id, args);
}
_ => t.super_visit_with(self),
Expand All @@ -140,6 +163,15 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
let mut generics = generics;
while let Some(def_id) = generics.parent {
generics = tcx.generics_of(def_id);

// Don't mark trait params generic if we're in an RPITIT.
if matches!(force_capture_trait_args, ForceCaptureTraitArgs::Yes)
&& generics.parent.is_none()
{
debug_assert_eq!(tcx.def_kind(def_id), DefKind::Trait);
break;
}

for param in &generics.own_params {
match param.kind {
ty::GenericParamDefKind::Lifetime => {
Expand Down
5 changes: 1 addition & 4 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -580,10 +580,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
placeholder.find_const_ty_from_env(param_env)
}

fn is_impl_trait_in_trait(
self,
def_id: DefId,
) -> bool {
fn is_impl_trait_in_trait(self, def_id: DefId) -> bool {
self.is_impl_trait_in_trait(def_id)
}
}
Expand Down
5 changes: 1 addition & 4 deletions compiler/rustc_type_ir/src/interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,10 +278,7 @@ pub trait Interner:
placeholder: Self::PlaceholderConst,
) -> Self::Ty;

fn is_impl_trait_in_trait(
self,
def_id: Self::DefId,
) -> bool;
fn is_impl_trait_in_trait(self, def_id: Self::DefId) -> bool;
}

/// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter`
Expand Down
8 changes: 4 additions & 4 deletions tests/ui/impl-trait/in-trait/variance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ impl<T> Captures<'_> for T {}

trait Foo<'i> {
fn implicit_capture_early<'a: 'a>() -> impl Sized {}
//~^ [o, *, *, o, o]
//~^ [o, o, *, o, o]
// Self, 'i, 'a, 'i_duplicated, 'a_duplicated

fn explicit_capture_early<'a: 'a>() -> impl Sized + Captures<'a> {} //~ [o, *, *, o, o]
fn explicit_capture_early<'a: 'a>() -> impl Sized + Captures<'a> {} //~ [o, o, *, o, o]

fn implicit_capture_late<'a>(_: &'a ()) -> impl Sized {} //~ [o, *, o, o]
fn implicit_capture_late<'a>(_: &'a ()) -> impl Sized {} //~ [o, o, o, o]

fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} //~ [o, *, o, o]
fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} //~ [o, o, o, o]
}

fn main() {}
8 changes: 4 additions & 4 deletions tests/ui/impl-trait/in-trait/variance.stderr
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
error: [o, *, *, o, o]
error: [o, o, *, o, o]
--> $DIR/variance.rs:9:44
|
LL | fn implicit_capture_early<'a: 'a>() -> impl Sized {}
| ^^^^^^^^^^

error: [o, *, *, o, o]
error: [o, o, *, o, o]
--> $DIR/variance.rs:13:44
|
LL | fn explicit_capture_early<'a: 'a>() -> impl Sized + Captures<'a> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^

error: [o, *, o, o]
error: [o, o, o, o]
--> $DIR/variance.rs:15:48
|
LL | fn implicit_capture_late<'a>(_: &'a ()) -> impl Sized {}
| ^^^^^^^^^^

error: [o, *, o, o]
error: [o, o, o, o]
--> $DIR/variance.rs:17:48
|
LL | fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ fn type_param<T>() -> impl Sized + use<> {}
trait Foo {
fn bar() -> impl Sized + use<>;
//~^ ERROR `impl Trait` must mention the `Self` type of the trait
//~| ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits
--> $DIR/forgot-to-capture-type.rs:7:30
|
LL | fn bar() -> impl Sized + use<>;
| ^^^^^
|
= note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope

error: `impl Trait` must mention all type parameters in scope in `use<...>`
--> $DIR/forgot-to-capture-type.rs:3:23
|
Expand All @@ -26,5 +18,5 @@ 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 3 previous errors
error: aborting due to 2 previous errors

13 changes: 5 additions & 8 deletions tests/ui/impl-trait/precise-capturing/redundant.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,24 @@
//@ compile-flags: -Zunstable-options --edition=2024
//@ revisions: normal rpitit
//@[normal] check-pass
//@ check-pass

#![feature(precise_capturing)]

fn hello<'a>() -> impl Sized + use<'a> {}
//[normal]~^ WARN all possible in-scope parameters are already captured
//~^ WARN all possible in-scope parameters are already captured

struct Inherent;
impl Inherent {
fn inherent(&self) -> impl Sized + use<'_> {}
//[normal]~^ WARN all possible in-scope parameters are already captured
//~^ WARN all possible in-scope parameters are already captured
}

#[cfg(rpitit)]
trait Test<'a> {
fn in_trait() -> impl Sized + use<'a, Self>;
//[rpitit]~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits
//~^ WARN all possible in-scope parameters are already captured
}
#[cfg(rpitit)]
impl<'a> Test<'a> for () {
fn in_trait() -> impl Sized + use<'a> {}
//[rpitit]~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits
//~^ WARN all possible in-scope parameters are already captured
}

fn main() {}
36 changes: 36 additions & 0 deletions tests/ui/impl-trait/precise-capturing/redundant.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
--> $DIR/redundant.rs:6:19
|
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:11:27
|
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:16:22
|
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:20:22
|
LL | fn in_trait() -> impl Sized + use<'a> {}
| ^^^^^^^^^^^^^-------
| |
| help: remove the `use<...>` syntax

warning: 4 warnings emitted

Loading

0 comments on commit 9b53b64

Please sign in to comment.