Rollup merge of #111741 - compiler-errors:custom-type-op, r=lcnr
Use `ObligationCtxt` in custom type ops We already make one when evaluating the `CustomTypeOp`, so it's simpler to just pass it to the user. Removes a redundant `ObligationCtxt::new_in_snapshot` usage and simplifies some other code. This makes several refactorings related to opaque types in the new solver simpler, but those are not included in this PR.
This commit is contained in:
commit
a9a4c9b3db
5 changed files with 66 additions and 60 deletions
|
@ -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()
|
||||||
|
|
|
@ -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!(
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue