Skip to content

Commit

Permalink
Auto merge of rust-lang#122077 - oli-obk:eager_opaque_checks4, r=<try>
Browse files Browse the repository at this point in the history
Pass list of defineable opaque types into canonical queries

based on rust-lang#121796

This eliminates `DefiningAnchor::Bubble` for good and brings the old solver closer to the new one wrt cycles and nested obligations.

r? `@ghost`
  • Loading branch information
bors committed Mar 6, 2024
2 parents 8039906 + 119a935 commit e41ca9a
Show file tree
Hide file tree
Showing 76 changed files with 572 additions and 415 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
13 changes: 12 additions & 1 deletion compiler/rustc_borrowck/src/region_infer/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,17 @@ impl<'tcx> RegionInferenceContext<'tcx> {
opaque_type_key,
universal_concrete_type,
);

// Sometimes, when the hidden type is an inference variable, it can happen that
// the hidden type becomes the opaque type itself. In this case, this was an opaque
// usage of the opaque type and we can ignore it. This check is mirrored in typeck's
// writeback.
if let ty::Alias(ty::Opaque, alias_ty) = universal_concrete_type.ty.kind()
&& alias_ty.def_id == opaque_type_key.def_id.to_def_id()
&& alias_ty.args == opaque_type_key.args
{
continue;
}
// Sometimes two opaque types are the same only after we remap the generic parameters
// back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)`
// and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we only know that
Expand Down Expand Up @@ -317,7 +328,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: 4 additions & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3605,6 +3605,10 @@ impl<'hir> Node<'hir> {
ImplItemKind::Type(ty) => Some(ty),
_ => None,
},
Node::ForeignItem(it) => match it.kind {
ForeignItemKind::Static(ty, _) => Some(ty),
_ => None,
},
_ => None,
}
}
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 @@ -1568,7 +1568,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
9 changes: 8 additions & 1 deletion compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ impl<'tcx> InferCtxt<'tcx> {
let param_env = self.tcx.canonical_param_env_cache.get_or_insert(
self.tcx,
param_env,
self.defining_use_anchor,
query_state,
|tcx, param_env, query_state| {
// FIXME(#118965): We don't canonicalize the static lifetimes that appear in the
Expand Down Expand Up @@ -540,6 +541,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
max_universe: ty::UniverseIndex::ROOT,
variables: List::empty(),
value: (),
defining_anchor: infcx.map(|i| i.defining_use_anchor).unwrap_or_default(),
};
Canonicalizer::canonicalize_with_base(
base,
Expand Down Expand Up @@ -609,7 +611,12 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
.max()
.unwrap_or(ty::UniverseIndex::ROOT);

Canonical { max_universe, variables: canonical_variables, value: (base.value, out_value) }
Canonical {
max_universe,
variables: canonical_variables,
value: (base.value, out_value),
defining_anchor: base.defining_anchor,
}
}

/// Creates a canonical variable replacing `kind` from the input,
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_infer/src/infer/canonical/query_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use rustc_index::Idx;
use rustc_index::IndexVec;
use rustc_middle::arena::ArenaAllocatable;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::traits::DefiningAnchor;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::{self, BoundVar, Ty, TyCtxt};
use rustc_middle::ty::{GenericArg, GenericArgKind};
Expand Down Expand Up @@ -163,6 +164,9 @@ impl<'tcx> InferCtxt<'tcx> {
}

fn take_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> {
if self.defining_use_anchor == DefiningAnchor::Error {
return vec![];
}
self.take_opaque_types().into_iter().map(|(k, v)| (k, v.hidden_type.ty)).collect()
}

Expand Down
22 changes: 10 additions & 12 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,17 +242,11 @@ impl<'tcx> InferCtxtInner<'tcx> {
pub struct InferCtxt<'tcx> {
pub tcx: TyCtxt<'tcx>,

/// The `DefId` of the item in whose context we are performing inference or typeck.
/// It is used to check whether an opaque type use is a defining use.
///
/// If it is `DefiningAnchor::Bubble`, we can't resolve opaque types here and need to bubble up
/// the obligation. This frequently happens for
/// 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.
/// The `DefIds` of the opaque types that may have their hidden types constrained.
///
/// 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 @@ -399,6 +393,10 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
fn probe_ct_var(&self, vid: ConstVid) -> Option<ty::Const<'tcx>> {
self.probe_const_var(vid).ok()
}

fn defining_anchor(&self) -> DefiningAnchor<'tcx> {
self.defining_use_anchor
}
}

