Skip to content
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

Tweak SubstFolder implementation #99600

Merged
merged 4 commits into from
Jul 25, 2022
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
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1122,6 +1122,7 @@ impl<'tcx> TypeVisitable<'tcx> for ty::Predicate<'tcx> {
visitor.visit_predicate(*self)
}

#[inline]
fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
self.outer_exclusive_binder() > binder
}
Expand Down
126 changes: 71 additions & 55 deletions compiler/rustc_middle/src/ty/subst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use rustc_data_structures::intern::{Interned, WithStableHash};
use rustc_hir::def_id::DefId;
use rustc_macros::HashStable;
use rustc_serialize::{self, Decodable, Encodable};
use rustc_span::DUMMY_SP;
use smallvec::SmallVec;

use core::intrinsics;
Expand Down Expand Up @@ -525,6 +524,7 @@ struct SubstFolder<'a, 'tcx> {
}

impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
#[inline]
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
self.tcx
}
Expand All @@ -540,6 +540,16 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
}

fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
#[cold]
#[inline(never)]
fn region_param_out_of_range(data: ty::EarlyBoundRegion) -> ! {
bug!(
"Region parameter out of range when substituting in region {} (index={})",
data.name,
data.index
)
}

// Note: This routine only handles regions that are bound on
// type declarations and other outer declarations, not those
// bound in *fn types*. Region substitution of the bound
Expand All @@ -550,14 +560,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
let rk = self.substs.get(data.index as usize).map(|k| k.unpack());
match rk {
Some(GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt),
_ => {
let msg = format!(
"Region parameter out of range \
when substituting in region {} (index={})",
data.name, data.index
);
span_bug!(DUMMY_SP, "{}", msg);
}
_ => region_param_out_of_range(data),
}
}
_ => r,
Expand Down Expand Up @@ -595,67 +598,80 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> {
let opt_ty = self.substs.get(p.index as usize).map(|k| k.unpack());
let ty = match opt_ty {
Some(GenericArgKind::Type(ty)) => ty,
Some(kind) => {
span_bug!(
DUMMY_SP,
"expected type for `{:?}` ({:?}/{}) but found {:?} \
when substituting, substs={:?}",
p,
source_ty,
p.index,
kind,
self.substs,
);
}
None => {
span_bug!(
DUMMY_SP,
"type parameter `{:?}` ({:?}/{}) out of range \
when substituting, substs={:?}",
p,
source_ty,
p.index,
self.substs,
);
}
Some(kind) => self.type_param_expected(p, source_ty, kind),
None => self.type_param_out_of_range(p, source_ty),
};

self.shift_vars_through_binders(ty)
}

#[cold]
#[inline(never)]
fn type_param_expected(&self, p: ty::ParamTy, ty: Ty<'tcx>, kind: GenericArgKind<'tcx>) -> ! {
bug!(
"expected type for `{:?}` ({:?}/{}) but found {:?} when substituting, substs={:?}",
p,
ty,
p.index,
kind,
self.substs,
)
}

#[cold]
#[inline(never)]
fn type_param_out_of_range(&self, p: ty::ParamTy, ty: Ty<'tcx>) -> ! {
bug!(
"type parameter `{:?}` ({:?}/{}) out of range when substituting, substs={:?}",
p,
ty,
p.index,
self.substs,
)
}

fn const_for_param(&self, p: ParamConst, source_ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
// Look up the const in the substitutions. It really should be in there.
let opt_ct = self.substs.get(p.index as usize).map(|k| k.unpack());
let ct = match opt_ct {
Some(GenericArgKind::Const(ct)) => ct,
Some(kind) => {
span_bug!(
DUMMY_SP,
"expected const for `{:?}` ({:?}/{}) but found {:?} \
when substituting substs={:?}",
p,
source_ct,
p.index,
kind,
self.substs,
);
}
None => {
span_bug!(
DUMMY_SP,
"const parameter `{:?}` ({:?}/{}) out of range \
when substituting substs={:?}",
p,
source_ct,
p.index,
self.substs,
);
}
Some(kind) => self.const_param_expected(p, source_ct, kind),
None => self.const_param_out_of_range(p, source_ct),
};

self.shift_vars_through_binders(ct)
}

#[cold]
#[inline(never)]
fn const_param_expected(
&self,
p: ty::ParamConst,
ct: ty::Const<'tcx>,
kind: GenericArgKind<'tcx>,
) -> ! {
bug!(
"expected const for `{:?}` ({:?}/{}) but found {:?} when substituting substs={:?}",
p,
ct,
p.index,
kind,
self.substs,
)
}

#[cold]
#[inline(never)]
fn const_param_out_of_range(&self, p: ty::ParamConst, ct: ty::Const<'tcx>) -> ! {
bug!(
"const parameter `{:?}` ({:?}/{}) out of range when substituting substs={:?}",
p,
ct,
p.index,
self.substs,
)
}

/// It is sometimes necessary to adjust the De Bruijn indices during substitution. This occurs
/// when we are substituting a type with escaping bound vars into a context where we have
/// passed through binders. That's quite a mouthful. Let's see an example:
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_type_ir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,25 +310,29 @@ impl DebruijnIndex {
/// for<'a> fn(for<'b> fn(&'a x))
///
/// you would need to shift the index for `'a` into a new binder.
#[inline]
#[must_use]
pub fn shifted_in(self, amount: u32) -> DebruijnIndex {
DebruijnIndex::from_u32(self.as_u32() + amount)
}

/// Update this index in place by shifting it "in" through
/// `amount` number of binders.
#[inline]
pub fn shift_in(&mut self, amount: u32) {
*self = self.shifted_in(amount);
}

/// Returns the resulting index when this value is moved out from
/// `amount` number of new binders.
#[inline]
#[must_use]
pub fn shifted_out(self, amount: u32) -> DebruijnIndex {
DebruijnIndex::from_u32(self.as_u32() - amount)
}

/// Update in place by shifting out from `amount` binders.
#[inline]
pub fn shift_out(&mut self, amount: u32) {
*self = self.shifted_out(amount);
}
Expand All @@ -353,6 +357,7 @@ impl DebruijnIndex {
/// If we invoke `shift_out_to_binder` and the region is in fact
/// bound by one of the binders we are shifting out of, that is an
/// error (and should fail an assertion failure).
#[inline]
pub fn shifted_out_to_binder(self, to_binder: DebruijnIndex) -> Self {
self.shifted_out(to_binder.as_u32() - INNERMOST.as_u32())
}
Expand Down