Auto merge of #86700 - lqd:matthews-nll-hrtb-errors, r=nikomatsakis
Matthew's work on improving NLL's "higher-ranked subtype error"s This PR rebases `@matthewjasper's` [branch](https://github.com/matthewjasper/rust/tree/nll-hrtb-errors) which has great work to fix the obscure higher-ranked subtype errors that are tracked in #57374. These are a blocker to turning full NLLs on, and doing some internal cleanups to remove some of the old region code. The goal is so `@nikomatsakis` can take a look at this early, and I'll then do my best to help do the changes and followup work to land this work, and move closer to turning off the migration mode. I've only updated the branch and made it compile, removed a warning or two. r? `@nikomatsakis` (Here's the [zulip topic to discuss this](https://rust-lang.zulipchat.com/#narrow/stream/122657-t-compiler.2Fwg-nll/topic/.2357374.3A.20improving.20higher-ranked.20subtype.20errors.20via.20.2386700) that Niko wanted)
This commit is contained in:
commit
3d0774d0dc
63 changed files with 1043 additions and 345 deletions
|
@ -1,13 +1,13 @@
|
|||
use crate::infer::{InferCtxt, InferOk};
|
||||
use crate::traits::query::Fallible;
|
||||
use std::fmt;
|
||||
|
||||
use crate::infer::canonical::query_response;
|
||||
use crate::infer::canonical::QueryRegionConstraints;
|
||||
use crate::infer::{InferCtxt, InferOk};
|
||||
use crate::traits::engine::TraitEngineExt as _;
|
||||
use crate::traits::query::type_op::TypeOpOutput;
|
||||
use crate::traits::query::Fallible;
|
||||
use crate::traits::{ObligationCause, TraitEngine};
|
||||
use rustc_infer::traits::TraitEngineExt as _;
|
||||
use rustc_span::source_map::DUMMY_SP;
|
||||
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct CustomTypeOp<F, G> {
|
||||
|
@ -35,10 +35,7 @@ where
|
|||
/// Processes the operation and all resulting obligations,
|
||||
/// returning the final result along with any region constraints
|
||||
/// (they will be given over to the NLL region solver).
|
||||
fn fully_perform(
|
||||
self,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)> {
|
||||
fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
|
||||
if cfg!(debug_assertions) {
|
||||
info!("fully_perform({:?})", self);
|
||||
}
|
||||
|
@ -58,10 +55,10 @@ where
|
|||
|
||||
/// Executes `op` and then scrapes out all the "old style" region
|
||||
/// constraints that result, creating query-region-constraints.
|
||||
fn scrape_region_constraints<'tcx, R>(
|
||||
fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
|
||||
) -> Fallible<(R, Option<Rc<QueryRegionConstraints<'tcx>>>)> {
|
||||
) -> Fallible<TypeOpOutput<'tcx, Op>> {
|
||||
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
|
||||
let dummy_body_id = ObligationCause::dummy().body_id;
|
||||
|
||||
|
@ -101,8 +98,12 @@ fn scrape_region_constraints<'tcx, R>(
|
|||
);
|
||||
|
||||
if region_constraints.is_empty() {
|
||||
Ok((value, None))
|
||||
Ok(TypeOpOutput { output: value, constraints: None, canonicalized_query: None })
|
||||
} else {
|
||||
Ok((value, Some(Rc::new(region_constraints))))
|
||||
Ok(TypeOpOutput {
|
||||
output: value,
|
||||
constraints: Some(Rc::new(region_constraints)),
|
||||
canonicalized_query: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::traits::query::outlives_bounds::OutlivesBound;
|
|||
use crate::traits::query::Fallible;
|
||||
use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
|
||||
|
||||
#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)]
|
||||
#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, Lift)]
|
||||
pub struct ImpliedOutlivesBounds<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ use crate::infer::canonical::{
|
|||
use crate::infer::{InferCtxt, InferOk};
|
||||
use crate::traits::query::Fallible;
|
||||
use crate::traits::ObligationCause;
|
||||
use rustc_infer::infer::canonical::Canonical;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
|
||||
use std::fmt;
|
||||
|
@ -30,10 +31,18 @@ pub trait TypeOp<'tcx>: Sized + fmt::Debug {
|
|||
/// Processes the operation and all resulting obligations,
|
||||
/// returning the final result along with any region constraints
|
||||
/// (they will be given over to the NLL region solver).
|
||||
fn fully_perform(
|
||||
self,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)>;
|
||||
fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>>;
|
||||
}
|
||||
|
||||
/// The output from performing a type op
|
||||
pub struct TypeOpOutput<'tcx, Op: TypeOp<'tcx>> {
|
||||
/// The output from the type op.
|
||||
pub output: Op::Output,
|
||||
/// Any region constraints from performing the type op.
|
||||
pub constraints: Option<Rc<QueryRegionConstraints<'tcx>>>,
|
||||
/// The canonicalized form of the query.
|
||||
/// This for error reporting to be able to rerun the query.
|
||||
pub canonicalized_query: Option<Canonical<'tcx, Op>>,
|
||||
}
|
||||
|
||||
/// "Query type ops" are type ops that are implemented using a
|
||||
|
@ -45,7 +54,7 @@ pub trait TypeOp<'tcx>: Sized + fmt::Debug {
|
|||
/// which produces the resulting query region constraints.
|
||||
///
|
||||
/// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
|
||||
pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx {
|
||||
pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<'tcx> + 'tcx {
|
||||
type QueryResponse: TypeFoldable<'tcx>;
|
||||
|
||||
/// Give query the option for a simple fast path that never
|
||||
|
@ -71,9 +80,9 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx {
|
|||
query_key: ParamEnvAnd<'tcx, Self>,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
|
||||
) -> Fallible<Self::QueryResponse> {
|
||||
) -> Fallible<(Self::QueryResponse, Option<Canonical<'tcx, ParamEnvAnd<'tcx, Self>>>)> {
|
||||
if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) {
|
||||
return Ok(result);
|
||||
return Ok((result, None));
|
||||
}
|
||||
|
||||
// FIXME(#33684) -- We need to use
|
||||
|
@ -101,14 +110,14 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx {
|
|||
// create obligations. In that case, we have to go
|
||||
// fulfill them. We do this via a (recursive) query.
|
||||
for obligation in obligations {
|
||||
let () = ProvePredicate::fully_perform_into(
|
||||
let ((), _) = ProvePredicate::fully_perform_into(
|
||||
obligation.param_env.and(ProvePredicate::new(obligation.predicate)),
|
||||
infcx,
|
||||
output_query_region_constraints,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(value)
|
||||
Ok((value, Some(canonical_self)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,18 +127,16 @@ where
|
|||
{
|
||||
type Output = Q::QueryResponse;
|
||||
|
||||
fn fully_perform(
|
||||
self,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)> {
|
||||
fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
|
||||
let mut region_constraints = QueryRegionConstraints::default();
|
||||
let r = Q::fully_perform_into(self, infcx, &mut region_constraints)?;
|
||||
let (output, canonicalized_query) =
|
||||
Q::fully_perform_into(self, infcx, &mut region_constraints)?;
|
||||
|
||||
// Promote the final query-region-constraints into a
|
||||
// (optional) ref-counted vector:
|
||||
let opt_qrc =
|
||||
let region_constraints =
|
||||
if region_constraints.is_empty() { None } else { Some(Rc::new(region_constraints)) };
|
||||
|
||||
Ok((r, opt_qrc))
|
||||
Ok(TypeOpOutput { output, constraints: region_constraints, canonicalized_query })
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue