Skip to content

Intern CanonicalVarValues #107303

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions compiler/rustc_infer/src/infer/canonical/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin, TypeVari
use rustc_index::vec::IndexVec;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::GenericArg;
use rustc_middle::ty::{self, BoundVar, List};
use rustc_middle::ty::{self, List};
use rustc_span::source_map::Span;

pub use rustc_middle::infer::canonical::*;
Expand Down Expand Up @@ -87,12 +87,13 @@ impl<'tcx> InferCtxt<'tcx> {
variables: &List<CanonicalVarInfo<'tcx>>,
universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
) -> CanonicalVarValues<'tcx> {
let var_values: IndexVec<BoundVar, GenericArg<'tcx>> = variables
.iter()
.map(|info| self.instantiate_canonical_var(span, info, &universe_map))
.collect();

CanonicalVarValues { var_values }
CanonicalVarValues {
var_values: self.tcx.mk_substs(
variables
.iter()
.map(|info| self.instantiate_canonical_var(span, info, &universe_map)),
),
}
}

/// Given the "info" about a canonical variable, creates a fresh
Expand Down
11 changes: 4 additions & 7 deletions compiler/rustc_infer/src/infer/canonical/query_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -482,11 +482,8 @@ impl<'tcx> InferCtxt<'tcx> {
// given variable in the loop above, use that. Otherwise, use
// a fresh inference variable.
let result_subst = CanonicalVarValues {
var_values: query_response
.variables
.iter()
.enumerate()
.map(|(index, info)| {
var_values: self.tcx.mk_substs(query_response.variables.iter().enumerate().map(
|(index, info)| {
if info.is_existential() {
match opt_values[BoundVar::new(index)] {
Some(k) => k,
Expand All @@ -499,8 +496,8 @@ impl<'tcx> InferCtxt<'tcx> {
universe_map[u.as_usize()]
})
}
})
.collect(),
},
)),
};

let mut obligations = vec![];
Expand Down
7 changes: 3 additions & 4 deletions compiler/rustc_infer/src/infer/canonical/substitute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,15 @@ where
value
} else {
let delegate = FnMutDelegate {
regions: &mut |br: ty::BoundRegion| match var_values.var_values[br.var].unpack() {
regions: &mut |br: ty::BoundRegion| match var_values[br.var].unpack() {
GenericArgKind::Lifetime(l) => l,
r => bug!("{:?} is a region but value is {:?}", br, r),
},
types: &mut |bound_ty: ty::BoundTy| match var_values.var_values[bound_ty.var].unpack() {
types: &mut |bound_ty: ty::BoundTy| match var_values[bound_ty.var].unpack() {
GenericArgKind::Type(ty) => ty,
r => bug!("{:?} is a type but value is {:?}", bound_ty, r),
},
consts: &mut |bound_ct: ty::BoundVar, _| match var_values.var_values[bound_ct].unpack()
{
consts: &mut |bound_ct: ty::BoundVar, _| match var_values[bound_ct].unpack() {
GenericArgKind::Const(ct) => ct,
c => bug!("{:?} is a const but value is {:?}", bound_ct, c),
},
Expand Down
88 changes: 43 additions & 45 deletions compiler/rustc_middle/src/infer/canonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,8 @@ use crate::infer::MemberConstraint;
use crate::mir::ConstraintCategory;
use crate::ty::subst::GenericArg;
use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
use rustc_index::vec::IndexVec;
use rustc_macros::HashStable;
use smallvec::SmallVec;
use std::iter;
use std::ops::Index;

/// A "canonicalized" type `V` is one where all free inference
Expand Down Expand Up @@ -62,23 +60,23 @@ impl<'tcx> ty::TypeFoldable<'tcx> for CanonicalVarInfos<'tcx> {
/// vectors with the original values that were replaced by canonical
/// variables. You will need to supply it later to instantiate the
/// canonicalized query response.
#[derive(Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
pub struct CanonicalVarValues<'tcx> {
pub var_values: IndexVec<BoundVar, GenericArg<'tcx>>,
pub var_values: ty::SubstsRef<'tcx>,
}

impl CanonicalVarValues<'_> {
pub fn is_identity(&self) -> bool {
self.var_values.iter_enumerated().all(|(bv, arg)| match arg.unpack() {
self.var_values.iter().enumerate().all(|(bv, arg)| match arg.unpack() {
ty::GenericArgKind::Lifetime(r) => {
matches!(*r, ty::ReLateBound(ty::INNERMOST, br) if br.var == bv)
matches!(*r, ty::ReLateBound(ty::INNERMOST, br) if br.var.as_usize() == bv)
}
ty::GenericArgKind::Type(ty) => {
matches!(*ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var == bv)
matches!(*ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var.as_usize() == bv)
}
ty::GenericArgKind::Const(ct) => {
matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc == bv)
matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.as_usize() == bv)
}
})
}
Expand Down Expand Up @@ -339,64 +337,64 @@ TrivialTypeTraversalAndLiftImpls! {
}

impl<'tcx> CanonicalVarValues<'tcx> {
// Given a list of canonical variables, construct a set of values which are
// the identity response.
pub fn make_identity(
tcx: TyCtxt<'tcx>,
infos: CanonicalVarInfos<'tcx>,
) -> CanonicalVarValues<'tcx> {
CanonicalVarValues {
var_values: tcx.mk_substs(infos.iter().enumerate().map(
|(i, info)| -> ty::GenericArg<'tcx> {
match info.kind {
CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => tcx
.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i).into()))
.into(),
CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
let br = ty::BoundRegion {
var: ty::BoundVar::from_usize(i),
kind: ty::BrAnon(i as u32, None),
};
tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
}
CanonicalVarKind::Const(_, ty)
| CanonicalVarKind::PlaceholderConst(_, ty) => tcx
.mk_const(
ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i)),
ty,
)
.into(),
}
},
)),
}
}

