Skip to content

Commit

Permalink
Stabilize anonymous_lifetime_in_impl_trait
Browse files Browse the repository at this point in the history
  • Loading branch information
c410-f3r committed Oct 3, 2023
1 parent e3c631b commit efad34f
Show file tree
Hide file tree
Showing 16 changed files with 202 additions and 259 deletions.
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/accepted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ declare_features! (
(accepted, abi_thiscall, "1.73.0", None, None),
/// Allows using ADX intrinsics from `core::arch::{x86, x86_64}`.
(accepted, adx_target_feature, "1.61.0", Some(44839), None),
/// Allows using anonymous lifetimes in argument-position impl-trait.
(accepted, anonymous_lifetime_in_impl_trait, "CURRENT_RUSTC_VERSION", None, None),
/// Allows explicit discriminants on non-unit enum variants.
(accepted, arbitrary_enum_discriminant, "1.66.0", Some(60553), None),
/// Allows using `sym` operands in inline assembly.
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,6 @@ declare_features! (
/// below (it has to be checked before expansion possibly makes
/// macros disappear).
(internal, allow_internal_unstable, "1.0.0", None, None),
/// Allows using anonymous lifetimes in argument-position impl-trait.
(active, anonymous_lifetime_in_impl_trait, "1.63.0", None, None),
/// Allows identifying the `compiler_builtins` crate.
(internal, compiler_builtins, "1.13.0", None, None),
/// Allows writing custom MIR
Expand Down
58 changes: 2 additions & 56 deletions compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use rustc_middle::query::Providers;
use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor};
use rustc_session::lint;
use rustc_span::def_id::DefId;
use rustc_span::symbol::{sym, Ident};
use rustc_span::symbol::Ident;
use rustc_span::{Span, DUMMY_SP};
use std::fmt;

Expand Down Expand Up @@ -1197,68 +1197,14 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
break None;
}

Scope::Binder { ref bound_vars, scope_type, s, where_bound_origin, .. } => {
Scope::Binder { ref bound_vars, scope_type, s, .. } => {
if let Some(&def) = bound_vars.get(&region_def_id) {
break Some(def.shifted(late_depth));
}
match scope_type {
BinderScopeType::Normal => late_depth += 1,
BinderScopeType::Concatenating => {}
}
// Fresh lifetimes in APIT used to be allowed in async fns and forbidden in
// regular fns.
if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin
&& let hir::LifetimeName::Param(param_id) = lifetime_ref.res
&& let Some(generics) = self.tcx.hir().get_generics(self.tcx.local_parent(param_id))
&& let Some(param) = generics.params.iter().find(|p| p.def_id == param_id)
&& param.is_elided_lifetime()
&& !self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id).is_async()
&& !self.tcx.features().anonymous_lifetime_in_impl_trait
{
let mut diag = rustc_session::parse::feature_err(
&self.tcx.sess.parse_sess,
sym::anonymous_lifetime_in_impl_trait,
lifetime_ref.ident.span,
"anonymous lifetimes in `impl Trait` are unstable",
);

if let Some(generics) =
self.tcx.hir().get_generics(lifetime_ref.hir_id.owner.def_id)
{
let new_param_sugg = if let Some(span) =
generics.span_for_lifetime_suggestion()
{
(span, "'a, ".to_owned())
} else {
(generics.span, "<'a>".to_owned())
};

let lifetime_sugg = match lifetime_ref.suggestion_position() {
(hir::LifetimeSuggestionPosition::Normal, span) => (span, "'a".to_owned()),
(hir::LifetimeSuggestionPosition::Ampersand, span) => (span, "'a ".to_owned()),
(hir::LifetimeSuggestionPosition::ElidedPath, span) => (span, "<'a>".to_owned()),
(hir::LifetimeSuggestionPosition::ElidedPathArgument, span) => (span, "'a, ".to_owned()),
(hir::LifetimeSuggestionPosition::ObjectDefault, span) => (span, "+ 'a".to_owned()),
};
let suggestions = vec![
lifetime_sugg,
new_param_sugg,
];

diag.span_label(
lifetime_ref.ident.span,
"expected named lifetime parameter",
);
diag.multipart_suggestion(
"consider introducing a named lifetime parameter",
suggestions,
rustc_errors::Applicability::MaybeIncorrect,
);
}

diag.emit();
return;
}
scope = s;
}