/// See the `error_reporting` module for more details.
Expand Down Expand Up @@ -613,7 +611,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 +642,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 Expand Up @@ -677,14 +675,14 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
/// the bound values in `C` to their instantiated values in `V`
/// (in other words, `S(C) = V`).
pub fn build_with_canonical<T>(
&mut self,
self,
span: Span,
canonical: &Canonical<'tcx, T>,
) -> (InferCtxt<'tcx>, T, CanonicalVarValues<'tcx>)
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
let infcx = self.build();
let infcx = self.with_opaque_type_inference(canonical.defining_anchor).build();
let (value, args) = infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
(infcx, value, args)
}
Expand Down
63 changes: 4 additions & 59 deletions compiler/rustc_infer/src/infer/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,6 @@ impl<'tcx> InferCtxt<'tcx> {
return None;
}
}
DefiningAnchor::Bubble => {}
DefiningAnchor::Error => {
return None;
}
Expand Down Expand Up @@ -378,28 +377,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::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 @@ -639,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
}
11 changes: 5 additions & 6 deletions compiler/rustc_middle/src/infer/canonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use std::ops::Index;

use crate::infer::MemberConstraint;
use crate::mir::ConstraintCategory;
use crate::traits::DefiningAnchor;
use crate::ty::GenericArg;
use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt, TypeFlags, TypeVisitableExt};

Expand Down Expand Up @@ -153,11 +154,6 @@ pub struct QueryResponse<'tcx, R> {
pub var_values: CanonicalVarValues<'tcx>,
pub region_constraints: QueryRegionConstraints<'tcx>,
pub certainty: Certainty,
/// List of opaque types which we tried to compare to another type.
/// Inside the query we don't know yet whether the opaque type actually
/// should get its hidden type inferred. So we bubble the opaque type
/// and the type it was compared against upwards and let the query caller
/// handle it.
pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>,
pub value: R,
}
Expand Down Expand Up @@ -316,6 +312,7 @@ impl<'tcx> CanonicalParamEnvCache<'tcx> {
&self,
tcx: TyCtxt<'tcx>,
key: ty::ParamEnv<'tcx>,
defining_anchor: DefiningAnchor<'tcx>,
state: &mut OriginalQueryValues<'tcx>,
canonicalize_op: fn(
TyCtxt<'tcx>,
Expand All @@ -330,6 +327,7 @@ impl<'tcx> CanonicalParamEnvCache<'tcx> {
max_universe: ty::UniverseIndex::ROOT,
variables: List::empty(),
value: key,
defining_anchor,
};
}

Expand All @@ -344,7 +342,8 @@ impl<'tcx> CanonicalParamEnvCache<'tcx> {
*canonical
}
Entry::Vacant(e) => {
let canonical = canonicalize_op(tcx, key, state);
let mut canonical = canonicalize_op(tcx, key, state);
canonical.defining_anchor = defining_anchor;
let OriginalQueryValues { var_values, universe_map } = state;
assert_eq!(universe_map.len(), 1);
e.insert((canonical, tcx.arena.alloc_slice(var_values)));
Expand Down
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 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,
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_middle/src/query/plumbing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,10 +340,10 @@ macro_rules! define_callbacks {
<$($K)* as keys::Key>::CacheSelector as CacheSelector<'tcx, Erase<$V>>
>::Cache;

// Ensure that keys grow no larger than 64 bytes
// Ensure that keys grow no larger than 72 bytes
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
const _: () = {
if mem::size_of::<Key<'static>>() > 64 {
if mem::size_of::<Key<'static>>() > 72 {
panic!("{}", concat!(
"the query `",
stringify!($name),
Expand All @@ -354,10 +354,10 @@ macro_rules! define_callbacks {
}
};

// Ensure that values grow no larger than 64 bytes
// Ensure that values grow no larger than 72 bytes
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
const _: () = {
if mem::size_of::<Value<'static>>() > 64 {
if mem::size_of::<Value<'static>>() > 72 {
panic!("{}", concat!(
"the query `",
stringify!($name),
Expand Down
Loading

0 comments on commit e41ca9a

Please sign in to comment.