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:
commit
5da220a095
@ -530,9 +530,13 @@ pub(super) fn type_of_opaque(
|
||||
Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id) {
|
||||
Node::Item(item) => match item.kind {
|
||||
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),
|
||||
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`.
|
||||
ItemKind::OpaqueTy(&OpaqueTy {
|
||||
origin:
|
||||
|
@ -23,6 +23,60 @@ pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed>
|
||||
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
|
||||
/// laid for "higher-order pattern unification".
|
||||
/// This ensures that inference is tractable.
|
||||
@ -128,9 +182,15 @@ struct TaitConstraintLocator<'tcx> {
|
||||
typeck_types: Vec<ty::OpaqueHiddenType<'tcx>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ImplTraitSource {
|
||||
AssocTy,
|
||||
TyAlias,
|
||||
}
|
||||
|
||||
impl TaitConstraintLocator<'_> {
|
||||
#[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.
|
||||
if !self.tcx.has_typeck_results(item_def_id) {
|
||||
debug!("no constraint: no typeck results");
|
||||
@ -182,7 +242,13 @@ fn check(&mut self, item_def_id: LocalDefId) {
|
||||
continue;
|
||||
}
|
||||
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 {
|
||||
span: hidden_type.span,
|
||||
item_span: self
|
||||
@ -240,7 +306,7 @@ fn nested_visit_map(&mut self) -> Self::Map {
|
||||
}
|
||||
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
|
||||
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);
|
||||
}
|
||||
@ -248,7 +314,7 @@ fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
|
||||
trace!(?it.owner_id);
|
||||
// The opaque type itself or its children are not within its reveal scope.
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -256,13 +322,13 @@ fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
|
||||
trace!(?it.owner_id);
|
||||
// The opaque type itself or its children are not within its reveal scope.
|
||||
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);
|
||||
}
|
||||
}
|
||||
fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
|
||||
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);
|
||||
}
|
||||
fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) {
|
||||
|
@ -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
|
||||
/// `SelectionCandidate::ProjectionCandidate(_)` and
|
||||
/// `ProjectionTyCandidate::TraitDef`.
|
||||
|
@ -118,6 +118,69 @@ fn visit_nested_body(&mut self, id: rustc_hir::BodyId) {
|
||||
}
|
||||
TaitInBodyFinder { collector: self }.visit_expr(body);
|
||||
}
|
||||
|
||||
fn visit_opaque_ty(&mut self, alias_ty: &ty::AliasTy<'tcx>) {
|
||||
if !self.seen.insert(alias_ty.def_id.expect_local()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TAITs outside their defining scopes are ignored.
|
||||
let origin = self.tcx.opaque_type_origin(alias_ty.def_id.expect_local());
|
||||
trace!(?origin);
|
||||
match origin {
|
||||
rustc_hir::OpaqueTyOrigin::FnReturn(_) | rustc_hir::OpaqueTyOrigin::AsyncFn(_) => {}
|
||||
rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => {
|
||||
if !in_assoc_ty {
|
||||
if !self.check_tait_defining_scope(alias_ty.def_id.expect_local()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.opaques.push(alias_ty.def_id.expect_local());
|
||||
|
||||
let parent_count = self.tcx.generics_of(alias_ty.def_id).parent_count;
|
||||
// Only check that the parent generics of the TAIT/RPIT are unique.
|
||||
// the args owned by the opaque are going to always be duplicate
|
||||
// lifetime params for RPITs, and empty for TAITs.
|
||||
match self
|
||||
.tcx
|
||||
.uses_unique_generic_params(&alias_ty.args[..parent_count], CheckRegions::FromFunction)
|
||||
{
|
||||
Ok(()) => {
|
||||
// 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
|
||||
// start seeing the error below.
|
||||
|
||||
// Collect opaque types nested within the associated type bounds of this opaque type.
|
||||
// We use identity args here, because we already know that the opaque type uses
|
||||
// only generic parameters, and thus substituting would not give us more information.
|
||||
for (pred, span) in self
|
||||
.tcx
|
||||
.explicit_item_bounds(alias_ty.def_id)
|
||||
.instantiate_identity_iter_copied()
|
||||
{
|
||||
trace!(?pred);
|
||||
self.visit_spanned(span, pred);
|
||||
}
|
||||
}
|
||||
Err(NotUniqueParam::NotParam(arg)) => {
|
||||
self.tcx.dcx().emit_err(NotParam {
|
||||
arg,
|
||||
span: self.span(),
|
||||
opaque_span: self.tcx.def_span(alias_ty.def_id),
|
||||
});
|
||||
}
|
||||
Err(NotUniqueParam::DuplicateParam(arg)) => {
|
||||
self.tcx.dcx().emit_err(DuplicateArg {
|
||||
arg,
|
||||
span: self.span(),
|
||||
opaque_span: self.tcx.def_span(alias_ty.def_id),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> super::sig_types::SpannedTypeVisitor<'tcx> for OpaqueTypeCollector<'tcx> {
|
||||
@ -134,67 +197,7 @@ 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()) {
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
// TAITs outside their defining scopes are ignored.
|
||||
let origin = self.tcx.opaque_type_origin(alias_ty.def_id.expect_local());
|
||||
trace!(?origin);
|
||||
match origin {
|
||||
rustc_hir::OpaqueTyOrigin::FnReturn(_)
|
||||
| rustc_hir::OpaqueTyOrigin::AsyncFn(_) => {}
|
||||
rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => {
|
||||
if !in_assoc_ty {
|
||||
if !self.check_tait_defining_scope(alias_ty.def_id.expect_local()) {
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.opaques.push(alias_ty.def_id.expect_local());
|
||||
|
||||
let parent_count = self.tcx.generics_of(alias_ty.def_id).parent_count;
|
||||
// Only check that the parent generics of the TAIT/RPIT are unique.
|
||||
// the args owned by the opaque are going to always be duplicate
|
||||
// lifetime params for RPITs, and empty for TAITs.
|
||||
match self.tcx.uses_unique_generic_params(
|
||||
&alias_ty.args[..parent_count],
|
||||
CheckRegions::FromFunction,
|
||||
) {
|
||||
Ok(()) => {
|
||||
// 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
|
||||
// start seeing the error below.
|
||||
|
||||
// Collect opaque types nested within the associated type bounds of this opaque type.
|
||||
// We use identity args here, because we already know that the opaque type uses
|
||||
// only generic parameters, and thus substituting would not give us more information.
|
||||
for (pred, span) in self
|
||||
.tcx
|
||||
.explicit_item_bounds(alias_ty.def_id)
|
||||
.instantiate_identity_iter_copied()
|
||||
{
|
||||
trace!(?pred);
|
||||
self.visit_spanned(span, pred);
|
||||
}
|
||||
}
|
||||
Err(NotUniqueParam::NotParam(arg)) => {
|
||||
self.tcx.dcx().emit_err(NotParam {
|
||||
arg,
|
||||
span: self.span(),
|
||||
opaque_span: self.tcx.def_span(alias_ty.def_id),
|
||||
});
|
||||
}
|
||||
Err(NotUniqueParam::DuplicateParam(arg)) => {
|
||||
self.tcx.dcx().emit_err(DuplicateArg {
|
||||
arg,
|
||||
span: self.span(),
|
||||
opaque_span: self.tcx.def_span(alias_ty.def_id),
|
||||
});
|
||||
}
|
||||
}
|
||||
self.visit_opaque_ty(alias_ty);
|
||||
}
|
||||
ty::Alias(ty::Weak, alias_ty) if alias_ty.def_id.is_local() => {
|
||||
self.tcx
|
||||
@ -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>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
item: LocalDefId,
|
||||
@ -321,5 +409,6 @@ fn opaque_types_defined_by<'tcx>(
|
||||
}
|
||||
|
||||
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 };
|
||||
}
|
||||
|
13
tests/ui/impl-trait/rpit/early_bound.rs
Normal file
13
tests/ui/impl-trait/rpit/early_bound.rs
Normal 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() {}
|
26
tests/ui/impl-trait/rpit/early_bound.stderr
Normal file
26
tests/ui/impl-trait/rpit/early_bound.stderr
Normal 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`.
|
@ -1,9 +1,8 @@
|
||||
//! This test shows that we can even follow projections
|
||||
//! into associated types of the same impl if they are
|
||||
//! indirectly mentioned in a struct field.
|
||||
//! This test shows that we do not treat opaque types
|
||||
//! as defined by a method if the opaque type is
|
||||
//! only indirectly mentioned in a struct field.
|
||||
|
||||
#![feature(impl_trait_in_assoc_type)]
|
||||
// check-pass
|
||||
|
||||
struct Bar;
|
||||
|
||||
@ -16,6 +15,7 @@ impl Trait for Bar {
|
||||
type Assoc = impl std::fmt::Debug;
|
||||
fn foo() -> Foo {
|
||||
Foo { field: () }
|
||||
//~^ ERROR: item constrains opaque type that is not in its signature
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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() {}
|
@ -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`.
|
@ -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() {}
|
@ -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`.
|
@ -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() {}
|
17
tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound.rs
Normal file
17
tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound.rs
Normal 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() {}
|
@ -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`.
|
21
tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound2.rs
Normal file
21
tests/ui/type-alias-impl-trait/in-assoc-ty-early-bound2.rs
Normal 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() {}
|
@ -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`.
|
@ -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`.
|
@ -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() {}
|
20
tests/ui/type-alias-impl-trait/itiat-forbid-nested-items.rs
Normal file
20
tests/ui/type-alias-impl-trait/itiat-forbid-nested-items.rs
Normal 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() {}
|
@ -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`.
|
Loading…
Reference in New Issue
Block a user