Expand Down
1 change: 0 additions & 1 deletion tests/ui/associated-type-bounds/elision.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#![feature(associated_type_bounds)]
#![feature(anonymous_lifetime_in_impl_trait)]

// The same thing should happen for constraints in dyn trait.
fn f(x: &mut dyn Iterator<Item: Iterator<Item = &'_ ()>>) -> Option<&'_ ()> { x.next() }
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/associated-type-bounds/elision.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0106]: missing lifetime specifier
--> $DIR/elision.rs:5:70
--> $DIR/elision.rs:4:70
|
LL | fn f(x: &mut dyn Iterator<Item: Iterator<Item = &'_ ()>>) -> Option<&'_ ()> { x.next() }
| ------------------------------------------------ ^^ expected named lifetime parameter
Expand All @@ -11,7 +11,7 @@ LL | fn f<'a>(x: &'a mut dyn Iterator<Item: Iterator<Item = &'a ()>>) -> Option<
| ++++ ++ ~~ ~~

error[E0308]: mismatched types
--> $DIR/elision.rs:5:79
--> $DIR/elision.rs:4:79
|
LL | fn f(x: &mut dyn Iterator<Item: Iterator<Item = &'_ ()>>) -> Option<&'_ ()> { x.next() }
| ----------------------------- -------------- ^^^^^^^^ expected `Option<&()>`, found `Option<impl Iterator<Item = &'_ ()>>`
Expand Down
2 changes: 0 additions & 2 deletions tests/ui/borrowck/anonymous-region-in-apit.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#![feature(anonymous_lifetime_in_impl_trait)]

trait Foo<T> {
fn bar(self, baz: T);
}
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/borrowck/anonymous-region-in-apit.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0521]: borrowed data escapes outside of closure
--> $DIR/anonymous-region-in-apit.rs:8:17
--> $DIR/anonymous-region-in-apit.rs:6:17
|
LL | fn qux(foo: impl Foo<&str>) {
| --- lifetime `'2` appears in the type of `foo`
Expand Down
1 change: 0 additions & 1 deletion tests/ui/generic-associated-types/issue-95305.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Forbid it for now but proper support might be added
// at some point in the future.

#![feature(anonymous_lifetime_in_impl_trait)]
trait Foo {
type Item<'a>;
}
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/generic-associated-types/issue-95305.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0637]: `'_` cannot be used here
--> $DIR/issue-95305.rs:10:26
--> $DIR/issue-95305.rs:9:26
|
LL | fn foo(x: &impl Foo<Item<'_> = u32>) { }
| ^^ `'_` is a reserved lifetime name
Expand Down
47 changes: 47 additions & 0 deletions tests/ui/impl-trait/impl-trait-lifetimes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
trait Foo<T> {
fn foo(&self, _: T) { }
}

mod foo {
fn fun(t: impl crate::Foo<&u32>, n: u32) {
t.foo(&n);
//~^ ERROR `n` does not live long enough
}
}

mod fun {
fn fun(t: impl Fn(&u32), n: u32) {
t(&n);
}
}

mod iterator_fun {
fn fun(t: impl Iterator<Item = impl Fn(&u32)>, n: u32) {
for elem in t {
elem(&n);
}
}
}

mod iterator_foo {
fn fun(t: impl Iterator<Item = impl crate::Foo<&u32>>, n: u32) {
for elem in t {
elem.foo(&n);
//~^ ERROR `n` does not live long enough
}
}
}

mod placeholder {
trait Placeholder<'a> {
fn foo(&self, _: &'a u32) {}
}

fn fun(t: impl Placeholder<'_>, n: u32) {
t.foo(&n);
//~^ ERROR `n` does not live long enough
}
}

fn main() {
}
43 changes: 43 additions & 0 deletions tests/ui/impl-trait/impl-trait-lifetimes.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
error[E0597]: `n` does not live long enough
--> $DIR/impl-trait-lifetimes.rs:7:15
|
LL | fn fun(t: impl crate::Foo<&u32>, n: u32) {
| - has type `t` - binding `n` declared here
LL | t.foo(&n);
| ------^^-
| | |
| | borrowed value does not live long enough
| argument requires that `n` is borrowed for `'1`
LL |
LL | }
| - `n` dropped here while still borrowed

error[E0597]: `n` does not live long enough
--> $DIR/impl-trait-lifetimes.rs:29:22
|
LL | fn fun(t: impl Iterator<Item = impl crate::Foo<&u32>>, n: u32) {
| - binding `n` declared here
LL | for elem in t {
LL | elem.foo(&n);
| ^^ borrowed value does not live long enough
...
LL | }
| - `n` dropped here while still borrowed

error[E0597]: `n` does not live long enough
--> $DIR/impl-trait-lifetimes.rs:41:15
|
LL | fn fun(t: impl Placeholder<'_>, n: u32) {
| - has type `t` - binding `n` declared here
LL | t.foo(&n);
| ------^^-
| | |
| | borrowed value does not live long enough
| argument requires that `n` is borrowed for `'1`
LL |
LL | }
| - `n` dropped here while still borrowed

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0597`.
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@

mod elided {
fn f(_: impl Iterator<Item = &()>) {}
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable

fn g(mut x: impl Iterator<Item = &()>) -> Option<&()> { x.next() }
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
//~| ERROR missing lifetime specifier
//~^ ERROR missing lifetime specifier

// Anonymous lifetimes in async fn are already allowed.
// This is understood as `fn foo<'_1>(_: impl Iterator<Item = &'_1 ()>) {}`.
Expand All @@ -17,16 +15,15 @@ mod elided {
// Anonymous lifetimes in async fn are already allowed.
// But that lifetime does not participate in resolution.
async fn i(mut x: impl Iterator<Item = &()>) -> Option<&()> { x.next() }
//~^ ERROR missing lifetime specifier
//~^ ERROR lifetime may not live long
//~| ERROR missing lifetime specifier
}

mod underscore {
fn f(_: impl Iterator<Item = &'_ ()>) {}
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable

fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
//~| ERROR missing lifetime specifier
//~^ ERROR missing lifetime specifier

// Anonymous lifetimes in async fn are already allowed.
// This is understood as `fn foo<'_1>(_: impl Iterator<Item = &'_1 ()>) {}`.
Expand All @@ -35,34 +32,31 @@ mod underscore {
// Anonymous lifetimes in async fn are already allowed.
// But that lifetime does not participate in resolution.
async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
//~^ ERROR missing lifetime specifier
//~^ ERROR lifetime may not live long
//~| ERROR missing lifetime specifier
}

mod alone_in_path {
trait Foo<'a> { fn next(&mut self) -> Option<&'a ()>; }

fn f(_: impl Foo) {}
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable

fn g(mut x: impl Foo) -> Option<&()> { x.next() }
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
//~| ERROR missing lifetime specifier
//~^ ERROR missing lifetime specifier
}

mod in_path {
trait Foo<'a, T> { fn next(&mut self) -> Option<&'a T>; }

fn f(_: impl Foo<()>) {}
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable

fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() }
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
//~| ERROR missing lifetime specifier
//~^ ERROR missing lifetime specifier
}

// This must not err, as the `&` actually resolves to `'a`.
fn resolved_anonymous<'a, T>(f: impl Fn(&'a str) -> &T) {
f("f")
fn resolved_anonymous<'a, T: 'a>(f: impl Fn(&'a str) -> &T) {
f("f");
}

fn main() {}
Loading

0 comments on commit efad34f

Please sign in to comment.