/// Creates dummy var values which should not be used in a
/// canonical response.
pub fn dummy() -> CanonicalVarValues<'tcx> {
CanonicalVarValues { var_values: Default::default() }
CanonicalVarValues { var_values: ty::List::empty() }
}

#[inline]
pub fn len(&self) -> usize {
self.var_values.len()
}

/// Makes an identity substitution from this one: each bound var
/// is matched to the same bound var, preserving the original kinds.
/// For example, if we have:
/// `self.var_values == [Type(u32), Lifetime('a), Type(u64)]`
/// we'll return a substitution `subst` with:
/// `subst.var_values == [Type(^0), Lifetime(^1), Type(^2)]`.
pub fn make_identity(&self, tcx: TyCtxt<'tcx>) -> Self {
use crate::ty::subst::GenericArgKind;

CanonicalVarValues {
var_values: iter::zip(&self.var_values, 0..)
.map(|(kind, i)| match kind.unpack() {
GenericArgKind::Type(..) => {
tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())).into()
}
GenericArgKind::Lifetime(..) => {
let br = ty::BoundRegion {
var: ty::BoundVar::from_u32(i),
kind: ty::BrAnon(i, None),
};
tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
}
GenericArgKind::Const(ct) => tcx
.mk_const(
ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i)),
ct.ty(),
)
.into(),
})
.collect(),
}
}
}

impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> {
type Item = GenericArg<'tcx>;
type IntoIter = ::std::iter::Cloned<::std::slice::Iter<'a, GenericArg<'tcx>>>;
type IntoIter = ::std::iter::Copied<::std::slice::Iter<'a, GenericArg<'tcx>>>;

fn into_iter(self) -> Self::IntoIter {
self.var_values.iter().cloned()
self.var_values.iter()
}
}

impl<'tcx> Index<BoundVar> for CanonicalVarValues<'tcx> {
type Output = GenericArg<'tcx>;

fn index(&self, value: BoundVar) -> &GenericArg<'tcx> {
&self.var_values[value]
&self.var_values[value.as_usize()]
}
}
29 changes: 3 additions & 26 deletions compiler/rustc_trait_selection/src/solve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,12 @@
// preserves universes and creates a unique var (in the highest universe) for each
// appearance of a region.

// FIXME: `CanonicalVarValues` should be interned and `Copy`.

// FIXME: uses of `infcx.at` need to enable deferred projection equality once that's implemented.

