Folding revamp.

This commit makes type folding more like the way chalk does it.

Currently, `TypeFoldable` has `fold_with` and `super_fold_with` methods.
- `fold_with` is the standard entry point, and defaults to calling
  `super_fold_with`.
- `super_fold_with` does the actual work of traversing a type.
- For a few types of interest (`Ty`, `Region`, etc.) `fold_with` instead
  calls into a `TypeFolder`, which can then call back into
  `super_fold_with`.

With the new approach, `TypeFoldable` has `fold_with` and
`TypeSuperFoldable` has `super_fold_with`.
- `fold_with` is still the standard entry point, *and* it does the
  actual work of traversing a type, for all types except types of
  interest.
- `super_fold_with` is only implemented for the types of interest.

Benefits of the new model.
- I find it easier to understand. The distinction between types of
  interest and other types is clearer, and `super_fold_with` doesn't
  exist for most types.
- With the current model is easy to get confused and implement a
  `super_fold_with` method that should be left defaulted. (Some of the
  precursor commits fixed such cases.)
- With the current model it's easy to call `super_fold_with` within
  `TypeFolder` impls where `fold_with` should be called. The new
  approach makes this mistake impossible, and this commit fixes a number
  of such cases.
- It's potentially faster, because it avoids the `fold_with` ->
  `super_fold_with` call in all cases except types of interest. A lot of
  the time the compile would inline those away, but not necessarily
  always.
This commit is contained in:
Nicholas Nethercote
2022-06-02 11:38:15 +10:00
parent 7480b501b4
commit 90db033955
47 changed files with 292 additions and 337 deletions

View File

@@ -29,7 +29,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_middle::traits::select::OverflowError;
use rustc_middle::ty::fold::{MaxUniverse, TypeFoldable, TypeFolder};
use rustc_middle::ty::fold::{MaxUniverse, TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, EarlyBinder, Term, ToPredicate, Ty, TyCtxt};
use rustc_span::symbol::sym;
@@ -514,7 +514,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
self.selcx.infcx().report_overflow_error(&obligation, true);
}
let substs = substs.super_fold_with(self);
let substs = substs.fold_with(self);
let generic_ty = self.tcx().bound_type_of(def_id);
let concrete_ty = generic_ty.subst(self.tcx(), substs);
self.depth += 1;
@@ -531,8 +531,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
// placeholders (see branch below). *Also*, we know that we can
// register an obligation to *later* project, since we know
// there won't be bound vars there.
let data = data.super_fold_with(self);
let data = data.fold_with(self);
let normalized_ty = if self.eager_inference_replacement {
normalize_projection_type(
self.selcx,
@@ -581,7 +580,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
let infcx = self.selcx.infcx();
let (data, mapped_regions, mapped_types, mapped_consts) =
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
let data = data.super_fold_with(self);
let data = data.fold_with(self);
let normalized_ty = opt_normalize_projection_type(
self.selcx,
self.param_env,
@@ -671,7 +670,7 @@ impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> {
universe_indices,
};
let value = value.super_fold_with(&mut replacer);
let value = value.fold_with(&mut replacer);
(value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts)
}
@@ -794,7 +793,7 @@ impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> {
universe_indices,
current_index: ty::INNERMOST,
};
value.super_fold_with(&mut replacer)
value.fold_with(&mut replacer)
}
}