From 22783658890baa33d468b4d98f21c123ed4bc24c Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 9 Jun 2023 14:48:45 +0200 Subject: [PATCH 1/3] recompute opaque type origin --- .../src/region_infer/opaque_types.rs | 23 +++++++--------- compiler/rustc_borrowck/src/type_check/mod.rs | 6 ++--- .../rustc_infer/src/infer/opaque_types.rs | 27 +++++++------------ .../src/infer/opaque_types/table.rs | 4 +-- 4 files changed, 22 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index a561496b02639..525b4c8777042 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -61,7 +61,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(crate) fn infer_opaque_types( &self, infcx: &InferCtxt<'tcx>, - opaque_ty_decls: FxIndexMap, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, + opaque_ty_decls: FxIndexMap, OpaqueHiddenType<'tcx>>, ) -> FxIndexMap> { let mut result: FxIndexMap> = FxIndexMap::default(); @@ -72,7 +72,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { .collect(); debug!(?member_constraints); - for (opaque_type_key, (concrete_type, origin)) in opaque_ty_decls { + for (opaque_type_key, concrete_type) in opaque_ty_decls { let substs = opaque_type_key.substs; debug!(?concrete_type, ?substs); @@ -143,7 +143,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { let ty = infcx.infer_opaque_definition_from_instantiation( opaque_type_key, universal_concrete_type, - origin, ); // Sometimes two opaque types are the same only after we remap the generic parameters // back to the opaque type definition. E.g. we may have `OpaqueType` mapped to `(X, Y)` @@ -215,7 +214,6 @@ pub trait InferCtxtExt<'tcx> { &self, opaque_type_key: OpaqueTypeKey<'tcx>, instantiated_ty: OpaqueHiddenType<'tcx>, - origin: OpaqueTyOrigin, ) -> Ty<'tcx>; } @@ -248,7 +246,6 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { &self, opaque_type_key: OpaqueTypeKey<'tcx>, instantiated_ty: OpaqueHiddenType<'tcx>, - origin: OpaqueTyOrigin, ) -> Ty<'tcx> { if let Some(e) = self.tainted_by_errors() { return self.tcx.ty_error(e); @@ -258,18 +255,16 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false) .ty; - if let Err(guar) = check_opaque_type_parameter_valid( - self.tcx, - opaque_type_key, - origin, - instantiated_ty.span, - ) { + if let Err(guar) = + check_opaque_type_parameter_valid(self.tcx, opaque_type_key, instantiated_ty.span) + { return self.tcx.ty_error(guar); } // Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs` // on stable and we'd break that. - let OpaqueTyOrigin::TyAlias { .. } = origin else { + let opaque_ty_hir = self.tcx.hir().expect_item(opaque_type_key.def_id); + let OpaqueTyOrigin::TyAlias { .. } = opaque_ty_hir.expect_opaque_ty().origin else { return definition_ty; }; let def_id = opaque_type_key.def_id; @@ -347,10 +342,10 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { fn check_opaque_type_parameter_valid( tcx: TyCtxt<'_>, opaque_type_key: OpaqueTypeKey<'_>, - origin: OpaqueTyOrigin, span: Span, ) -> Result<(), ErrorGuaranteed> { - match origin { + let opaque_ty_hir = tcx.hir().expect_item(opaque_type_key.def_id); + match opaque_ty_hir.expect_opaque_ty().origin { // No need to check return position impl trait (RPIT) // because for type and const parameters they are correct // by construction: we convert diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 00fd3762fa773..63a2a24fd43db 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -7,7 +7,6 @@ use std::{fmt, iter, mem}; use either::Either; -use hir::OpaqueTyOrigin; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::ErrorGuaranteed; @@ -241,7 +240,7 @@ pub(crate) fn type_check<'mir, 'tcx>( hidden_type.ty = infcx.tcx.ty_error(reported); } - (opaque_type_key, (hidden_type, decl.origin)) + (opaque_type_key, hidden_type) }) .collect(); @@ -878,8 +877,7 @@ struct BorrowCheckContext<'a, 'tcx> { pub(crate) struct MirTypeckResults<'tcx> { pub(crate) constraints: MirTypeckRegionConstraints<'tcx>, pub(crate) universal_region_relations: Frozen>, - pub(crate) opaque_type_values: - FxIndexMap, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, + pub(crate) opaque_type_values: FxIndexMap, OpaqueHiddenType<'tcx>>, } /// A collection of region constraints that must be satisfied for the diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index a9ead429f4c71..44efd334a16df 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -33,9 +33,6 @@ pub struct OpaqueTypeDecl<'tcx> { /// There can be multiple, but they are all `lub`ed together at the end /// to obtain the canonical hidden type. pub hidden_type: OpaqueHiddenType<'tcx>, - - /// The origin of the opaque type. - pub origin: hir::OpaqueTyOrigin, } impl<'tcx> InferCtxt<'tcx> { @@ -108,7 +105,7 @@ impl<'tcx> InferCtxt<'tcx> { let process = |a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected| match *a.kind() { ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) if def_id.is_local() => { let def_id = def_id.expect_local(); - let origin = match self.defining_use_anchor { + match self.defining_use_anchor { DefiningAnchor::Bind(_) => { // Check that this is `impl Trait` type is // declared by `parent_def_id` -- i.e., one whose @@ -144,9 +141,11 @@ impl<'tcx> InferCtxt<'tcx> { // let x = || foo(); // returns the Opaque assoc with `foo` // } // ``` - self.opaque_type_origin(def_id)? + if self.opaque_type_origin(def_id).is_none() { + return None; + } } - DefiningAnchor::Bubble => self.opaque_type_origin_unchecked(def_id), + DefiningAnchor::Bubble => {} DefiningAnchor::Error => return None, }; if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() { @@ -170,7 +169,6 @@ impl<'tcx> InferCtxt<'tcx> { cause.clone(), param_env, b, - origin, a_is_expected, )) } @@ -524,7 +522,6 @@ impl<'tcx> InferCtxt<'tcx> { cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, hidden_ty: Ty<'tcx>, - origin: hir::OpaqueTyOrigin, a_is_expected: bool, ) -> InferResult<'tcx, ()> { // Ideally, we'd get the span where *this specific `ty` came @@ -544,11 +541,11 @@ impl<'tcx> InferCtxt<'tcx> { ty::PredicateKind::Ambiguous, )] } else { - let prev = self.inner.borrow_mut().opaque_types().register( - opaque_type_key, - OpaqueHiddenType { ty: hidden_ty, span }, - origin, - ); + let prev = self + .inner + .borrow_mut() + .opaque_types() + .register(opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span }); if let Some(prev) = prev { self.at(&cause, param_env) .eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)? @@ -579,15 +576,11 @@ impl<'tcx> InferCtxt<'tcx> { hidden_ty: Ty<'tcx>, ) -> InferResult<'tcx, ()> { assert!(self.next_trait_solver()); - let origin = self - .opaque_type_origin(opaque_type_key.def_id) - .expect("should be called for defining usages only"); self.register_hidden_type( opaque_type_key, ObligationCause::dummy(), param_env, hidden_ty, - origin, true, ) } diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index a0f6d7ecab70f..a737761ba2282 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -1,5 +1,4 @@ use rustc_data_structures::undo_log::UndoLogs; -use rustc_hir::OpaqueTyOrigin; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty}; use rustc_span::DUMMY_SP; @@ -60,14 +59,13 @@ impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> { &mut self, key: OpaqueTypeKey<'tcx>, hidden_type: OpaqueHiddenType<'tcx>, - origin: OpaqueTyOrigin, ) -> Option> { if let Some(decl) = self.storage.opaque_types.get_mut(&key) { let prev = std::mem::replace(&mut decl.hidden_type, hidden_type); self.undo_log.push(UndoLog::OpaqueTypes(key, Some(prev))); return Some(prev.ty); } - let decl = OpaqueTypeDecl { hidden_type, origin }; + let decl = OpaqueTypeDecl { hidden_type }; self.storage.opaque_types.insert(key, decl); self.undo_log.push(UndoLog::OpaqueTypes(key, None)); None From 669d609dfda2f61f2b358c9e9061f76ebd852e7e Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 9 Jun 2023 16:04:41 +0200 Subject: [PATCH 2/3] extract opaque type wf check into separate fn --- .../src/region_infer/opaque_types.rs | 139 ++++++++++-------- 1 file changed, 74 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 525b4c8777042..b5d5071dc0536 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -251,91 +251,100 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { return self.tcx.ty_error(e); } - let definition_ty = instantiated_ty - .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false) - .ty; - if let Err(guar) = check_opaque_type_parameter_valid(self.tcx, opaque_type_key, instantiated_ty.span) { return self.tcx.ty_error(guar); } - // Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs` - // on stable and we'd break that. - let opaque_ty_hir = self.tcx.hir().expect_item(opaque_type_key.def_id); - let OpaqueTyOrigin::TyAlias { .. } = opaque_ty_hir.expect_opaque_ty().origin else { - return definition_ty; - }; - let def_id = opaque_type_key.def_id; - // This logic duplicates most of `check_opaque_meets_bounds`. - // FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely. - let param_env = self.tcx.param_env(def_id); - // HACK This bubble is required for this tests to pass: - // nested-return-type2-tait2.rs - // nested-return-type2-tait3.rs - // FIXME(-Ztrait-solver=next): We probably should use `DefiningAnchor::Error` - // and prepopulate this `InferCtxt` with known opaque values, rather than - // using the `Bind` anchor here. For now it's fine. - let infcx = self - .tcx - .infer_ctxt() - .with_opaque_type_inference(if self.next_trait_solver() { - DefiningAnchor::Bind(def_id) - } else { - DefiningAnchor::Bubble - }) - .build(); - let ocx = ObligationCtxt::new(&infcx); - // Require the hidden type to be well-formed with only the generics of the opaque type. - // Defining use functions may have more bounds than the opaque type, which is ok, as long as the - // hidden type is well formed even without those bounds. - let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into())); - - let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id); + let definition_ty = instantiated_ty + .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false) + .ty; - // Require that the hidden type actually fulfills all the bounds of the opaque type, even without - // the bounds that the function supplies. - let opaque_ty = self.tcx.mk_opaque(def_id.to_def_id(), id_substs); - if let Err(err) = ocx.eq( - &ObligationCause::misc(instantiated_ty.span, def_id), - param_env, - opaque_ty, + // `definition_ty` does not live in of the current inference context, + // so lets make sure that we don't accidentally misuse our current `infcx`. + match check_opaque_type_well_formed( + self.tcx, + self.next_trait_solver(), + opaque_type_key.def_id, + instantiated_ty.span, definition_ty, ) { + Ok(hidden_ty) => hidden_ty, + Err(guar) => self.tcx.ty_error(guar), + } + } +} + +/// This logic duplicates most of `check_opaque_meets_bounds`. +/// FIXME(oli-obk): Also do region checks here and then consider removing +/// `check_opaque_meets_bounds` entirely. +fn check_opaque_type_well_formed<'tcx>( + tcx: TyCtxt<'tcx>, + next_trait_solver: bool, + def_id: LocalDefId, + definition_span: Span, + definition_ty: Ty<'tcx>, +) -> Result, ErrorGuaranteed> { + // Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs` + // on stable and we'd break that. + let opaque_ty_hir = tcx.hir().expect_item(def_id); + let OpaqueTyOrigin::TyAlias { .. } = opaque_ty_hir.expect_opaque_ty().origin else { + return Ok(definition_ty); + }; + let param_env = tcx.param_env(def_id); + // HACK This bubble is required for this tests to pass: + // nested-return-type2-tait2.rs + // nested-return-type2-tait3.rs + // FIXME(-Ztrait-solver=next): We probably should use `DefiningAnchor::Error` + // and prepopulate this `InferCtxt` with known opaque values, rather than + // using the `Bind` anchor here. For now it's fine. + let infcx = tcx + .infer_ctxt() + .with_next_trait_solver(next_trait_solver) + .with_opaque_type_inference(if next_trait_solver { + DefiningAnchor::Bind(def_id) + } else { + DefiningAnchor::Bubble + }) + .build(); + let ocx = ObligationCtxt::new(&infcx); + let identity_substs = InternalSubsts::identity_for_item(tcx, def_id); + + // Require that the hidden type actually fulfills all the bounds of the opaque type, even without + // the bounds that the function supplies. + let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), identity_substs); + ocx.eq(&ObligationCause::misc(definition_span, def_id), param_env, opaque_ty, definition_ty) + .map_err(|err| { infcx .err_ctxt() .report_mismatched_types( - &ObligationCause::misc(instantiated_ty.span, def_id), + &ObligationCause::misc(definition_span, def_id), opaque_ty, definition_ty, err, ) - .emit(); - } + .emit() + })?; - ocx.register_obligation(Obligation::misc( - infcx.tcx, - instantiated_ty.span, - def_id, - param_env, - predicate, - )); + // Require the hidden type to be well-formed with only the generics of the opaque type. + // Defining use functions may have more bounds than the opaque type, which is ok, as long as the + // hidden type is well formed even without those bounds. + let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into())); + ocx.register_obligation(Obligation::misc(tcx, definition_span, def_id, param_env, predicate)); - // Check that all obligations are satisfied by the implementation's - // version. - let errors = ocx.select_all_or_error(); + // Check that all obligations are satisfied by the implementation's + // version. + let errors = ocx.select_all_or_error(); - // This is still required for many(half of the tests in ui/type-alias-impl-trait) - // tests to pass - let _ = infcx.take_opaque_types(); + // This is still required for many(half of the tests in ui/type-alias-impl-trait) + // tests to pass + let _ = infcx.take_opaque_types(); - if errors.is_empty() { - definition_ty - } else { - let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); - self.tcx.ty_error(reported) - } + if errors.is_empty() { + Ok(definition_ty) + } else { + Err(infcx.err_ctxt().report_fulfillment_errors(&errors)) } } From b62e20d2fd5fd186a662c5621a41b717fcc313e0 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 9 Jun 2023 16:41:11 +0200 Subject: [PATCH 3/3] split opaque type handling in new solver be more explicit in where we only add new hidden types and where we also have to deal with item bounds. --- compiler/rustc_borrowck/src/type_check/mod.rs | 28 +++++-- .../rustc_infer/src/infer/opaque_types.rs | 83 +++++++++++-------- .../src/solve/eval_ctxt.rs | 69 +++++++++------ .../src/solve/eval_ctxt/canonical.rs | 9 +- .../src/solve/opaques.rs | 3 +- 5 files changed, 114 insertions(+), 78 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 63a2a24fd43db..6697e1aff7dd0 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -27,6 +27,7 @@ use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::AssertKind; use rustc_middle::mir::*; use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::subst::{SubstsRef, UserSubsts}; @@ -1051,15 +1052,28 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ConstraintCategory::OpaqueType, CustomTypeOp::new( |ocx| { - for (key, hidden_ty) in renumbered_opaques { - ocx.register_infer_ok_obligations( - ocx.infcx.register_hidden_type_in_new_solver( - key, - param_env, - hidden_ty.ty, - )?, + 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, + true, + &mut obligations, + )?; + + ocx.infcx.add_item_bounds_for_hidden_type( + opaque_type_key, + cause, + param_env, + hidden_ty.ty, + &mut obligations, ); } + + ocx.register_obligations(obligations); Ok(()) }, "register pre-defined opaques", diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 44efd334a16df..6b8293f90f10a 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -524,22 +524,60 @@ impl<'tcx> InferCtxt<'tcx> { hidden_ty: Ty<'tcx>, a_is_expected: bool, ) -> InferResult<'tcx, ()> { + let mut obligations = Vec::new(); + + self.insert_hidden_type( + opaque_type_key, + &cause, + param_env, + hidden_ty, + a_is_expected, + &mut obligations, + )?; + + self.add_item_bounds_for_hidden_type( + opaque_type_key, + cause, + param_env, + hidden_ty, + &mut obligations, + ); + + Ok(InferOk { value: (), obligations }) + } + + /// Insert a hidden type into the opaque type storage, equating it + /// with any previous entries if necessary. + /// + /// This **does not** add the item bounds of the opaque as nested + /// obligations. That is only necessary when normalizing the opaque + /// itself, not when getting the opaque type constraints from + /// somewhere else. + pub fn insert_hidden_type( + &self, + opaque_type_key: OpaqueTypeKey<'tcx>, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + hidden_ty: Ty<'tcx>, + a_is_expected: bool, + obligations: &mut Vec>, + ) -> Result<(), TypeError<'tcx>> { // Ideally, we'd get the span where *this specific `ty` came // from*, but right now we just use the span from the overall // value being folded. In simple cases like `-> impl Foo`, // these are the same span, but not in cases like `-> (impl // Foo, impl Bar)`. let span = cause.span; - let mut obligations = if self.intercrate { + if self.intercrate { // During intercrate we do not define opaque types but instead always // force ambiguity unless the hidden type is known to not implement // our trait. - vec![traits::Obligation::new( + obligations.push(traits::Obligation::new( self.tcx, cause.clone(), param_env, ty::PredicateKind::Ambiguous, - )] + )) } else { let prev = self .inner @@ -547,42 +585,15 @@ impl<'tcx> InferCtxt<'tcx> { .opaque_types() .register(opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span }); if let Some(prev) = prev { - self.at(&cause, param_env) - .eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)? - .obligations - } else { - Vec::new() + obligations.extend( + self.at(&cause, param_env) + .eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)? + .obligations, + ); } }; - self.add_item_bounds_for_hidden_type( - opaque_type_key, - cause, - param_env, - hidden_ty, - &mut obligations, - ); - - Ok(InferOk { value: (), obligations }) - } - - /// Registers an opaque's hidden type -- only should be used when the opaque - /// can be defined. For something more fallible -- checks the anchors, tries - /// to unify opaques in both dirs, etc. -- use `InferCtxt::handle_opaque_type`. - pub fn register_hidden_type_in_new_solver( - &self, - opaque_type_key: OpaqueTypeKey<'tcx>, - param_env: ty::ParamEnv<'tcx>, - hidden_ty: Ty<'tcx>, - ) -> InferResult<'tcx, ()> { - assert!(self.next_trait_solver()); - self.register_hidden_type( - opaque_type_key, - ObligationCause::dummy(), - param_env, - hidden_ty, - true, - ) + Ok(()) } pub fn add_item_bounds_for_hidden_type( diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 3001d9f1b1f3f..e01187bcd3c2a 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -15,8 +15,8 @@ use rustc_middle::traits::solve::{ }; use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, - TypeVisitor, + self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, + TypeVisitableExt, TypeVisitor, }; use rustc_span::DUMMY_SP; use std::ops::ControlFlow; @@ -191,16 +191,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { .with_opaque_type_inference(canonical_input.value.anchor) .build_with_canonical(DUMMY_SP, &canonical_input); - for &(a, b) in &input.predefined_opaques_in_body.opaque_types { - let InferOk { value: (), obligations } = infcx - .register_hidden_type_in_new_solver(a, input.goal.param_env, b) - .expect("expected opaque type instantiation to succeed"); - // We're only registering opaques already defined by the caller, - // so we're not responsible for proving that they satisfy their - // item bounds, unless we use them in a normalizes-to goal, - // which is handled in `EvalCtxt::unify_existing_opaque_tys`. - let _ = obligations; - } let mut ecx = EvalCtxt { infcx, var_values, @@ -211,6 +201,15 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { tainted: Ok(()), }; + 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"); + } + + if !ecx.nested_goals.is_empty() { + panic!("prepopulating opaque types shouldn't add goals: {:?}", ecx.nested_goals); + } + let result = ecx.compute_goal(input.goal); // When creating a query response we clone the opaque type constraints @@ -729,18 +728,42 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.infcx.opaque_type_origin(def_id).is_some() } - pub(super) fn register_opaque_ty( + pub(super) fn insert_hidden_type( &mut self, - a: ty::OpaqueTypeKey<'tcx>, - b: Ty<'tcx>, + opaque_type_key: OpaqueTypeKey<'tcx>, param_env: ty::ParamEnv<'tcx>, + hidden_ty: Ty<'tcx>, ) -> Result<(), NoSolution> { - let InferOk { value: (), obligations } = - self.infcx.register_hidden_type_in_new_solver(a, param_env, b)?; - self.add_goals(obligations.into_iter().map(|obligation| obligation.into())); + let mut obligations = Vec::new(); + self.infcx.insert_hidden_type( + opaque_type_key, + &ObligationCause::dummy(), + param_env, + hidden_ty, + true, + &mut obligations, + )?; + self.add_goals(obligations.into_iter().map(|o| o.into())); Ok(()) } + pub(super) fn add_item_bounds_for_hidden_type( + &mut self, + opaque_type_key: OpaqueTypeKey<'tcx>, + param_env: ty::ParamEnv<'tcx>, + hidden_ty: Ty<'tcx>, + ) { + let mut obligations = Vec::new(); + self.infcx.add_item_bounds_for_hidden_type( + opaque_type_key, + ObligationCause::dummy(), + param_env, + hidden_ty, + &mut obligations, + ); + self.add_goals(obligations.into_iter().map(|o| o.into())); + } + // Do something for each opaque/hidden pair defined with `def_id` in the // current inference context. pub(super) fn unify_existing_opaque_tys( @@ -762,15 +785,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ecx.eq(param_env, a, b)?; } ecx.eq(param_env, candidate_ty, ty)?; - let mut obl = vec![]; - ecx.infcx.add_item_bounds_for_hidden_type( - candidate_key, - ObligationCause::dummy(), - param_env, - candidate_ty, - &mut obl, - ); - ecx.add_goals(obl.into_iter().map(Into::into)); + ecx.add_item_bounds_for_hidden_type(candidate_key, param_env, candidate_ty); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) })); } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index bca2343e42422..db6734100088f 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -15,7 +15,6 @@ use rustc_index::IndexVec; use rustc_infer::infer::canonical::query_response::make_query_region_constraints; use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints}; -use rustc_infer::infer::InferOk; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{ ExternalConstraints, ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput, @@ -317,12 +316,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { param_env: ty::ParamEnv<'tcx>, opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)], ) -> Result<(), NoSolution> { - for &(a, b) in opaque_types { - let InferOk { value: (), obligations } = - self.infcx.register_hidden_type_in_new_solver(a, param_env, b)?; - // It's sound to drop these obligations, since the normalizes-to goal - // is responsible for proving these obligations. - let _ = obligations; + for &(key, ty) in opaque_types { + self.insert_hidden_type(key, param_env, ty)?; } Ok(()) } diff --git a/compiler/rustc_trait_selection/src/solve/opaques.rs b/compiler/rustc_trait_selection/src/solve/opaques.rs index a5de4ddee82ba..538c16c8ce2cd 100644 --- a/compiler/rustc_trait_selection/src/solve/opaques.rs +++ b/compiler/rustc_trait_selection/src/solve/opaques.rs @@ -50,7 +50,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } // Otherwise, define a new opaque type - self.register_opaque_ty(opaque_ty, expected, goal.param_env)?; + self.insert_hidden_type(opaque_ty, goal.param_env, expected)?; + self.add_item_bounds_for_hidden_type(opaque_ty, goal.param_env, expected); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } (Reveal::UserFacing, SolverMode::Coherence) => {