Auto merge of #124822 - matthiaskrgr:rollup-h7fc52t, r=matthiaskrgr
Rollup of 3 pull requests Successful merges: - #124759 (Record impl args in the proof tree in new solver) - #124809 (borrowck: prepopulate opaque storage more eagerly) - #124815 (Update books) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
7d83a4c131
29 changed files with 231 additions and 235 deletions
|
@ -2,7 +2,6 @@
|
|||
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::mir::{Body, Promoted};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use std::rc::Rc;
|
||||
|
@ -105,8 +104,7 @@ pub fn get_body_with_borrowck_facts(
|
|||
options: ConsumerOptions,
|
||||
) -> BodyWithBorrowckFacts<'_> {
|
||||
let (input_body, promoted) = tcx.mir_promoted(def);
|
||||
let infcx = tcx.infer_ctxt().with_opaque_type_inference(def).build();
|
||||
let input_body: &Body<'_> = &input_body.borrow();
|
||||
let promoted: &IndexSlice<_, _> = &promoted.borrow();
|
||||
*super::do_mir_borrowck(&infcx, input_body, promoted, Some(options)).1.unwrap()
|
||||
*super::do_mir_borrowck(tcx, input_body, promoted, Some(options)).1.unwrap()
|
||||
}
|
||||
|
|
|
@ -23,9 +23,8 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_index::bit_set::{BitSet, ChunkedBitSet};
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_infer::infer::{
|
||||
InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt,
|
||||
};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
|
||||
use rustc_middle::mir::tcx::PlaceTy;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::query::Providers;
|
||||
|
@ -123,9 +122,8 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> {
|
|||
return tcx.arena.alloc(result);
|
||||
}
|
||||
|
||||
let infcx = tcx.infer_ctxt().with_opaque_type_inference(def).build();
|
||||
let promoted: &IndexSlice<_, _> = &promoted.borrow();
|
||||
let opt_closure_req = do_mir_borrowck(&infcx, input_body, promoted, None).0;
|
||||
let opt_closure_req = do_mir_borrowck(tcx, input_body, promoted, None).0;
|
||||
debug!("mir_borrowck done");
|
||||
|
||||
tcx.arena.alloc(opt_closure_req)
|
||||
|
@ -136,18 +134,15 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> {
|
|||
/// Use `consumer_options: None` for the default behavior of returning
|
||||
/// [`BorrowCheckResult`] only. Otherwise, return [`BodyWithBorrowckFacts`] according
|
||||
/// to the given [`ConsumerOptions`].
|
||||
#[instrument(skip(infcx, input_body, input_promoted), fields(id=?input_body.source.def_id()), level = "debug")]
|
||||
#[instrument(skip(tcx, input_body, input_promoted), fields(id=?input_body.source.def_id()), level = "debug")]
|
||||
fn do_mir_borrowck<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
input_body: &Body<'tcx>,
|
||||
input_promoted: &IndexSlice<Promoted, Body<'tcx>>,
|
||||
consumer_options: Option<ConsumerOptions>,
|
||||
) -> (BorrowCheckResult<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) {
|
||||
let def = input_body.source.def_id().expect_local();
|
||||
debug!(?def);
|
||||
|
||||
let tcx = infcx.tcx;
|
||||
let infcx = BorrowckInferCtxt::new(infcx);
|
||||
let infcx = BorrowckInferCtxt::new(tcx, def);
|
||||
let param_env = tcx.param_env(def);
|
||||
|
||||
let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
|
||||
|
@ -187,6 +182,12 @@ fn do_mir_borrowck<'tcx>(
|
|||
nll::replace_regions_in_mir(&infcx, param_env, &mut body_owned, &mut promoted);
|
||||
let body = &body_owned; // no further changes
|
||||
|
||||
// FIXME(-Znext-solver): A bit dubious that we're only registering
|
||||
// predefined opaques in the typeck root.
|
||||
if infcx.next_trait_solver() && !infcx.tcx.is_typeck_child(body.source.def_id()) {
|
||||
infcx.register_predefined_opaques_for_next_solver(def);
|
||||
}
|
||||
|
||||
let location_table = LocationTable::new(body);
|
||||
|
||||
let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true);
|
||||
|
@ -440,13 +441,14 @@ fn do_mir_borrowck<'tcx>(
|
|||
(result, body_with_facts)
|
||||
}
|
||||
|
||||
pub struct BorrowckInferCtxt<'cx, 'tcx> {
|
||||
pub(crate) infcx: &'cx InferCtxt<'tcx>,
|
||||
pub struct BorrowckInferCtxt<'tcx> {
|
||||
pub(crate) infcx: InferCtxt<'tcx>,
|
||||
pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>,
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> {
|
||||
pub(crate) fn new(infcx: &'cx InferCtxt<'tcx>) -> Self {
|
||||
impl<'tcx> BorrowckInferCtxt<'tcx> {
|
||||
pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
|
||||
let infcx = tcx.infer_ctxt().with_opaque_type_inference(def_id).build();
|
||||
BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()) }
|
||||
}
|
||||
|
||||
|
@ -492,18 +494,40 @@ impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> {
|
|||
|
||||
next_region
|
||||
}
|
||||
|
||||
/// With the new solver we prepopulate the opaque type storage during
|
||||
/// MIR borrowck with the hidden types from HIR typeck. This is necessary
|
||||
/// to avoid ambiguities as earlier goals can rely on the hidden type
|
||||
/// of an opaque which is only constrained by a later goal.
|
||||
fn register_predefined_opaques_for_next_solver(&self, def_id: LocalDefId) {
|
||||
let tcx = self.tcx;
|
||||
// OK to use the identity arguments for each opaque type key, since
|
||||
// we remap opaques from HIR typeck back to their definition params.
|
||||
for data in tcx.typeck(def_id).concrete_opaque_types.iter().map(|(k, v)| (*k, *v)) {
|
||||
// HIR typeck did not infer the regions of the opaque, so we instantiate
|
||||
// them with fresh inference variables.
|
||||
let (key, hidden_ty) = tcx.fold_regions(data, |_, _| {
|
||||
self.next_nll_region_var_in_universe(
|
||||
NllRegionVariableOrigin::Existential { from_forall: false },
|
||||
ty::UniverseIndex::ROOT,
|
||||
)
|
||||
});
|
||||
|
||||
self.inject_new_hidden_type_unchecked(key, hidden_ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> Deref for BorrowckInferCtxt<'cx, 'tcx> {
|
||||
impl<'tcx> Deref for BorrowckInferCtxt<'tcx> {
|
||||
type Target = InferCtxt<'tcx>;
|
||||
|
||||
fn deref(&self) -> &'cx Self::Target {
|
||||
self.infcx
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.infcx
|
||||
}
|
||||
}
|
||||
|
||||
struct MirBorrowckCtxt<'cx, 'tcx> {
|
||||
infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>,
|
||||
infcx: &'cx BorrowckInferCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
body: &'cx Body<'tcx>,
|
||||
move_data: &'cx MoveData<'tcx>,
|
||||
|
|
|
@ -51,7 +51,7 @@ pub(crate) struct NllOutput<'tcx> {
|
|||
/// `compute_regions`.
|
||||
#[instrument(skip(infcx, param_env, body, promoted), level = "debug")]
|
||||
pub(crate) fn replace_regions_in_mir<'tcx>(
|
||||
infcx: &BorrowckInferCtxt<'_, 'tcx>,
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
body: &mut Body<'tcx>,
|
||||
promoted: &mut IndexSlice<Promoted, Body<'tcx>>,
|
||||
|
@ -75,7 +75,7 @@ pub(crate) fn replace_regions_in_mir<'tcx>(
|
|||
///
|
||||
/// This may result in errors being reported.
|
||||
pub(crate) fn compute_regions<'cx, 'tcx>(
|
||||
infcx: &BorrowckInferCtxt<'_, 'tcx>,
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
universal_regions: UniversalRegions<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
promoted: &IndexSlice<Promoted, Body<'tcx>>,
|
||||
|
@ -202,7 +202,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
|
|||
}
|
||||
|
||||
pub(super) fn dump_mir_results<'tcx>(
|
||||
infcx: &BorrowckInferCtxt<'_, 'tcx>,
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||
|
@ -254,7 +254,7 @@ pub(super) fn dump_mir_results<'tcx>(
|
|||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
pub(super) fn dump_annotation<'tcx>(
|
||||
infcx: &BorrowckInferCtxt<'_, 'tcx>,
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||
|
|
|
@ -250,10 +250,7 @@ pub enum ExtraConstraintInfo {
|
|||
}
|
||||
|
||||
#[instrument(skip(infcx, sccs), level = "debug")]
|
||||
fn sccs_info<'cx, 'tcx>(
|
||||
infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>,
|
||||
sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>,
|
||||
) {
|
||||
fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>) {
|
||||
use crate::renumber::RegionCtxt;
|
||||
|
||||
let var_to_origin = infcx.reg_var_to_origin.borrow();
|
||||
|
@ -322,8 +319,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
///
|
||||
/// The `outlives_constraints` and `type_tests` are an initial set
|
||||
/// of constraints produced by the MIR type check.
|
||||
pub(crate) fn new<'cx>(
|
||||
_infcx: &BorrowckInferCtxt<'cx, 'tcx>,
|
||||
pub(crate) fn new(
|
||||
_infcx: &BorrowckInferCtxt<'tcx>,
|
||||
var_infos: VarInfos,
|
||||
universal_regions: Rc<UniversalRegions<'tcx>>,
|
||||
placeholder_indices: Rc<PlaceholderIndices>,
|
||||
|
|
|
@ -11,7 +11,7 @@ use rustc_span::Symbol;
|
|||
/// inference variables, returning the number of variables created.
|
||||
#[instrument(skip(infcx, body, promoted), level = "debug")]
|
||||
pub fn renumber_mir<'tcx>(
|
||||
infcx: &BorrowckInferCtxt<'_, 'tcx>,
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
body: &mut Body<'tcx>,
|
||||
promoted: &mut IndexSlice<Promoted, Body<'tcx>>,
|
||||
) {
|
||||
|
@ -57,7 +57,7 @@ impl RegionCtxt {
|
|||
}
|
||||
|
||||
struct RegionRenumberer<'a, 'tcx> {
|
||||
infcx: &'a BorrowckInferCtxt<'a, 'tcx>,
|
||||
infcx: &'a BorrowckInferCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> RegionRenumberer<'a, 'tcx> {
|
||||
|
|
|
@ -24,7 +24,6 @@ use rustc_middle::mir::tcx::PlaceTy;
|
|||
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||
use rustc_middle::ty::cast::CastTy;
|
||||
use rustc_middle::ty::visit::TypeVisitableExt;
|
||||
|
@ -122,7 +121,7 @@ mod relate_tys;
|
|||
/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
|
||||
/// - `elements` -- MIR region map
|
||||
pub(crate) fn type_check<'mir, 'tcx>(
|
||||
infcx: &BorrowckInferCtxt<'_, 'tcx>,
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
promoted: &IndexSlice<Promoted, Body<'tcx>>,
|
||||
|
@ -865,7 +864,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
/// way, it accrues region constraints -- these can later be used by
|
||||
/// NLL region checking.
|
||||
struct TypeChecker<'a, 'tcx> {
|
||||
infcx: &'a BorrowckInferCtxt<'a, 'tcx>,
|
||||
infcx: &'a BorrowckInferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
last_span: Span,
|
||||
body: &'a Body<'tcx>,
|
||||
|
@ -1020,7 +1019,7 @@ impl Locations {
|
|||
|
||||
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
fn new(
|
||||
infcx: &'a BorrowckInferCtxt<'a, 'tcx>,
|
||||
infcx: &'a BorrowckInferCtxt<'tcx>,
|
||||
body: &'a Body<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
|
@ -1028,7 +1027,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
implicit_region_bound: ty::Region<'tcx>,
|
||||
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
|
||||
) -> Self {
|
||||
let mut checker = Self {
|
||||
Self {
|
||||
infcx,
|
||||
last_span: body.span,
|
||||
body,
|
||||
|
@ -1039,74 +1038,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
implicit_region_bound,
|
||||
borrowck_context,
|
||||
reported_errors: Default::default(),
|
||||
};
|
||||
|
||||
// FIXME(-Znext-solver): A bit dubious that we're only registering
|
||||
// predefined opaques in the typeck root.
|
||||
if infcx.next_trait_solver() && !infcx.tcx.is_typeck_child(body.source.def_id()) {
|
||||
checker.register_predefined_opaques_for_next_solver();
|
||||
}
|
||||
|
||||
checker
|
||||
}
|
||||
|
||||
pub(super) fn register_predefined_opaques_for_next_solver(&mut self) {
|
||||
// OK to use the identity arguments for each opaque type key, since
|
||||
// we remap opaques from HIR typeck back to their definition params.
|
||||
let opaques: Vec<_> = self
|
||||
.infcx
|
||||
.tcx
|
||||
.typeck(self.body.source.def_id().expect_local())
|
||||
.concrete_opaque_types
|
||||
.iter()
|
||||
.map(|(k, v)| (*k, *v))
|
||||
.collect();
|
||||
|
||||
let renumbered_opaques = self.infcx.tcx.fold_regions(opaques, |_, _| {
|
||||
self.infcx.next_nll_region_var_in_universe(
|
||||
NllRegionVariableOrigin::Existential { from_forall: false },
|
||||
ty::UniverseIndex::ROOT,
|
||||
)
|
||||
});
|
||||
|
||||
let param_env = self.param_env;
|
||||
let result = self.fully_perform_op(
|
||||
Locations::All(self.body.span),
|
||||
ConstraintCategory::OpaqueType,
|
||||
CustomTypeOp::new(
|
||||
|ocx| {
|
||||
let mut obligations = Vec::new();
|
||||
for (opaque_type_key, hidden_ty) in renumbered_opaques {
|
||||
let cause = ObligationCause::dummy();
|
||||
ocx.infcx.insert_hidden_type(
|
||||
opaque_type_key,
|
||||
&cause,
|
||||
param_env,
|
||||
hidden_ty.ty,
|
||||
&mut obligations,
|
||||
)?;
|
||||
|
||||
ocx.infcx.add_item_bounds_for_hidden_type(
|
||||
opaque_type_key.def_id.to_def_id(),
|
||||
opaque_type_key.args,
|
||||
cause,
|
||||
param_env,
|
||||
hidden_ty.ty,
|
||||
&mut obligations,
|
||||
);
|
||||
}
|
||||
|
||||
ocx.register_obligations(obligations);
|
||||
Ok(())
|
||||
},
|
||||
"register pre-defined opaques",
|
||||
),
|
||||
);
|
||||
|
||||
if result.is_err() {
|
||||
self.infcx
|
||||
.dcx()
|
||||
.span_bug(self.body.span, "failed re-defining predefined opaques in mir typeck");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -240,7 +240,7 @@ impl<'tcx> UniversalRegions<'tcx> {
|
|||
/// signature. This will also compute the relationships that are
|
||||
/// known between those regions.
|
||||
pub fn new(
|
||||
infcx: &BorrowckInferCtxt<'_, 'tcx>,
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
mir_def: LocalDefId,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Self {
|
||||
|
@ -411,7 +411,7 @@ impl<'tcx> UniversalRegions<'tcx> {
|
|||
}
|
||||
|
||||
struct UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>,
|
||||
infcx: &'cx BorrowckInferCtxt<'tcx>,
|
||||
mir_def: LocalDefId,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
}
|
||||
|
@ -796,7 +796,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
#[extension(trait InferCtxtExt<'tcx>)]
|
||||
impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> {
|
||||
impl<'tcx> BorrowckInferCtxt<'tcx> {
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn replace_free_regions_with_nll_infer_vars<T>(
|
||||
&self,
|
||||
|
|
|
@ -485,6 +485,19 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
Ok(InferOk { value: (), obligations })
|
||||
}
|
||||
|
||||
/// Insert a hidden type into the opaque type storage, making sure
|
||||
/// it hasn't previously been defined. This does not emit any
|
||||
/// constraints and it's the responsibility of the caller to make
|
||||
/// sure that the item bounds of the opaque are checked.
|
||||
pub fn inject_new_hidden_type_unchecked(
|
||||
&self,
|
||||
opaque_type_key: OpaqueTypeKey<'tcx>,
|
||||
hidden_ty: OpaqueHiddenType<'tcx>,
|
||||
) {
|
||||
let prev = self.inner.borrow_mut().opaque_types().register(opaque_type_key, hidden_ty);
|
||||
assert_eq!(prev, None);
|
||||
}
|
||||
|
||||
/// Insert a hidden type into the opaque type storage, equating it
|
||||
/// with any previous entries if necessary.
|
||||
///
|
||||
|
|
|
@ -123,6 +123,8 @@ pub enum ProbeStep<'tcx> {
|
|||
/// used whenever there are multiple candidates to prove the
|
||||
/// current goalby .
|
||||
NestedProbe(Probe<'tcx>),
|
||||
/// A trait goal was satisfied by an impl candidate.
|
||||
RecordImplArgs { impl_args: CanonicalState<'tcx, ty::GenericArgsRef<'tcx>> },
|
||||
/// A call to `EvalCtxt::evaluate_added_goals_make_canonical_response` with
|
||||
/// `Certainty` was made. This is the certainty passed in, so it's not unified
|
||||
/// with the certainty of the `try_evaluate_added_goals` that is done within;
|
||||
|
|
|
@ -136,6 +136,9 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
|
|||
ProbeStep::MakeCanonicalResponse { shallow_certainty } => {
|
||||
writeln!(this.f, "EVALUATE GOALS AND MAKE RESPONSE: {shallow_certainty:?}")?
|
||||
}
|
||||
ProbeStep::RecordImplArgs { impl_args } => {
|
||||
writeln!(this.f, "RECORDED IMPL ARGS: {impl_args:?}")?
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -236,7 +236,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
normalization_nested_goals,
|
||||
} = external_constraints.deref();
|
||||
self.register_region_constraints(region_constraints);
|
||||
self.register_new_opaque_types(param_env, opaque_types);
|
||||
self.register_new_opaque_types(opaque_types);
|
||||
(normalization_nested_goals.clone(), certainty)
|
||||
}
|
||||
|
||||
|
@ -368,13 +368,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
assert!(region_constraints.member_constraints.is_empty());
|
||||
}
|
||||
|
||||
fn register_new_opaque_types(
|
||||
&mut self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)],
|
||||
) {
|
||||
fn register_new_opaque_types(&mut self, opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)]) {
|
||||
for &(key, ty) in opaque_types {
|
||||
self.insert_hidden_type(key, param_env, ty).unwrap();
|
||||
let hidden_ty = ty::OpaqueHiddenType { ty, span: DUMMY_SP };
|
||||
self.infcx.inject_new_hidden_type_unchecked(key, hidden_ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -248,8 +248,8 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
};
|
||||
|
||||
for &(key, ty) in &input.predefined_opaques_in_body.opaque_types {
|
||||
ecx.insert_hidden_type(key, input.goal.param_env, ty)
|
||||
.expect("failed to prepopulate opaque types");
|
||||
let hidden_ty = ty::OpaqueHiddenType { ty, span: DUMMY_SP };
|
||||
ecx.infcx.inject_new_hidden_type_unchecked(key, hidden_ty);
|
||||
}
|
||||
|
||||
if !ecx.nested_goals.is_empty() {
|
||||
|
@ -587,6 +587,11 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
|
||||
Ok(unchanged_certainty)
|
||||
}
|
||||
|
||||
/// Record impl args in the proof tree for later access by `InspectCandidate`.
|
||||
pub(crate) fn record_impl_args(&mut self, impl_args: ty::GenericArgsRef<'tcx>) {
|
||||
self.inspect.record_impl_args(self.infcx, self.max_input_universe, impl_args)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
use std::ops::ControlFlow;
|
||||
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_infer::traits::solve::inspect::ProbeKind;
|
||||
use rustc_infer::traits::solve::{CandidateSource, Certainty, Goal};
|
||||
use rustc_infer::traits::{
|
||||
BuiltinImplSource, ImplSource, ImplSourceUserDefinedData, Obligation, ObligationCause,
|
||||
PolyTraitObligation, PredicateObligation, Selection, SelectionError, SelectionResult,
|
||||
PolyTraitObligation, Selection, SelectionError, SelectionResult,
|
||||
};
|
||||
use rustc_macros::extension;
|
||||
use rustc_span::Span;
|
||||
|
@ -141,32 +140,32 @@ fn to_selection<'tcx>(
|
|||
return None;
|
||||
}
|
||||
|
||||
let make_nested = || {
|
||||
cand.instantiate_nested_goals(span)
|
||||
.into_iter()
|
||||
.map(|nested| {
|
||||
Obligation::new(
|
||||
nested.infcx().tcx,
|
||||
ObligationCause::dummy_with_span(span),
|
||||
nested.goal().param_env,
|
||||
nested.goal().predicate,
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
let (nested, impl_args) = cand.instantiate_nested_goals_and_opt_impl_args(span);
|
||||
let nested = nested
|
||||
.into_iter()
|
||||
.map(|nested| {
|
||||
Obligation::new(
|
||||
nested.infcx().tcx,
|
||||
ObligationCause::dummy_with_span(span),
|
||||
nested.goal().param_env,
|
||||
nested.goal().predicate,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
Some(match cand.kind() {
|
||||
ProbeKind::TraitCandidate { source, result: _ } => match source {
|
||||
CandidateSource::Impl(impl_def_id) => {
|
||||
// FIXME: Remove this in favor of storing this in the tree
|
||||
// For impl candidates, we do the rematch manually to compute the args.
|
||||
ImplSource::UserDefined(rematch_impl(cand.goal(), impl_def_id, span))
|
||||
}
|
||||
CandidateSource::BuiltinImpl(builtin) => ImplSource::Builtin(builtin, make_nested()),
|
||||
CandidateSource::ParamEnv(_) => ImplSource::Param(make_nested()),
|
||||
CandidateSource::AliasBound => {
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, make_nested())
|
||||
ImplSource::UserDefined(ImplSourceUserDefinedData {
|
||||
impl_def_id,
|
||||
args: impl_args.expect("expected recorded impl args for impl candidate"),
|
||||
nested,
|
||||
})
|
||||
}
|
||||
CandidateSource::BuiltinImpl(builtin) => ImplSource::Builtin(builtin, nested),
|
||||
CandidateSource::ParamEnv(_) | CandidateSource::AliasBound => ImplSource::Param(nested),
|
||||
CandidateSource::CoherenceUnknowable => {
|
||||
span_bug!(span, "didn't expect to select an unknowable candidate")
|
||||
}
|
||||
|
@ -181,40 +180,3 @@ fn to_selection<'tcx>(
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn rematch_impl<'tcx>(
|
||||
goal: &inspect::InspectGoal<'_, 'tcx>,
|
||||
impl_def_id: DefId,
|
||||
span: Span,
|
||||
) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> {
|
||||
let infcx = goal.infcx();
|
||||
let goal_trait_ref = infcx
|
||||
.enter_forall_and_leak_universe(goal.goal().predicate.to_opt_poly_trait_pred().unwrap())
|
||||
.trait_ref;
|
||||
|
||||
let args = infcx.fresh_args_for_item(span, impl_def_id);
|
||||
let impl_trait_ref =
|
||||
infcx.tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(infcx.tcx, args);
|
||||
|
||||
let InferOk { value: (), obligations: mut nested } = infcx
|
||||
.at(&ObligationCause::dummy_with_span(span), goal.goal().param_env)
|
||||
.eq(DefineOpaqueTypes::Yes, goal_trait_ref, impl_trait_ref)
|
||||
.expect("rematching impl failed");
|
||||
|
||||
// FIXME(-Znext-solver=coinductive): We need to add supertraits here eventually.
|
||||
|
||||
nested.extend(
|
||||
infcx.tcx.predicates_of(impl_def_id).instantiate(infcx.tcx, args).into_iter().map(
|
||||
|(clause, _)| {
|
||||
Obligation::new(
|
||||
infcx.tcx,
|
||||
ObligationCause::dummy_with_span(span),
|
||||
goal.goal().param_env,
|
||||
clause,
|
||||
)
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
ImplSourceUserDefinedData { impl_def_id, nested, args }
|
||||
}
|
||||
|
|
|
@ -93,6 +93,7 @@ pub struct InspectCandidate<'a, 'tcx> {
|
|||
kind: inspect::ProbeKind<'tcx>,
|
||||
nested_goals: Vec<(GoalSource, inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>)>,
|
||||
final_state: inspect::CanonicalState<'tcx, ()>,
|
||||
impl_args: Option<inspect::CanonicalState<'tcx, ty::GenericArgsRef<'tcx>>>,
|
||||
result: QueryResult<'tcx>,
|
||||
shallow_certainty: Certainty,
|
||||
}
|
||||
|
@ -135,7 +136,20 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
|
|||
|
||||
/// Instantiate the nested goals for the candidate without rolling back their
|
||||
/// inference constraints. This function modifies the state of the `infcx`.
|
||||
///
|
||||
/// See [`Self::instantiate_nested_goals_and_opt_impl_args`] if you need the impl args too.
|
||||
pub fn instantiate_nested_goals(&self, span: Span) -> Vec<InspectGoal<'a, 'tcx>> {
|
||||
self.instantiate_nested_goals_and_opt_impl_args(span).0
|
||||
}
|
||||
|
||||
/// Instantiate the nested goals for the candidate without rolling back their
|
||||
/// inference constraints, and optionally the args of an impl if this candidate
|
||||
/// came from a `CandidateSource::Impl`. This function modifies the state of the
|
||||
/// `infcx`.
|
||||
pub fn instantiate_nested_goals_and_opt_impl_args(
|
||||
&self,
|
||||
span: Span,
|
||||
) -> (Vec<InspectGoal<'a, 'tcx>>, Option<ty::GenericArgsRef<'tcx>>) {
|
||||
let infcx = self.goal.infcx;
|
||||
let param_env = self.goal.goal.param_env;
|
||||
let mut orig_values = self.goal.orig_values.to_vec();
|
||||
|
@ -164,6 +178,17 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
|
|||
self.final_state,
|
||||
);
|
||||
|
||||
let impl_args = self.impl_args.map(|impl_args| {
|
||||
canonical::instantiate_canonical_state(
|
||||
infcx,
|
||||
span,
|
||||
param_env,
|
||||
&mut orig_values,
|
||||
impl_args,
|
||||
)
|
||||
.fold_with(&mut EagerResolver::new(infcx))
|
||||
});
|
||||
|
||||
if let Some(term_hack) = self.goal.normalizes_to_term_hack {
|
||||
// FIXME: We ignore the expected term of `NormalizesTo` goals
|
||||
// when computing the result of its candidates. This is
|
||||
|
@ -171,7 +196,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
|
|||
let _ = term_hack.constrain(infcx, span, param_env);
|
||||
}
|
||||
|
||||
instantiated_goals
|
||||
let goals = instantiated_goals
|
||||
.into_iter()
|
||||
.map(|(source, goal)| match goal.predicate.kind().no_bound_vars() {
|
||||
Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })) => {
|
||||
|
@ -208,7 +233,9 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
|
|||
source,
|
||||
),
|
||||
})
|
||||
.collect()
|
||||
.collect();
|
||||
|
||||
(goals, impl_args)
|
||||
}
|
||||
|
||||
/// Visit all nested goals of this candidate, rolling back
|
||||
|
@ -245,9 +272,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
|
|||
probe: &inspect::Probe<'tcx>,
|
||||
) {
|
||||
let mut shallow_certainty = None;
|
||||
let mut impl_args = None;
|
||||
for step in &probe.steps {
|
||||
match step {
|
||||
&inspect::ProbeStep::AddGoal(source, goal) => nested_goals.push((source, goal)),
|
||||
match *step {
|
||||
inspect::ProbeStep::AddGoal(source, goal) => nested_goals.push((source, goal)),
|
||||
inspect::ProbeStep::NestedProbe(ref probe) => {
|
||||
// Nested probes have to prove goals added in their parent
|
||||
// but do not leak them, so we truncate the added goals
|
||||
|
@ -257,7 +285,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
|
|||
nested_goals.truncate(num_goals);
|
||||
}
|
||||
inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => {
|
||||
assert_eq!(shallow_certainty.replace(*c), None);
|
||||
assert_eq!(shallow_certainty.replace(c), None);
|
||||
}
|
||||
inspect::ProbeStep::RecordImplArgs { impl_args: i } => {
|
||||
assert_eq!(impl_args.replace(i), None);
|
||||
}
|
||||
inspect::ProbeStep::EvaluateGoals(_) => (),
|
||||
}
|
||||
|
@ -284,6 +315,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
|
|||
final_state: probe.final_state,
|
||||
result,
|
||||
shallow_certainty,
|
||||
impl_args,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -242,6 +242,7 @@ enum WipProbeStep<'tcx> {
|
|||
EvaluateGoals(WipAddedGoalsEvaluation<'tcx>),
|
||||
NestedProbe(WipProbe<'tcx>),
|
||||
MakeCanonicalResponse { shallow_certainty: Certainty },
|
||||
RecordImplArgs { impl_args: inspect::CanonicalState<'tcx, ty::GenericArgsRef<'tcx>> },
|
||||
}
|
||||
|
||||
impl<'tcx> WipProbeStep<'tcx> {
|
||||
|
@ -250,6 +251,9 @@ impl<'tcx> WipProbeStep<'tcx> {
|
|||
WipProbeStep::AddGoal(source, goal) => inspect::ProbeStep::AddGoal(source, goal),
|
||||
WipProbeStep::EvaluateGoals(eval) => inspect::ProbeStep::EvaluateGoals(eval.finalize()),
|
||||
WipProbeStep::NestedProbe(probe) => inspect::ProbeStep::NestedProbe(probe.finalize()),
|
||||
WipProbeStep::RecordImplArgs { impl_args } => {
|
||||
inspect::ProbeStep::RecordImplArgs { impl_args }
|
||||
}
|
||||
WipProbeStep::MakeCanonicalResponse { shallow_certainty } => {
|
||||
inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty }
|
||||
}
|
||||
|
@ -534,6 +538,30 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn record_impl_args(
|
||||
&mut self,
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
max_input_universe: ty::UniverseIndex,
|
||||
impl_args: ty::GenericArgsRef<'tcx>,
|
||||
) {
|
||||
match self.as_mut() {
|
||||
Some(DebugSolver::GoalEvaluationStep(state)) => {
|
||||
let impl_args = canonical::make_canonical_state(
|
||||
infcx,
|
||||
&state.var_values,
|
||||
max_input_universe,
|
||||
impl_args,
|
||||
);
|
||||
state
|
||||
.current_evaluation_scope()
|
||||
.steps
|
||||
.push(WipProbeStep::RecordImplArgs { impl_args });
|
||||
}
|
||||
None => {}
|
||||
_ => bug!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_canonical_response(&mut self, shallow_certainty: Certainty) {
|
||||
match self.as_mut() {
|
||||
Some(DebugSolver::GoalEvaluationStep(state)) => {
|
||||
|
@ -543,7 +571,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
|
|||
.push(WipProbeStep::MakeCanonicalResponse { shallow_certainty });
|
||||
}
|
||||
None => {}
|
||||
_ => {}
|
||||
_ => bug!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -75,6 +75,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||
|
||||
ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
|
||||
let impl_args = ecx.fresh_args_for_item(impl_def_id);
|
||||
ecx.record_impl_args(impl_args);
|
||||
let impl_trait_ref = impl_trait_header.trait_ref.instantiate(tcx, impl_args);
|
||||
|
||||
ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit d207d894cc5e1d496ab99beeacd1a420e5d4d238
|
||||
Subproject commit bebcf527e67755a989a1739b7cfaa8f0e6b30040
|
|
@ -1 +1 @@
|
|||
Subproject commit aa7d4b0b4653ddb47cb1de2036d090ec2ba9dab1
|
||||
Subproject commit 17842ebb050f62e40a4618edeb8e8ee86e758707
|
|
@ -1 +1 @@
|
|||
Subproject commit 5854fcc286557ad3ab34d325073d11d8118096b6
|
||||
Subproject commit 51817951d0d213a0011f82b62aae02c3b3f2472e
|
|
@ -1 +1 @@
|
|||
Subproject commit 60d34b5fd33db1346f9aabfc0c9d0bda6c8e42be
|
||||
Subproject commit 229ad13b64d919b12e548d560f06d88963b25cd3
|
|
@ -1 +1 @@
|
|||
Subproject commit 07425fed36b00e60341c5e29e28d37d40cbd4451
|
||||
Subproject commit 2d1947ff34d50ca46dfe242ad75531a4c429bb52
|
|
@ -2,6 +2,9 @@
|
|||
// when there are multiple inputs. The `dyn Bar` should default to `+
|
||||
// 'static`. This used to erroneously generate an error (cc #62517).
|
||||
//
|
||||
//@ revisions: current next
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||
//@ check-pass
|
||||
|
||||
trait Foo {
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
//@ revisions: current next
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||
//@ check-pass
|
||||
|
||||
pub fn main() {}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
//@ revisions: current next
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||
//@ check-pass
|
||||
|
||||
use std::io::Write;
|
||||
|
|
13
tests/ui/traits/next-solver/select-alias-bound-as-param.rs
Normal file
13
tests/ui/traits/next-solver/select-alias-bound-as-param.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
//@ check-pass
|
||||
//@ compile-flags: -Znext-solver
|
||||
|
||||
pub(crate) fn y() -> impl FnMut() {
|
||||
|| {}
|
||||
}
|
||||
|
||||
pub(crate) fn x(a: (), b: ()) {
|
||||
let x = ();
|
||||
y()()
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -1,14 +0,0 @@
|
|||
error: internal compiler error: error performing operation: query type op
|
||||
--> $DIR/illegal-upcast-from-impl-opaque.rs:25:1
|
||||
|
|
||||
LL | fn illegal(x: &dyn Sub<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note:
|
||||
--> $DIR/illegal-upcast-from-impl-opaque.rs:25:1
|
||||
|
|
||||
LL | fn illegal(x: &dyn Sub<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
query stack during panic:
|
||||
end of query stack
|
|
@ -1,29 +0,0 @@
|
|||
//@ revisions: current next
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
//@[next] failure-status: 101
|
||||
//@[next] known-bug: unknown
|
||||
//@[next] normalize-stderr-test "note: .*\n\n" -> ""
|
||||
//@[next] normalize-stderr-test "thread 'rustc' panicked.*\n.*\n" -> ""
|
||||
//@[next] normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: "
|
||||
//@[next] normalize-stderr-test "delayed at .*" -> ""
|
||||
//@[next] rustc-env:RUST_BACKTRACE=0
|
||||
|
||||
#![feature(trait_upcasting, type_alias_impl_trait)]
|
||||
|
||||
trait Super {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
trait Sub: Super {}
|
||||
|
||||
impl<T: ?Sized> Super for T {
|
||||
type Assoc = i32;
|
||||
}
|
||||
|
||||
type Foo = impl Sized;
|
||||
|
||||
fn illegal(x: &dyn Sub<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
|
||||
x //[current]~ mismatched types
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -1,11 +1,11 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/illegal-upcast-from-impl-opaque.rs:26:5
|
||||
--> $DIR/upcast-defining-opaque.rs:21:5
|
||||
|
|
||||
LL | type Foo = impl Sized;
|
||||
| ---------- the found opaque type
|
||||
LL |
|
||||
LL | fn illegal(x: &dyn Sub<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
|
||||
| ----------------------- expected `&dyn Super<Assoc = i32>` because of return type
|
||||
LL | fn upcast(x: &dyn Sub<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
|
||||
| ----------------------- expected `&dyn Super<Assoc = i32>` because of return type
|
||||
LL | x
|
||||
| ^ expected trait `Super`, found trait `Sub`
|
||||
|
|
24
tests/ui/traits/trait-upcasting/upcast-defining-opaque.rs
Normal file
24
tests/ui/traits/trait-upcasting/upcast-defining-opaque.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
//@ revisions: current next
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||
//@[next] check-pass
|
||||
|
||||
#![feature(trait_upcasting, type_alias_impl_trait)]
|
||||
|
||||
trait Super {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
trait Sub: Super {}
|
||||
|
||||
impl<T: ?Sized> Super for T {
|
||||
type Assoc = i32;
|
||||
}
|
||||
|
||||
type Foo = impl Sized;
|
||||
|
||||
fn upcast(x: &dyn Sub<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
|
||||
x //[current]~ mismatched types
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Add table
Reference in a new issue