Use the opaque_types_defined_by query to cheaply check for whether a hidden type may be registered for an opaque type
This commit is contained in:
@@ -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, self.param_env).is_some() {
|
&& self.opaque_type_origin(def_id).is_some() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
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::{self, MiscObligation};
|
use rustc_hir::def::DefKind;
|
||||||
|
use rustc_middle::traits::ObligationCauseCode;
|
||||||
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::{
|
||||||
@@ -258,9 +257,9 @@ impl<T> Trait<T> for X {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if matches!(cause.code(), MiscObligation) => {
|
(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 let Some(def_id) = alias.def_id.as_local() {
|
if tcx.is_type_alias_impl_trait(alias.def_id) {
|
||||||
if may_define_impl_trait_in_assoc_ty_modulo_sig(tcx, body_owner_def_id.expect_local(), def_id).is_some() {
|
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), "\
|
diag.span_note(tcx.def_span(body_owner_def_id), "\
|
||||||
this item must have the opaque type in its signature \
|
this item must have the opaque type in its signature \
|
||||||
in order to be able to register hidden types");
|
in order to be able to register hidden types");
|
||||||
|
|||||||
@@ -3,10 +3,9 @@ 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::{FxHashSet, FxIndexMap};
|
use rustc_data_structures::fx::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;
|
||||||
@@ -54,9 +53,7 @@ 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
|
def_id.as_local().map_or(false, |def_id| self.opaque_type_origin(def_id).is_some())
|
||||||
.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,
|
||||||
@@ -141,7 +138,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, param_env)?
|
self.opaque_type_origin(def_id)?
|
||||||
}
|
}
|
||||||
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,
|
||||||
@@ -152,9 +149,8 @@ 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 { .. }) = b_def_id
|
if let Some(OpaqueTyOrigin::TyAlias { .. }) =
|
||||||
.as_local()
|
b_def_id.as_local().and_then(|b_def_id| self.opaque_type_origin(b_def_id))
|
||||||
.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,
|
||||||
@@ -370,12 +366,8 @@ 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, param_env), level = "trace", ret)]
|
#[instrument(skip(self), level = "trace", ret)]
|
||||||
pub fn opaque_type_origin(
|
pub fn opaque_type_origin(&self, def_id: LocalDefId) -> Option<OpaqueTyOrigin> {
|
||||||
&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,
|
||||||
@@ -391,7 +383,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
// Named `type Foo = impl Bar;`
|
// Named `type Foo = impl Bar;`
|
||||||
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => {
|
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => {
|
||||||
if in_assoc_ty {
|
if in_assoc_ty {
|
||||||
may_define_impl_trait_in_assoc_ty(self.tcx, parent_def_id, def_id, param_env)
|
self.tcx.opaque_types_defined_by(parent_def_id).contains(&def_id)
|
||||||
} else {
|
} else {
|
||||||
may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id)
|
may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id)
|
||||||
}
|
}
|
||||||
@@ -654,105 +646,3 @@ 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()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -172,6 +172,10 @@ impl EraseType for ty::Binder<'_, ty::FnSig<'_>> {
|
|||||||
type Result = [u8; size_of::<ty::Binder<'static, ty::FnSig<'static>>>()];
|
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) {
|
impl<T0, T1> EraseType for (&'_ T0, &'_ T1) {
|
||||||
type Result = [u8; size_of::<(&'static (), &'static ())>()];
|
type Result = [u8; size_of::<(&'static (), &'static ())>()];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1265,7 +1265,7 @@ impl<'tcx> AliasTy<'tcx> {
|
|||||||
|
|
||||||
/// Extracts the underlying trait reference and own substs from this projection.
|
/// Extracts the underlying trait reference and own substs from this projection.
|
||||||
/// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
|
/// 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(
|
pub fn trait_ref_and_own_substs(
|
||||||
self,
|
self,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
|||||||
@@ -36,7 +36,12 @@ pub struct Discr<'tcx> {
|
|||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum CheckRegions {
|
pub enum CheckRegions {
|
||||||
No,
|
No,
|
||||||
|
/// Only permit early bound regions. This is useful for Adts which
|
||||||
|
/// can never have late bound regions.
|
||||||
OnlyEarlyBound,
|
OnlyEarlyBound,
|
||||||
|
/// Permit both late bound and early bound regions. Use this for functions,
|
||||||
|
/// which frequently have late bound regions.
|
||||||
|
Bound,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
@@ -471,15 +476,21 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
ignore_regions: CheckRegions,
|
ignore_regions: CheckRegions,
|
||||||
) -> Result<(), NotUniqueParam<'tcx>> {
|
) -> Result<(), NotUniqueParam<'tcx>> {
|
||||||
let mut seen = GrowableBitSet::default();
|
let mut seen = GrowableBitSet::default();
|
||||||
|
let mut seen_late = FxHashSet::default();
|
||||||
for arg in substs {
|
for arg in substs {
|
||||||
match arg.unpack() {
|
match arg.unpack() {
|
||||||
GenericArgKind::Lifetime(lt) => match (ignore_regions, lt.kind()) {
|
GenericArgKind::Lifetime(lt) => match (ignore_regions, lt.kind()) {
|
||||||
(CheckRegions::OnlyEarlyBound, ty::ReEarlyBound(p)) => {
|
(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) {
|
if !seen.insert(p.index) {
|
||||||
return Err(NotUniqueParam::DuplicateParam(lt.into()));
|
return Err(NotUniqueParam::DuplicateParam(lt.into()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(CheckRegions::OnlyEarlyBound, _) => {
|
(CheckRegions::OnlyEarlyBound | CheckRegions::Bound, _) => {
|
||||||
return Err(NotUniqueParam::NotParam(lt.into()));
|
return Err(NotUniqueParam::NotParam(lt.into()));
|
||||||
}
|
}
|
||||||
(CheckRegions::No, _) => {}
|
(CheckRegions::No, _) => {}
|
||||||
|
|||||||
@@ -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_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_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
|
//! Errors emitted by ty_utils
|
||||||
|
|
||||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||||
use rustc_middle::ty::Ty;
|
use rustc_middle::ty::{GenericArg, Ty};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
@@ -100,3 +100,25 @@ pub struct NonPrimitiveSimdType<'tcx> {
|
|||||||
pub ty: Ty<'tcx>,
|
pub ty: Ty<'tcx>,
|
||||||
pub e_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,
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,46 +1,165 @@
|
|||||||
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
|
use rustc_errors::ErrorGuaranteed;
|
||||||
use rustc_hir::{def::DefKind, def_id::LocalDefId};
|
use rustc_hir::{def::DefKind, def_id::LocalDefId};
|
||||||
use rustc_middle::ty::util::CheckRegions;
|
use rustc_middle::ty::util::{CheckRegions, NotUniqueParam};
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
|
use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
|
||||||
|
use rustc_span::Span;
|
||||||
use rustc_type_ir::AliasKind;
|
use rustc_type_ir::AliasKind;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
|
use crate::errors::{DuplicateArg, NotParam};
|
||||||
|
|
||||||
struct OpaqueTypeCollector<'tcx> {
|
struct OpaqueTypeCollector<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
opaques: Vec<LocalDefId>,
|
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> {
|
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
|
||||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<!> {
|
type BreakTy = ErrorGuaranteed;
|
||||||
|
|
||||||
|
#[instrument(skip(self), ret, level = "trace")]
|
||||||
|
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<ErrorGuaranteed> {
|
||||||
match t.kind() {
|
match t.kind() {
|
||||||
ty::Alias(AliasKind::Opaque, alias_ty) => {
|
ty::Alias(AliasKind::Opaque, alias_ty) if alias_ty.def_id.is_local() => {
|
||||||
if let Some(def_id) = alias_ty.def_id.as_local() {
|
if !self.seen.insert(alias_ty.def_id.expect_local()) {
|
||||||
if self
|
|
||||||
.tcx
|
|
||||||
.uses_unique_generic_params(alias_ty.substs, CheckRegions::OnlyEarlyBound)
|
|
||||||
.is_ok()
|
|
||||||
{
|
|
||||||
self.opaques.push(def_id);
|
|
||||||
return ControlFlow::Continue(());
|
return ControlFlow::Continue(());
|
||||||
} else {
|
}
|
||||||
warn!(?t, "opaque types with non-unique params in sig: {t:?}");
|
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)
|
||||||
}
|
}
|
||||||
|
_ => t.super_visit_with(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [LocalDefId] {
|
fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [LocalDefId] {
|
||||||
// FIXME(type_alias_impl_trait): This is definitely still wrong except for RPIT.
|
let kind = tcx.def_kind(item);
|
||||||
match tcx.def_kind(item) {
|
trace!(?kind);
|
||||||
DefKind::Fn | DefKind::AssocFn => {
|
// FIXME(type_alias_impl_trait): This is definitely still wrong except for RPIT and impl trait in assoc types.
|
||||||
let sig = tcx.fn_sig(item).subst_identity();
|
match kind {
|
||||||
let mut collector = OpaqueTypeCollector { tcx, opaques: Vec::new() };
|
// We're also doing this for `AssocTy` for the wf checks in `check_opaque_meets_bounds`
|
||||||
sig.visit_with(&mut collector);
|
DefKind::Fn | DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => {
|
||||||
tcx.arena.alloc_from_iter(collector.opaques)
|
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::Mod
|
||||||
| DefKind::Struct
|
| DefKind::Struct
|
||||||
@@ -51,13 +170,11 @@ fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [
|
|||||||
| DefKind::TyAlias
|
| DefKind::TyAlias
|
||||||
| DefKind::ForeignTy
|
| DefKind::ForeignTy
|
||||||
| DefKind::TraitAlias
|
| DefKind::TraitAlias
|
||||||
| DefKind::AssocTy
|
|
||||||
| DefKind::TyParam
|
| DefKind::TyParam
|
||||||
| DefKind::Const
|
| DefKind::Const
|
||||||
| DefKind::ConstParam
|
| DefKind::ConstParam
|
||||||
| DefKind::Static(_)
|
| DefKind::Static(_)
|
||||||
| DefKind::Ctor(_, _)
|
| DefKind::Ctor(_, _)
|
||||||
| DefKind::AssocConst
|
|
||||||
| DefKind::Macro(_)
|
| DefKind::Macro(_)
|
||||||
| DefKind::ExternCrate
|
| DefKind::ExternCrate
|
||||||
| DefKind::Use
|
| DefKind::Use
|
||||||
|
|||||||
@@ -19,4 +19,5 @@ impl<'a> A<'a> for C {
|
|||||||
type B<'b> = impl Clone;
|
type B<'b> = impl Clone;
|
||||||
|
|
||||||
fn a(&'a self) -> Self::B<'a> {} //~ ERROR: non-defining opaque type use in defining scope
|
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
|
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> {}
|
LL | fn a(&'a self) -> Self::B<'a> {}
|
||||||
| ^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ generic argument `'a` used twice
|
||||||
|
|
|
|
||||||
note: lifetime used multiple times
|
note: for this opaque type
|
||||||
--> $DIR/issue-88595.rs:18:6
|
--> $DIR/issue-88595.rs:19:18
|
||||||
|
|
|
|
||||||
LL | impl<'a> A<'a> for C {
|
|
||||||
| ^^
|
|
||||||
LL | type B<'b> = impl Clone;
|
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)) -> _`
|
= note: expected signature `fn(&b::Bar, &(b::Foo, i32)) -> _`
|
||||||
found signature `fn(&b::Bar, &(b::Bar, 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
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ 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) -> (Self::Opaque1, Self::Opaque2) {
|
fn constrain(self) -> (Self::Opaque1, Self::Opaque2) {
|
||||||
((), self)
|
let a: Self::Opaque1 = ();
|
||||||
|
let b: Self::Opaque2 = self;
|
||||||
|
(a, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user