mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 08:44:35 +00:00
Require impl Trait
in associated types to appear in method signatures
This commit is contained in:
parent
699a862a3d
commit
f08b517597
@ -305,7 +305,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
);
|
);
|
||||||
this.arena.alloc(this.ty(span, hir::TyKind::Err(guar)))
|
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)
|
hir::ItemKind::TyAlias(ty, generics)
|
||||||
@ -852,7 +855,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
hir::ImplItemKind::Type(ty)
|
hir::ImplItemKind::Type(ty)
|
||||||
}
|
}
|
||||||
Some(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)
|
hir::ImplItemKind::Type(ty)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -247,7 +247,7 @@ enum ImplTraitContext {
|
|||||||
in_trait: bool,
|
in_trait: bool,
|
||||||
},
|
},
|
||||||
/// Impl trait in type aliases.
|
/// Impl trait in type aliases.
|
||||||
TypeAliasesOpaqueTy,
|
TypeAliasesOpaqueTy { in_assoc_ty: bool },
|
||||||
/// `impl Trait` is unstably accepted in this position.
|
/// `impl Trait` is unstably accepted in this position.
|
||||||
FeatureGated(ImplTraitPosition, Symbol),
|
FeatureGated(ImplTraitPosition, Symbol),
|
||||||
/// `impl Trait` is not accepted in this position.
|
/// `impl Trait` is not accepted in this position.
|
||||||
@ -1407,14 +1407,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
*in_trait,
|
*in_trait,
|
||||||
itctx,
|
itctx,
|
||||||
),
|
),
|
||||||
ImplTraitContext::TypeAliasesOpaqueTy => self.lower_opaque_impl_trait(
|
&ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty } => self
|
||||||
span,
|
.lower_opaque_impl_trait(
|
||||||
hir::OpaqueTyOrigin::TyAlias,
|
span,
|
||||||
*def_node_id,
|
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty },
|
||||||
bounds,
|
*def_node_id,
|
||||||
false,
|
bounds,
|
||||||
itctx,
|
false,
|
||||||
),
|
itctx,
|
||||||
|
),
|
||||||
ImplTraitContext::Universal => {
|
ImplTraitContext::Universal => {
|
||||||
let span = t.span;
|
let span = t.span;
|
||||||
self.create_def(
|
self.create_def(
|
||||||
@ -1534,13 +1535,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
// If this came from a TAIT (as opposed to a function that returns an RPIT), we only want
|
// 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
|
// to capture the lifetimes that appear in the bounds. So visit the bounds to find out
|
||||||
// exactly which ones those are.
|
// exactly which ones those are.
|
||||||
let lifetimes_to_remap = if origin == hir::OpaqueTyOrigin::TyAlias {
|
let lifetimes_to_remap = match origin {
|
||||||
// in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters
|
hir::OpaqueTyOrigin::TyAlias { .. } => {
|
||||||
Vec::new()
|
// in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters
|
||||||
} else {
|
Vec::new()
|
||||||
// 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:
|
hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..) => {
|
||||||
lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds)
|
// 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);
|
debug!(?lifetimes_to_remap);
|
||||||
|
|
||||||
|
@ -265,7 +265,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
|||||||
|
|
||||||
// Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs`
|
// Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs`
|
||||||
// on stable and we'd break that.
|
// on stable and we'd break that.
|
||||||
let OpaqueTyOrigin::TyAlias = origin else {
|
let OpaqueTyOrigin::TyAlias { .. } = origin else {
|
||||||
return definition_ty;
|
return definition_ty;
|
||||||
};
|
};
|
||||||
let def_id = opaque_type_key.def_id;
|
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.
|
// which would error here on all of the `'static` args.
|
||||||
OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return Ok(()),
|
OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return Ok(()),
|
||||||
// Check these
|
// Check these
|
||||||
OpaqueTyOrigin::TyAlias => {}
|
OpaqueTyOrigin::TyAlias { .. } => {}
|
||||||
}
|
}
|
||||||
let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
|
let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
|
||||||
let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();
|
let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();
|
||||||
|
@ -2662,7 +2662,10 @@ pub enum OpaqueTyOrigin {
|
|||||||
/// `async fn`
|
/// `async fn`
|
||||||
AsyncFn(LocalDefId),
|
AsyncFn(LocalDefId),
|
||||||
/// type aliases: `type Foo = impl Trait;`
|
/// 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.
|
/// The various kinds of types recognized by the compiler.
|
||||||
|
@ -397,7 +397,14 @@ fn check_opaque_meets_bounds<'tcx>(
|
|||||||
) {
|
) {
|
||||||
let defining_use_anchor = match *origin {
|
let defining_use_anchor = match *origin {
|
||||||
hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
|
hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
|
||||||
hir::OpaqueTyOrigin::TyAlias => def_id,
|
hir::OpaqueTyOrigin::TyAlias { .. } => {
|
||||||
|
let mut def_id = def_id;
|
||||||
|
// Find the surrounding item (type alias or assoc type)
|
||||||
|
while let DefKind::OpaqueTy = tcx.def_kind(def_id) {
|
||||||
|
def_id = tcx.local_parent(def_id);
|
||||||
|
}
|
||||||
|
def_id
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let param_env = tcx.param_env(defining_use_anchor);
|
let param_env = tcx.param_env(defining_use_anchor);
|
||||||
|
|
||||||
@ -455,10 +462,10 @@ fn check_opaque_meets_bounds<'tcx>(
|
|||||||
// They can only be referenced as `<Opaque<T> as Trait<&'static T>>::AssocTy`.
|
// 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
|
// 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.
|
// 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 => {}
|
if tcx.def_kind(tcx.parent(def_id.to_def_id())) == DefKind::OpaqueTy => {}
|
||||||
// Can have different predicates to their defining use
|
// 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 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 implied_bounds = infcx.implied_bounds_tys(param_env, def_id, wf_tys);
|
||||||
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
||||||
|
@ -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 {
|
fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
|
||||||
match tcx.hir().get_by_def_id(def_id) {
|
match tcx.hir().get_by_def_id(def_id) {
|
||||||
Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. }) => {
|
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),
|
_ => 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())
|
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);
|
let parent_id = tcx.hir().get_parent_item(hir_id);
|
||||||
assert_ne!(parent_id, hir::CRATE_OWNER_ID);
|
assert_ne!(parent_id, hir::CRATE_OWNER_ID);
|
||||||
debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_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::TyAlias(_, generics)
|
||||||
| ItemKind::OpaqueTy(OpaqueTy {
|
| ItemKind::OpaqueTy(OpaqueTy {
|
||||||
generics,
|
generics,
|
||||||
origin: hir::OpaqueTyOrigin::TyAlias,
|
origin: hir::OpaqueTyOrigin::TyAlias { .. },
|
||||||
..
|
..
|
||||||
})
|
})
|
||||||
| ItemKind::Enum(_, generics)
|
| ItemKind::Enum(_, generics)
|
||||||
|
@ -526,7 +526,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
|
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
|
||||||
origin: hir::OpaqueTyOrigin::TyAlias, ..
|
origin: hir::OpaqueTyOrigin::TyAlias { .. },
|
||||||
|
..
|
||||||
}) => {
|
}) => {
|
||||||
// Opaque types are visited when we visit the
|
// Opaque types are visited when we visit the
|
||||||
// `TyKind::OpaqueDef`, so that they have the lifetimes from
|
// `TyKind::OpaqueDef`, so that they have the lifetimes from
|
||||||
@ -707,7 +708,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||||||
let opaque_ty = self.tcx.hir().item(item_id);
|
let opaque_ty = self.tcx.hir().item(item_id);
|
||||||
match &opaque_ty.kind {
|
match &opaque_ty.kind {
|
||||||
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
|
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
|
||||||
origin: hir::OpaqueTyOrigin::TyAlias,
|
origin: hir::OpaqueTyOrigin::TyAlias { .. },
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
intravisit::walk_ty(self, ty);
|
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);
|
let substs = InternalSubsts::identity_for_item(tcx, def_id);
|
||||||
tcx.mk_adt(def, substs)
|
tcx.mk_adt(def, substs)
|
||||||
}
|
}
|
||||||
ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
|
ItemKind::OpaqueTy(OpaqueTy {
|
||||||
find_opaque_ty_constraints_for_tait(tcx, def_id)
|
origin: hir::OpaqueTyOrigin::TyAlias { .. },
|
||||||
}
|
..
|
||||||
|
}) => find_opaque_ty_constraints_for_tait(tcx, def_id),
|
||||||
// Opaque types desugared from `impl Trait`.
|
// Opaque types desugared from `impl Trait`.
|
||||||
ItemKind::OpaqueTy(OpaqueTy {
|
ItemKind::OpaqueTy(OpaqueTy {
|
||||||
origin:
|
origin:
|
||||||
|
@ -735,7 +735,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
if let ty::subst::GenericArgKind::Type(ty) = ty.unpack()
|
if let ty::subst::GenericArgKind::Type(ty) = ty.unpack()
|
||||||
&& let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *ty.kind()
|
&& let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *ty.kind()
|
||||||
&& let Some(def_id) = def_id.as_local()
|
&& let Some(def_id) = def_id.as_local()
|
||||||
&& self.opaque_type_origin(def_id).is_some() {
|
&& self.opaque_type_origin(def_id, self.param_env).is_some() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
|
use crate::infer::opaque_types::may_define_impl_trait_in_assoc_ty_modulo_sig;
|
||||||
|
|
||||||
use super::TypeErrCtxt;
|
use super::TypeErrCtxt;
|
||||||
use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
|
use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
|
||||||
use rustc_errors::{pluralize, Diagnostic, MultiSpan};
|
use rustc_errors::{pluralize, Diagnostic, MultiSpan};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_middle::traits::ObligationCauseCode;
|
use rustc_middle::traits::ObligationCauseCode::{self, MiscObligation};
|
||||||
use rustc_middle::ty::error::ExpectedFound;
|
use rustc_middle::ty::error::ExpectedFound;
|
||||||
use rustc_middle::ty::print::Printer;
|
use rustc_middle::ty::print::Printer;
|
||||||
use rustc_middle::{
|
use rustc_middle::{
|
||||||
@ -256,6 +258,15 @@ impl<T> Trait<T> for X {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if matches!(cause.code(), MiscObligation) => {
|
||||||
|
if let Some(def_id) = alias.def_id.as_local() {
|
||||||
|
if may_define_impl_trait_in_assoc_ty_modulo_sig(tcx, body_owner_def_id.expect_local(), def_id).is_some() {
|
||||||
|
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, _))
|
(ty::FnPtr(_), ty::FnDef(def, _))
|
||||||
if let hir::def::DefKind::Fn = tcx.def_kind(def) => {
|
if let hir::def::DefKind::Fn = tcx.def_kind(def) => {
|
||||||
diag.note(
|
diag.note(
|
||||||
|
@ -3,9 +3,10 @@ use super::{DefineOpaqueTypes, InferResult};
|
|||||||
use crate::errors::OpaqueHiddenTypeDiag;
|
use crate::errors::OpaqueHiddenTypeDiag;
|
||||||
use crate::infer::{DefiningAnchor, InferCtxt, InferOk};
|
use crate::infer::{DefiningAnchor, InferCtxt, InferOk};
|
||||||
use crate::traits;
|
use crate::traits;
|
||||||
|
use hir::def::DefKind;
|
||||||
use hir::def_id::{DefId, LocalDefId};
|
use hir::def_id::{DefId, LocalDefId};
|
||||||
use hir::OpaqueTyOrigin;
|
use hir::OpaqueTyOrigin;
|
||||||
use rustc_data_structures::fx::FxIndexMap;
|
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_middle::traits::ObligationCause;
|
use rustc_middle::traits::ObligationCause;
|
||||||
@ -53,7 +54,9 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
}
|
}
|
||||||
let mut obligations = vec![];
|
let mut obligations = vec![];
|
||||||
let replace_opaque_type = |def_id: DefId| {
|
let replace_opaque_type = |def_id: DefId| {
|
||||||
def_id.as_local().map_or(false, |def_id| self.opaque_type_origin(def_id).is_some())
|
def_id
|
||||||
|
.as_local()
|
||||||
|
.map_or(false, |def_id| self.opaque_type_origin(def_id, param_env).is_some())
|
||||||
};
|
};
|
||||||
let value = value.fold_with(&mut BottomUpFolder {
|
let value = value.fold_with(&mut BottomUpFolder {
|
||||||
tcx: self.tcx,
|
tcx: self.tcx,
|
||||||
@ -138,7 +141,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
// let x = || foo(); // returns the Opaque assoc with `foo`
|
// let x = || foo(); // returns the Opaque assoc with `foo`
|
||||||
// }
|
// }
|
||||||
// ```
|
// ```
|
||||||
self.opaque_type_origin(def_id)?
|
self.opaque_type_origin(def_id, param_env)?
|
||||||
}
|
}
|
||||||
DefiningAnchor::Bubble => self.opaque_type_origin_unchecked(def_id),
|
DefiningAnchor::Bubble => self.opaque_type_origin_unchecked(def_id),
|
||||||
DefiningAnchor::Error => return None,
|
DefiningAnchor::Error => return None,
|
||||||
@ -149,8 +152,9 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
// no one encounters it in practice.
|
// no one encounters it in practice.
|
||||||
// It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`,
|
// 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.
|
// 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
|
||||||
b_def_id.as_local().and_then(|b_def_id| self.opaque_type_origin(b_def_id))
|
.as_local()
|
||||||
|
.and_then(|b_def_id| self.opaque_type_origin(b_def_id, param_env))
|
||||||
{
|
{
|
||||||
self.tcx.sess.emit_err(OpaqueHiddenTypeDiag {
|
self.tcx.sess.emit_err(OpaqueHiddenTypeDiag {
|
||||||
span: cause.span,
|
span: cause.span,
|
||||||
@ -366,8 +370,12 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
|
|
||||||
/// Returns the origin of the opaque type `def_id` if we're currently
|
/// Returns the origin of the opaque type `def_id` if we're currently
|
||||||
/// in its defining scope.
|
/// in its defining scope.
|
||||||
#[instrument(skip(self), level = "trace", ret)]
|
#[instrument(skip(self, param_env), level = "trace", ret)]
|
||||||
pub fn opaque_type_origin(&self, def_id: LocalDefId) -> Option<OpaqueTyOrigin> {
|
pub fn opaque_type_origin(
|
||||||
|
&self,
|
||||||
|
def_id: LocalDefId,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
) -> Option<OpaqueTyOrigin> {
|
||||||
let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
|
let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
|
||||||
let parent_def_id = match self.defining_use_anchor {
|
let parent_def_id = match self.defining_use_anchor {
|
||||||
DefiningAnchor::Bubble | DefiningAnchor::Error => return None,
|
DefiningAnchor::Bubble | DefiningAnchor::Error => return None,
|
||||||
@ -381,8 +389,12 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
// Anonymous `impl Trait`
|
// Anonymous `impl Trait`
|
||||||
hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
|
hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
|
||||||
// Named `type Foo = impl Bar;`
|
// Named `type Foo = impl Bar;`
|
||||||
hir::OpaqueTyOrigin::TyAlias => {
|
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => {
|
||||||
may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id)
|
if in_assoc_ty {
|
||||||
|
may_define_impl_trait_in_assoc_ty(self.tcx, parent_def_id, def_id, param_env)
|
||||||
|
} else {
|
||||||
|
may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
in_definition_scope.then_some(origin)
|
in_definition_scope.then_some(origin)
|
||||||
@ -642,3 +654,105 @@ fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hi
|
|||||||
);
|
);
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, TypeVisitable, Clone)]
|
||||||
|
/// Helper datastructure containing the signature
|
||||||
|
/// that the opaque type extraction logic uses for determining
|
||||||
|
/// whether an opaque type may have its hidden types registered
|
||||||
|
/// by an item.
|
||||||
|
enum FnSigOrTy<'tcx> {
|
||||||
|
FnSig(ty::PolyFnSig<'tcx>),
|
||||||
|
Ty(Ty<'tcx>),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks that the item may register hidden types for the
|
||||||
|
/// opaque type, if the opaque type shows up in its signature.
|
||||||
|
#[instrument(level = "debug", skip(tcx), ret)]
|
||||||
|
pub fn may_define_impl_trait_in_assoc_ty_modulo_sig<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
def_id: LocalDefId,
|
||||||
|
opaque_def_id: LocalDefId,
|
||||||
|
) -> Option<impl TypeVisitable<TyCtxt<'tcx>>> {
|
||||||
|
let sig = match tcx.def_kind(def_id) {
|
||||||
|
DefKind::AssocFn => FnSigOrTy::FnSig(tcx.fn_sig(def_id).subst_identity()),
|
||||||
|
DefKind::AssocConst | DefKind::AssocTy => {
|
||||||
|
FnSigOrTy::Ty(tcx.type_of(def_id).subst_identity())
|
||||||
|
}
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
let impl_id = tcx.local_parent(def_id);
|
||||||
|
trace!(?impl_id);
|
||||||
|
let mut assoc_id = opaque_def_id;
|
||||||
|
// Peel nested opaque types.
|
||||||
|
while let DefKind::OpaqueTy = tcx.def_kind(assoc_id) {
|
||||||
|
trace!(?assoc_id);
|
||||||
|
assoc_id = tcx.local_parent(assoc_id);
|
||||||
|
}
|
||||||
|
trace!(?assoc_id);
|
||||||
|
if !matches!(tcx.def_kind(assoc_id), DefKind::AssocTy) {
|
||||||
|
tcx.sess
|
||||||
|
.delay_span_bug(tcx.def_span(opaque_def_id), format!("{:?}", tcx.def_kind(assoc_id)));
|
||||||
|
}
|
||||||
|
let assoc_impl_id = tcx.local_parent(assoc_id);
|
||||||
|
trace!(?assoc_impl_id);
|
||||||
|
|
||||||
|
if impl_id != assoc_impl_id {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(sig)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(tcx, param_env), ret)]
|
||||||
|
fn may_define_impl_trait_in_assoc_ty<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
def_id: LocalDefId,
|
||||||
|
opaque_def_id: LocalDefId,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
) -> bool {
|
||||||
|
let Some(sig) = may_define_impl_trait_in_assoc_ty_modulo_sig(tcx, def_id, opaque_def_id) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Visitor<'tcx> {
|
||||||
|
opaque_def_id: LocalDefId,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
seen: FxHashSet<LocalDefId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Visitor<'tcx> {
|
||||||
|
type BreakTy = ();
|
||||||
|
#[instrument(level = "trace", skip(self), ret)]
|
||||||
|
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> {
|
||||||
|
// FIXME(oli-obk): We should be checking if the associated type
|
||||||
|
// is mentioned instead of normalizing to find the opaque type.
|
||||||
|
// But that requires a way to figure out that a projection refers
|
||||||
|
// to a specific opaque type. That is probably doable by checking for
|
||||||
|
// `Self` as the `substs[0]`.
|
||||||
|
let normalized_ty = self.tcx.normalize_erasing_regions(self.param_env, ty);
|
||||||
|
if let ty::Alias(ty::Opaque, alias) = normalized_ty.kind() {
|
||||||
|
if let Some(def_id) = alias.def_id.as_local() {
|
||||||
|
trace!(?alias.def_id);
|
||||||
|
if def_id == self.opaque_def_id {
|
||||||
|
return ControlFlow::Break(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.seen.insert(def_id) {
|
||||||
|
// Look into nested obligations like `impl Trait<Assoc = impl OtherTrait>`.
|
||||||
|
for (pred, _) in self
|
||||||
|
.tcx
|
||||||
|
.explicit_item_bounds(alias.def_id)
|
||||||
|
.subst_iter_copied(self.tcx, alias.substs)
|
||||||
|
{
|
||||||
|
pred.visit_with(self)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
normalized_ty.super_visit_with(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sig.visit_with(&mut Visitor { opaque_def_id, param_env, tcx, seen: Default::default() })
|
||||||
|
.is_break()
|
||||||
|
}
|
||||||
|
@ -1641,9 +1641,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
hir::ItemKind::OpaqueTy(ref opaque) => {
|
hir::ItemKind::OpaqueTy(ref opaque) => {
|
||||||
self.encode_explicit_item_bounds(def_id);
|
self.encode_explicit_item_bounds(def_id);
|
||||||
self.tables
|
self.tables.is_type_alias_impl_trait.set(
|
||||||
.is_type_alias_impl_trait
|
def_id.index,
|
||||||
.set(def_id.index, matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias));
|
matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. }),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
|
hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
|
||||||
self.tables.impl_defaultness.set_some(def_id.index, *defaultness);
|
self.tables.impl_defaultness.set_some(def_id.index, *defaultness);
|
||||||
|
@ -2520,7 +2520,7 @@ pub fn is_impl_trait_defn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<LocalDefId>
|
|||||||
hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent) => {
|
hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent) => {
|
||||||
Some(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,
|
/// This should only be used outside of type inference. For example,
|
||||||
/// it assumes that normalization will succeed.
|
/// 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
|
pub fn normalize_erasing_regions<T>(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T
|
||||||
where
|
where
|
||||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||||
|
@ -455,7 +455,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||||||
| hir::ItemKind::Union(..)
|
| hir::ItemKind::Union(..)
|
||||||
| hir::ItemKind::TyAlias(..)
|
| hir::ItemKind::TyAlias(..)
|
||||||
| hir::ItemKind::OpaqueTy(hir::OpaqueTy {
|
| hir::ItemKind::OpaqueTy(hir::OpaqueTy {
|
||||||
origin: hir::OpaqueTyOrigin::TyAlias, ..
|
origin: hir::OpaqueTyOrigin::TyAlias { .. },
|
||||||
|
..
|
||||||
})
|
})
|
||||||
| hir::ItemKind::Static(..)
|
| hir::ItemKind::Static(..)
|
||||||
| hir::ItemKind::Trait(..)
|
| hir::ItemKind::Trait(..)
|
||||||
|
@ -5,15 +5,14 @@
|
|||||||
trait Trait {
|
trait Trait {
|
||||||
type Opaque1;
|
type Opaque1;
|
||||||
type Opaque2;
|
type Opaque2;
|
||||||
fn constrain(self);
|
fn constrain(self) -> (Self::Opaque1, Self::Opaque2);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Trait for &'a () {
|
impl<'a> Trait for &'a () {
|
||||||
type Opaque1 = impl Sized;
|
type Opaque1 = impl Sized;
|
||||||
type Opaque2 = impl Sized + 'a;
|
type Opaque2 = impl Sized + 'a;
|
||||||
fn constrain(self) {
|
fn constrain(self) -> (Self::Opaque1, Self::Opaque2) {
|
||||||
let _: Self::Opaque1 = ();
|
((), self)
|
||||||
let _: Self::Opaque2 = self;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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