Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stabilize impl_trait_projections #115659

Merged
merged 1 commit into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_error_codes/src/error_codes/E0760.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ or `Self` that references lifetimes from a parent scope.

Erroneous code example:

```compile_fail,edition2018
```ignore,edition2018
struct S<'a>(&'a i32);

impl<'a> S<'a> {
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/accepted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ declare_features! (
/// + `impl<I:Iterator> Iterator for &mut Iterator`
/// + `impl Debug for Foo<'_>`
(accepted, impl_header_lifetime_elision, "1.31.0", Some(15872), None),
/// Allows referencing `Self` and projections in impl-trait.
(accepted, impl_trait_projections, "CURRENT_RUSTC_VERSION", Some(103532), None),
/// Allows using `a..=b` and `..=b` as inclusive range syntaxes.
(accepted, inclusive_range_syntax, "1.26.0", Some(28237), None),
/// Allows inferring outlives requirements (RFC 2093).
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 @@ -465,8 +465,6 @@ declare_features! (
(active, impl_trait_in_assoc_type, "1.70.0", Some(63063), None),
/// Allows `impl Trait` as output type in `Fn` traits in return position of functions.
(active, impl_trait_in_fn_trait_return, "1.64.0", Some(99697), None),
/// Allows referencing `Self` and projections in impl-trait.
(active, impl_trait_projections, "1.67.0", Some(103532), None),
/// Allows using imported `main` function
(active, imported_main, "1.53.0", Some(28937), None),
/// Allows associated types in inherent impls.
Expand Down
135 changes: 3 additions & 132 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,15 @@ 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_errors::{Applicability, ErrorGuaranteed, MultiSpan};
use rustc_errors::{ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def::{CtorKind, DefKind};
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
use rustc_hir::intravisit::Visitor;
use rustc_hir::{ItemKind, Node, PathSegment};
use rustc_infer::infer::opaque_types::ConstrainOpaqueTypeRegionVisitor;
use rustc_hir::Node;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
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::hir::nested_filter;
use rustc_middle::middle::stability::EvalResult;
use rustc_middle::traits::DefiningAnchor;
use rustc_middle::ty::fold::BottomUpFolder;
Expand Down Expand Up @@ -218,9 +215,6 @@ fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) {
let args = GenericArgs::identity_for_item(tcx, item.owner_id);
let span = tcx.def_span(item.owner_id.def_id);

if !tcx.features().impl_trait_projections {
check_opaque_for_inheriting_lifetimes(tcx, item.owner_id.def_id, span);
}
if tcx.type_of(item.owner_id.def_id).instantiate_identity().references_error() {
return;
}
Expand All @@ -231,129 +225,6 @@ fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) {
let _ = check_opaque_meets_bounds(tcx, item.owner_id.def_id, span, &origin);
}

/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
/// in "inheriting lifetimes".
#[instrument(level = "debug", skip(tcx, span))]
pub(super) fn check_opaque_for_inheriting_lifetimes(
tcx: TyCtxt<'_>,
def_id: LocalDefId,
span: Span,
) {
let item = tcx.hir().expect_item(def_id);
debug!(?item, ?span);

struct ProhibitOpaqueVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
opaque_identity_ty: Ty<'tcx>,
parent_count: u32,
references_parent_regions: bool,
selftys: Vec<(Span, Option<String>)>,
}

impl<'tcx> ty::visit::TypeVisitor<TyCtxt<'tcx>> for ProhibitOpaqueVisitor<'tcx> {
type BreakTy = Ty<'tcx>;

fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
debug!(?t, "root_visit_ty");
if t == self.opaque_identity_ty {
ControlFlow::Continue(())
} else {
t.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
tcx: self.tcx,
op: |region| {
if let ty::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = *region
&& index < self.parent_count
{
self.references_parent_regions= true;
}
},
});
if self.references_parent_regions {
ControlFlow::Break(t)
} else {
ControlFlow::Continue(())
}
}
}
}

impl<'tcx> Visitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
type NestedFilter = nested_filter::OnlyBodies;

fn nested_visit_map(&mut self) -> Self::Map {
self.tcx.hir()
}

fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
match arg.kind {
hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
[PathSegment { res: Res::SelfTyParam { .. }, .. }] => {
let impl_ty_name = None;
self.selftys.push((path.span, impl_ty_name));
}
[PathSegment { res: Res::SelfTyAlias { alias_to: def_id, .. }, .. }] => {
let impl_ty_name = Some(self.tcx.def_path_str(*def_id));
self.selftys.push((path.span, impl_ty_name));
}
_ => {}
},
_ => {}
}
hir::intravisit::walk_ty(self, arg);
}
}

if let ItemKind::OpaqueTy(&hir::OpaqueTy {
origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
..
}) = item.kind
{
let args = GenericArgs::identity_for_item(tcx, def_id);
let opaque_identity_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
let mut visitor = ProhibitOpaqueVisitor {
opaque_identity_ty,
parent_count: tcx.generics_of(def_id).parent_count as u32,
references_parent_regions: false,
tcx,
selftys: vec![],
};
let prohibit_opaque = tcx
.explicit_item_bounds(def_id)
.instantiate_identity_iter_copied()
.try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor));

if let Some(ty) = prohibit_opaque.break_value() {
visitor.visit_item(&item);
let is_async = match item.kind {
ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
matches!(origin, hir::OpaqueTyOrigin::AsyncFn(..))
}
_ => unreachable!(),
};

