Skip to content

Commit

Permalink
Don't ICE when opaque types get their hidden type constrained again.
Browse files Browse the repository at this point in the history
Contrary to popular belief, `codegen_fulfill_obligation` does not get used solely in codegen, so we cannot rely on `param_env` being set to RevealAll and thus revealing the hidden types instead of constraining them.
  • Loading branch information
oli-obk committed Mar 30, 2022
1 parent e50ff9b commit 1144677
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 13 deletions.
19 changes: 6 additions & 13 deletions compiler/rustc_trait_selection/src/traits/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use rustc_middle::ty::{self, TyCtxt};
/// obligations *could be* resolved if we wanted to.
///
/// This also expects that `trait_ref` is fully normalized.
#[instrument(level = "debug", skip(tcx))]
pub fn codegen_fulfill_obligation<'tcx>(
tcx: TyCtxt<'tcx>,
(param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
Expand All @@ -27,11 +28,6 @@ pub fn codegen_fulfill_obligation<'tcx>(
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),
trait_ref.def_id()
);

// Do the initial selection for the obligation. This yields the
// shallow result we are looking for -- that is, what specific impl.
Expand Down Expand Up @@ -80,25 +76,22 @@ pub fn codegen_fulfill_obligation<'tcx>(
}
};

debug!("fulfill_obligation: selection={:?}", selection);
debug!(?selection);

// Currently, we use a fulfillment context to completely resolve
// all nested obligations. This is because they can inform the
// inference of the impl's type parameters.
let mut fulfill_cx = FulfillmentContext::new();
let impl_source = selection.map(|predicate| {
debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
fulfill_cx.register_predicate_obligation(&infcx, predicate);
});
let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source);

// There should be no opaque types during codegen, they all get revealed.
let opaque_types = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
if !opaque_types.is_empty() {
bug!("{:#?}", opaque_types);
}
// Opaque types may have gotten their hidden types constrained, but we can ignore them safely
// as they will get constrained elsewhere, too.
let _opaque_types = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();

debug!("Cache miss: {:?} => {:?}", trait_ref, impl_source);
debug!("Cache miss: {trait_ref:?} => {impl_source:?}");
Ok(&*tcx.arena.alloc(impl_source))
})
}
Expand Down
24 changes: 24 additions & 0 deletions src/test/ui/type-alias-impl-trait/assoc-projection-ice.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#![feature(type_alias_impl_trait)]

// build-pass

trait T { type Item; }

type Alias<'a> = impl T<Item = &'a ()>;

struct S;
impl<'a> T for &'a S {
type Item = &'a ();
}

fn filter_positive<'a>() -> Alias<'a> {
&S
}

fn with_positive(fun: impl Fn(Alias<'_>)) {
fun(filter_positive());
}

fn main() {
with_positive(|_| ());
}

0 comments on commit 1144677

Please sign in to comment.