Rollup merge of #119766 - oli-obk:split_tait_and_atpit, r=compiler-errors

Split tait and impl trait in assoc items logic

And simplify the assoc item logic where applicable.

This separation shows that it is easier to reason about impl trait in assoc items compared with TAITs. See https://rust-lang.zulipchat.com/#narrow/stream/315482-t-compiler.2Fetc.2Fopaque-types/topic/impl.20trait.20in.20associated.20type for some discussion.

The current plan is to try to stabilize impl trait in associated items before TAIT, as they do not have any issues with their defining scopes (see https://github.com/rust-lang/rust/issues/107645 for why this is not a trivial or uncontroversial topic).
This commit is contained in:
León Orell Valerian Liehr 2024-01-23 21:53:56 +01:00 committed by GitHub
commit 5da220a095
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 615 additions and 73 deletions

View File

@ -530,9 +530,13 @@ pub(super) fn type_of_opaque(
Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id) { Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id) {
Node::Item(item) => match item.kind { Node::Item(item) => match item.kind {
ItemKind::OpaqueTy(OpaqueTy { ItemKind::OpaqueTy(OpaqueTy {
origin: hir::OpaqueTyOrigin::TyAlias { .. }, origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false },
.. ..
}) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id), }) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id),
ItemKind::OpaqueTy(OpaqueTy {
origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true },
..
}) => opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(tcx, def_id),
// Opaque types desugared from `impl Trait`. // Opaque types desugared from `impl Trait`.
ItemKind::OpaqueTy(&OpaqueTy { ItemKind::OpaqueTy(&OpaqueTy {
origin: origin:

View File

@ -23,6 +23,60 @@ pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed>
res res
} }
/// Checks "defining uses" of opaque `impl Trait` in associated types.
/// These can only be defined by associated items of the same trait.
#[instrument(skip(tcx), level = "debug")]
pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
tcx: TyCtxt<'_>,
def_id: LocalDefId,
) -> Ty<'_> {
let mut parent_def_id = def_id;
while tcx.def_kind(parent_def_id) == def::DefKind::OpaqueTy {
// Account for `type Alias = impl Trait<Foo = impl Trait>;` (#116031)
parent_def_id = tcx.local_parent(parent_def_id);
}
let impl_def_id = tcx.local_parent(parent_def_id);
match tcx.def_kind(impl_def_id) {
DefKind::Impl { .. } => {}
other => bug!("invalid impl trait in assoc type parent: {other:?}"),
}
let mut locator = TaitConstraintLocator { def_id, tcx, found: None, typeck_types: vec![] };
for &assoc_id in tcx.associated_item_def_ids(impl_def_id) {
let assoc = tcx.associated_item(assoc_id);
match assoc.kind {
ty::AssocKind::Const | ty::AssocKind::Fn => {
locator.check(assoc_id.expect_local(), ImplTraitSource::AssocTy)
}
// Associated types don't have bodies, so they can't constrain hidden types
ty::AssocKind::Type => {}
}
}
if let Some(hidden) = locator.found {
// Only check against typeck if we didn't already error
if !hidden.ty.references_error() {
for concrete_type in locator.typeck_types {
if concrete_type.ty != tcx.erase_regions(hidden.ty)
&& !(concrete_type, hidden).references_error()
{
hidden.report_mismatch(&concrete_type, def_id, tcx).emit();
}
}
}
hidden.ty
} else {
let reported = tcx.dcx().emit_err(UnconstrainedOpaqueType {
span: tcx.def_span(def_id),
name: tcx.item_name(parent_def_id.to_def_id()),
what: "impl",
});
Ty::new_error(tcx, reported)
}
}
/// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions /// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions
/// laid for "higher-order pattern unification". /// laid for "higher-order pattern unification".
/// This ensures that inference is tractable. /// This ensures that inference is tractable.
@ -128,9 +182,15 @@ struct TaitConstraintLocator<'tcx> {
typeck_types: Vec<ty::OpaqueHiddenType<'tcx>>, typeck_types: Vec<ty::OpaqueHiddenType<'tcx>>,
} }
#[derive(Debug)]
enum ImplTraitSource {
AssocTy,
TyAlias,
}
impl TaitConstraintLocator<'_> { impl TaitConstraintLocator<'_> {
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
fn check(&mut self, item_def_id: LocalDefId) { fn check(&mut self, item_def_id: LocalDefId, source: ImplTraitSource) {
// Don't try to check items that cannot possibly constrain the type. // Don't try to check items that cannot possibly constrain the type.
if !self.tcx.has_typeck_results(item_def_id) { if !self.tcx.has_typeck_results(item_def_id) {
debug!("no constraint: no typeck results"); debug!("no constraint: no typeck results");
@ -182,7 +242,13 @@ fn check(&mut self, item_def_id: LocalDefId) {
continue; continue;
} }
constrained = true; constrained = true;
if !self.tcx.opaque_types_defined_by(item_def_id).contains(&self.def_id) { let opaque_types_defined_by = match source {
ImplTraitSource::AssocTy => {
self.tcx.impl_trait_in_assoc_types_defined_by(item_def_id)
}
ImplTraitSource::TyAlias => self.tcx.opaque_types_defined_by(item_def_id),
};
if !opaque_types_defined_by.contains(&self.def_id) {
self.tcx.dcx().emit_err(TaitForwardCompat { self.tcx.dcx().emit_err(TaitForwardCompat {
span: hidden_type.span, span: hidden_type.span,
item_span: self item_span: self
@ -240,7 +306,7 @@ fn nested_visit_map(&mut self) -> Self::Map {
} }
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
if let hir::ExprKind::Closure(closure) = ex.kind { if let hir::ExprKind::Closure(closure) = ex.kind {
self.check(closure.def_id); self.check(closure.def_id, ImplTraitSource::TyAlias);
} }
intravisit::walk_expr(self, ex); intravisit::walk_expr(self, ex);
} }
@ -248,7 +314,7 @@ fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
trace!(?it.owner_id); trace!(?it.owner_id);
// The opaque type itself or its children are not within its reveal scope. // The opaque type itself or its children are not within its reveal scope.
if it.owner_id.def_id != self.def_id { if it.owner_id.def_id != self.def_id {
self.check(it.owner_id.def_id); self.check(it.owner_id.def_id, ImplTraitSource::TyAlias);
intravisit::walk_item(self, it); intravisit::walk_item(self, it);
} }
} }
@ -256,13 +322,13 @@ fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
trace!(?it.owner_id); trace!(?it.owner_id);
// The opaque type itself or its children are not within its reveal scope. // The opaque type itself or its children are not within its reveal scope.
if it.owner_id.def_id != self.def_id { if it.owner_id.def_id != self.def_id {
self.check(it.owner_id.def_id); self.check(it.owner_id.def_id, ImplTraitSource::TyAlias);
intravisit::walk_impl_item(self, it); intravisit::walk_impl_item(self, it);
} }
} }
fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) { fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
trace!(?it.owner_id); trace!(?it.owner_id);
self.check(it.owner_id.def_id); self.check(it.owner_id.def_id, ImplTraitSource::TyAlias);
intravisit::walk_trait_item(self, it); intravisit::walk_trait_item(self, it);
} }
fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) { fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) {

View File

@ -343,6 +343,15 @@
} }
} }
query impl_trait_in_assoc_types_defined_by(
key: LocalDefId
) -> &'tcx ty::List<LocalDefId> {
desc {
|tcx| "computing the opaque types defined by `{}`",
tcx.def_path_str(key.to_def_id())
}
}
/// Returns the list of bounds that can be used for /// Returns the list of bounds that can be used for
/// `SelectionCandidate::ProjectionCandidate(_)` and /// `SelectionCandidate::ProjectionCandidate(_)` and
/// `ProjectionTyCandidate::TraitDef`. /// `ProjectionTyCandidate::TraitDef`.

