Use ObligationCtxt in custom type ops

This commit is contained in:
Michael Goulet 2023-05-18 20:42:46 +00:00
parent 70db836922
commit 521a0bcd1f
5 changed files with 66 additions and 60 deletions

View File

@ -128,7 +128,7 @@ impl<'tcx> ToUniverseInfo<'tcx>
} }
} }
impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::CustomTypeOp<F, G>> { impl<'tcx, F> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::CustomTypeOp<F>> {
fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
// We can't rerun custom type ops. // We can't rerun custom type ops.
UniverseInfo::other() UniverseInfo::other()

View File

@ -1,13 +1,13 @@
use std::fmt; use std::fmt;
use rustc_infer::infer::{canonical::Canonical, InferOk}; use rustc_infer::infer::canonical::Canonical;
use rustc_middle::mir::ConstraintCategory; use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
use rustc_span::def_id::DefId; use rustc_span::def_id::DefId;
use rustc_span::Span; use rustc_span::Span;
use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput}; use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
use rustc_trait_selection::traits::query::{Fallible, NoSolution}; use rustc_trait_selection::traits::query::{Fallible, NoSolution};
use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; use rustc_trait_selection::traits::ObligationCause;
use crate::diagnostics::{ToUniverseInfo, UniverseInfo}; use crate::diagnostics::{ToUniverseInfo, UniverseInfo};
@ -219,20 +219,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let cause = ObligationCause::dummy_with_span(span); let cause = ObligationCause::dummy_with_span(span);
let param_env = self.param_env; let param_env = self.param_env;
let op = |infcx: &'_ _| {
let ocx = ObligationCtxt::new_in_snapshot(infcx);
let user_ty = ocx.normalize(&cause, param_env, user_ty);
ocx.eq(&cause, param_env, user_ty, mir_ty)?;
if !ocx.select_all_or_error().is_empty() {
return Err(NoSolution);
}
Ok(InferOk { value: (), obligations: vec![] })
};
self.fully_perform_op( self.fully_perform_op(
Locations::All(span), Locations::All(span),
ConstraintCategory::Boring, ConstraintCategory::Boring,
type_op::custom::CustomTypeOp::new(op, || "ascribe_user_type_skip_wf".to_string()), type_op::custom::CustomTypeOp::new(
|ocx| {
let user_ty = ocx.normalize(&cause, param_env, user_ty);
ocx.eq(&cause, param_env, user_ty, mir_ty)?;
Ok(())
},
"ascribe_user_type_skip_wf",
),
) )
.unwrap_or_else(|err| { .unwrap_or_else(|err| {
span_mirbug!( span_mirbug!(

View File

@ -20,7 +20,7 @@ use rustc_infer::infer::outlives::env::RegionBoundPairs;
use rustc_infer::infer::region_constraints::RegionConstraintData; use rustc_infer::infer::region_constraints::RegionConstraintData;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{ use rustc_infer::infer::{
InferCtxt, InferOk, LateBoundRegion, LateBoundRegionConversionTime, NllRegionVariableOrigin, InferCtxt, LateBoundRegion, LateBoundRegionConversionTime, NllRegionVariableOrigin,
}; };
use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
@ -218,16 +218,16 @@ pub(crate) fn type_check<'mir, 'tcx>(
Locations::All(body.span), Locations::All(body.span),
ConstraintCategory::OpaqueType, ConstraintCategory::OpaqueType,
CustomTypeOp::new( CustomTypeOp::new(
|infcx| { |ocx| {
infcx.register_member_constraints( ocx.infcx.register_member_constraints(
param_env, param_env,
opaque_type_key, opaque_type_key,
decl.hidden_type.ty, decl.hidden_type.ty,
decl.hidden_type.span, decl.hidden_type.span,
); );
Ok(InferOk { value: (), obligations: vec![] }) Ok(())
}, },
|| "opaque_type_map".to_string(), "opaque_type_map",
), ),
) )
.unwrap(); .unwrap();
@ -2713,8 +2713,9 @@ impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> {
type ErrorInfo = InstantiateOpaqueType<'tcx>; type ErrorInfo = InstantiateOpaqueType<'tcx>;
fn fully_perform(mut self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> { fn fully_perform(mut self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
let (mut output, region_constraints) = scrape_region_constraints(infcx, || { let (mut output, region_constraints) = scrape_region_constraints(infcx, |ocx| {
Ok(InferOk { value: (), obligations: self.obligations.clone() }) ocx.register_obligations(self.obligations.clone());
Ok(())
})?; })?;
self.region_constraints = Some(region_constraints); self.region_constraints = Some(region_constraints);
output.error_info = Some(self); output.error_info = Some(self);

View File

@ -185,17 +185,25 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
} }
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
self.type_checker match self.type_checker.fully_perform_op(
.fully_perform_op( self.locations,
self.locations, self.category,
self.category, InstantiateOpaqueType {
InstantiateOpaqueType { obligations,
obligations, // These fields are filled in during execution of the operation
// These fields are filled in during execution of the operation base_universe: None,
base_universe: None, region_constraints: None,
region_constraints: None, },
}, ) {
) Ok(()) => {}
.unwrap(); Err(_) => {
// It's a bit redundant to delay a bug here, but I'd rather
// delay more bugs than accidentally not delay a bug at all.
self.type_checker.tcx().sess.delay_span_bug(
self.locations.span(self.type_checker.body),
"errors selecting obligation during MIR typeck",
);
}
};
} }
} }

View File

@ -1,32 +1,31 @@
use crate::infer::canonical::query_response; use crate::infer::canonical::query_response;
use crate::infer::{InferCtxt, InferOk}; use crate::infer::InferCtxt;
use crate::traits::query::type_op::TypeOpOutput; use crate::traits::query::type_op::TypeOpOutput;
use crate::traits::query::Fallible; use crate::traits::query::Fallible;
use crate::traits::ObligationCtxt; use crate::traits::ObligationCtxt;
use rustc_infer::infer::region_constraints::RegionConstraintData; use rustc_infer::infer::region_constraints::RegionConstraintData;
use rustc_middle::traits::query::NoSolution;
use rustc_span::source_map::DUMMY_SP; use rustc_span::source_map::DUMMY_SP;
use std::fmt; use std::fmt;
pub struct CustomTypeOp<F, G> { pub struct CustomTypeOp<F> {
closure: F, closure: F,
description: G, description: &'static str,
} }
impl<F, G> CustomTypeOp<F, G> { impl<F> CustomTypeOp<F> {
pub fn new<'tcx, R>(closure: F, description: G) -> Self pub fn new<'tcx, R>(closure: F, description: &'static str) -> Self
where where
F: FnOnce(&InferCtxt<'tcx>) -> Fallible<InferOk<'tcx, R>>, F: FnOnce(&ObligationCtxt<'_, 'tcx>) -> Fallible<R>,
G: Fn() -> String,
{ {
CustomTypeOp { closure, description } CustomTypeOp { closure, description }
} }
} }
impl<'tcx, F, R: fmt::Debug, G> super::TypeOp<'tcx> for CustomTypeOp<F, G> impl<'tcx, F, R: fmt::Debug> super::TypeOp<'tcx> for CustomTypeOp<F>
where where
F: for<'a, 'cx> FnOnce(&'a InferCtxt<'tcx>) -> Fallible<InferOk<'tcx, R>>, F: FnOnce(&ObligationCtxt<'_, 'tcx>) -> Fallible<R>,
G: Fn() -> String,
{ {
type Output = R; type Output = R;
/// We can't do any custom error reporting for `CustomTypeOp`, so /// We can't do any custom error reporting for `CustomTypeOp`, so
@ -41,16 +40,13 @@ where
info!("fully_perform({:?})", self); info!("fully_perform({:?})", self);
} }
Ok(scrape_region_constraints(infcx, || (self.closure)(infcx))?.0) Ok(scrape_region_constraints(infcx, self.closure)?.0)
} }
} }
impl<F, G> fmt::Debug for CustomTypeOp<F, G> impl<F> fmt::Debug for CustomTypeOp<F> {
where
G: Fn() -> String,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", (self.description)()) self.description.fmt(f)
} }
} }
@ -58,7 +54,7 @@ where
/// constraints that result, creating query-region-constraints. /// constraints that result, creating query-region-constraints.
pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
infcx: &InferCtxt<'tcx>, infcx: &InferCtxt<'tcx>,
op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>, op: impl FnOnce(&ObligationCtxt<'_, 'tcx>) -> Fallible<R>,
) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> { ) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> {
// During NLL, we expect that nobody will register region // During NLL, we expect that nobody will register region
// obligations **except** as part of a custom type op (and, at the // obligations **except** as part of a custom type op (and, at the
@ -72,16 +68,20 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
pre_obligations, pre_obligations,
); );
let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?; let value = infcx.commit_if_ok(|_| {
let ocx = ObligationCtxt::new(infcx); let ocx = ObligationCtxt::new_in_snapshot(infcx);
ocx.register_obligations(obligations); let value = op(&ocx)?;
let errors = ocx.select_all_or_error(); let errors = ocx.select_all_or_error();
if !errors.is_empty() { if errors.is_empty() {
infcx.tcx.sess.diagnostic().delay_span_bug( Ok(value)
DUMMY_SP, } else {
format!("errors selecting obligation during MIR typeck: {:?}", errors), infcx.tcx.sess.delay_span_bug(
); DUMMY_SP,
} format!("errors selecting obligation during MIR typeck: {:?}", errors),
);
Err(NoSolution)
}
})?;
let region_obligations = infcx.take_registered_region_obligations(); let region_obligations = infcx.take_registered_region_obligations();
let region_constraint_data = infcx.take_and_reset_region_constraints(); let region_constraint_data = infcx.take_and_reset_region_constraints();