1
Fork 0

Clean up dropck code a bit

- Remove `Result` that couldn't be Err on valid compilation.
- Always compute errors on failure.
This commit is contained in:
Matthew Jasper 2025-02-11 15:36:24 +00:00
parent 87e5969572
commit 49cf00c7c0
4 changed files with 38 additions and 55 deletions

View file

@ -4,6 +4,7 @@ use rustc_index::interval::IntervalSet;
use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_infer::infer::outlives::for_liveness; use rustc_infer::infer::outlives::for_liveness;
use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, HasLocalDecls, Local, Location}; use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, HasLocalDecls, Local, Location};
use rustc_middle::span_bug;
use rustc_middle::traits::query::DropckOutlivesResult; use rustc_middle::traits::query::DropckOutlivesResult;
use rustc_middle::ty::relate::Relate; use rustc_middle::ty::relate::Relate;
use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
@ -613,9 +614,8 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
// can't rely on the the `ErrorGuaranteed` from `fully_perform` here // can't rely on the the `ErrorGuaranteed` from `fully_perform` here
// because it comes from delay_span_bug. // because it comes from delay_span_bug.
let ocx = ObligationCtxt::new_with_diagnostics(&typeck.infcx); let ocx = ObligationCtxt::new_with_diagnostics(&typeck.infcx);
let errors = match dropck_outlives::compute_dropck_outlives_with_errors( let errors =
&ocx, op, span, true, match dropck_outlives::compute_dropck_outlives_with_errors(&ocx, op, span) {
) {
Ok(_) => ocx.select_all_or_error(), Ok(_) => ocx.select_all_or_error(),
Err(e) => { Err(e) => {
if e.is_empty() { if e.is_empty() {
@ -629,7 +629,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
if !errors.is_empty() { if !errors.is_empty() {
typeck.infcx.err_ctxt().report_fulfillment_errors(errors); typeck.infcx.err_ctxt().report_fulfillment_errors(errors);
} else { } else {
rustc_middle::span_bug!(span, "Rerunning drop data query produced no error."); span_bug!(span, "Rerunning drop data query produced no error.");
} }
DropData { dropck_result: Default::default(), region_constraint_data: None } DropData { dropck_result: Default::default(), region_constraint_data: None }
} }

View file

@ -802,7 +802,7 @@ rustc_queries! {
query adt_dtorck_constraint( query adt_dtorck_constraint(
key: DefId key: DefId
) -> Result<&'tcx DropckConstraint<'tcx>, NoSolution> { ) -> &'tcx DropckConstraint<'tcx> {
desc { |tcx| "computing drop-check constraints for `{}`", tcx.def_path_str(key) } desc { |tcx| "computing drop-check constraints for `{}`", tcx.def_path_str(key) }
} }

View file

@ -94,7 +94,7 @@ pub fn compute_dropck_outlives_inner<'tcx>(
goal: ParamEnvAnd<'tcx, DropckOutlives<'tcx>>, goal: ParamEnvAnd<'tcx, DropckOutlives<'tcx>>,
span: Span, span: Span,
) -> Result<DropckOutlivesResult<'tcx>, NoSolution> { ) -> Result<DropckOutlivesResult<'tcx>, NoSolution> {
match compute_dropck_outlives_with_errors(ocx, goal, span, false) { match compute_dropck_outlives_with_errors(ocx, goal, span) {
Ok(r) => Ok(r), Ok(r) => Ok(r),
Err(_) => Err(NoSolution), Err(_) => Err(NoSolution),
} }
@ -104,7 +104,6 @@ pub fn compute_dropck_outlives_with_errors<'tcx, E>(
ocx: &ObligationCtxt<'_, 'tcx, E>, ocx: &ObligationCtxt<'_, 'tcx, E>,
goal: ParamEnvAnd<'tcx, DropckOutlives<'tcx>>, goal: ParamEnvAnd<'tcx, DropckOutlives<'tcx>>,
span: Span, span: Span,
report_errors: bool,
) -> Result<DropckOutlivesResult<'tcx>, Vec<E>> ) -> Result<DropckOutlivesResult<'tcx>, Vec<E>>
where where
E: FromSolverError<'tcx, NextSolverError<'tcx>>, E: FromSolverError<'tcx, NextSolverError<'tcx>>,
@ -162,17 +161,14 @@ where
result.overflows.len(), result.overflows.len(),
ty_stack.len() ty_stack.len()
); );
match dtorck_constraint_for_ty_inner( dtorck_constraint_for_ty_inner(
tcx, tcx,
ocx.infcx.typing_env(param_env), ocx.infcx.typing_env(param_env),
span, span,
depth, depth,
ty, ty,
&mut constraints, &mut constraints,
) { );
Err(_) => return Err(Vec::new()),
_ => (),
};
// "outlives" represent types/regions that may be touched // "outlives" represent types/regions that may be touched
// by a destructor. // by a destructor.
@ -192,16 +188,7 @@ where
// do not themselves define a destructor", more or less. We have // do not themselves define a destructor", more or less. We have
// to push them onto the stack to be expanded. // to push them onto the stack to be expanded.
for ty in constraints.dtorck_types.drain(..) { for ty in constraints.dtorck_types.drain(..) {
let ty = if report_errors { let ty = if let Ok(Normalized { value: ty, obligations }) =
let normalized_ty = ocx.deeply_normalize(&cause, param_env, ty)?;
let errors = ocx.select_where_possible();
if !errors.is_empty() {
debug!("failed to normalize dtorck type: {ty} ~> {errors:#?}");
return Err(errors);
}
normalized_ty
} else if let Ok(Normalized { value: ty, obligations }) =
ocx.infcx.at(&cause, param_env).query_normalize(ty) ocx.infcx.at(&cause, param_env).query_normalize(ty)
{ {
ocx.register_obligations(obligations); ocx.register_obligations(obligations);
@ -209,7 +196,11 @@ where
debug!("dropck_outlives: ty from dtorck_types = {:?}", ty); debug!("dropck_outlives: ty from dtorck_types = {:?}", ty);
ty ty
} else { } else {
return Err(Vec::new()); ocx.deeply_normalize(&cause, param_env, ty)?;
let errors = ocx.select_where_possible();
debug!("normalize errors: {ty} ~> {errors:#?}");
return Err(errors);
}; };
match ty.kind() { match ty.kind() {
@ -246,14 +237,14 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
depth: usize, depth: usize,
ty: Ty<'tcx>, ty: Ty<'tcx>,
constraints: &mut DropckConstraint<'tcx>, constraints: &mut DropckConstraint<'tcx>,
) -> Result<(), NoSolution> { ) {
if !tcx.recursion_limit().value_within_limit(depth) { if !tcx.recursion_limit().value_within_limit(depth) {
constraints.overflows.push(ty); constraints.overflows.push(ty);
return Ok(()); return;
} }
if trivial_dropck_outlives(tcx, ty) { if trivial_dropck_outlives(tcx, ty) {
return Ok(()); return;
} }
match ty.kind() { match ty.kind() {
@ -277,22 +268,20 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
// single-element containers, behave like their element // single-element containers, behave like their element
rustc_data_structures::stack::ensure_sufficient_stack(|| { rustc_data_structures::stack::ensure_sufficient_stack(|| {
dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, *ety, constraints) dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, *ety, constraints)
})?; });
} }
ty::Tuple(tys) => rustc_data_structures::stack::ensure_sufficient_stack(|| { ty::Tuple(tys) => rustc_data_structures::stack::ensure_sufficient_stack(|| {
for ty in tys.iter() { for ty in tys.iter() {
dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints)?; dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints);
} }
Ok::<_, NoSolution>(()) }),
})?,
ty::Closure(_, args) => rustc_data_structures::stack::ensure_sufficient_stack(|| { ty::Closure(_, args) => rustc_data_structures::stack::ensure_sufficient_stack(|| {
for ty in args.as_closure().upvar_tys() { for ty in args.as_closure().upvar_tys() {
dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints)?; dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints);
} }
Ok::<_, NoSolution>(()) }),
})?,
ty::CoroutineClosure(_, args) => { ty::CoroutineClosure(_, args) => {
rustc_data_structures::stack::ensure_sufficient_stack(|| { rustc_data_structures::stack::ensure_sufficient_stack(|| {
@ -304,10 +293,9 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
depth + 1, depth + 1,
ty, ty,
constraints, constraints,
)?; );
} }
Ok::<_, NoSolution>(()) })
})?
} }
ty::Coroutine(_, args) => { ty::Coroutine(_, args) => {
@ -346,7 +334,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
ty::Adt(def, args) => { ty::Adt(def, args) => {
let DropckConstraint { dtorck_types, outlives, overflows } = let DropckConstraint { dtorck_types, outlives, overflows } =
tcx.at(span).adt_dtorck_constraint(def.did())?; tcx.at(span).adt_dtorck_constraint(def.did());
// FIXME: we can try to recursively `dtorck_constraint_on_ty` // FIXME: we can try to recursively `dtorck_constraint_on_ty`
// there, but that needs some way to handle cycles. // there, but that needs some way to handle cycles.
constraints constraints
@ -379,9 +367,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => { ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => {
// By the time this code runs, all type variables ought to // By the time this code runs, all type variables ought to
// be fully resolved. // be fully resolved.
return Err(NoSolution); tcx.dcx().span_delayed_bug(span, format!("Unresolved type in dropck: {:?}.", ty));
} }
} }
Ok(())
} }

