let terminator = bb_data.terminator();
if let TerminatorKind::Call { func: ref op, .. } = terminator.kind {
if let ty::FnDef(callee_def_id, substs) = *op.ty(caller_body, self.tcx).kind() {
- let instance = Instance::resolve(self.tcx, self.param_env, callee_def_id, substs)
- .ok()
- .flatten()?;
+ // To resolve an instance its substs have to be fully normalized, so
+ // we do this here.
+ let normalized_substs = self.tcx.normalize_erasing_regions(self.param_env, substs);
+ let instance =
+ Instance::resolve(self.tcx, self.param_env, callee_def_id, normalized_substs)
+ .ok()
+ .flatten()?;
if let InstanceDef::Virtual(..) = instance.def {
return None;
/// (necessarily) resolve all nested obligations on the impl. Note
/// that type check should guarantee to us that all nested
/// obligations *could be* resolved if we wanted to.
+///
/// Assumes that this is run after the entire crate has been successfully type-checked.
+/// This also expects that `trait_ref` is fully normalized.
pub fn codegen_fulfill_obligation<'tcx>(
tcx: TyCtxt<'tcx>,
(param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
) -> Result<ImplSource<'tcx, ()>, ErrorReported> {
- // Remove any references to regions and normalize; this helps improve caching.
- let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref);
-
+ // Remove any references to regions; this helps improve caching.
+ let trait_ref = tcx.erase_regions(&trait_ref);
+ // We expect the input to be fully normalized.
+ debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(param_env, trait_ref));
debug!(
"codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})",
(param_env, trait_ref),
--- /dev/null
+// run-pass
+// compile-flags:-Zmir-opt-level=2
+
+// Previously ICEd because we did not normalize during inlining,
+// see https://github.com/rust-lang/rust/pull/77306 for more discussion.
+
+pub fn write() {
+ create()()
+}
+
+pub fn create() -> impl FnOnce() {
+ || ()
+}
+
+fn main() {
+ write();
+}