Auto merge of #121796 - oli-obk:eager_opaque_checks3, r=lcnr
Make `DefiningAnchor::Bind` only store the opaque types that may be constrained, instead of the current infcx root item. This makes `Bind` almost always be empty, so we can start forwarding it to queries, allowing us to remove `Bubble` entirely (not done in this PR) The only behaviour change is in diagnostics. r? `@lcnr` `@compiler-errors`
This commit is contained in:
commit
4ccbb7dc95
48 changed files with 322 additions and 251 deletions
|
@ -106,7 +106,7 @@ pub fn get_body_with_borrowck_facts(
|
|||
options: ConsumerOptions,
|
||||
) -> BodyWithBorrowckFacts<'_> {
|
||||
let (input_body, promoted) = tcx.mir_promoted(def);
|
||||
let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(def)).build();
|
||||
let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::bind(tcx, def)).build();
|
||||
let input_body: &Body<'_> = &input_body.borrow();
|
||||
let promoted: &IndexSlice<_, _> = &promoted.borrow();
|
||||
*super::do_mir_borrowck(&infcx, input_body, promoted, Some(options)).1.unwrap()
|
||||
|
|
|
@ -126,10 +126,7 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> {
|
|||
return tcx.arena.alloc(result);
|
||||
}
|
||||
|
||||
let hir_owner = tcx.local_def_id_to_hir_id(def).owner;
|
||||
|
||||
let infcx =
|
||||
tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id)).build();
|
||||
let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::bind(tcx, def)).build();
|
||||
let promoted: &IndexSlice<_, _> = &promoted.borrow();
|
||||
let opt_closure_req = do_mir_borrowck(&infcx, input_body, promoted, None).0;
|
||||
debug!("mir_borrowck done");
|
||||
|
|
|
@ -311,13 +311,13 @@ fn check_opaque_type_well_formed<'tcx>(
|
|||
parent_def_id = tcx.local_parent(parent_def_id);
|
||||
}
|
||||
|
||||
// FIXME(-Znext-solver): We probably should use `DefiningAnchor::Error`
|
||||
// FIXME(-Znext-solver): We probably should use `DefiningAnchor::Bind(&[])`
|
||||
// and prepopulate this `InferCtxt` with known opaque values, rather than
|
||||
// using the `Bind` anchor here. For now it's fine.
|
||||
let infcx = tcx
|
||||
.infer_ctxt()
|
||||
.with_next_trait_solver(next_trait_solver)
|
||||
.with_opaque_type_inference(DefiningAnchor::Bind(parent_def_id))
|
||||
.with_opaque_type_inference(DefiningAnchor::bind(tcx, parent_def_id))
|
||||
.build();
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
let identity_args = GenericArgs::identity_for_item(tcx, def_id);
|
||||
|
|
|
@ -347,7 +347,7 @@ fn check_opaque_meets_bounds<'tcx>(
|
|||
|
||||
let infcx = tcx
|
||||
.infer_ctxt()
|
||||
.with_opaque_type_inference(DefiningAnchor::Bind(defining_use_anchor))
|
||||
.with_opaque_type_inference(DefiningAnchor::bind(tcx, defining_use_anchor))
|
||||
.build();
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
|
||||
|
@ -1558,7 +1558,7 @@ pub(super) fn check_coroutine_obligations(
|
|||
.ignoring_regions()
|
||||
// Bind opaque types to type checking root, as they should have been checked by borrowck,
|
||||
// but may show up in some cases, like when (root) obligations are stalled in the new solver.
|
||||
.with_opaque_type_inference(DefiningAnchor::Bind(typeck.hir_owner.def_id))
|
||||
.with_opaque_type_inference(DefiningAnchor::bind(tcx, typeck.hir_owner.def_id))
|
||||
.build();
|
||||
|
||||
let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(&infcx);
|
||||
|
|
|
@ -79,7 +79,7 @@ impl<'tcx> Inherited<'tcx> {
|
|||
let infcx = tcx
|
||||
.infer_ctxt()
|
||||
.ignoring_regions()
|
||||
.with_opaque_type_inference(DefiningAnchor::Bind(def_id))
|
||||
.with_opaque_type_inference(DefiningAnchor::bind(tcx, def_id))
|
||||
.build();
|
||||
let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner));
|
||||
|
||||
|
|
|
@ -242,9 +242,10 @@ pub struct InferCtxt<'tcx> {
|
|||
/// short lived InferCtxt within queries. The opaque type obligations are forwarded
|
||||
/// to the outside until the end up in an `InferCtxt` for typeck or borrowck.
|
||||
///
|
||||
/// Its default value is `DefiningAnchor::Error`, this way it is easier to catch errors that
|
||||
/// Its default value is `DefiningAnchor::Bind(&[])`, which means no opaque types may be defined.
|
||||
/// This way it is easier to catch errors that
|
||||
/// might come up during inference or typeck.
|
||||
pub defining_use_anchor: DefiningAnchor,
|
||||
pub defining_use_anchor: DefiningAnchor<'tcx>,
|
||||
|
||||
/// Whether this inference context should care about region obligations in
|
||||
/// the root universe. Most notably, this is used during hir typeck as region
|
||||
|
@ -605,7 +606,7 @@ impl fmt::Display for FixupError {
|
|||
/// Used to configure inference contexts before their creation.
|
||||
pub struct InferCtxtBuilder<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
defining_use_anchor: DefiningAnchor,
|
||||
defining_use_anchor: DefiningAnchor<'tcx>,
|
||||
considering_regions: bool,
|
||||
skip_leak_check: bool,
|
||||
/// Whether we are in coherence mode.
|
||||
|
@ -620,7 +621,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
|
||||
InferCtxtBuilder {
|
||||
tcx: self,
|
||||
defining_use_anchor: DefiningAnchor::Error,
|
||||
defining_use_anchor: DefiningAnchor::Bind(ty::List::empty()),
|
||||
considering_regions: true,
|
||||
skip_leak_check: false,
|
||||
intercrate: false,
|
||||
|
@ -636,7 +637,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
|||
/// It is only meant to be called in two places, for typeck
|
||||
/// (via `Inherited::build`) and for the inference context used
|
||||
/// in mir borrowck.
|
||||
pub fn with_opaque_type_inference(mut self, defining_use_anchor: DefiningAnchor) -> Self {
|
||||
pub fn with_opaque_type_inference(mut self, defining_use_anchor: DefiningAnchor<'tcx>) -> Self {
|
||||
self.defining_use_anchor = defining_use_anchor;
|
||||
self
|
||||
}
|
||||
|
@ -1208,13 +1209,11 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
pub fn take_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx> {
|
||||
debug_assert_ne!(self.defining_use_anchor, DefiningAnchor::Error);
|
||||
std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
pub fn clone_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx> {
|
||||
debug_assert_ne!(self.defining_use_anchor, DefiningAnchor::Error);
|
||||
self.inner.borrow().opaque_type_storage.opaque_types.clone()
|
||||
}
|
||||
|
||||
|
|
|
@ -150,9 +150,6 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
DefiningAnchor::Bubble => {}
|
||||
DefiningAnchor::Error => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() {
|
||||
// We could accept this, but there are various ways to handle this situation, and we don't
|
||||
|
@ -378,28 +375,14 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
/// in its defining scope.
|
||||
#[instrument(skip(self), level = "trace", ret)]
|
||||
pub fn opaque_type_origin(&self, def_id: LocalDefId) -> Option<OpaqueTyOrigin> {
|
||||
let opaque_hir_id = self.tcx.local_def_id_to_hir_id(def_id);
|
||||
let parent_def_id = match self.defining_use_anchor {
|
||||
DefiningAnchor::Bubble | DefiningAnchor::Error => return None,
|
||||
let defined_opaque_types = match self.defining_use_anchor {
|
||||
DefiningAnchor::Bubble => return None,
|
||||
DefiningAnchor::Bind(bind) => bind,
|
||||
};
|
||||
|
||||
let origin = self.tcx.opaque_type_origin(def_id);
|
||||
let in_definition_scope = match origin {
|
||||
// Async `impl Trait`
|
||||
hir::OpaqueTyOrigin::AsyncFn(parent) => parent == parent_def_id,
|
||||
// Anonymous `impl Trait`
|
||||
hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
|
||||
// Named `type Foo = impl Bar;`
|
||||
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)
|
||||
|
||||
defined_opaque_types.contains(&def_id).then_some(origin)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -656,43 +639,3 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if `opaque_hir_id` is a sibling or a child of a sibling of `def_id`.
|
||||
///
|
||||
/// Example:
|
||||
/// ```ignore UNSOLVED (is this a bug?)
|
||||
/// # #![feature(type_alias_impl_trait)]
|
||||
/// pub mod foo {
|
||||
/// pub mod bar {
|
||||
/// pub trait Bar { /* ... */ }
|
||||
/// pub type Baz = impl Bar;
|
||||
///
|
||||
/// # impl Bar for () {}
|
||||
/// fn f1() -> Baz { /* ... */ }
|
||||
/// }
|
||||
/// fn f2() -> bar::Baz { /* ... */ }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Here, `def_id` is the `LocalDefId` of the defining use of the opaque type (e.g., `f1` or `f2`),
|
||||
/// and `opaque_hir_id` is the `HirId` of the definition of the opaque type `Baz`.
|
||||
/// For the above example, this function returns `true` for `f1` and `false` for `f2`.
|
||||
fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hir::HirId) -> bool {
|
||||
let mut hir_id = tcx.local_def_id_to_hir_id(def_id);
|
||||
|
||||
// Named opaque types can be defined by any siblings or children of siblings.
|
||||
let scope = tcx.hir().get_defining_scope(opaque_hir_id);
|
||||
// We walk up the node tree until we hit the root or the scope of the opaque type.
|
||||
while hir_id != scope && hir_id != hir::CRATE_HIR_ID {
|
||||
hir_id = tcx.hir().get_parent_item(hir_id).into();
|
||||
}
|
||||
// Syntactically, we are allowed to define the concrete type if:
|
||||
let res = hir_id == scope;
|
||||
trace!(
|
||||
"may_define_opaque_type(def={:?}, opaque_node={:?}) = {}",
|
||||
tcx.hir_node(hir_id),
|
||||
tcx.hir_node(opaque_hir_id),
|
||||
res
|
||||
);
|
||||
res
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! `TypeFoldable` implementations for MIR types
|
||||
|
||||
use rustc_ast::InlineAsmTemplatePiece;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
@ -44,6 +45,15 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx [Span] {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<LocalDefId> {
|
||||
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
|
||||
self,
|
||||
_folder: &mut F,
|
||||
) -> Result<Self, F::Error> {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<PlaceElem<'tcx>> {
|
||||
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
|
||||
self,
|
||||
|
|
|
@ -12,8 +12,8 @@ pub mod util;
|
|||
use crate::infer::canonical::Canonical;
|
||||
use crate::mir::ConstraintCategory;
|
||||
use crate::ty::abstract_const::NotConstEvaluatable;
|
||||
use crate::ty::GenericArgsRef;
|
||||
use crate::ty::{self, AdtKind, Ty};
|
||||
use crate::ty::{GenericArgsRef, TyCtxt};
|
||||
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{Applicability, Diag, EmissionGuarantee};
|
||||
|
@ -1001,10 +1001,14 @@ pub enum CodegenObligationError {
|
|||
/// opaques are replaced with inference vars eagerly in the old solver (e.g.
|
||||
/// in projection, and in the signature during function type-checking).
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub enum DefiningAnchor {
|
||||
/// Define opaques which are in-scope of the `LocalDefId`. Also, eagerly
|
||||
/// replace opaque types in `replace_opaque_types_with_inference_vars`.
|
||||
Bind(LocalDefId),
|
||||
pub enum DefiningAnchor<'tcx> {
|
||||
/// Define opaques which are in-scope of the current item being analyzed.
|
||||
/// Also, eagerly replace these opaque types in `replace_opaque_types_with_inference_vars`.
|
||||
///
|
||||
/// If the list is empty, do not allow any opaques to be defined. This is used to catch type mismatch
|
||||
/// errors when handling opaque types, and also should be used when we would
|
||||
/// otherwise reveal opaques (such as [`Reveal::All`] reveal mode).
|
||||
Bind(&'tcx ty::List<LocalDefId>),
|
||||
/// In contexts where we don't currently know what opaques are allowed to be
|
||||
/// defined, such as (old solver) canonical queries, we will simply allow
|
||||
/// opaques to be defined, but "bubble" them up in the canonical response or
|
||||
|
@ -1013,8 +1017,10 @@ pub enum DefiningAnchor {
|
|||
/// We do not eagerly replace opaque types in `replace_opaque_types_with_inference_vars`,
|
||||
/// which may affect what predicates pass and fail in the old trait solver.
|
||||
Bubble,
|
||||
/// Do not allow any opaques to be defined. This is used to catch type mismatch
|
||||
/// errors when handling opaque types, and also should be used when we would
|
||||
/// otherwise reveal opaques (such as [`Reveal::All`] reveal mode).
|
||||
Error,
|
||||
}
|
||||
|
||||
impl<'tcx> DefiningAnchor<'tcx> {
|
||||
pub fn bind(tcx: TyCtxt<'tcx>, item: LocalDefId) -> Self {
|
||||
Self::Bind(tcx.opaque_types_defined_by(item))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ impl MaybeCause {
|
|||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct QueryInput<'tcx, T> {
|
||||
pub goal: Goal<'tcx, T>,
|
||||
pub anchor: DefiningAnchor,
|
||||
pub anchor: DefiningAnchor<'tcx>,
|
||||
pub predefined_opaques_in_body: PredefinedOpaques<'tcx>,
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ use crate::traits;
|
|||
use crate::ty::GenericArgsRef;
|
||||
use crate::ty::{self, AdtDef, Ty};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_serialize::{Decodable, Encodable};
|
||||
use rustc_span::Span;
|
||||
|
@ -431,6 +432,15 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<Fi
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<LocalDefId> {
|
||||
fn decode(decoder: &mut D) -> &'tcx Self {
|
||||
let len = decoder.read_usize();
|
||||
decoder.interner().mk_local_def_ids_from_iter(
|
||||
(0..len).map::<LocalDefId, _>(|_| Decodable::decode(decoder)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
|
||||
for ty::List<(VariantIdx, FieldIdx)>
|
||||
{
|
||||
|
|
|
@ -2014,6 +2014,14 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
self.intern_local_def_ids(clauses)
|
||||
}
|
||||
|
||||
pub fn mk_local_def_ids_from_iter<I, T>(self, iter: I) -> T::Output
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
T: CollectAndApply<LocalDefId, &'tcx List<LocalDefId>>,
|
||||
{
|
||||
T::collect_and_apply(iter, |xs| self.mk_local_def_ids(xs))
|
||||
}
|
||||
|
||||
pub fn mk_const_list_from_iter<I, T>(self, iter: I) -> T::Output
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
|
|
|
@ -16,7 +16,7 @@ use rustc_middle::traits::solve::{
|
|||
CanonicalInput, CanonicalResponse, Certainty, IsNormalizesToHack, PredefinedOpaques,
|
||||
PredefinedOpaquesData, QueryResult,
|
||||
};
|
||||
use rustc_middle::traits::{specialization_graph, DefiningAnchor};
|
||||
use rustc_middle::traits::specialization_graph;
|
||||
use rustc_middle::ty::{
|
||||
self, InferCtxtLike, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
|
||||
TypeVisitable, TypeVisitableExt, TypeVisitor,
|
||||
|
@ -258,10 +258,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
// instead of taking them. This would cause an ICE here, since we have
|
||||
// assertions against dropping an `InferCtxt` without taking opaques.
|
||||
// FIXME: Once we remove support for the old impl we can remove this.
|
||||
if input.anchor != DefiningAnchor::Error {
|
||||
// This seems ok, but fragile.
|
||||
let _ = infcx.take_opaque_types();
|
||||
}
|
||||
let _ = infcx.take_opaque_types();
|
||||
|
||||
result
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ use rustc_hir::{GenericParam, Item, Node};
|
|||
use rustc_infer::infer::error_reporting::TypeErrCtxt;
|
||||
use rustc_infer::infer::{InferOk, TypeTrace};
|
||||
use rustc_middle::traits::select::OverflowError;
|
||||
use rustc_middle::traits::{DefiningAnchor, SignatureMismatchData};
|
||||
use rustc_middle::traits::SignatureMismatchData;
|
||||
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::fold::{BottomUpFolder, TypeFolder, TypeSuperFoldable};
|
||||
|
@ -3390,19 +3390,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
obligation.cause.span,
|
||||
format!("cannot check whether the hidden type of {name} satisfies auto traits"),
|
||||
);
|
||||
|
||||
err.note(
|
||||
"fetching the hidden types of an opaque inside of the defining scope is not supported. \
|
||||
You can try moving the opaque type and the item that actually registers a hidden type into a new submodule",
|
||||
);
|
||||
err.span_note(self.tcx.def_span(def_id), "opaque type is declared here");
|
||||
match self.defining_use_anchor {
|
||||
DefiningAnchor::Bubble | DefiningAnchor::Error => {}
|
||||
DefiningAnchor::Bind(bind) => {
|
||||
err.span_note(
|
||||
self.tcx.def_ident_span(bind).unwrap_or_else(|| self.tcx.def_span(bind)),
|
||||
"this item depends on auto traits of the hidden type, \
|
||||
but may also be registering the hidden type. \
|
||||
This is not supported right now. \
|
||||
You can try moving the opaque type and the item that actually registers a hidden type into a new submodule".to_string(),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
self.note_obligation_cause(&mut err, &obligation);
|
||||
self.point_at_returns_when_relevant(&mut err, &obligation);
|
||||
|
|
|
@ -54,7 +54,7 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
|
|||
self.span = old;
|
||||
}
|
||||
|
||||
fn parent_trait_ref(&self) -> Option<ty::TraitRef<'tcx>> {
|
||||
fn parent_impl_trait_ref(&self) -> Option<ty::TraitRef<'tcx>> {
|
||||
let parent = self.parent()?;
|
||||
if matches!(self.tcx.def_kind(parent), DefKind::Impl { .. }) {
|
||||
Some(self.tcx.impl_trait_ref(parent)?.instantiate_identity())
|
||||
|
@ -210,6 +210,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
|
|||
ty::Alias(ty::Opaque, alias_ty) if alias_ty.def_id.is_local() => {
|
||||
self.visit_opaque_ty(alias_ty);
|
||||
}
|
||||
// Skips type aliases, as they are meant to be transparent.
|
||||
ty::Alias(ty::Weak, alias_ty) if alias_ty.def_id.is_local() => {
|
||||
self.tcx
|
||||
.type_of(alias_ty.def_id)
|
||||
|
@ -220,11 +221,11 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
|
|||
// 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 let Some(parent_trait_ref) = self.parent_trait_ref() {
|
||||
if let Some(impl_trait_ref) = self.parent_impl_trait_ref() {
|
||||
// If the trait ref of the associated item and the impl differs,
|
||||
// then we can't use the impl's identity args below, so
|
||||
// just skip.
|
||||
if alias_ty.trait_ref(self.tcx) == parent_trait_ref {
|
||||
if alias_ty.trait_ref(self.tcx) == impl_trait_ref {
|
||||
let parent = self.parent().expect("we should have a parent here");
|
||||
|
||||
for &assoc in self.tcx.associated_items(parent).in_definition_order() {
|
||||
|
@ -241,7 +242,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
|
|||
|
||||
let impl_args = alias_ty.args.rebase_onto(
|
||||
self.tcx,
|
||||
parent_trait_ref.def_id,
|
||||
impl_trait_ref.def_id,
|
||||
ty::GenericArgs::identity_for_item(self.tcx, parent),
|
||||
);
|
||||
|
||||
|
@ -259,6 +260,24 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) =
|
||||
self.tcx.opt_rpitit_info(alias_ty.def_id)
|
||||
&& fn_def_id == self.item.into()
|
||||
{
|
||||
// RPITIT in trait definitions get desugared to an associated type. For
|
||||
// default methods we also create an opaque type this associated type
|
||||
// normalizes to. The associated type is only known to normalize to the
|
||||
// opaque if it is fully concrete. There could otherwise be an impl
|
||||
// overwriting the default method.
|
||||
//
|
||||
// However, we have to be able to normalize the associated type while inside
|
||||
// of the default method. This is normally handled by adding an unchecked
|
||||
// `Projection(<Self as Trait>::synthetic_assoc_ty, trait_def::opaque)`
|
||||
// assumption to the `param_env` of the default method. We also separately
|
||||
// rely on that assumption here.
|
||||
let ty = self.tcx.type_of(alias_ty.def_id).instantiate(self.tcx, alias_ty.args);
|
||||
let ty::Alias(ty::Opaque, alias_ty) = ty.kind() else { bug!("{ty:?}") };
|
||||
self.visit_opaque_ty(alias_ty);
|
||||
}
|
||||
}
|
||||
ty::Adt(def, _) if def.did().is_local() => {
|
||||
|
|
|
@ -23,8 +23,14 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>(
|
|||
match kind {
|
||||
// Walk over the signature of the function
|
||||
DefKind::AssocFn | DefKind::Fn => {
|
||||
let ty_sig = tcx.fn_sig(item).instantiate_identity();
|
||||
let hir_sig = tcx.hir_node_by_def_id(item).fn_decl().unwrap();
|
||||
// If the type of the item uses `_`, we're gonna error out anyway, but
|
||||
// typeck (which type_of invokes below), will call back into opaque_types_defined_by
|
||||
// causing a cycle. So we just bail out in this case.
|
||||
if hir_sig.output.get_infer_ret_ty().is_some() {
|
||||
return V::Result::output();
|
||||
}
|
||||
let ty_sig = tcx.fn_sig(item).instantiate_identity();
|
||||
// Walk over the inputs and outputs manually in order to get good spans for them.
|
||||
try_visit!(visitor.visit(hir_sig.output.span(), ty_sig.output()));
|
||||
for (hir, ty) in hir_sig.inputs.iter().zip(ty_sig.inputs().iter()) {
|
||||
|
@ -39,6 +45,12 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>(
|
|||
// Walk over the type of the item
|
||||
DefKind::Static(_) | DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => {
|
||||
if let Some(ty) = tcx.hir_node_by_def_id(item).ty() {
|
||||
// If the type of the item uses `_`, we're gonna error out anyway, but
|
||||
// typeck (which type_of invokes below), will call back into opaque_types_defined_by
|
||||
// causing a cycle. So we just bail out in this case.
|
||||
if ty.is_suggestable_infer_ty() {
|
||||
return V::Result::output();
|
||||
}
|
||||
// Associated types in traits don't necessarily have a type that we can visit
|
||||
try_visit!(visitor.visit(ty.span, tcx.type_of(item).instantiate_identity()));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue