Opt-in diagnostics reporting to avoid doing extra work in the new solver
This commit is contained in:
parent
54b2b7d460
commit
eb0a70a557
31 changed files with 200 additions and 107 deletions
|
@ -1,14 +1,16 @@
|
|||
use crate::solve::NextSolverError;
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
use crate::traits::{self, ObligationCtxt, SelectionContext};
|
||||
use crate::traits::{
|
||||
self, FromSolverError, Obligation, ObligationCause, ObligationCtxt, OldSolverError,
|
||||
SelectionContext,
|
||||
};
|
||||
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_infer::traits::Obligation;
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::arena::ArenaAllocatable;
|
||||
use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryResponse};
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
|
||||
use rustc_middle::ty::{GenericArg, Upcast};
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
@ -94,7 +96,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
ty::TraitRef::new(self.tcx, trait_def_id, [ty]),
|
||||
)) {
|
||||
Ok(Some(selection)) => {
|
||||
let ocx = ObligationCtxt::new(self);
|
||||
let ocx = ObligationCtxt::new_with_diagnostics(self);
|
||||
ocx.register_obligations(selection.nested_obligations());
|
||||
Some(ocx.select_all_or_error())
|
||||
}
|
||||
|
@ -122,19 +124,21 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
|||
/// bound for the closure and in part because it is convenient to
|
||||
/// have `'tcx` be free on this function so that we can talk about
|
||||
/// `K: TypeFoldable<TyCtxt<'tcx>>`.)
|
||||
fn enter_canonical_trait_query<K, R>(
|
||||
fn enter_canonical_trait_query<K, R, E>(
|
||||
self,
|
||||
canonical_key: &Canonical<'tcx, K>,
|
||||
operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Result<R, NoSolution>,
|
||||
operation: impl FnOnce(&ObligationCtxt<'_, 'tcx, E>, K) -> Result<R, NoSolution>,
|
||||
) -> Result<CanonicalQueryResponse<'tcx, R>, NoSolution>
|
||||
where
|
||||
K: TypeFoldable<TyCtxt<'tcx>>,
|
||||
R: Debug + TypeFoldable<TyCtxt<'tcx>>,
|
||||
Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>,
|
||||
E: FromSolverError<'tcx, NextSolverError<'tcx>>
|
||||
+ FromSolverError<'tcx, OldSolverError<'tcx>>,
|
||||
{
|
||||
let (infcx, key, canonical_inference_vars) =
|
||||
self.build_with_canonical(DUMMY_SP, canonical_key);
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
let ocx = ObligationCtxt::new_generic(&infcx);
|
||||
let value = operation(&ocx, key)?;
|
||||
ocx.make_canonicalized_query_response(canonical_inference_vars, value)
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
|||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
use crate::traits::FulfillmentError;
|
||||
use crate::traits::{FulfillmentError, ScrubbedTraitError};
|
||||
|
||||
use super::eval_ctxt::GenerateProofTree;
|
||||
use super::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor};
|
||||
|
@ -226,6 +226,17 @@ impl<'tcx> FromSolverError<'tcx, NextSolverError<'tcx>> for FulfillmentError<'tc
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> FromSolverError<'tcx, NextSolverError<'tcx>> for ScrubbedTraitError {
|
||||
fn from_solver_error(_infcx: &InferCtxt<'tcx>, error: NextSolverError<'tcx>) -> Self {
|
||||
match error {
|
||||
NextSolverError::TrueError(_) => ScrubbedTraitError::TrueError,
|
||||
NextSolverError::Ambiguity(_) | NextSolverError::Overflow(_) => {
|
||||
ScrubbedTraitError::Ambiguity
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fulfillment_error_for_no_solution<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
root_obligation: PredicateObligation<'tcx>,
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
use rustc_ast_ir::try_visit;
|
||||
use rustc_ast_ir::visit::VisitorResult;
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
|
||||
use rustc_infer::traits::FulfillmentErrorLike as _;
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::traits::solve::{inspect, QueryResult};
|
||||
|
|
|
@ -360,7 +360,7 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
|
|||
let infcx = selcx.infcx;
|
||||
|
||||
if infcx.next_trait_solver() {
|
||||
let ocx = ObligationCtxt::new(infcx);
|
||||
let ocx = ObligationCtxt::new_with_diagnostics(infcx);
|
||||
ocx.register_obligations(obligations.iter().cloned());
|
||||
let errors_and_ambiguities = ocx.select_all_or_error();
|
||||
// We only care about the obligations that are *definitely* true errors.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use std::cell::RefCell;
|
||||
use std::fmt::Debug;
|
||||
|
||||
use super::FulfillmentContext;
|
||||
use super::{FromSolverError, TraitEngine};
|
||||
use super::{FulfillmentContext, ScrubbedTraitError};
|
||||
use crate::regions::InferCtxtRegionExt;
|
||||
use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt;
|
||||
use crate::solve::NextSolverError;
|
||||
|
@ -21,6 +21,7 @@ use rustc_infer::infer::canonical::{
|
|||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc_infer::infer::RegionResolutionError;
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
|
||||
use rustc_infer::traits::FulfillmentErrorLike;
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::arena::ArenaAllocatable;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
|
@ -53,20 +54,36 @@ impl<
|
|||
|
||||
/// Used if you want to have pleasant experience when dealing
|
||||
/// with obligations outside of hir or mir typeck.
|
||||
pub struct ObligationCtxt<'a, 'tcx> {
|
||||
pub struct ObligationCtxt<'a, 'tcx, E = ScrubbedTraitError> {
|
||||
pub infcx: &'a InferCtxt<'tcx>,
|
||||
engine: RefCell<Box<dyn TraitEngine<'tcx, FulfillmentError<'tcx>>>>,
|
||||
engine: RefCell<Box<dyn TraitEngine<'tcx, E>>>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
|
||||
pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
|
||||
// TODO:
|
||||
Self {
|
||||
infcx,
|
||||
engine: RefCell::new(<dyn TraitEngine<'tcx, FulfillmentError<'tcx>>>::new(infcx)),
|
||||
}
|
||||
impl<'a, 'tcx> ObligationCtxt<'a, 'tcx, FulfillmentError<'tcx>> {
|
||||
pub fn new_with_diagnostics(infcx: &'a InferCtxt<'tcx>) -> Self {
|
||||
Self { infcx, engine: RefCell::new(<dyn TraitEngine<'tcx, _>>::new(infcx)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> ObligationCtxt<'a, 'tcx, ScrubbedTraitError> {
|
||||
pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
|
||||
Self { infcx, engine: RefCell::new(<dyn TraitEngine<'tcx, _>>::new(infcx)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, E> ObligationCtxt<'a, 'tcx, E>
|
||||
where
|
||||
E: FromSolverError<'tcx, NextSolverError<'tcx>> + FromSolverError<'tcx, OldSolverError<'tcx>>,
|
||||
{
|
||||
pub fn new_generic(infcx: &'a InferCtxt<'tcx>) -> Self {
|
||||
Self { infcx, engine: RefCell::new(<dyn TraitEngine<'tcx, _>>::new(infcx)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, E> ObligationCtxt<'a, 'tcx, E>
|
||||
where
|
||||
E: FulfillmentErrorLike<'tcx>,
|
||||
{
|
||||
pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) {
|
||||
self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation);
|
||||
}
|
||||
|
@ -118,26 +135,6 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
|
|||
self.register_infer_ok_obligations(infer_ok)
|
||||
}
|
||||
|
||||
pub fn deeply_normalize<T: TypeFoldable<TyCtxt<'tcx>>>(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
value: T,
|
||||
) -> Result<T, Vec<FulfillmentError<'tcx>>> {
|
||||
self.infcx.at(cause, param_env).deeply_normalize(value, &mut **self.engine.borrow_mut())
|
||||
}
|
||||
|
||||
pub fn structurally_normalize(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
value: Ty<'tcx>,
|
||||
) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>> {
|
||||
self.infcx
|
||||
.at(cause, param_env)
|
||||
.structurally_normalize(value, &mut **self.engine.borrow_mut())
|
||||
}
|
||||
|
||||
pub fn eq<T: ToTrace<'tcx>>(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
|
@ -194,12 +191,12 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn select_where_possible(&self) -> Vec<FulfillmentError<'tcx>> {
|
||||
pub fn select_where_possible(&self) -> Vec<E> {
|
||||
self.engine.borrow_mut().select_where_possible(self.infcx)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn select_all_or_error(&self) -> Vec<FulfillmentError<'tcx>> {
|
||||
pub fn select_all_or_error(&self) -> Vec<E> {
|
||||
self.engine.borrow_mut().select_all_or_error(self.infcx)
|
||||
}
|
||||
|
||||
|
@ -244,6 +241,24 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
|
|||
self.infcx.resolve_regions(outlives_env)
|
||||
}
|
||||
|
||||
pub fn make_canonicalized_query_response<T>(
|
||||
&self,
|
||||
inference_vars: CanonicalVarValues<'tcx>,
|
||||
answer: T,
|
||||
) -> Result<CanonicalQueryResponse<'tcx, T>, NoSolution>
|
||||
where
|
||||
T: Debug + TypeFoldable<TyCtxt<'tcx>>,
|
||||
Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>,
|
||||
{
|
||||
self.infcx.make_canonicalized_query_response(
|
||||
inference_vars,
|
||||
answer,
|
||||
&mut **self.engine.borrow_mut(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ObligationCtxt<'_, 'tcx, FulfillmentError<'tcx>> {
|
||||
pub fn assumed_wf_types_and_report_errors(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
|
@ -252,12 +267,17 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
|
|||
self.assumed_wf_types(param_env, def_id)
|
||||
.map_err(|errors| self.infcx.err_ctxt().report_fulfillment_errors(errors))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, E> ObligationCtxt<'_, 'tcx, E>
|
||||
where
|
||||
E: FromSolverError<'tcx, NextSolverError<'tcx>>,
|
||||
{
|
||||
pub fn assumed_wf_types(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
) -> Result<FxIndexSet<Ty<'tcx>>, Vec<FulfillmentError<'tcx>>> {
|
||||
) -> Result<FxIndexSet<Ty<'tcx>>, Vec<E>> {
|
||||
let tcx = self.infcx.tcx;
|
||||
let mut implied_bounds = FxIndexSet::default();
|
||||
let mut errors = Vec::new();
|
||||
|
@ -289,19 +309,23 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
|
|||
if errors.is_empty() { Ok(implied_bounds) } else { Err(errors) }
|
||||
}
|
||||
|
||||
pub fn make_canonicalized_query_response<T>(
|
||||
pub fn deeply_normalize<T: TypeFoldable<TyCtxt<'tcx>>>(
|
||||
&self,
|
||||
inference_vars: CanonicalVarValues<'tcx>,
|
||||
answer: T,
|
||||
) -> Result<CanonicalQueryResponse<'tcx, T>, NoSolution>
|
||||
where
|
||||
T: Debug + TypeFoldable<TyCtxt<'tcx>>,
|
||||
Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>,
|
||||
{
|
||||
self.infcx.make_canonicalized_query_response(
|
||||
inference_vars,
|
||||
answer,
|
||||
&mut **self.engine.borrow_mut(),
|
||||
)
|
||||
cause: &ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
value: T,
|
||||
) -> Result<T, Vec<E>> {
|
||||
self.infcx.at(cause, param_env).deeply_normalize(value, &mut **self.engine.borrow_mut())
|
||||
}
|
||||
|
||||
pub fn structurally_normalize(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
value: Ty<'tcx>,
|
||||
) -> Result<Ty<'tcx>, Vec<E>> {
|
||||
self.infcx
|
||||
.at(cause, param_env)
|
||||
.structurally_normalize(value, &mut **self.engine.borrow_mut())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,13 +16,13 @@ use rustc_middle::ty::GenericArgsRef;
|
|||
use rustc_middle::ty::{self, Binder, Const, TypeVisitableExt};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use super::const_evaluatable;
|
||||
use super::project::{self, ProjectAndUnifyResult};
|
||||
use super::select::SelectionContext;
|
||||
use super::wf;
|
||||
use super::EvaluationResult;
|
||||
use super::PredicateObligation;
|
||||
use super::Unimplemented;
|
||||
use super::{const_evaluatable, ScrubbedTraitError};
|
||||
use super::{FulfillmentError, FulfillmentErrorCode};
|
||||
|
||||
use crate::traits::project::PolyProjectionObligation;
|
||||
|
@ -855,3 +855,17 @@ impl<'tcx> FromSolverError<'tcx, OldSolverError<'tcx>> for FulfillmentError<'tcx
|
|||
FulfillmentError::new(obligation, error.error, root_obligation)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> FromSolverError<'tcx, OldSolverError<'tcx>> for ScrubbedTraitError {
|
||||
fn from_solver_error(_infcx: &InferCtxt<'tcx>, error: OldSolverError<'tcx>) -> Self {
|
||||
match error.error {
|
||||
FulfillmentErrorCode::Select(_)
|
||||
| FulfillmentErrorCode::Project(_)
|
||||
| FulfillmentErrorCode::Subtype(_, _)
|
||||
| FulfillmentErrorCode::ConstEquate(_, _) => ScrubbedTraitError::TrueError,
|
||||
FulfillmentErrorCode::Cycle(_) | FulfillmentErrorCode::Ambiguity { overflow: _ } => {
|
||||
ScrubbedTraitError::Ambiguity
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@ pub fn all_fields_implement_trait<'tcx>(
|
|||
for field in &variant.fields {
|
||||
// Do this per-field to get better error messages.
|
||||
let infcx = tcx.infer_ctxt().build();
|
||||
let ocx = traits::ObligationCtxt::new(&infcx);
|
||||
let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
|
||||
|
||||
let unnormalized_ty = field.ty(tcx, args);
|
||||
if unnormalized_ty.references_error() {
|
||||
|
|
|
@ -46,7 +46,7 @@ pub use self::coherence::{add_placeholder_note, orphan_check_trait_ref, overlapp
|
|||
pub use self::coherence::{InCrate, IsFirstInputType, UncoveredTyParams};
|
||||
pub use self::coherence::{OrphanCheckErr, OrphanCheckMode, OverlapResult};
|
||||
pub use self::engine::{ObligationCtxt, TraitEngineExt};
|
||||
pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation};
|
||||
pub use self::fulfill::{FulfillmentContext, OldSolverError, PendingPredicateObligation};
|
||||
pub use self::normalize::NormalizeExt;
|
||||
pub use self::object_safety::hir_ty_lowering_object_safety_violations;
|
||||
pub use self::object_safety::is_vtable_safe_method;
|
||||
|
@ -70,6 +70,28 @@ pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, Placeh
|
|||
|
||||
pub use rustc_infer::traits::*;
|
||||
|
||||
// A trait error without any information in it. You likely want to alternately use [`ObligationCtxt::new_with_diagnostics`] to get a [`FulfillmentError`].
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum ScrubbedTraitError {
|
||||
TrueError,
|
||||
Ambiguity,
|
||||
}
|
||||
|
||||
impl ScrubbedTraitError {
|
||||
fn is_true_error(&self) -> bool {
|
||||
match self {
|
||||
ScrubbedTraitError::TrueError => true,
|
||||
ScrubbedTraitError::Ambiguity => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> FulfillmentErrorLike<'tcx> for ScrubbedTraitError {
|
||||
fn is_true_error(&self) -> bool {
|
||||
self.is_true_error()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FulfillmentError<'tcx> {
|
||||
pub obligation: PredicateObligation<'tcx>,
|
||||
pub code: FulfillmentErrorCode<'tcx>,
|
||||
|
@ -450,7 +472,7 @@ pub fn fully_normalize<'tcx, T>(
|
|||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
let ocx = ObligationCtxt::new(infcx);
|
||||
let ocx = ObligationCtxt::new_with_diagnostics(infcx);
|
||||
debug!(?value);
|
||||
let normalized_value = ocx.normalize(&cause, param_env, value);
|
||||
debug!(?normalized_value);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue