Rollup merge of #110454 - oli-obk:limited_impl_trait_in_assoc_type, r=compiler-errors
Require impl Trait in associated types to appear in method signatures This implements the limited version of TAIT that was proposed in https://github.com/rust-lang/rust/issues/107645#issuecomment-1477899536 Similar to `impl Trait` in return types, `impl Trait` in associated types may only be used within the impl block which it is a part of. To make everything simpler and forward compatible to getting desugared to a plain type alias impl trait in the future, we're requiring that any associated functions or constants that want to register hidden types must be using the associated type in their signature (type of the constant or argument/return type of the associated method. Where bounds mentioning the associated type are ignored). We have preexisting tests checking that this works transitively across multiple associated types in situations like ```rust impl Foo for Bar { type A = impl Trait; type B = impl Iterator<Item = Self::A>; fn foo() -> Self::B { ...... } } ```
This commit is contained in:
commit
6cb13585d0
@ -305,7 +305,10 @@ fn lower_item_kind(
|
||||
);
|
||||
this.arena.alloc(this.ty(span, hir::TyKind::Err(guar)))
|
||||
}
|
||||
Some(ty) => this.lower_ty(ty, &ImplTraitContext::TypeAliasesOpaqueTy),
|
||||
Some(ty) => this.lower_ty(
|
||||
ty,
|
||||
&ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: false },
|
||||
),
|
||||
},
|
||||
);
|
||||
hir::ItemKind::TyAlias(ty, generics)
|
||||
@ -852,7 +855,10 @@ fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
|
||||
hir::ImplItemKind::Type(ty)
|
||||
}
|
||||
Some(ty) => {
|
||||
let ty = this.lower_ty(ty, &ImplTraitContext::TypeAliasesOpaqueTy);
|
||||
let ty = this.lower_ty(
|
||||
ty,
|
||||
&ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: true },
|
||||
);
|
||||
hir::ImplItemKind::Type(ty)
|
||||
}
|
||||
},
|
||||
|
@ -247,7 +247,7 @@ enum ImplTraitContext {
|
||||
in_trait: bool,
|
||||
},
|
||||
/// Impl trait in type aliases.
|
||||
TypeAliasesOpaqueTy,
|
||||
TypeAliasesOpaqueTy { in_assoc_ty: bool },
|
||||
/// `impl Trait` is unstably accepted in this position.
|
||||
FeatureGated(ImplTraitPosition, Symbol),
|
||||
/// `impl Trait` is not accepted in this position.
|
||||
@ -1407,14 +1407,15 @@ fn lower_ty_direct(&mut self, t: &Ty, itctx: &ImplTraitContext) -> hir::Ty<'hir>
|
||||
*in_trait,
|
||||
itctx,
|
||||
),
|
||||
ImplTraitContext::TypeAliasesOpaqueTy => self.lower_opaque_impl_trait(
|
||||
span,
|
||||
hir::OpaqueTyOrigin::TyAlias,
|
||||
*def_node_id,
|
||||
bounds,
|
||||
false,
|
||||
itctx,
|
||||
),
|
||||
&ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty } => self
|
||||
.lower_opaque_impl_trait(
|
||||
span,
|
||||
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty },
|
||||
*def_node_id,
|
||||
bounds,
|
||||
false,
|
||||
itctx,
|
||||
),
|
||||
ImplTraitContext::Universal => {
|
||||
let span = t.span;
|
||||
self.create_def(
|
||||
@ -1534,13 +1535,16 @@ fn lower_opaque_impl_trait(
|
||||
// If this came from a TAIT (as opposed to a function that returns an RPIT), we only want
|
||||
// to capture the lifetimes that appear in the bounds. So visit the bounds to find out
|
||||
// exactly which ones those are.
|
||||
let lifetimes_to_remap = if origin == hir::OpaqueTyOrigin::TyAlias {
|
||||
// in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters
|
||||
Vec::new()
|
||||
} else {
|
||||
// in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
|
||||
// we only keep the lifetimes that appear in the `impl Debug` itself:
|
||||
lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds)
|
||||
let lifetimes_to_remap = match origin {
|
||||
hir::OpaqueTyOrigin::TyAlias { .. } => {
|
||||
// in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters
|
||||
Vec::new()
|
||||
}
|
||||
hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..) => {
|
||||
// in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
|
||||
// we only keep the lifetimes that appear in the `impl Debug` itself:
|
||||
lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds)
|
||||
}
|
||||
};
|
||||
debug!(?lifetimes_to_remap);
|
||||
|
||||
|
@ -265,7 +265,7 @@ fn infer_opaque_definition_from_instantiation(
|
||||
|
||||
// Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs`
|
||||
// on stable and we'd break that.
|
||||
let OpaqueTyOrigin::TyAlias = origin else {
|
||||
let OpaqueTyOrigin::TyAlias { .. } = origin else {
|
||||
return definition_ty;
|
||||
};
|
||||
let def_id = opaque_type_key.def_id;
|
||||
@ -360,7 +360,7 @@ fn check_opaque_type_parameter_valid(
|
||||
// which would error here on all of the `'static` args.
|
||||
OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return Ok(()),
|
||||
// Check these
|
||||
OpaqueTyOrigin::TyAlias => {}
|
||||
OpaqueTyOrigin::TyAlias { .. } => {}
|
||||
}
|
||||
let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
|
||||
let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();
|
||||
|
@ -2662,7 +2662,10 @@ pub enum OpaqueTyOrigin {
|
||||
/// `async fn`
|
||||
AsyncFn(LocalDefId),
|
||||
/// type aliases: `type Foo = impl Trait;`
|
||||
TyAlias,
|
||||
TyAlias {
|
||||
/// associated types in impl blocks for traits.
|
||||
in_assoc_ty: bool,
|
||||
},
|
||||
}
|
||||
|
||||
/// The various kinds of types recognized by the compiler.
|
||||
|
@ -397,7 +397,7 @@ fn check_opaque_meets_bounds<'tcx>(
|
||||
) {
|
||||
let defining_use_anchor = match *origin {
|
||||
hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
|
||||
hir::OpaqueTyOrigin::TyAlias => def_id,
|
||||
hir::OpaqueTyOrigin::TyAlias { .. } => tcx.impl_trait_parent(def_id),
|
||||
};
|
||||
let param_env = tcx.param_env(defining_use_anchor);
|
||||
|
||||
@ -455,10 +455,10 @@ fn check_opaque_meets_bounds<'tcx>(
|
||||
// They can only be referenced as `<Opaque<T> as Trait<&'static T>>::AssocTy`.
|
||||
// We don't have to check them here because their well-formedness follows from the WF of
|
||||
// the projection input types in the defining- and use-sites.
|
||||
hir::OpaqueTyOrigin::TyAlias
|
||||
hir::OpaqueTyOrigin::TyAlias { .. }
|
||||
if tcx.def_kind(tcx.parent(def_id.to_def_id())) == DefKind::OpaqueTy => {}
|
||||
// Can have different predicates to their defining use
|
||||
hir::OpaqueTyOrigin::TyAlias => {
|
||||
hir::OpaqueTyOrigin::TyAlias { .. } => {
|
||||
let wf_tys = ocx.assumed_wf_types(param_env, span, def_id);
|
||||
let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, wf_tys);
|
||||
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
||||
|
@ -6,7 +6,7 @@
|
||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_middle::ty::util::IgnoreRegions;
|
||||
use rustc_middle::ty::util::CheckRegions;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_trait_selection::traits::{self, ObligationCtxt};
|
||||
|
||||
@ -81,7 +81,7 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
|
||||
self_type_did: DefId,
|
||||
adt_to_impl_substs: SubstsRef<'tcx>,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let Err(arg) = tcx.uses_unique_generic_params(adt_to_impl_substs, IgnoreRegions::No) else {
|
||||
let Err(arg) = tcx.uses_unique_generic_params(adt_to_impl_substs, CheckRegions::OnlyEarlyBound) else {
|
||||
return Ok(())
|
||||
};
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
use rustc_errors::{Diagnostic, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::ty::subst::InternalSubsts;
|
||||
use rustc_middle::ty::util::IgnoreRegions;
|
||||
use rustc_middle::ty::util::CheckRegions;
|
||||
use rustc_middle::ty::{
|
||||
self, AliasKind, ImplPolarity, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
|
||||
TypeVisitor,
|
||||
@ -507,7 +507,7 @@ fn lint_auto_trait_impl<'tcx>(
|
||||
// Impls which completely cover a given root type are fine as they
|
||||
// disable auto impls entirely. So only lint if the substs
|
||||
// are not a permutation of the identity substs.
|
||||
let Err(arg) = tcx.uses_unique_generic_params(substs, IgnoreRegions::Yes) else {
|
||||
let Err(arg) = tcx.uses_unique_generic_params(substs, CheckRegions::No) else {
|
||||
// ok
|
||||
return;
|
||||
};
|
||||
|
@ -1483,7 +1483,7 @@ fn generator_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<hir::GeneratorK
|
||||
fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
|
||||
match tcx.hir().get_by_def_id(def_id) {
|
||||
Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. }) => {
|
||||
matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias)
|
||||
matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. })
|
||||
}
|
||||
_ => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id),
|
||||
}
|
||||
|
@ -159,7 +159,10 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
||||
}
|
||||
Some(fn_def_id.to_def_id())
|
||||
}
|
||||
ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
|
||||
ItemKind::OpaqueTy(hir::OpaqueTy {
|
||||
origin: hir::OpaqueTyOrigin::TyAlias { .. },
|
||||
..
|
||||
}) => {
|
||||
let parent_id = tcx.hir().get_parent_item(hir_id);
|
||||
assert_ne!(parent_id, hir::CRATE_OWNER_ID);
|
||||
debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id);
|
||||
|
@ -721,7 +721,7 @@ pub(super) fn type_param_predicates(
|
||||
| ItemKind::TyAlias(_, generics)
|
||||
| ItemKind::OpaqueTy(OpaqueTy {
|
||||
generics,
|
||||
origin: hir::OpaqueTyOrigin::TyAlias,
|
||||
origin: hir::OpaqueTyOrigin::TyAlias { .. },
|
||||
..
|
||||
})
|
||||
| ItemKind::Enum(_, generics)
|
||||
|
@ -526,7 +526,8 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
|
||||
});
|
||||
}
|
||||
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
|
||||
origin: hir::OpaqueTyOrigin::TyAlias, ..
|
||||
origin: hir::OpaqueTyOrigin::TyAlias { .. },
|
||||
..
|
||||
}) => {
|
||||
// Opaque types are visited when we visit the
|
||||
// `TyKind::OpaqueDef`, so that they have the lifetimes from
|
||||
@ -707,7 +708,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
|
||||
let opaque_ty = self.tcx.hir().item(item_id);
|
||||
match &opaque_ty.kind {
|
||||
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
|
||||
origin: hir::OpaqueTyOrigin::TyAlias,
|
||||
origin: hir::OpaqueTyOrigin::TyAlias { .. },
|
||||
..
|
||||
}) => {
|
||||
intravisit::walk_ty(self, ty);
|
||||
|
@ -426,9 +426,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
|
||||
let substs = InternalSubsts::identity_for_item(tcx, def_id);
|
||||
tcx.mk_adt(def, substs)
|
||||
}
|
||||
ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
|
||||
find_opaque_ty_constraints_for_tait(tcx, def_id)
|
||||
}
|
||||
ItemKind::OpaqueTy(OpaqueTy {
|
||||
origin: hir::OpaqueTyOrigin::TyAlias { .. },
|
||||
..
|
||||
}) => find_opaque_ty_constraints_for_tait(tcx, def_id),
|
||||
// Opaque types desugared from `impl Trait`.
|
||||
ItemKind::OpaqueTy(OpaqueTy {
|
||||
origin:
|
||||
|
@ -2,6 +2,7 @@
|
||||
use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
|
||||
use rustc_errors::{pluralize, Diagnostic, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_middle::traits::ObligationCauseCode;
|
||||
use rustc_middle::ty::error::ExpectedFound;
|
||||
use rustc_middle::ty::print::Printer;
|
||||
@ -256,6 +257,15 @@ fn foo(&self, x: T) -> T { x }
|
||||
);
|
||||
}
|
||||
}
|
||||
(ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if alias.def_id.is_local() && matches!(tcx.def_kind(body_owner_def_id), DefKind::AssocFn | DefKind::AssocConst) => {
|
||||
if tcx.is_type_alias_impl_trait(alias.def_id) {
|
||||
if !tcx.opaque_types_defined_by(body_owner_def_id.expect_local()).contains(&alias.def_id.expect_local()) {
|
||||
diag.span_note(tcx.def_span(body_owner_def_id), "\
|
||||
this item must have the opaque type in its signature \
|
||||
in order to be able to register hidden types");
|
||||
}
|
||||
}
|
||||
}
|
||||
(ty::FnPtr(_), ty::FnDef(def, _))
|
||||
if let hir::def::DefKind::Fn = tcx.def_kind(def) => {
|
||||
diag.note(
|
||||
|
@ -149,7 +149,7 @@ pub fn handle_opaque_type(
|
||||
// no one encounters it in practice.
|
||||
// It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`,
|
||||
// where it is of no concern, so we only check for TAITs.
|
||||
if let Some(OpaqueTyOrigin::TyAlias) =
|
||||
if let Some(OpaqueTyOrigin::TyAlias { .. }) =
|
||||
b_def_id.as_local().and_then(|b_def_id| self.opaque_type_origin(b_def_id))
|
||||
{
|
||||
self.tcx.sess.emit_err(OpaqueHiddenTypeDiag {
|
||||
@ -381,8 +381,12 @@ pub fn opaque_type_origin(&self, def_id: LocalDefId) -> Option<OpaqueTyOrigin> {
|
||||
// Anonymous `impl Trait`
|
||||
hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
|
||||
// Named `type Foo = impl Bar;`
|
||||
hir::OpaqueTyOrigin::TyAlias => {
|
||||
may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id)
|
||||
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => {
|
||||
if in_assoc_ty {
|
||||
self.tcx.opaque_types_defined_by(parent_def_id).contains(&def_id)
|
||||
} else {
|
||||
may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id)
|
||||
}
|
||||
}
|
||||
};
|
||||
in_definition_scope.then_some(origin)
|
||||
|
@ -1641,9 +1641,10 @@ fn encode_info_for_item(&mut self, item: &'tcx hir::Item<'tcx>) {
|
||||
}
|
||||
hir::ItemKind::OpaqueTy(ref opaque) => {
|
||||
self.encode_explicit_item_bounds(def_id);
|
||||
self.tables
|
||||
.is_type_alias_impl_trait
|
||||
.set(def_id.index, matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias));
|
||||
self.tables.is_type_alias_impl_trait.set(
|
||||
def_id.index,
|
||||
matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. }),
|
||||
);
|
||||
}
|
||||
hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
|
||||
self.tables.impl_defaultness.set_some(def_id.index, *defaultness);
|
||||
|
@ -172,6 +172,10 @@ impl EraseType for ty::Binder<'_, ty::FnSig<'_>> {
|
||||
type Result = [u8; size_of::<ty::Binder<'static, ty::FnSig<'static>>>()];
|
||||
}
|
||||
|
||||
impl EraseType for ty::Binder<'_, &'_ ty::List<Ty<'_>>> {
|
||||
type Result = [u8; size_of::<ty::Binder<'static, &'static ty::List<Ty<'static>>>>()];
|
||||
}
|
||||
|
||||
impl<T0, T1> EraseType for (&'_ T0, &'_ T1) {
|
||||
type Result = [u8; size_of::<(&'static (), &'static ())>()];
|
||||
}
|
||||
|
@ -236,6 +236,15 @@
|
||||
cache_on_disk_if { key.is_local() }
|
||||
}
|
||||
|
||||
query opaque_types_defined_by(
|
||||
key: LocalDefId
|
||||
) -> &'tcx [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`.
|
||||
|
@ -2476,6 +2476,18 @@ pub fn impl_trait_in_trait_parent_fn(self, mut def_id: DefId) -> DefId {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the `DefId` of the item within which the `impl Trait` is declared.
|
||||
/// For type-alias-impl-trait this is the `type` alias.
|
||||
/// For impl-trait-in-assoc-type this is the assoc type.
|
||||
/// For return-position-impl-trait this is the function.
|
||||
pub fn impl_trait_parent(self, mut def_id: LocalDefId) -> LocalDefId {
|
||||
// Find the surrounding item (type alias or assoc type)
|
||||
while let DefKind::OpaqueTy = self.def_kind(def_id) {
|
||||
def_id = self.local_parent(def_id);
|
||||
}
|
||||
def_id
|
||||
}
|
||||
|
||||
pub fn impl_method_has_trait_impl_trait_tys(self, def_id: DefId) -> bool {
|
||||
if self.def_kind(def_id) != DefKind::AssocFn {
|
||||
return false;
|
||||
@ -2520,7 +2532,7 @@ pub fn is_impl_trait_defn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<LocalDefId>
|
||||
hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent) => {
|
||||
Some(parent)
|
||||
}
|
||||
hir::OpaqueTyOrigin::TyAlias => None,
|
||||
hir::OpaqueTyOrigin::TyAlias { .. } => None,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
///
|
||||
/// This should only be used outside of type inference. For example,
|
||||
/// it assumes that normalization will succeed.
|
||||
#[tracing::instrument(level = "debug", skip(self, param_env))]
|
||||
#[tracing::instrument(level = "debug", skip(self, param_env), ret)]
|
||||
pub fn normalize_erasing_regions<T>(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
|
@ -1265,7 +1265,7 @@ pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
|
||||
|
||||
/// Extracts the underlying trait reference and own substs from this projection.
|
||||
/// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
|
||||
/// then this function would return a `T: Iterator` trait reference and `['a]` as the own substs
|
||||
/// then this function would return a `T: StreamingIterator` trait reference and `['a]` as the own substs
|
||||
pub fn trait_ref_and_own_substs(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
@ -34,9 +34,14 @@ pub struct Discr<'tcx> {
|
||||
|
||||
/// Used as an input to [`TyCtxt::uses_unique_generic_params`].
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum IgnoreRegions {
|
||||
Yes,
|
||||
pub enum CheckRegions {
|
||||
No,
|
||||
/// Only permit early bound regions. This is useful for Adts which
|
||||
/// can never have late bound regions.
|
||||
OnlyEarlyBound,
|
||||
/// Permit both late bound and early bound regions. Use this for functions,
|
||||
/// which frequently have late bound regions.
|
||||
Bound,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
@ -468,21 +473,28 @@ pub fn destructor_constraints(self, def: ty::AdtDef<'tcx>) -> Vec<ty::subst::Gen
|
||||
pub fn uses_unique_generic_params(
|
||||
self,
|
||||
substs: SubstsRef<'tcx>,
|
||||
ignore_regions: IgnoreRegions,
|
||||
ignore_regions: CheckRegions,
|
||||
) -> Result<(), NotUniqueParam<'tcx>> {
|
||||
let mut seen = GrowableBitSet::default();
|
||||
let mut seen_late = FxHashSet::default();
|
||||
for arg in substs {
|
||||
match arg.unpack() {
|
||||
GenericArgKind::Lifetime(lt) => {
|
||||
if ignore_regions == IgnoreRegions::No {
|
||||
let ty::ReEarlyBound(p) = lt.kind() else {
|
||||
return Err(NotUniqueParam::NotParam(lt.into()))
|
||||
};
|
||||
GenericArgKind::Lifetime(lt) => match (ignore_regions, lt.kind()) {
|
||||
(CheckRegions::Bound, ty::ReLateBound(di, reg)) => {
|
||||
if !seen_late.insert((di, reg)) {
|
||||
return Err(NotUniqueParam::DuplicateParam(lt.into()));
|
||||
}
|
||||
}
|
||||
(CheckRegions::OnlyEarlyBound | CheckRegions::Bound, ty::ReEarlyBound(p)) => {
|
||||
if !seen.insert(p.index) {
|
||||
return Err(NotUniqueParam::DuplicateParam(lt.into()));
|
||||
}
|
||||
}
|
||||
}
|
||||
(CheckRegions::OnlyEarlyBound | CheckRegions::Bound, _) => {
|
||||
return Err(NotUniqueParam::NotParam(lt.into()));
|
||||
}
|
||||
(CheckRegions::No, _) => {}
|
||||
},
|
||||
GenericArgKind::Type(t) => match t.kind() {
|
||||
ty::Param(p) => {
|
||||
if !seen.insert(p.index) {
|
||||
|
@ -55,3 +55,11 @@ ty_utils_multiple_array_fields_simd_type = monomorphising SIMD type `{$ty}` with
|
||||
ty_utils_oversized_simd_type = monomorphising SIMD type `{$ty}` of length greater than {$max_lanes}
|
||||
|
||||
ty_utils_non_primitive_simd_type = monomorphising SIMD type `{$ty}` with a non-primitive-scalar (integer/float/pointer) element type `{$e_ty}`
|
||||
|
||||
ty_utils_impl_trait_duplicate_arg = non-defining opaque type use in defining scope
|
||||
.label = generic argument `{$arg}` used twice
|
||||
.note = for this opaque type
|
||||
|
||||
ty_utils_impl_trait_not_param = non-defining opaque type use in defining scope
|
||||
.label = argument `{$arg}` is not a generic parameter
|
||||
.note = for this opaque type
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Errors emitted by ty_utils
|
||||
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_middle::ty::{GenericArg, Ty};
|
||||
use rustc_span::Span;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
@ -100,3 +100,25 @@ pub struct NonPrimitiveSimdType<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
pub e_ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ty_utils_impl_trait_duplicate_arg)]
|
||||
pub struct DuplicateArg<'tcx> {
|
||||
pub arg: GenericArg<'tcx>,
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[note]
|
||||
pub opaque_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ty_utils_impl_trait_not_param)]
|
||||
pub struct NotParam<'tcx> {
|
||||
pub arg: GenericArg<'tcx>,
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[note]
|
||||
pub opaque_span: Span,
|
||||
}
|
||||
|
@ -33,6 +33,7 @@
|
||||
mod layout;
|
||||
mod layout_sanity_check;
|
||||
mod needs_drop;
|
||||
mod opaque_types;
|
||||
pub mod representability;
|
||||
mod structural_match;
|
||||
mod ty;
|
||||
@ -47,6 +48,7 @@ pub fn provide(providers: &mut Providers) {
|
||||
implied_bounds::provide(providers);
|
||||
layout::provide(providers);
|
||||
needs_drop::provide(providers);
|
||||
opaque_types::provide(providers);
|
||||
representability::provide(providers);
|
||||
ty::provide(providers);
|
||||
instance::provide(providers);
|
||||
|
197
compiler/rustc_ty_utils/src/opaque_types.rs
Normal file
197
compiler/rustc_ty_utils/src/opaque_types.rs
Normal file
@ -0,0 +1,197 @@
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::{def::DefKind, def_id::LocalDefId};
|
||||
use rustc_middle::ty::util::{CheckRegions, NotUniqueParam};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
|
||||
use rustc_span::Span;
|
||||
use rustc_type_ir::AliasKind;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use crate::errors::{DuplicateArg, NotParam};
|
||||
|
||||
struct OpaqueTypeCollector<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
opaques: Vec<LocalDefId>,
|
||||
/// The `DefId` of the item which we are collecting opaque types for.
|
||||
item: LocalDefId,
|
||||
|
||||
/// Avoid infinite recursion due to recursive declarations.
|
||||
seen: FxHashSet<LocalDefId>,
|
||||
}
|
||||
|
||||
impl<'tcx> OpaqueTypeCollector<'tcx> {
|
||||
fn collect(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
item: LocalDefId,
|
||||
val: ty::Binder<'tcx, impl TypeVisitable<TyCtxt<'tcx>>>,
|
||||
) -> Vec<LocalDefId> {
|
||||
let mut collector = Self { tcx, opaques: Vec::new(), item, seen: Default::default() };
|
||||
val.skip_binder().visit_with(&mut collector);
|
||||
collector.opaques
|
||||
}
|
||||
|
||||
fn span(&self) -> Span {
|
||||
self.tcx.def_span(self.item)
|
||||
}
|
||||
|
||||
fn parent(&self) -> Option<LocalDefId> {
|
||||
match self.tcx.def_kind(self.item) {
|
||||
DefKind::Fn => None,
|
||||
DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => {
|
||||
Some(self.tcx.local_parent(self.item))
|
||||
}
|
||||
other => span_bug!(
|
||||
self.tcx.def_span(self.item),
|
||||
"unhandled item with opaque types: {other:?}"
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
|
||||
type BreakTy = ErrorGuaranteed;
|
||||
|
||||
#[instrument(skip(self), ret, level = "trace")]
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<ErrorGuaranteed> {
|
||||
match t.kind() {
|
||||
ty::Alias(AliasKind::Opaque, alias_ty) if alias_ty.def_id.is_local() => {
|
||||
if !self.seen.insert(alias_ty.def_id.expect_local()) {
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
match self.tcx.uses_unique_generic_params(alias_ty.substs, CheckRegions::Bound) {
|
||||
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.
|
||||
|
||||
self.opaques.push(alias_ty.def_id.expect_local());
|
||||
|
||||
// Collect opaque types nested within the associated type bounds of this opaque type.
|
||||
for (pred, _span) in self
|
||||
.tcx
|
||||
.explicit_item_bounds(alias_ty.def_id)
|
||||
.subst_iter_copied(self.tcx, alias_ty.substs)
|
||||
{
|
||||
trace!(?pred);
|
||||
pred.visit_with(self)?;
|
||||
}
|
||||
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
Err(NotUniqueParam::NotParam(arg)) => {
|
||||
let err = self.tcx.sess.emit_err(NotParam {
|
||||
arg,
|
||||
span: self.span(),
|
||||
opaque_span: self.tcx.def_span(alias_ty.def_id),
|
||||
});
|
||||
ControlFlow::Break(err)
|
||||
}
|
||||
Err(NotUniqueParam::DuplicateParam(arg)) => {
|
||||
let err = self.tcx.sess.emit_err(DuplicateArg {
|
||||
arg,
|
||||
span: self.span(),
|
||||
opaque_span: self.tcx.def_span(alias_ty.def_id),
|
||||
});
|
||||
ControlFlow::Break(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::Alias(AliasKind::Projection, alias_ty) => {
|
||||
if let Some(parent) = self.parent() {
|
||||
trace!(?alias_ty);
|
||||
let (trait_ref, own_substs) = alias_ty.trait_ref_and_own_substs(self.tcx);
|
||||
|
||||
trace!(?trait_ref, ?own_substs);
|
||||
// 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.
|
||||
if trait_ref.self_ty() == self.tcx.type_of(parent).subst_identity() {
|
||||
for assoc in self.tcx.associated_items(parent).in_definition_order() {
|
||||
trace!(?assoc);
|
||||
if assoc.trait_item_def_id == Some(alias_ty.def_id) {
|
||||
// We reconstruct the generic args of the associated type within the impl
|
||||
// from the impl's generics and the generic args passed to the type via the
|
||||
// projection.
|
||||
let substs = ty::InternalSubsts::identity_for_item(
|
||||
self.tcx,
|
||||
parent.to_def_id(),
|
||||
);
|
||||
trace!(?substs);
|
||||
let substs: Vec<_> =
|
||||
substs.iter().chain(own_substs.iter().copied()).collect();
|
||||
trace!(?substs);
|
||||
// Find opaque types in this associated type.
|
||||
return self
|
||||
.tcx
|
||||
.type_of(assoc.def_id)
|
||||
.subst(self.tcx, &substs)
|
||||
.visit_with(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
_ => t.super_visit_with(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [LocalDefId] {
|
||||
let kind = tcx.def_kind(item);
|
||||
trace!(?kind);
|
||||
// FIXME(type_alias_impl_trait): This is definitely still wrong except for RPIT and impl trait in assoc types.
|
||||
match kind {
|
||||
// We're also doing this for `AssocTy` for the wf checks in `check_opaque_meets_bounds`
|
||||
DefKind::Fn | DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => {
|
||||
let defined_opaques = match kind {
|
||||
DefKind::Fn => {
|
||||
OpaqueTypeCollector::collect(tcx, item, tcx.fn_sig(item).subst_identity())
|
||||
}
|
||||
DefKind::AssocFn => {
|
||||
OpaqueTypeCollector::collect(tcx, item, tcx.fn_sig(item).subst_identity())
|
||||
}
|
||||
DefKind::AssocTy | DefKind::AssocConst => OpaqueTypeCollector::collect(
|
||||
tcx,
|
||||
item,
|
||||
ty::Binder::dummy(tcx.type_of(item).subst_identity()),
|
||||
),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
tcx.arena.alloc_from_iter(defined_opaques)
|
||||
}
|
||||
DefKind::Mod
|
||||
| DefKind::Struct
|
||||
| DefKind::Union
|
||||
| DefKind::Enum
|
||||
| DefKind::Variant
|
||||
| DefKind::Trait
|
||||
| DefKind::TyAlias
|
||||
| DefKind::ForeignTy
|
||||
| DefKind::TraitAlias
|
||||
| DefKind::TyParam
|
||||
| DefKind::Const
|
||||
| DefKind::ConstParam
|
||||
| DefKind::Static(_)
|
||||
| DefKind::Ctor(_, _)
|
||||
| DefKind::Macro(_)
|
||||
| DefKind::ExternCrate
|
||||
| DefKind::Use
|
||||
| DefKind::ForeignMod
|
||||
| DefKind::AnonConst
|
||||
| DefKind::InlineConst
|
||||
| DefKind::OpaqueTy
|
||||
| DefKind::ImplTraitPlaceholder
|
||||
| DefKind::Field
|
||||
| DefKind::LifetimeParam
|
||||
| DefKind::GlobalAsm
|
||||
| DefKind::Impl { .. }
|
||||
| DefKind::Closure
|
||||
| DefKind::Generator => &[],
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn provide(providers: &mut ty::query::Providers) {
|
||||
*providers = ty::query::Providers { opaque_types_defined_by, ..*providers };
|
||||
}
|
@ -455,7 +455,8 @@ fn visit_item_inner(
|
||||
| hir::ItemKind::Union(..)
|
||||
| hir::ItemKind::TyAlias(..)
|
||||
| hir::ItemKind::OpaqueTy(hir::OpaqueTy {
|
||||
origin: hir::OpaqueTyOrigin::TyAlias, ..
|
||||
origin: hir::OpaqueTyOrigin::TyAlias { .. },
|
||||
..
|
||||
})
|
||||
| hir::ItemKind::Static(..)
|
||||
| hir::ItemKind::Trait(..)
|
||||
|
@ -19,4 +19,5 @@ impl<'a> A<'a> for C {
|
||||
type B<'b> = impl Clone;
|
||||
|
||||
fn a(&'a self) -> Self::B<'a> {} //~ ERROR: non-defining opaque type use in defining scope
|
||||
//~^ ERROR: mismatched types
|
||||
}
|
||||
|
@ -1,16 +1,34 @@
|
||||
error: non-defining opaque type use in defining scope
|
||||
--> $DIR/issue-88595.rs:21:35
|
||||
--> $DIR/issue-88595.rs:21:5
|
||||
|
|
||||
LL | fn a(&'a self) -> Self::B<'a> {}
|
||||
| ^^
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ generic argument `'a` used twice
|
||||
|
|
||||
note: lifetime used multiple times
|
||||
--> $DIR/issue-88595.rs:18:6
|
||||
note: for this opaque type
|
||||
--> $DIR/issue-88595.rs:19:18
|
||||
|
|
||||
LL | impl<'a> A<'a> for C {
|
||||
| ^^
|
||||
LL | type B<'b> = impl Clone;
|
||||
| ^^
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-88595.rs:21:23
|
||||
|
|
||||
LL | type B<'b> = impl Clone;
|
||||
| ---------- the expected opaque type
|
||||
LL |
|
||||
LL | fn a(&'a self) -> Self::B<'a> {}
|
||||
| - ^^^^^^^^^^^ expected opaque type, found `()`
|
||||
| |
|
||||
| implicitly returns `()` as its body has no tail or `return` expression
|
||||
|
|
||||
= note: expected opaque type `<C as A<'a>>::B<'a>`
|
||||
found unit type `()`
|
||||
note: this item must have the opaque type in its signature in order to be able to register hidden types
|
||||
--> $DIR/issue-88595.rs:21:5
|
||||
|
|
||||
LL | fn a(&'a self) -> Self::B<'a> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
27
tests/ui/impl-trait/in-assoc-type-unconstrained.rs
Normal file
27
tests/ui/impl-trait/in-assoc-type-unconstrained.rs
Normal file
@ -0,0 +1,27 @@
|
||||
#![feature(impl_trait_in_assoc_type)]
|
||||
|
||||
mod compare_ty {
|
||||
trait Trait {
|
||||
type Ty: IntoIterator<Item = ()>;
|
||||
}
|
||||
impl Trait for () {
|
||||
type Ty = Option<impl Sized>;
|
||||
//~^ ERROR: unconstrained opaque type
|
||||
//~| ERROR: type mismatch resolving `<Option<<() as Trait>::Ty::{opaque#0}> as IntoIterator>::Item == ()`
|
||||
}
|
||||
}
|
||||
|
||||
mod compare_method {
|
||||
trait Trait {
|
||||
type Ty;
|
||||
fn method() -> Self::Ty;
|
||||
}
|
||||
impl Trait for () {
|
||||
type Ty = impl Sized;
|
||||
//~^ ERROR: unconstrained opaque type
|
||||
fn method() -> () {}
|
||||
//~^ ERROR: method `method` has an incompatible type for trait
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
59
tests/ui/impl-trait/in-assoc-type-unconstrained.stderr
Normal file
59
tests/ui/impl-trait/in-assoc-type-unconstrained.stderr
Normal file
@ -0,0 +1,59 @@
|
||||
error[E0271]: type mismatch resolving `<Option<<() as Trait>::Ty::{opaque#0}> as IntoIterator>::Item == ()`
|
||||
--> $DIR/in-assoc-type-unconstrained.rs:8:19
|
||||
|
|
||||
LL | type Ty = Option<impl Sized>;
|
||||
| ^^^^^^^^^^^^^^^^^^ expected `()`, found opaque type
|
||||
|
|
||||
= note: expected unit type `()`
|
||||
found opaque type `<() as compare_ty::Trait>::Ty::{opaque#0}`
|
||||
note: required by a bound in `compare_ty::Trait::Ty`
|
||||
--> $DIR/in-assoc-type-unconstrained.rs:5:31
|
||||
|
|
||||
LL | type Ty: IntoIterator<Item = ()>;
|
||||
| ^^^^^^^^^ required by this bound in `Trait::Ty`
|
||||
|
||||
error: unconstrained opaque type
|
||||
--> $DIR/in-assoc-type-unconstrained.rs:8:26
|
||||
|
|
||||
LL | type Ty = Option<impl Sized>;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: `Ty` must be used in combination with a concrete type within the same impl
|
||||
|
||||
error[E0053]: method `method` has an incompatible type for trait
|
||||
--> $DIR/in-assoc-type-unconstrained.rs:22:24
|
||||
|
|
||||
LL | type Ty = impl Sized;
|
||||
| ---------- the expected opaque type
|
||||
LL |
|
||||
LL | fn method() -> () {}
|
||||
| ^^
|
||||
| |
|
||||
| expected opaque type, found `()`
|
||||
| help: change the output type to match the trait: `<() as compare_method::Trait>::Ty`
|
||||
|
|
||||
note: type in trait
|
||||
--> $DIR/in-assoc-type-unconstrained.rs:17:24
|
||||
|
|
||||
LL | fn method() -> Self::Ty;
|
||||
| ^^^^^^^^
|
||||
= note: expected signature `fn() -> <() as compare_method::Trait>::Ty`
|
||||
found signature `fn()`
|
||||
note: this item must have the opaque type in its signature in order to be able to register hidden types
|
||||
--> $DIR/in-assoc-type-unconstrained.rs:22:9
|
||||
|
|
||||
LL | fn method() -> () {}
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: unconstrained opaque type
|
||||
--> $DIR/in-assoc-type-unconstrained.rs:20:19
|
||||
|
|
||||
LL | type Ty = impl Sized;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: `Ty` must be used in combination with a concrete type within the same impl
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0053, E0271.
|
||||
For more information about an error, try `rustc --explain E0053`.
|
21
tests/ui/impl-trait/in-assoc-type.rs
Normal file
21
tests/ui/impl-trait/in-assoc-type.rs
Normal file
@ -0,0 +1,21 @@
|
||||
#![feature(impl_trait_in_assoc_type)]
|
||||
|
||||
trait Foo<T> {
|
||||
type Bar;
|
||||
fn foo(&self) -> <Self as Foo<()>>::Bar
|
||||
where
|
||||
Self: Foo<()>;
|
||||
}
|
||||
|
||||
impl Foo<()> for () {
|
||||
type Bar = impl std::fmt::Debug;
|
||||
fn foo(&self) -> Self::Bar {}
|
||||
}
|
||||
|
||||
impl Foo<i32> for () {
|
||||
type Bar = u32;
|
||||
fn foo(&self) -> <Self as Foo<()>>::Bar {}
|
||||
//~^ ERROR: mismatched types
|
||||
}
|
||||
|
||||
fn main() {}
|
22
tests/ui/impl-trait/in-assoc-type.stderr
Normal file
22
tests/ui/impl-trait/in-assoc-type.stderr
Normal file
@ -0,0 +1,22 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/in-assoc-type.rs:17:22
|
||||
|
|
||||
LL | type Bar = impl std::fmt::Debug;
|
||||
| -------------------- the expected opaque type
|
||||
...
|
||||
LL | fn foo(&self) -> <Self as Foo<()>>::Bar {}
|
||||
| --- ^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found `()`
|
||||
| |
|
||||
| implicitly returns `()` as its body has no tail or `return` expression
|
||||
|
|
||||
= note: expected opaque type `<() as Foo<()>>::Bar`
|
||||
found unit type `()`
|
||||
note: this item must have the opaque type in its signature in order to be able to register hidden types
|
||||
--> $DIR/in-assoc-type.rs:17:5
|
||||
|
|
||||
LL | fn foo(&self) -> <Self as Foo<()>>::Bar {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
@ -43,6 +43,11 @@ LL | fn eq(&self, _other: &(Bar, i32)) -> bool {
|
||||
|
|
||||
= note: expected signature `fn(&b::Bar, &(b::Foo, i32)) -> _`
|
||||
found signature `fn(&b::Bar, &(b::Bar, i32)) -> _`
|
||||
note: this item must have the opaque type in its signature in order to be able to register hidden types
|
||||
--> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:24:9
|
||||
|
|
||||
LL | fn eq(&self, _other: &(Bar, i32)) -> bool {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
@ -5,15 +5,16 @@
|
||||
trait Trait {
|
||||
type Opaque1;
|
||||
type Opaque2;
|
||||
fn constrain(self);
|
||||
fn constrain(self) -> (Self::Opaque1, Self::Opaque2);
|
||||
}
|
||||
|
||||
impl<'a> Trait for &'a () {
|
||||
type Opaque1 = impl Sized;
|
||||
type Opaque2 = impl Sized + 'a;
|
||||
fn constrain(self) {
|
||||
let _: Self::Opaque1 = ();
|
||||
let _: Self::Opaque2 = self;
|
||||
fn constrain(self) -> (Self::Opaque1, Self::Opaque2) {
|
||||
let a: Self::Opaque1 = ();
|
||||
let b: Self::Opaque2 = self;
|
||||
(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,16 @@
|
||||
#![feature(impl_trait_in_assoc_type)]
|
||||
|
||||
trait Foo {
|
||||
type Foo;
|
||||
fn bar();
|
||||
}
|
||||
|
||||
impl Foo for () {
|
||||
type Foo = impl std::fmt::Debug;
|
||||
fn bar() {
|
||||
let x: Self::Foo = ();
|
||||
//~^ ERROR: mismatched types
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,22 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/invalid_impl_trait_in_assoc_ty.rs:11:28
|
||||
|
|
||||
LL | type Foo = impl std::fmt::Debug;
|
||||
| -------------------- the expected opaque type
|
||||
LL | fn bar() {
|
||||
LL | let x: Self::Foo = ();
|
||||
| --------- ^^ expected opaque type, found `()`
|
||||
| |
|
||||
| expected due to this
|
||||
|
|
||||
= note: expected opaque type `<() as Foo>::Foo`
|
||||
found unit type `()`
|
||||
note: this item must have the opaque type in its signature in order to be able to register hidden types
|
||||
--> $DIR/invalid_impl_trait_in_assoc_ty.rs:10:5
|
||||
|
|
||||
LL | fn bar() {
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Reference in New Issue
Block a user