Skip to content

Commit 17596bb

Browse files
committed
Extract helper function for normalizing free/assoc terms
1 parent bb32b29 commit 17596bb

File tree

3 files changed

+81
-72
lines changed

3 files changed

+81
-72
lines changed

compiler/rustc_middle/src/mir/consts.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,10 @@ impl<'tcx> Const<'tcx> {
362362
}
363363
Const::Unevaluated(uneval, _) => {
364364
// FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
365-
let uneval_ty_ct = ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(uneval.def, uneval.args));
365+
let uneval_ty_ct = ty::Const::new_unevaluated(
366+
tcx,
367+
ty::UnevaluatedConst::new(uneval.def, uneval.args),
368+
);
366369
let mir_ct = tcx.normalize_erasing_regions(typing_env, uneval_ty_ct);
367370
// FIXME: duplicated with above match arm
368371
match mir_ct.kind() {

compiler/rustc_trait_selection/src/traits/normalize.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,9 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
444444
let ct = match tcx.def_kind(uv.def) {
445445
DefKind::AssocConst => match tcx.def_kind(tcx.parent(uv.def)) {
446446
DefKind::Trait => self.normalize_trait_projection(uv.into()).expect_const(),
447-
DefKind::Impl { of_trait: false } => self.normalize_inherent_projection(uv.into()).expect_const(),
447+
DefKind::Impl { of_trait: false } => {
448+
self.normalize_inherent_projection(uv.into()).expect_const()
449+
}
448450
kind => unreachable!(
449451
"unexpected `DefKind` for const alias' resolution's parent def: {:?}",
450452
kind

compiler/rustc_trait_selection/src/traits/query/normalize.rs

Lines changed: 74 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -253,76 +253,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
253253
}
254254
}
255255

256-
ty::Projection | ty::Inherent | ty::Free => {
257-
// See note in `rustc_trait_selection::traits::project`
258-
259-
let infcx = self.infcx;
260-
let tcx = infcx.tcx;
261-
// Just an optimization: When we don't have escaping bound vars,
262-
// we don't need to replace them with placeholders.
263-
let (data, maps) = if data.has_escaping_bound_vars() {
264-
let (data, mapped_regions, mapped_types, mapped_consts) =
265-
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
266-
(data, Some((mapped_regions, mapped_types, mapped_consts)))
267-
} else {
268-
(data, None)
269-
};
270-
let data = data.try_fold_with(self)?;
271-
272-
let mut orig_values = OriginalQueryValues::default();
273-
let c_data = infcx.canonicalize_query(self.param_env.and(data), &mut orig_values);
274-
debug!("QueryNormalizer: c_data = {:#?}", c_data);
275-
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
276-
let result = match kind {
277-
ty::Projection => tcx.normalize_canonicalized_projection_ty(c_data),
278-
ty::Free => tcx.normalize_canonicalized_free_alias(c_data),
279-
ty::Inherent => tcx.normalize_canonicalized_inherent_projection_ty(c_data),
280-
kind => unreachable!("did not expect {kind:?} due to match arm above"),
281-
}?;
282-
// We don't expect ambiguity.
283-
if !result.value.is_proven() {
284-
// Rustdoc normalizes possibly not well-formed types, so only
285-
// treat this as a bug if we're not in rustdoc.
286-
if !tcx.sess.opts.actually_rustdoc {
287-
tcx.dcx()
288-
.delayed_bug(format!("unexpected ambiguity: {c_data:?} {result:?}"));
289-
}
290-
return Err(NoSolution);
291-
}
292-
let InferOk { value: result, obligations } = infcx
293-
.instantiate_query_response_and_region_obligations(
294-
self.cause,
295-
self.param_env,
296-
&orig_values,
297-
result,
298-
)?;
299-
debug!("QueryNormalizer: result = {:#?}", result);
300-
debug!("QueryNormalizer: obligations = {:#?}", obligations);
301-
self.obligations.extend(obligations);
302-
let res = if let Some((mapped_regions, mapped_types, mapped_consts)) = maps {
303-
PlaceholderReplacer::replace_placeholders(
304-
infcx,
305-
mapped_regions,
306-
mapped_types,
307-
mapped_consts,
308-
&self.universes,
309-
result.normalized_ty,
310-
)
311-
} else {
312-
result.normalized_ty
313-
};
314-
// `tcx.normalize_canonicalized_projection_ty` may normalize to a type that
315-
// still has unevaluated consts, so keep normalizing here if that's the case.
316-
// Similarly, `tcx.normalize_canonicalized_free_alias` will only unwrap one layer
317-
// of type and we need to continue folding it to reveal the TAIT behind it.
318-
if res != ty
319-
&& (res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) || kind == ty::Free)
320-
{
321-
res.try_fold_with(self)?
322-
} else {
323-
res
324-
}
325-
}
256+
ty::Projection | ty::Inherent | ty::Free => self.try_fold_free_or_assoc(ty, kind, data)?,
326257
};
327258