View file

@ -30,10 +30,7 @@ fn dropck_outlives<'tcx>(
} }
/// Calculates the dtorck constraint for a type. /// Calculates the dtorck constraint for a type.
pub(crate) fn adt_dtorck_constraint( pub(crate) fn adt_dtorck_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> &DropckConstraint<'_> {
tcx: TyCtxt<'_>,
def_id: DefId,
) -> Result<&DropckConstraint<'_>, NoSolution> {
let def = tcx.adt_def(def_id); let def = tcx.adt_def(def_id);
let span = tcx.def_span(def_id); let span = tcx.def_span(def_id);
let typing_env = ty::TypingEnv::non_body_analysis(tcx, def_id); let typing_env = ty::TypingEnv::non_body_analysis(tcx, def_id);
@ -52,20 +49,20 @@ pub(crate) fn adt_dtorck_constraint(
overflows: vec![], overflows: vec![],
}; };
debug!("dtorck_constraint: {:?} => {:?}", def, result); debug!("dtorck_constraint: {:?} => {:?}", def, result);
return Ok(tcx.arena.alloc(result)); return tcx.arena.alloc(result);
} }
let mut result = DropckConstraint::empty(); let mut result = DropckConstraint::empty();
for field in def.all_fields() { for field in def.all_fields() {
let fty = tcx.type_of(field.did).instantiate_identity(); let fty = tcx.type_of(field.did).instantiate_identity();
dtorck_constraint_for_ty_inner(tcx, typing_env, span, 0, fty, &mut result)?; dtorck_constraint_for_ty_inner(tcx, typing_env, span, 0, fty, &mut result);
} }
result.outlives.extend(tcx.destructor_constraints(def)); result.outlives.extend(tcx.destructor_constraints(def));
dedup_dtorck_constraint(&mut result); dedup_dtorck_constraint(&mut result);
debug!("dtorck_constraint: {:?} => {:?}", def, result); debug!("dtorck_constraint: {:?} => {:?}", def, result);
Ok(tcx.arena.alloc(result)) tcx.arena.alloc(result)
} }
fn dedup_dtorck_constraint(c: &mut DropckConstraint<'_>) { fn dedup_dtorck_constraint(c: &mut DropckConstraint<'_>) {