Skip to content

Commit

Permalink
Make DefiningAnchor::Bind only store the opaque types that may be c…
Browse files Browse the repository at this point in the history
…onstrained, 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
  • Loading branch information
oli-obk committed Mar 5, 2024
1 parent da35734 commit 04461ee
Show file tree
Hide file tree
Showing 45 changed files with 281 additions and 227 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/consumers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,10 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> {

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, hir_owner.def_id))
.build();
let promoted: &IndexSlice<_, _> = &promoted.borrow();
let opt_closure_req = do_mir_borrowck(&infcx, input_body, promoted, None).0;
debug!("mir_borrowck done");
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/region_infer/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ fn check_opaque_type_well_formed<'tcx>(
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);
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,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);

Expand Down Expand Up @@ -1569,7 +1569,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);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/inherited.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));

Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ pub struct InferCtxt<'tcx> {
///
/// Its default value is `DefiningAnchor::Error`, 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
Expand Down Expand Up @@ -613,7 +613,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.
Expand Down Expand Up @@ -644,7 +644,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
}
Expand Down
60 changes: 3 additions & 57 deletions compiler/rustc_infer/src/infer/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,28 +368,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 {
let defined_opaque_types = match self.defining_use_anchor {
DefiningAnchor::Bubble | DefiningAnchor::Error => 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)
}
}

Expand Down Expand Up @@ -638,43 +624,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
}
10 changes: 10 additions & 0 deletions compiler/rustc_middle/src/mir/type_foldable.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! `TypeFoldable` implementations for MIR types
use rustc_ast::InlineAsmTemplatePiece;
use rustc_hir::def_id::LocalDefId;

use super::*;

Expand Down Expand Up @@ -44,6 +45,15 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx [Span] {
}
}

impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx [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,
Expand Down
16 changes: 11 additions & 5 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -1001,10 +1001,10 @@ 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`.
Bind(&'tcx [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
Expand All @@ -1018,3 +1018,9 @@ pub enum DefiningAnchor {
/// 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))
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/traits/solve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,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>,
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,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};
Expand Down Expand Up @@ -3373,19 +3373,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);
Expand Down
16 changes: 15 additions & 1 deletion compiler/rustc_ty_utils/src/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,9 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {

#[instrument(level = "trace", skip(self))]
fn collect_taits_declared_in_body(&mut self) {
let body = self.tcx.hir().body(self.tcx.hir().body_owned_by(self.item)).value;
// Some things not necessarily have bodies, like method declarations in traits.
let Some(body_owner) = self.tcx.hir().maybe_body_owned_by(self.item) else { return };
let body = self.tcx.hir().body(body_owner).value;
struct TaitInBodyFinder<'a, 'tcx> {
collector: &'a mut OpaqueTypeCollector<'tcx>,
}
Expand Down Expand Up @@ -212,12 +214,24 @@ 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)
.instantiate(self.tcx, alias_ty.args)
.visit_with(self)?;
}
// RPITIT are encoded as projections, not opaque types, make sure to handle these special
// projections independently of the projection handling below.
ty::Alias(ty::Projection, alias_ty)
if let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) =
self.tcx.opt_rpitit_info(alias_ty.def_id)
&& fn_def_id == self.item.into() =>
{
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::Alias(ty::Projection, alias_ty) => {
// This avoids having to do normalization of `Self::AssocTy` by only
// supporting the case of a method defining opaque types from assoc types
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_ty_utils/src/sig_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,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 ControlFlow::Continue(());
}
// Associated types in traits don't necessarily have a type that we can visit
visitor.visit(ty.span, tcx.type_of(item).instantiate_identity())?;
}
Expand Down
1 change: 1 addition & 0 deletions tests/ui/generic-associated-types/issue-88595.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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: non-defining opaque type use in defining scope
}
16 changes: 15 additions & 1 deletion tests/ui/generic-associated-types/issue-88595.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,19 @@ note: for this opaque type
LL | type B<'b> = impl Clone;
| ^^^^^^^^^^

error: aborting due to 1 previous error
error: non-defining opaque type use in defining scope
--> $DIR/issue-88595.rs:21:35
|
LL | fn a(&'a self) -> Self::B<'a> {}
| ^^
|
note: lifetime used multiple times
--> $DIR/issue-88595.rs:18:6
|
LL | impl<'a> A<'a> for C {
| ^^
LL | type B<'b> = impl Clone;
| ^^

error: aborting due to 2 previous errors

6 changes: 1 addition & 5 deletions tests/ui/impl-trait/auto-trait-leak.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,12 @@ LL | send(cycle1().clone());
| |
| required by a bound introduced by this call
|
= 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
note: opaque type is declared here
--> $DIR/auto-trait-leak.rs:11:16
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^
note: 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
--> $DIR/auto-trait-leak.rs:17:4
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^
note: required by a bound in `send`
--> $DIR/auto-trait-leak.rs:4:12
|
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/impl-trait/issues/issue-78722-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ struct Bug {
//~^ ERROR future that resolves to `u8`, but it resolves to `()`
async {}
}
// FIXME(type_alias_impl_trait): inform the user about why `F` is not available here.
let f: F = async { 1 };
//~^ ERROR item constrains opaque type that is not in its signature
//~| ERROR `async` blocks are not allowed in constants
//~^ ERROR mismatched types
1
}],
}
Expand Down
Loading

0 comments on commit 04461ee

Please sign in to comment.