Check unnormalized signature on pointer cast
This commit is contained in:
parent
eb33b43bab
commit
e8472e84e3
7 changed files with 127 additions and 13 deletions
|
@ -1979,19 +1979,76 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
|
||||
match cast_kind {
|
||||
CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer) => {
|
||||
let fn_sig = op.ty(body, tcx).fn_sig(tcx);
|
||||
let src_sig = op.ty(body, tcx).fn_sig(tcx);
|
||||
|
||||
// HACK: This shouldn't be necessary... We can remove this when we actually
|
||||
// get binders with where clauses, then elaborate implied bounds into that
|
||||
// binder, and implement a higher-ranked subtyping algorithm that actually
|
||||
// respects these implied bounds.
|
||||
//
|
||||
// This protects against the case where we are casting from a higher-ranked
|
||||
// fn item to a non-higher-ranked fn pointer, where the cast throws away
|
||||
// implied bounds that would've needed to be checked at the call site. This
|
||||
// only works when we're casting to a non-higher-ranked fn ptr, since
|
||||
// placeholders in the target signature could have untracked implied
|
||||
// bounds, resulting in incorrect errors.
|
||||
//
|
||||
// We check that this signature is WF before subtyping the signature with
|
||||
// the target fn sig.
|
||||
if src_sig.has_bound_regions()
|
||||
&& let ty::FnPtr(target_fn_tys, target_hdr) = *ty.kind()
|
||||
&& let target_sig = target_fn_tys.with(target_hdr)
|
||||
&& let Some(target_sig) = target_sig.no_bound_vars()
|
||||
{
|
||||
let src_sig = self.infcx.instantiate_binder_with_fresh_vars(
|
||||
span,
|
||||
BoundRegionConversionTime::HigherRankedType,
|
||||
src_sig,
|
||||
);
|
||||
let src_ty = Ty::new_fn_ptr(self.tcx(), ty::Binder::dummy(src_sig));
|
||||
self.prove_predicate(
|
||||
ty::ClauseKind::WellFormed(src_ty.into()),
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast { unsize_to: None },
|
||||
);
|
||||
|
||||
let src_ty = self.normalize(src_ty, location);
|
||||
if let Err(terr) = self.sub_types(
|
||||
src_ty,
|
||||
*ty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast { unsize_to: None },
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
rvalue,
|
||||
"equating {:?} with {:?} yields {:?}",
|
||||
target_sig,
|
||||
src_sig,
|
||||
terr
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
let src_ty = Ty::new_fn_ptr(tcx, src_sig);
|
||||
// HACK: We want to assert that the signature of the source fn is
|
||||
// well-formed, because we don't enforce that via the WF of FnDef
|
||||
// types normally. This should be removed when we improve the tracking
|
||||
// of implied bounds of fn signatures.
|
||||
self.prove_predicate(
|
||||
ty::ClauseKind::WellFormed(src_ty.into()),
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast { unsize_to: None },
|
||||
);
|
||||
|
||||
// The type that we see in the fcx is like
|
||||
// `foo::<'a, 'b>`, where `foo` is the path to a
|
||||
// function definition. When we extract the
|
||||
// signature, it comes from the `fn_sig` query,
|
||||
// and hence may contain unnormalized results.
|
||||
let fn_sig = self.normalize(fn_sig, location);
|
||||
|
||||
let ty_fn_ptr_from = Ty::new_fn_ptr(tcx, fn_sig);
|
||||
|
||||
let src_ty = self.normalize(src_ty, location);
|
||||
if let Err(terr) = self.sub_types(
|
||||
ty_fn_ptr_from,
|
||||
src_ty,
|
||||
*ty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast { unsize_to: None },
|
||||
|
@ -2000,7 +2057,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
self,
|
||||
rvalue,
|
||||
"equating {:?} with {:?} yields {:?}",
|
||||
ty_fn_ptr_from,
|
||||
src_ty,
|
||||
ty,
|
||||
terr
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue