Review comments
This commit is contained in:
parent
9891e470b1
commit
af14db14f4
3 changed files with 68 additions and 41 deletions
|
@ -169,8 +169,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
{
|
{
|
||||||
// FIXME(jackh726): This is a hack. It's somewhat like
|
// FIXME(jackh726): This is a hack. It's somewhat like
|
||||||
// `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd
|
// `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd
|
||||||
// like to normalize *before* inserting into `local_decls`, but I
|
// like to normalize *before* inserting into `local_decls`, but
|
||||||
// couldn't figure out where the heck that was.
|
// doing so ends up causing some other trouble.
|
||||||
let b = match self
|
let b = match self
|
||||||
.infcx
|
.infcx
|
||||||
.at(&ObligationCause::dummy(), ty::ParamEnv::empty())
|
.at(&ObligationCause::dummy(), ty::ParamEnv::empty())
|
||||||
|
|
|
@ -363,12 +363,28 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
|
||||||
return ty;
|
return ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
// N.b. while we want to call `super_fold_with(self)` on `ty` before
|
// We try to be a little clever here as a performance optimization in
|
||||||
// normalization, we wait until we know whether we need to normalize the
|
// cases where there are nested projections under binders.
|
||||||
// current type. If we do, then we only fold the ty *after* replacing bound
|
// For example:
|
||||||
// vars with placeholders. This means that nested types don't need to replace
|
// ```
|
||||||
// bound vars at the current binder level or above. A key assumption here is
|
// for<'a> fn(<T as Foo>::One<'a, Box<dyn Bar<'a, Item=<T as Foo>::Two<'a>>>>)
|
||||||
// that folding the type can't introduce new bound vars.
|
// ```
|
||||||
|
// We normalize the substs on the projection before the projecting, but
|
||||||
|
// if we're naive, we'll
|
||||||
|
// replace bound vars on inner, project inner, replace placeholders on inner,
|
||||||
|
// replace bound vars on outer, project outer, replace placeholders on outer
|
||||||
|
//
|
||||||
|
// However, if we're a bit more clever, we can replace the bound vars
|
||||||
|
// on the entire type before normalizing nested projections, meaning we
|
||||||
|
// replace bound vars on outer, project inner,
|
||||||
|
// project outer, replace placeholders on outer
|
||||||
|
//
|
||||||
|
// This is possible because the inner `'a` will already be a placeholder
|
||||||
|
// when we need to normalize the inner projection
|
||||||
|
//
|
||||||
|
// On the other hand, this does add a bit of complexity, since we only
|
||||||
|
// replace bound vars if the current type is a `Projection` and we need
|
||||||
|
// to make sure we don't forget to fold the substs regardless.
|
||||||
|
|
||||||
match *ty.kind() {
|
match *ty.kind() {
|
||||||
ty::Opaque(def_id, substs) => {
|
ty::Opaque(def_id, substs) => {
|
||||||
|
@ -380,7 +396,6 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
|
||||||
// N.b. there is an assumption here all this code can handle
|
// N.b. there is an assumption here all this code can handle
|
||||||
// escaping bound vars.
|
// escaping bound vars.
|
||||||
|
|
||||||
let substs = substs.super_fold_with(self);
|
|
||||||
let recursion_limit = self.tcx().recursion_limit();
|
let recursion_limit = self.tcx().recursion_limit();
|
||||||
if !recursion_limit.value_within_limit(self.depth) {
|
if !recursion_limit.value_within_limit(self.depth) {
|
||||||
let obligation = Obligation::with_depth(
|
let obligation = Obligation::with_depth(
|
||||||
|
@ -392,6 +407,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
|
||||||
self.selcx.infcx().report_overflow_error(&obligation, true);
|
self.selcx.infcx().report_overflow_error(&obligation, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let substs = substs.super_fold_with(self);
|
||||||
let generic_ty = self.tcx().type_of(def_id);
|
let generic_ty = self.tcx().type_of(def_id);
|
||||||
let concrete_ty = generic_ty.subst(self.tcx(), substs);
|
let concrete_ty = generic_ty.subst(self.tcx(), substs);
|
||||||
self.depth += 1;
|
self.depth += 1;
|
||||||
|
@ -430,12 +446,16 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
|
||||||
|
|
||||||
ty::Projection(data) => {
|
ty::Projection(data) => {
|
||||||
// If there are escaping bound vars, we temporarily replace the
|
// If there are escaping bound vars, we temporarily replace the
|
||||||
// bound vars with placeholders. Note though, that in the cas
|
// bound vars with placeholders. Note though, that in the case
|
||||||
// that we still can't project for whatever reason (e.g. self
|
// that we still can't project for whatever reason (e.g. self
|
||||||
// type isn't known enough), we *can't* register an obligation
|
// type isn't known enough), we *can't* register an obligation
|
||||||
// and return an inference variable (since then that obligation
|
// and return an inference variable (since then that obligation
|
||||||
// would have bound vars and that's a can of worms). Instead,
|
// would have bound vars and that's a can of worms). Instead,
|
||||||
// we just give up and fall back to pretending like we never tried!
|
// we just give up and fall back to pretending like we never tried!
|
||||||
|
//
|
||||||
|
// Note: this isn't necessarily the final approach here; we may
|
||||||
|
// want to figure out how to register obligations with escaping vars
|
||||||
|
// or handle this some other way.
|
||||||
|
|
||||||
let infcx = self.selcx.infcx();
|
let infcx = self.selcx.infcx();
|
||||||
let (data, mapped_regions, mapped_types, mapped_consts) =
|
let (data, mapped_regions, mapped_types, mapped_consts) =
|
||||||
|
@ -451,16 +471,18 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
|
||||||
)
|
)
|
||||||
.ok()
|
.ok()
|
||||||
.flatten()
|
.flatten()
|
||||||
|
.map(|normalized_ty| {
|
||||||
|
PlaceholderReplacer::replace_placeholders(
|
||||||
|
infcx,
|
||||||
|
mapped_regions,
|
||||||
|
mapped_types,
|
||||||
|
mapped_consts,
|
||||||
|
&self.universes,
|
||||||
|
normalized_ty,
|
||||||
|
)
|
||||||
|
})
|
||||||
.unwrap_or_else(|| ty.super_fold_with(self));
|
.unwrap_or_else(|| ty.super_fold_with(self));
|
||||||
|
|
||||||
let normalized_ty = PlaceholderReplacer::replace_placeholders(
|
|
||||||
infcx,
|
|
||||||
mapped_regions,
|
|
||||||
mapped_types,
|
|
||||||
mapped_consts,
|
|
||||||
&self.universes,
|
|
||||||
normalized_ty,
|
|
||||||
);
|
|
||||||
debug!(
|
debug!(
|
||||||
?self.depth,
|
?self.depth,
|
||||||
?ty,
|
?ty,
|
||||||
|
|
|
@ -67,6 +67,16 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
|
||||||
universes: vec![],
|
universes: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// This is actually a consequence by the way `normalize_erasing_regions` works currently.
|
||||||
|
// Because it needs to call the `normalize_generic_arg_after_erasing_regions`, it folds
|
||||||
|
// through tys and consts in a `TypeFoldable`. Importantly, it skips binders, leaving us
|
||||||
|
// with trying to normalize with escaping bound vars.
|
||||||
|
//
|
||||||
|
// Here, we just add the universes that we *would* have created had we passed through the binders.
|
||||||
|
//
|
||||||
|
// We *could* replace escaping bound vars eagerly here, but it doesn't seem really necessary.
|
||||||
|
// The rest of the code is already set up to be lazy about replacing bound vars,
|
||||||
|
// and only when we actually have to normalize.
|
||||||
if value.has_escaping_bound_vars() {
|
if value.has_escaping_bound_vars() {
|
||||||
let mut max_visitor =
|
let mut max_visitor =
|
||||||
MaxEscapingBoundVarVisitor { outer_index: ty::INNERMOST, escaping: 0 };
|
MaxEscapingBoundVarVisitor { outer_index: ty::INNERMOST, escaping: 0 };
|
||||||
|
@ -183,12 +193,8 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
|
||||||
return ty;
|
return ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
// N.b. while we want to call `super_fold_with(self)` on `ty` before
|
// See note in `rustc_trait_selection::traits::project` about why we
|
||||||
// normalization, we wait until we know whether we need to normalize the
|
// wait to fold the substs.
|
||||||
// current type. If we do, then we only fold the ty *after* replacing bound
|
|
||||||
// vars with placeholders. This means that nested types don't need to replace
|
|
||||||
// bound vars at the current binder level or above. A key assumption here is
|
|
||||||
// that folding the type can't introduce new bound vars.
|
|
||||||
|
|
||||||
// Wrap this in a closure so we don't accidentally return from the outer function
|
// Wrap this in a closure so we don't accidentally return from the outer function
|
||||||
let res = (|| match *ty.kind() {
|
let res = (|| match *ty.kind() {
|
||||||
|
@ -253,7 +259,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
|
||||||
// We don't expect ambiguity.
|
// We don't expect ambiguity.
|
||||||
if result.is_ambiguous() {
|
if result.is_ambiguous() {
|
||||||
self.error = true;
|
self.error = true;
|
||||||
return ty;
|
return ty.super_fold_with(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.infcx.instantiate_query_response_and_region_obligations(
|
match self.infcx.instantiate_query_response_and_region_obligations(
|
||||||
|
@ -271,14 +277,14 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
|
||||||
|
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
self.error = true;
|
self.error = true;
|
||||||
ty
|
ty.super_fold_with(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(NoSolution) => {
|
Err(NoSolution) => {
|
||||||
self.error = true;
|
self.error = true;
|
||||||
ty
|
ty.super_fold_with(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -304,12 +310,12 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
|
||||||
.canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
|
.canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
|
||||||
debug!("QueryNormalizer: c_data = {:#?}", c_data);
|
debug!("QueryNormalizer: c_data = {:#?}", c_data);
|
||||||
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
|
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
|
||||||
let normalized_ty = match tcx.normalize_projection_ty(c_data) {
|
match tcx.normalize_projection_ty(c_data) {
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
// We don't expect ambiguity.
|
// We don't expect ambiguity.
|
||||||
if result.is_ambiguous() {
|
if result.is_ambiguous() {
|
||||||
self.error = true;
|
self.error = true;
|
||||||
return ty;
|
return ty.super_fold_with(self);
|
||||||
}
|
}
|
||||||
match self.infcx.instantiate_query_response_and_region_obligations(
|
match self.infcx.instantiate_query_response_and_region_obligations(
|
||||||
self.cause,
|
self.cause,
|
||||||
|
@ -321,27 +327,26 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
|
||||||
debug!("QueryNormalizer: result = {:#?}", result);
|
debug!("QueryNormalizer: result = {:#?}", result);
|
||||||
debug!("QueryNormalizer: obligations = {:#?}", obligations);
|
debug!("QueryNormalizer: obligations = {:#?}", obligations);
|
||||||
self.obligations.extend(obligations);
|
self.obligations.extend(obligations);
|
||||||
result.normalized_ty
|
crate::traits::project::PlaceholderReplacer::replace_placeholders(
|
||||||
|
infcx,
|
||||||
|
mapped_regions,
|
||||||
|
mapped_types,
|
||||||
|
mapped_consts,
|
||||||
|
&self.universes,
|
||||||
|
result.normalized_ty,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
self.error = true;
|
self.error = true;
|
||||||
ty
|
ty.super_fold_with(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(NoSolution) => {
|
Err(NoSolution) => {
|
||||||
self.error = true;
|
self.error = true;
|
||||||
ty
|
ty.super_fold_with(self)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
crate::traits::project::PlaceholderReplacer::replace_placeholders(
|
|
||||||
infcx,
|
|
||||||
mapped_regions,
|
|
||||||
mapped_types,
|
|
||||||
mapped_consts,
|
|
||||||
&self.universes,
|
|
||||||
normalized_ty,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => ty.super_fold_with(self),
|
_ => ty.super_fold_with(self),
|
||||||
|
|
Loading…
Add table
Reference in a new issue