328259
self.cache.insert(ty, res);
@@ -359,3 +290,76 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
359290
}
360291
}
361292
}
293+
294+
impl<'a, 'tcx> QueryNormalizer<'a, 'tcx> {
295+
fn try_fold_free_or_assoc(
296+
&mut self,
297+
ty: Ty<'tcx>,
298+
kind: ty::AliasTyKind,
299+
data: ty::AliasTy<'tcx>,
300+
) -> Result<Ty<'tcx>, NoSolution> {
301+
let infcx = self.infcx;
302+
let tcx = infcx.tcx;
303+
// Just an optimization: When we don't have escaping bound vars,
304+
// we don't need to replace them with placeholders.
305+
let (data, maps) = if data.has_escaping_bound_vars() {
306+
let (data, mapped_regions, mapped_types, mapped_consts) =
307+
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
308+
(data, Some((mapped_regions, mapped_types, mapped_consts)))
309+
} else {
310+
(data, None)
311+
};
312+
let data = data.try_fold_with(self)?;
313+
314+
let mut orig_values = OriginalQueryValues::default();
315+
let c_data = infcx.canonicalize_query(self.param_env.and(data), &mut orig_values);
316+
debug!("QueryNormalizer: c_data = {:#?}", c_data);
317+
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
318+
let result = match kind {
319+
ty::Projection => tcx.normalize_canonicalized_projection_ty(c_data),
320+
ty::Free => tcx.normalize_canonicalized_free_alias(c_data),
321+
ty::Inherent => tcx.normalize_canonicalized_inherent_projection_ty(c_data),
322+
kind => unreachable!("did not expect {kind:?} due to match arm above"),
323+
}?;
324+
// We don't expect ambiguity.
325+
if !result.value.is_proven() {
326+
// Rustdoc normalizes possibly not well-formed types, so only
327+
// treat this as a bug if we're not in rustdoc.
328+
if !tcx.sess.opts.actually_rustdoc {
329+
tcx.dcx().delayed_bug(format!("unexpected ambiguity: {c_data:?} {result:?}"));
330+
}
331+
return Err(NoSolution);
332+
}
333+
let InferOk { value: result, obligations } = infcx
334+
.instantiate_query_response_and_region_obligations(
335+
self.cause,
336+
self.param_env,
337+
&orig_values,
338+
result,
339+
)?;
340+
debug!("QueryNormalizer: result = {:#?}", result);
341+
debug!("QueryNormalizer: obligations = {:#?}", obligations);
342+
self.obligations.extend(obligations);
343+
let res = if let Some((mapped_regions, mapped_types, mapped_consts)) = maps {
344+
PlaceholderReplacer::replace_placeholders(
345+
infcx,
346+
mapped_regions,
347+
mapped_types,
348+
mapped_consts,
349+
&self.universes,
350+
result.normalized_ty,
351+
)
352+
} else {
353+
result.normalized_ty
354+
};
355+
// `tcx.normalize_canonicalized_projection_ty` may normalize to a type that
356+
// still has unevaluated consts, so keep normalizing here if that's the case.
357+
// Similarly, `tcx.normalize_canonicalized_free_alias` will only unwrap one layer
358+
// of type and we need to continue folding it to reveal the TAIT behind it.
359+
if res != ty && (res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) || kind == ty::Free) {
360+
res.try_fold_with(self)
361+
} else {
362+
Ok(res)
363+
}
364+
}
365+
}

0 commit comments

Comments
 (0)