let mut err = feature_err(
&tcx.sess.parse_sess,
sym::impl_trait_projections,
span,
format!(
"`{}` return type cannot contain a projection or `Self` that references \
lifetimes from a parent scope",
if is_async { "async fn" } else { "impl Trait" },
),
);
for (span, name) in visitor.selftys {
err.span_suggestion(
span,
"consider spelling out the type instead",
name.unwrap_or_else(|| format!("{ty:?}")),
Applicability::MaybeIncorrect,
);
}
err.emit();
}
}
}

/// Checks that an opaque type does not contain cycles.
pub(super) fn check_opaque_for_cycles<'tcx>(
tcx: TyCtxt<'tcx>,
Expand Down
1 change: 0 additions & 1 deletion tests/ui/async-await/feature-self-return-type.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// edition:2018
#![feature(impl_trait_projections)]

// This test checks that we emit the correct borrowck error when `Self` is used as a return type.
// See #61949 for context.
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/async-await/feature-self-return-type.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0597]: `bar` does not live long enough
--> $DIR/feature-self-return-type.rs:22:18
--> $DIR/feature-self-return-type.rs:21:18
|
LL | let x = {
| - borrow later stored here
Expand Down
1 change: 0 additions & 1 deletion tests/ui/async-await/in-trait/async-associated-types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// edition: 2021

#![feature(async_fn_in_trait)]
#![feature(impl_trait_projections)]
#![allow(incomplete_features)]

use std::fmt::Debug;
Expand Down
28 changes: 0 additions & 28 deletions tests/ui/async-await/issue-61949-self-return-type.rs

This file was deleted.

26 changes: 0 additions & 26 deletions tests/ui/async-await/issue-61949-self-return-type.stderr

This file was deleted.

2 changes: 1 addition & 1 deletion tests/ui/async-await/issues/issue-78600.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// check-pass
// edition:2018

struct S<'a>(&'a i32);

impl<'a> S<'a> {
async fn new(i: &'a i32) -> Result<Self, ()> {
//~^ ERROR: `async fn`
Ok(S(&22))
}
}
Expand Down
14 changes: 0 additions & 14 deletions tests/ui/async-await/issues/issue-78600.stderr

This file was deleted.

3 changes: 1 addition & 2 deletions tests/ui/impl-trait/bound-normalization-fail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ mod lifetimes {

/// Missing bound constraining `Assoc`, `T::Assoc` can't be normalized further.
fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output = T::Assoc> {
//~^ ERROR `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
//~| ERROR: type mismatch
//~^ ERROR: type mismatch
Foo(())
}
}
Expand Down
16 changes: 3 additions & 13 deletions tests/ui/impl-trait/bound-normalization-fail.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,12 @@ help: consider constraining the associated type `<T as impl_trait::Trait>::Assoc
LL | fn foo_fail<T: Trait<Assoc = ()>>() -> impl FooLike<Output = T::Assoc> {
| ++++++++++++

error[E0658]: `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
--> $DIR/bound-normalization-fail.rs:41:41
|
LL | fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output = T::Assoc> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #103532 <https://github.com/rust-lang/rust/issues/103532> for more information
= help: add `#![feature(impl_trait_projections)]` to the crate attributes to enable

error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as Trait<'a>>::Assoc`
--> $DIR/bound-normalization-fail.rs:41:41
|
LL | fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output = T::Assoc> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Foo<()> as FooLike>::Output == <T as Trait<'a>>::Assoc`
...
LL |
LL | Foo(())
| ------- return type was inferred to be `Foo<()>` here
|
Expand All @@ -49,7 +40,6 @@ help: consider constraining the associated type `<T as lifetimes::Trait<'a>>::As
LL | fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike<Output = T::Assoc> {
| ++++++++++++

error: aborting due to 3 previous errors
error: aborting due to 2 previous errors

Some errors have detailed explanations: E0271, E0658.
For more information about an error, try `rustc --explain E0271`.
For more information about this error, try `rustc --explain E0271`.
21 changes: 21 additions & 0 deletions tests/ui/impl-trait/capture-lifetime-not-in-hir.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#![feature(rustc_attrs)]
#![rustc_variance_of_opaques]

trait Bar<'a> {
type Assoc: From<()>;
}

fn foo<'a, T: Bar<'a>>() -> impl Into<T::Assoc> {
//~^ ERROR [o, o]
// captures both T and 'a invariantly
()
}

fn foo2<'a, T: Bar<'a>>() -> impl Into<T::Assoc> + 'a {
//~^ ERROR [o, o, o]
// captures both T and 'a invariantly, and also duplicates `'a`
// i.e. the opaque looks like `impl Into<<T as Bar<'a>>::Assoc> + 'a_duplicated`
()
}

fn main() {}
14 changes: 14 additions & 0 deletions tests/ui/impl-trait/capture-lifetime-not-in-hir.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error: [o, o]
--> $DIR/capture-lifetime-not-in-hir.rs:8:29
|
LL | fn foo<'a, T: Bar<'a>>() -> impl Into<T::Assoc> {
| ^^^^^^^^^^^^^^^^^^^

error: [o, o, o]
--> $DIR/capture-lifetime-not-in-hir.rs:14:30
|
LL | fn foo2<'a, T: Bar<'a>>() -> impl Into<T::Assoc> + 'a {
| ^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors

1 change: 0 additions & 1 deletion tests/ui/impl-trait/feature-self-return-type.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// edition:2018
#![feature(impl_trait_projections)]

// This test checks that we emit the correct borrowck error when `Self` or a projection is used as
// a return type. See #61949 for context.
Expand Down
Loading
Loading