Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -162,18 +162,15 @@ pub(crate) trait TypeOpInfo<'tcx> {

let placeholder_region = ty::Region::new_placeholder(
tcx,
ty::PlaceholderRegion::new(adjusted_universe.into(), placeholder.bound),
placeholder.with_updated_universe(adjusted_universe.into()),
);

// FIXME: one day this should just be error_element,
// and this method shouldn't do anything.
let error_region = error_element.and_then(|e| {
let adjusted_universe = e.universe.as_u32().checked_sub(base_universe.as_u32());
adjusted_universe.map(|adjusted| {
ty::Region::new_placeholder(
tcx,
ty::PlaceholderRegion::new(adjusted.into(), e.bound),
)
ty::Region::new_placeholder(tcx, e.with_updated_universe(adjusted.into()))
})
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,7 @@ pub(crate) fn apply_definition_site_hidden_types<'tcx>(
},
"equating opaque types",
),
&[],
) {
add_hidden_type(
tcx,
Expand Down
68 changes: 67 additions & 1 deletion compiler/rustc_borrowck/src/type_check/canonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ use std::fmt;
use rustc_errors::ErrorGuaranteed;
use rustc_infer::infer::canonical::Canonical;
use rustc_infer::infer::outlives::env::RegionBoundPairs;
use rustc_infer::infer::region_constraints::GenericKind;
use rustc_middle::bug;
use rustc_middle::mir::{Body, ConstraintCategory};
use rustc_middle::traits::query::OutlivesBound;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Unnormalized, Upcast};
use rustc_span::Span;
use rustc_span::def_id::DefId;
Expand All @@ -29,6 +31,7 @@ pub(crate) fn fully_perform_op_raw<'tcx, R: fmt::Debug, Op>(
locations: Locations,
category: ConstraintCategory<'tcx>,
op: Op,
assumptions: &[ty::ArgOutlivesPredicate<'tcx>],
) -> Result<R, ErrorGuaranteed>
where
Op: type_op::TypeOp<'tcx, Output = R>,
Expand Down Expand Up @@ -58,7 +61,7 @@ where
category,
constraints,
)
.convert_all(data);
.convert_all_with_assumptions(data, assumptions);
}

// If the query has created new universes and errors are going to be emitted, register the
Expand Down Expand Up @@ -108,6 +111,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
locations,
category,
op,
&[],
)
}

Expand Down Expand Up @@ -185,6 +189,68 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);
}

/// Proves that the already instantiated fn-pointer type `src_ty` is
/// well-formed, while assuming the outlives implied bounds of its input
/// types.
pub(super) fn prove_fn_ptr_wf(
&mut self,
src_ty: Ty<'tcx>,
locations: Locations,
category: ConstraintCategory<'tcx>,
) {
let ty::FnPtr(sig_tys, hdr) = *src_ty.kind() else {
self.prove_clause(ty::ClauseKind::WellFormed(src_ty.into()), locations, category);
return;
};

let span = locations.span(self.body);
let mut region_bound_pairs = self.region_bound_pairs.clone();
let mut assumptions: Vec<ty::ArgOutlivesPredicate<'tcx>> = Vec::new();
for input in sig_tys.with(hdr).skip_binder().inputs() {
let Ok(TypeOpOutput { output: bounds, constraints, .. }) =
self.infcx.fully_perform(type_op::ImpliedOutlivesBounds { ty: *input }, span)
else {
continue;
};
if let Some(constraints) = constraints {
self.push_region_constraints(locations, category, constraints);
}
for bound in bounds {
match bound {
OutlivesBound::RegionSubParam(r, param) => {
region_bound_pairs
.insert(ty::OutlivesPredicate(GenericKind::Param(param), r));
}
OutlivesBound::RegionSubAlias(r, alias) => {
region_bound_pairs
.insert(ty::OutlivesPredicate(GenericKind::Alias(alias), r));
}
// Region-region bounds 'b: 'a can't go in region_bound_pairs,
// so they are passed to the WF proof as higher-ranked assumptions.
OutlivesBound::RegionSubRegion(r_a, r_b) => {
assumptions.push(ty::OutlivesPredicate(r_b.into(), r_a));
}
}
}
}

let param_env = self.infcx.param_env;
let clause: ty::Clause<'tcx> = ty::ClauseKind::WellFormed(src_ty.into()).upcast(self.tcx());
let predicate: ty::Predicate<'tcx> = clause.upcast(self.tcx());
let _: Result<_, ErrorGuaranteed> = fully_perform_op_raw(
self.infcx,
self.body,
self.universal_regions,
&region_bound_pairs,
self.known_type_outlives_obligations,
self.constraints,
locations,
category,
param_env.and(type_op::prove_predicate::ProvePredicate { predicate }),
&assumptions,
);
}

pub(super) fn normalize<T>(
&mut self,
value: Unnormalized<'tcx, T>,
Expand Down
27 changes: 21 additions & 6 deletions compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,22 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {

#[instrument(skip(self), level = "debug")]
pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<'tcx>) {
self.convert_all_with_assumptions(query_constraints, &[]);
}

/// Like [`Self::convert_all`], but additionally treats `extra_assumptions` as
/// higher-ranked outlives assumptions: any converted obligation that matches
/// one of them is discharged.
pub(super) fn convert_all_with_assumptions(
&mut self,
query_constraints: &QueryRegionConstraints<'tcx>,
extra_assumptions: &[ty::ArgOutlivesPredicate<'tcx>],
) {
let QueryRegionConstraints { constraints, assumptions } = query_constraints;
let assumptions =
elaborate::elaborate_outlives_assumptions(self.infcx.tcx, assumptions.iter().copied());
let assumptions = elaborate::elaborate_outlives_assumptions(
self.infcx.tcx,
assumptions.iter().copied().chain(extra_assumptions.iter().copied()),
);

for &QueryRegionConstraint { constraint, category, .. } in constraints {
constraint.iter_outlives().for_each(|predicate| {
Expand Down Expand Up @@ -142,10 +155,12 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
} = *self;

let pred = predicate;
// Constraint is implied by a coroutine's well-formedness.
if self.infcx.tcx.sess.opts.unstable_opts.higher_ranked_assumptions
&& higher_ranked_assumptions.contains(&pred)
{
// Skip any outlives obligation covered by a higher-ranked assumption (an
// implied bound carried along a binder). This set is empty unless
// assumptions were explicitly registered — via `-Zhigher-ranked-assumptions`
// or by the fn-pointer reification WF check (see `prove_fn_ptr_wf`) — so it
// is a no-op in normal compilation.
if higher_ranked_assumptions.contains(&pred) {
return;
}

Expand Down
Loading
Loading