View File

@ -118,36 +118,21 @@ fn visit_nested_body(&mut self, id: rustc_hir::BodyId) {
} }
TaitInBodyFinder { collector: self }.visit_expr(body); TaitInBodyFinder { collector: self }.visit_expr(body);
} }
}
impl<'tcx> super::sig_types::SpannedTypeVisitor<'tcx> for OpaqueTypeCollector<'tcx> { fn visit_opaque_ty(&mut self, alias_ty: &ty::AliasTy<'tcx>) {
#[instrument(skip(self), ret, level = "trace")]
fn visit(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) -> ControlFlow<!> {
self.visit_spanned(span, value);
ControlFlow::Continue(())
}
}
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
#[instrument(skip(self), ret, level = "trace")]
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<!> {
t.super_visit_with(self)?;
match t.kind() {
ty::Alias(ty::Opaque, alias_ty) if alias_ty.def_id.is_local() => {
if !self.seen.insert(alias_ty.def_id.expect_local()) { if !self.seen.insert(alias_ty.def_id.expect_local()) {
return ControlFlow::Continue(()); return;
} }
// TAITs outside their defining scopes are ignored. // TAITs outside their defining scopes are ignored.
let origin = self.tcx.opaque_type_origin(alias_ty.def_id.expect_local()); let origin = self.tcx.opaque_type_origin(alias_ty.def_id.expect_local());
trace!(?origin); trace!(?origin);
match origin { match origin {
rustc_hir::OpaqueTyOrigin::FnReturn(_) rustc_hir::OpaqueTyOrigin::FnReturn(_) | rustc_hir::OpaqueTyOrigin::AsyncFn(_) => {}
| rustc_hir::OpaqueTyOrigin::AsyncFn(_) => {}
rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => { rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => {
if !in_assoc_ty { if !in_assoc_ty {
if !self.check_tait_defining_scope(alias_ty.def_id.expect_local()) { if !self.check_tait_defining_scope(alias_ty.def_id.expect_local()) {
return ControlFlow::Continue(()); return;
} }
} }
} }
@ -159,10 +144,10 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<!> {
// Only check that the parent generics of the TAIT/RPIT are unique. // Only check that the parent generics of the TAIT/RPIT are unique.
// the args owned by the opaque are going to always be duplicate // the args owned by the opaque are going to always be duplicate
// lifetime params for RPITs, and empty for TAITs. // lifetime params for RPITs, and empty for TAITs.
match self.tcx.uses_unique_generic_params( match self
&alias_ty.args[..parent_count], .tcx
CheckRegions::FromFunction, .uses_unique_generic_params(&alias_ty.args[..parent_count], CheckRegions::FromFunction)
) { {
Ok(()) => { Ok(()) => {
// FIXME: implement higher kinded lifetime bounds on nested opaque types. They are not // FIXME: implement higher kinded lifetime bounds on nested opaque types. They are not
// supported at all, so this is sound to do, but once we want to support them, you'll // supported at all, so this is sound to do, but once we want to support them, you'll
@ -196,6 +181,24 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<!> {
} }
} }
} }
}
impl<'tcx> super::sig_types::SpannedTypeVisitor<'tcx> for OpaqueTypeCollector<'tcx> {
#[instrument(skip(self), ret, level = "trace")]
fn visit(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) -> ControlFlow<!> {
self.visit_spanned(span, value);
ControlFlow::Continue(())
}
}
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
#[instrument(skip(self), ret, level = "trace")]
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<!> {
t.super_visit_with(self)?;
match t.kind() {
ty::Alias(ty::Opaque, alias_ty) if alias_ty.def_id.is_local() => {
self.visit_opaque_ty(alias_ty);
}
ty::Alias(ty::Weak, alias_ty) if alias_ty.def_id.is_local() => { ty::Alias(ty::Weak, alias_ty) if alias_ty.def_id.is_local() => {
self.tcx self.tcx
.type_of(alias_ty.def_id) .type_of(alias_ty.def_id)
@ -272,6 +275,91 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<!> {
} }
} }
struct ImplTraitInAssocTypeCollector<'tcx>(OpaqueTypeCollector<'tcx>);
impl<'tcx> super::sig_types::SpannedTypeVisitor<'tcx> for ImplTraitInAssocTypeCollector<'tcx> {
#[instrument(skip(self), ret, level = "trace")]
fn visit(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) -> ControlFlow<!> {
let old = self.0.span;
self.0.span = Some(span);
value.visit_with(self);
self.0.span = old;
ControlFlow::Continue(())
}
}
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInAssocTypeCollector<'tcx> {
#[instrument(skip(self), ret, level = "trace")]
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<!> {
t.super_visit_with(self)?;
match t.kind() {
ty::Alias(ty::Opaque, alias_ty) if alias_ty.def_id.is_local() => {
self.0.visit_opaque_ty(alias_ty);
}
ty::Alias(ty::Projection, alias_ty) => {
// This avoids having to do normalization of `Self::AssocTy` by only
// supporting the case of a method defining opaque types from assoc types
// in the same impl block.
let parent_trait_ref = self
.0
.parent_trait_ref()
.expect("impl trait in assoc type collector used on non-assoc item");
// If the trait ref of the associated item and the impl differs,
// then we can't use the impl's identity substitutions below, so
// just skip.
if alias_ty.trait_ref(self.0.tcx) == parent_trait_ref {
let parent = self.0.parent().expect("we should have a parent here");
for &assoc in self.0.tcx.associated_items(parent).in_definition_order() {
trace!(?assoc);
if assoc.trait_item_def_id != Some(alias_ty.def_id) {
continue;
}
// If the type is further specializable, then the type_of
// is not actually correct below.
if !assoc.defaultness(self.0.tcx).is_final() {
continue;
}
let impl_args = alias_ty.args.rebase_onto(
self.0.tcx,
parent_trait_ref.def_id,
ty::GenericArgs::identity_for_item(self.0.tcx, parent),
);
if check_args_compatible(self.0.tcx, assoc, impl_args) {
return self
.0
.tcx
.type_of(assoc.def_id)
.instantiate(self.0.tcx, impl_args)
.visit_with(self);
} else {
self.0.tcx.dcx().span_delayed_bug(
self.0.tcx.def_span(assoc.def_id),
"item had incorrect args",
);
}
}
}
}
_ => trace!(kind=?t.kind()),
}
ControlFlow::Continue(())
}
}
fn impl_trait_in_assoc_types_defined_by<'tcx>(
tcx: TyCtxt<'tcx>,
item: LocalDefId,
) -> &'tcx ty::List<LocalDefId> {
let mut collector = ImplTraitInAssocTypeCollector(OpaqueTypeCollector::new(tcx, item));
super::sig_types::walk_types(tcx, item, &mut collector);
tcx.mk_local_def_ids(&collector.0.opaques)
}
fn opaque_types_defined_by<'tcx>( fn opaque_types_defined_by<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
item: LocalDefId, item: LocalDefId,
@ -321,5 +409,6 @@ fn opaque_types_defined_by<'tcx>(
} }
pub(super) fn provide(providers: &mut Providers) { pub(super) fn provide(providers: &mut Providers) {
*providers = Providers { opaque_types_defined_by, ..*providers }; *providers =
Providers { opaque_types_defined_by, impl_trait_in_assoc_types_defined_by, ..*providers };
} }

View File

@ -0,0 +1,13 @@
use std::convert::identity;
fn test<'a: 'a>(n: bool) -> impl Sized + 'a {
//~^ ERROR concrete type differs from previous defining opaque type use
let true = n else { loop {} };
let _ = || {
let _ = identity::<&'a ()>(test(false));
//~^ ERROR hidden type for `impl Sized + 'a` captures lifetime that does not appear in bounds
};
loop {}
}
fn main() {}

View File

@ -0,0 +1,26 @@
error[E0700]: hidden type for `impl Sized + 'a` captures lifetime that does not appear in bounds
--> $DIR/early_bound.rs:7:17
|
LL | fn test<'a: 'a>(n: bool) -> impl Sized + 'a {
| -- --------------- opaque type defined here
| |
| hidden type `&'a ()` captures the lifetime `'a` as defined here
...
LL | let _ = identity::<&'a ()>(test(false));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: concrete type differs from previous defining opaque type use
--> $DIR/early_bound.rs:3:29
|
LL | fn test<'a: 'a>(n: bool) -> impl Sized + 'a {
| ^^^^^^^^^^^^^^^ expected `&()`, got `()`
|
note: previous use here
--> $DIR/early_bound.rs:7:36
|
LL | let _ = identity::<&'a ()>(test(false));
| ^^^^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0700`.

View File

@ -1,9 +1,8 @@
//! This test shows that we can even follow projections //! This test shows that we do not treat opaque types
//! into associated types of the same impl if they are //! as defined by a method if the opaque type is
//! indirectly mentioned in a struct field. //! only indirectly mentioned in a struct field.
#![feature(impl_trait_in_assoc_type)] #![feature(impl_trait_in_assoc_type)]
// check-pass
struct Bar; struct Bar;
@ -16,6 +15,7 @@ impl Trait for Bar {
type Assoc = impl std::fmt::Debug; type Assoc = impl std::fmt::Debug;
fn foo() -> Foo { fn foo() -> Foo {
Foo { field: () } Foo { field: () }
//~^ ERROR: item constrains opaque type that is not in its signature
} }
} }

View File

@ -0,0 +1,15 @@
error: item constrains opaque type that is not in its signature
--> $DIR/hidden_behind_struct_field2.rs:17:22
|
LL | Foo { field: () }
| ^^
|
= note: this item must mention the opaque type in its signature in order to be able to register hidden types
note: this item must mention the opaque type in its signature in order to be able to register hidden types
--> $DIR/hidden_behind_struct_field2.rs:16:8
|
LL | fn foo() -> Foo {
| ^^^
error: aborting due to 1 previous error

View File

@ -0,0 +1,38 @@
//! Check that we cannot instantiate a hidden type in the body
//! of an assoc fn or const unless mentioned in the signature.
#![feature(impl_trait_in_assoc_type)]
trait Trait: Sized {
type Assoc;
fn foo();
fn bar() -> Self::Assoc;
}
impl Trait for () {
type Assoc = impl std::fmt::Debug;
fn foo() {
let x: Self::Assoc = 42; //~ ERROR: mismatched types
}
fn bar() -> Self::Assoc {
""
}
}
trait Trait2: Sized {
type Assoc;
const FOO: ();
fn bar() -> Self::Assoc;
}
impl Trait2 for () {
type Assoc = impl std::fmt::Debug;
const FOO: () = {
let x: Self::Assoc = 42; //~ ERROR: mismatched types
};
fn bar() -> Self::Assoc {
""
}
}
fn main() {}

View File

@ -0,0 +1,41 @@
error[E0308]: mismatched types
--> $DIR/impl_trait_in_trait_defined_outside_trait.rs:15:30
|
LL | type Assoc = impl std::fmt::Debug;
| -------------------- the expected opaque type
LL | fn foo() {
LL | let x: Self::Assoc = 42;
| ----------- ^^ expected opaque type, found integer
| |
| expected due to this
|
= note: expected opaque type `<() as Trait>::Assoc`
found type `{integer}`
note: this item must have the opaque type in its signature in order to be able to register hidden types
--> $DIR/impl_trait_in_trait_defined_outside_trait.rs:14:8
|
LL | fn foo() {
| ^^^
error[E0308]: mismatched types
--> $DIR/impl_trait_in_trait_defined_outside_trait.rs:31:30
|
LL | type Assoc = impl std::fmt::Debug;
| -------------------- the expected opaque type
LL | const FOO: () = {
LL | let x: Self::Assoc = 42;
| ----------- ^^ expected opaque type, found integer
| |
| expected due to this
|
= note: expected opaque type `<() as Trait2>::Assoc`
found type `{integer}`
note: this item must have the opaque type in its signature in order to be able to register hidden types
--> $DIR/impl_trait_in_trait_defined_outside_trait.rs:30:11
|
LL | const FOO: () = {
| ^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -0,0 +1,22 @@
//! Check that we cannot instantiate a hidden type from another assoc type.
#![feature(impl_trait_in_assoc_type)]
trait Trait: Sized {
type Assoc;
type Foo;
fn foo() -> Self::Assoc;
}
impl Trait for () {
type Assoc = impl std::fmt::Debug;
type Foo = [(); {
let x: Self::Assoc = 42; //~ ERROR: mismatched types
3
}];
fn foo() -> Self::Assoc {
""
}
}
fn main() {}

View File

@ -0,0 +1,17 @@
error[E0308]: mismatched types
--> $DIR/impl_trait_in_trait_defined_outside_trait2.rs:14:30
|
LL | type Assoc = impl std::fmt::Debug;
| -------------------- the expected opaque type
LL | type Foo = [(); {
LL | let x: Self::Assoc = 42;
| ----------- ^^ expected opaque type, found integer
| |
| expected due to this
|
= note: expected opaque type `<() as Trait>::Assoc`
found type `{integer}`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.

View File

@ -0,0 +1,38 @@
//! Check that non-defining assoc items can use the opaque type
//! opaquely.
// check-pass
#![feature(impl_trait_in_assoc_type)]
trait Trait: Sized {
type Assoc;
fn foo();
fn bar() -> Self::Assoc;
}
impl Trait for () {
type Assoc = impl std::fmt::Debug;
fn foo() {
let x: Self::Assoc = Self::bar();
}
fn bar() -> Self::Assoc {
""
}
}
trait Trait2: Sized {
type Assoc;
const FOO: ();
const BAR: Self::Assoc;
}
impl Trait2 for () {
type Assoc = impl Copy;
const FOO: () = {
let x: Self::Assoc = Self::BAR;
};
const BAR: Self::Assoc = "";
}
fn main() {}

View File

@ -0,0 +1,17 @@
#![feature(impl_trait_in_assoc_type)]
trait Foo {
type Assoc<'a, 'b>;
fn bar<'a: 'a, 'b: 'b>(_: &'a ()) -> Self::Assoc<'a, 'b>;
}
impl Foo for () {
type Assoc<'a, 'b> = impl Sized;
fn bar<'a: 'a, 'b: 'b>(x: &'a ()) -> Self::Assoc<'a, 'b> {
let closure = |x: &'a ()| -> Self::Assoc<'b, 'a> { x };
//~^ ERROR `<() as Foo>::Assoc<'b, 'a>` captures lifetime that does not appear in bounds
x
}
}
fn main() {}

View File

@ -0,0 +1,13 @@
error[E0700]: hidden type for `<() as Foo>::Assoc<'b, 'a>` captures lifetime that does not appear in bounds
--> $DIR/in-assoc-ty-early-bound.rs:11:60
|
LL | type Assoc<'a, 'b> = impl Sized;
| ---------- opaque type defined here
LL | fn bar<'a: 'a, 'b: 'b>(x: &'a ()) -> Self::Assoc<'a, 'b> {
| -- hidden type `&'a ()` captures the lifetime `'a` as defined here
LL | let closure = |x: &'a ()| -> Self::Assoc<'b, 'a> { x };
| ^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0700`.

View File

@ -0,0 +1,21 @@
#![feature(impl_trait_in_assoc_type)]
trait Foo {
type Assoc<'a>;
fn bar<'a: 'a>();
}
impl Foo for () {
type Assoc<'a> = impl Sized; //~ ERROR unconstrained opaque type
fn bar<'a: 'a>()
where
Self::Assoc<'a>:,
{
let _ = |x: &'a ()| {
let _: Self::Assoc<'a> = x;
//~^ ERROR `<() as Foo>::Assoc<'a>` captures lifetime that does not appear in bound
};
}
}
fn main() {}

View File

@ -0,0 +1,22 @@
error[E0700]: hidden type for `<() as Foo>::Assoc<'a>` captures lifetime that does not appear in bounds
--> $DIR/in-assoc-ty-early-bound2.rs:15:20
|
LL | type Assoc<'a> = impl Sized;
| ---------- opaque type defined here
LL | fn bar<'a: 'a>()
| -- hidden type `&'a ()` captures the lifetime `'a` as defined here
...
LL | let _: Self::Assoc<'a> = x;
| ^^^^^^^^^^^^^^^
error: unconstrained opaque type
--> $DIR/in-assoc-ty-early-bound2.rs:9:22
|
LL | type Assoc<'a> = impl Sized;
| ^^^^^^^^^^
|
= note: `Assoc` must be used in combination with a concrete type within the same impl
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0700`.

View File

@ -0,0 +1,23 @@
error[E0308]: mismatched types
--> $DIR/itiat-allow-nested-closures.rs:21:22
|
LL | type Assoc = impl Sized;
| ---------- the found opaque type
...
LL | let _: i32 = closure();
| --- ^^^^^^^^^ expected `i32`, found opaque type
| |
| expected due to this
error[E0308]: mismatched types
--> $DIR/itiat-allow-nested-closures.rs:22:9
|
LL | fn bar() -> Self::Assoc {
| ----------- expected `()` because of return type
...
LL | 1i32
| ^^^^ expected `()`, found `i32`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -0,0 +1,26 @@
#![feature(impl_trait_in_assoc_type)]
// revisions: ok bad
// [ok] check-pass
trait Foo {
type Assoc;
fn bar() -> Self::Assoc;
}
impl Foo for () {
type Assoc = impl Sized;
fn bar() -> Self::Assoc {
let closure = || -> Self::Assoc {
#[cfg(ok)]
let x: Self::Assoc = 42_i32;
#[cfg(bad)]
let x: Self::Assoc = ();
x
};
let _: i32 = closure(); //[bad]~ ERROR mismatched types
1i32 //[bad]~ ERROR mismatched types
}
}
fn main() {}

View File

@ -0,0 +1,20 @@
#![feature(impl_trait_in_assoc_type)]
trait Foo {
type Assoc;
fn bar() -> Self::Assoc;
}
impl Foo for () {
type Assoc = impl Sized;
fn bar() -> Self::Assoc {
fn foo() -> <() as Foo>::Assoc {
let x: <() as Foo>::Assoc = 42_i32; //~ ERROR mismatched types
x
};
let _: i32 = foo();
1i32
}
}
fn main() {}

View File

@ -0,0 +1,22 @@
error[E0308]: mismatched types
--> $DIR/itiat-forbid-nested-items.rs:12:41
|
LL | type Assoc = impl Sized;
| ---------- the expected opaque type
...
LL | let x: <() as Foo>::Assoc = 42_i32;
| ------------------ ^^^^^^ expected opaque type, found `i32`
| |
| expected due to this
|
= note: expected opaque type `<() as Foo>::Assoc`
found type `i32`
note: this item must have the opaque type in its signature in order to be able to register hidden types
--> $DIR/itiat-forbid-nested-items.rs:11:12
|
LL | fn foo() -> <() as Foo>::Assoc {
| ^^^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.