Skip to content

Commit

Permalink
Pass list of defineable opaque types into canonical queries
Browse files Browse the repository at this point in the history
  • Loading branch information
oli-obk committed Mar 6, 2024
1 parent 0087834 commit 119a935
Show file tree
Hide file tree
Showing 29 changed files with 89 additions and 130 deletions.
11 changes: 11 additions & 0 deletions 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
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
16 changes: 7 additions & 9 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,13 +242,7 @@ 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.
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 @@ -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
3 changes: 1 addition & 2 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 @@ -379,7 +378,7 @@ impl<'tcx> InferCtxt<'tcx> {
#[instrument(skip(self), level = "trace", ret)]
pub fn opaque_type_origin(&self, def_id: LocalDefId) -> Option<OpaqueTyOrigin> {
let defined_opaque_types = match self.defining_use_anchor {
DefiningAnchor::Bubble | DefiningAnchor::Error => return None,
DefiningAnchor::Error => return None,
DefiningAnchor::Bind(bind) => bind,
};

Expand Down
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
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
10 changes: 2 additions & 8 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1001,21 +1001,15 @@ 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)]
#[derive(Default, TyEncodable, TyDecodable)]
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 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
/// otherwise treat them to be handled later.
///
/// 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).
#[default]
Error,
}

Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_middle/src/traits/solve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use rustc_span::def_id::DefId;

use crate::infer::canonical::{CanonicalVarValues, QueryRegionConstraints};
use crate::traits::query::NoSolution;
use crate::traits::{Canonical, DefiningAnchor};
use crate::traits::Canonical;
use crate::ty::{
self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable,
TypeVisitor,
Expand Down Expand Up @@ -114,7 +114,6 @@ 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<'tcx>,
pub predefined_opaques_in_body: PredefinedOpaques<'tcx>,
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ use std::ops::{Bound, Deref};
#[allow(rustc::usage_of_ty_tykind)]
impl<'tcx> Interner for TyCtxt<'tcx> {
type DefId = DefId;
type DefiningAnchor = traits::DefiningAnchor<'tcx>;
type AdtDef = ty::AdtDef<'tcx>;
type GenericArgs = ty::GenericArgsRef<'tcx>;
type GenericArg = ty::GenericArg<'tcx>;
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_next_trait_solver/src/canonicalizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ impl<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> Canonicalizer<'a, Infc

let (max_universe, variables) = canonicalizer.finalize();

Canonical { max_universe, variables, value }
let defining_anchor = infcx.defining_anchor();
Canonical { defining_anchor, max_universe, variables, value }
}

fn finalize(self) -> (ty::UniverseIndex, I::CanonicalVars) {
Expand Down
7 changes: 3 additions & 4 deletions compiler/rustc_trait_selection/src/infer.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use crate::traits::{self, DefiningAnchor, ObligationCtxt, SelectionContext};
use crate::traits::{self, ObligationCtxt, SelectionContext};

use crate::traits::TraitEngineExt as _;
use rustc_hir::def_id::DefId;
Expand Down Expand Up @@ -133,9 +133,8 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
R: Debug + TypeFoldable<TyCtxt<'tcx>>,
Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>,
{
let (infcx, key, canonical_inference_vars) = self
.with_opaque_type_inference(DefiningAnchor::Bubble)
.build_with_canonical(DUMMY_SP, canonical_key);
let (infcx, key, canonical_inference_vars) =
self.build_with_canonical(DUMMY_SP, canonical_key);
let ocx = ObligationCtxt::new(&infcx);
let value = operation(&ocx, key)?;
ocx.make_canonicalized_query_response(canonical_inference_vars, value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
&mut orig_values,
QueryInput {
goal,
anchor: self.infcx.defining_use_anchor,
predefined_opaques_in_body: self
.tcx()
.mk_predefined_opaques_in_body(PredefinedOpaquesData { opaque_types }),
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
.infer_ctxt()
.intercrate(intercrate)
.with_next_trait_solver(true)
.with_opaque_type_inference(canonical_input.value.anchor)
.build_with_canonical(DUMMY_SP, &canonical_input);

let mut ecx = EvalCtxt {
Expand Down Expand Up @@ -258,7 +257,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 {
if canonical_input.defining_anchor != DefiningAnchor::Error {
// This seems ok, but fragile.
let _ = infcx.take_opaque_types();
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_trait_selection/src/solve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,5 +320,6 @@ fn response_no_constraints_raw<'tcx>(
external_constraints: tcx.mk_external_constraints(ExternalConstraintsData::default()),
certainty,
},
defining_anchor: Default::default(),
}
}
10 changes: 6 additions & 4 deletions compiler/rustc_type_ir/src/canonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::{Interner, PlaceholderLike, UniverseIndex};
pub struct Canonical<I: Interner, V> {
pub value: V,
pub max_universe: UniverseIndex,
pub defining_anchor: I::DefiningAnchor,
pub variables: I::CanonicalVars,
}

Expand Down Expand Up @@ -44,8 +45,8 @@ impl<I: Interner, V> Canonical<I, V> {
/// let b: Canonical<I, (T, Ty<I>)> = a.unchecked_map(|v| (v, ty));
/// ```
pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<I, W> {
let Canonical { max_universe, variables, value } = self;
Canonical { max_universe, variables, value: map_op(value) }
let Canonical { defining_anchor, max_universe, variables, value } = self;
Canonical { defining_anchor, max_universe, variables, value: map_op(value) }
}

/// Allows you to map the `value` of a canonical while keeping the same set of
Expand All @@ -54,8 +55,8 @@ impl<I: Interner, V> Canonical<I, V> {
/// **WARNING:** This function is very easy to mis-use, hence the name! See
/// the comment of [Canonical::unchecked_map] for more details.
pub fn unchecked_rebind<W>(self, value: W) -> Canonical<I, W> {
let Canonical { max_universe, variables, value: _ } = self;
Canonical { max_universe, variables, value }
let Canonical { defining_anchor, max_universe, variables, value: _ } = self;
Canonical { defining_anchor, max_universe, variables, value }
}
}

Expand Down Expand Up @@ -100,6 +101,7 @@ where
value: self.value.try_fold_with(folder)?,
max_universe: self.max_universe.try_fold_with(folder)?,
variables: self.variables.try_fold_with(folder)?,
defining_anchor: self.defining_anchor,
})
}
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_type_ir/src/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ impl<I: Interner> InferCtxtLike for NoInfcx<I> {
fn probe_ct_var(&self, _vid: ConstVid) -> Option<I::Const> {
None
}

fn defining_anchor(&self) -> <Self::Interner as Interner>::DefiningAnchor {
Default::default()
}
}

pub trait DebugWithInfcx<I: Interner>: fmt::Debug {
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_type_ir/src/infcx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,6 @@ pub trait InferCtxtLike {

/// Resolve `ConstVid` to its inferred type, if it has been equated with a non-infer type.
fn probe_ct_var(&self, vid: ConstVid) -> Option<<Self::Interner as Interner>::Const>;

fn defining_anchor(&self) -> <Self::Interner as Interner>::DefiningAnchor;
}
1 change: 1 addition & 0 deletions compiler/rustc_type_ir/src/interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::{

pub trait Interner: Sized {
type DefId: Copy + Debug + Hash + Ord;
type DefiningAnchor: Copy + Debug + Hash + Default;
type AdtDef: Copy + Debug + Hash + Ord;

type GenericArgs: Copy
Expand Down
23 changes: 0 additions & 23 deletions tests/ui/impl-trait/equality-in-canonical-query.clone.stderr

This file was deleted.

Loading

0 comments on commit 119a935

Please sign in to comment.