use std::mem;

use rustc_hir::def_id::DefId;
use rustc_infer::infer::canonical::{Canonical, CanonicalVarKind, CanonicalVarValues};
use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
use rustc_infer::infer::canonical::{OriginalQueryValues, QueryRegionConstraints, QueryResponse};
use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
use rustc_infer::traits::query::NoSolution;
Expand Down Expand Up @@ -227,7 +225,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
let external_constraints = take_external_constraints(self.infcx)?;

Ok(self.infcx.canonicalize_response(Response {
var_values: self.var_values.clone(),
var_values: self.var_values,
external_constraints,
certainty,
}))
Expand Down Expand Up @@ -483,32 +481,11 @@ pub(super) fn response_no_constraints<'tcx>(
goal: Canonical<'tcx, impl Sized>,
certainty: Certainty,
) -> QueryResult<'tcx> {
let var_values = goal
.variables
.iter()
.enumerate()
.map(|(i, info)| match info.kind {
CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => {
tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i).into())).into()
}
CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
let br = ty::BoundRegion {
var: ty::BoundVar::from_usize(i),
kind: ty::BrAnon(i as u32, None),
};
tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
}
CanonicalVarKind::Const(_, ty) | CanonicalVarKind::PlaceholderConst(_, ty) => tcx
.mk_const(ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i)), ty)
.into(),
})
.collect();

Ok(Canonical {
max_universe: goal.max_universe,
variables: goal.variables,
value: Response {
var_values: CanonicalVarValues { var_values },
var_values: CanonicalVarValues::make_identity(tcx, goal.variables),
external_constraints: Default::default(),
certainty,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ impl<'tcx> ProvisionalCache<'tcx> {
}

pub(super) fn provisional_result(&self, entry_index: EntryIndex) -> QueryResult<'tcx> {
// FIXME: Responses should probably be `Copy` as well
self.entries[entry_index].response.clone()
}
}
Expand Down
18 changes: 8 additions & 10 deletions compiler/rustc_traits/src/chalk/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,10 @@ pub(crate) mod lowering;

use rustc_data_structures::fx::FxHashMap;

use rustc_index::vec::IndexVec;

use rustc_middle::infer::canonical::{CanonicalTyVarKind, CanonicalVarKind};
use rustc_middle::traits::ChalkRustInterner;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::subst::GenericArg;
use rustc_middle::ty::{self, BoundVar, ParamTy, TyCtxt, TypeFoldable, TypeVisitable};
use rustc_middle::ty::{self, ParamTy, TyCtxt, TypeFoldable, TypeVisitable};

use rustc_infer::infer::canonical::{
Canonical, CanonicalVarValues, Certainty, QueryRegionConstraints, QueryResponse,
Expand Down Expand Up @@ -100,11 +97,13 @@ pub(crate) fn evaluate_goal<'tcx>(
binders: chalk_ir::CanonicalVarKinds<_>| {
use rustc_middle::infer::canonical::CanonicalVarInfo;

let mut var_values: IndexVec<BoundVar, GenericArg<'tcx>> = IndexVec::new();
let mut reverse_param_substitutor = ReverseParamsSubstitutor::new(tcx, params);
subst.as_slice(interner).iter().for_each(|p| {
var_values.push(p.lower_into(interner).fold_with(&mut reverse_param_substitutor));
});
let var_values = tcx.mk_substs(
subst
.as_slice(interner)
.iter()
.map(|p| p.lower_into(interner).fold_with(&mut reverse_param_substitutor)),
);
let variables: Vec<_> = binders
.iter(interner)
.map(|var| {
Expand Down Expand Up @@ -159,8 +158,7 @@ pub(crate) fn evaluate_goal<'tcx>(
max_universe: ty::UniverseIndex::from_usize(0),
variables: obligation.variables,
value: QueryResponse {
var_values: CanonicalVarValues { var_values: IndexVec::new() }
.make_identity(tcx),
var_values: CanonicalVarValues::dummy(),
region_constraints: QueryRegionConstraints::default(),
certainty: Certainty::Ambiguous,
opaque_types: vec![],
Expand Down