1
Fork 0

Auto merge of #112466 - lcnr:opaque-type-cleanup, r=compiler-errors

opaque type cleanup

the commits are pretty self-contained.

r? `@compiler-errors` cc `@oli-obk`
This commit is contained in:
bors 2023-06-11 03:42:14 +00:00
commit 34d64ab7a2
7 changed files with 208 additions and 179 deletions

View file

@ -61,7 +61,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
pub(crate) fn infer_opaque_types( pub(crate) fn infer_opaque_types(
&self, &self,
infcx: &InferCtxt<'tcx>, infcx: &InferCtxt<'tcx>,
opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
) -> FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> { ) -> FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> {
let mut result: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> = FxIndexMap::default(); let mut result: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> = FxIndexMap::default();
@ -72,7 +72,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
.collect(); .collect();
debug!(?member_constraints); 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; let substs = opaque_type_key.substs;
debug!(?concrete_type, ?substs); debug!(?concrete_type, ?substs);
@ -143,7 +143,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let ty = infcx.infer_opaque_definition_from_instantiation( let ty = infcx.infer_opaque_definition_from_instantiation(
opaque_type_key, opaque_type_key,
universal_concrete_type, universal_concrete_type,
origin,
); );
// Sometimes two opaque types are the same only after we remap the generic parameters // 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<X, Y>` mapped to `(X, Y)` // back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)`
@ -215,7 +214,6 @@ pub trait InferCtxtExt<'tcx> {
&self, &self,
opaque_type_key: OpaqueTypeKey<'tcx>, opaque_type_key: OpaqueTypeKey<'tcx>,
instantiated_ty: OpaqueHiddenType<'tcx>, instantiated_ty: OpaqueHiddenType<'tcx>,
origin: OpaqueTyOrigin,
) -> Ty<'tcx>; ) -> Ty<'tcx>;
} }
@ -248,109 +246,115 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
&self, &self,
opaque_type_key: OpaqueTypeKey<'tcx>, opaque_type_key: OpaqueTypeKey<'tcx>,
instantiated_ty: OpaqueHiddenType<'tcx>, instantiated_ty: OpaqueHiddenType<'tcx>,
origin: OpaqueTyOrigin,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
if let Some(e) = self.tainted_by_errors() { if let Some(e) = self.tainted_by_errors() {
return self.tcx.ty_error(e); return self.tcx.ty_error(e);
} }
if let Err(guar) =
check_opaque_type_parameter_valid(self.tcx, opaque_type_key, instantiated_ty.span)
{
return self.tcx.ty_error(guar);
}
let definition_ty = instantiated_ty let definition_ty = instantiated_ty
.remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false) .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false)
.ty; .ty;
if let Err(guar) = check_opaque_type_parameter_valid( // `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.tcx,
opaque_type_key, self.next_trait_solver(),
origin, opaque_type_key.def_id,
instantiated_ty.span, 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 {
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);
// 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, 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<Ty<'tcx>, 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 infcx
.err_ctxt() .err_ctxt()
.report_mismatched_types( .report_mismatched_types(
&ObligationCause::misc(instantiated_ty.span, def_id), &ObligationCause::misc(definition_span, def_id),
opaque_ty, opaque_ty,
definition_ty, definition_ty,
err, err,
) )
.emit(); .emit()
} })?;
ocx.register_obligation(Obligation::misc( // Require the hidden type to be well-formed with only the generics of the opaque type.
infcx.tcx, // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
instantiated_ty.span, // hidden type is well formed even without those bounds.
def_id, let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()));
param_env, ocx.register_obligation(Obligation::misc(tcx, definition_span, def_id, param_env, predicate));
predicate,
));
// Check that all obligations are satisfied by the implementation's // Check that all obligations are satisfied by the implementation's
// version. // version.
let errors = ocx.select_all_or_error(); let errors = ocx.select_all_or_error();
// This is still required for many(half of the tests in ui/type-alias-impl-trait) // This is still required for many(half of the tests in ui/type-alias-impl-trait)
// tests to pass // tests to pass
let _ = infcx.take_opaque_types(); let _ = infcx.take_opaque_types();
if errors.is_empty() { if errors.is_empty() {
definition_ty Ok(definition_ty)
} else { } else {
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); Err(infcx.err_ctxt().report_fulfillment_errors(&errors))
self.tcx.ty_error(reported)
}
} }
} }
fn check_opaque_type_parameter_valid( fn check_opaque_type_parameter_valid(
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
opaque_type_key: OpaqueTypeKey<'_>, opaque_type_key: OpaqueTypeKey<'_>,
origin: OpaqueTyOrigin,
span: Span, span: Span,
) -> Result<(), ErrorGuaranteed> { ) -> 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) // No need to check return position impl trait (RPIT)
// because for type and const parameters they are correct // because for type and const parameters they are correct
// by construction: we convert // by construction: we convert

View file

@ -7,7 +7,6 @@ use std::{fmt, iter, mem};
use either::Either; use either::Either;
use hir::OpaqueTyOrigin;
use rustc_data_structures::frozen::Frozen; use rustc_data_structures::frozen::Frozen;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_errors::ErrorGuaranteed; use rustc_errors::ErrorGuaranteed;
@ -28,6 +27,7 @@ use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::AssertKind; use rustc_middle::mir::AssertKind;
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::cast::CastTy;
use rustc_middle::ty::subst::{SubstsRef, UserSubsts}; use rustc_middle::ty::subst::{SubstsRef, UserSubsts};
@ -241,7 +241,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
hidden_type.ty = infcx.tcx.ty_error(reported); hidden_type.ty = infcx.tcx.ty_error(reported);
} }
(opaque_type_key, (hidden_type, decl.origin)) (opaque_type_key, hidden_type)
}) })
.collect(); .collect();
@ -878,8 +878,7 @@ struct BorrowCheckContext<'a, 'tcx> {
pub(crate) struct MirTypeckResults<'tcx> { pub(crate) struct MirTypeckResults<'tcx> {
pub(crate) constraints: MirTypeckRegionConstraints<'tcx>, pub(crate) constraints: MirTypeckRegionConstraints<'tcx>,
pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
pub(crate) opaque_type_values: pub(crate) opaque_type_values: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
} }
/// A collection of region constraints that must be satisfied for the /// A collection of region constraints that must be satisfied for the
@ -1053,15 +1052,28 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ConstraintCategory::OpaqueType, ConstraintCategory::OpaqueType,
CustomTypeOp::new( CustomTypeOp::new(
|ocx| { |ocx| {
for (key, hidden_ty) in renumbered_opaques { let mut obligations = Vec::new();
ocx.register_infer_ok_obligations( for (opaque_type_key, hidden_ty) in renumbered_opaques {
ocx.infcx.register_hidden_type_in_new_solver( let cause = ObligationCause::dummy();
key, ocx.infcx.insert_hidden_type(
param_env, opaque_type_key,
hidden_ty.ty, &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(()) Ok(())
}, },
"register pre-defined opaques", "register pre-defined opaques",

View file

@ -33,9 +33,6 @@ pub struct OpaqueTypeDecl<'tcx> {
/// There can be multiple, but they are all `lub`ed together at the end /// There can be multiple, but they are all `lub`ed together at the end
/// to obtain the canonical hidden type. /// to obtain the canonical hidden type.
pub hidden_type: OpaqueHiddenType<'tcx>, pub hidden_type: OpaqueHiddenType<'tcx>,
/// The origin of the opaque type.
pub origin: hir::OpaqueTyOrigin,
} }
impl<'tcx> InferCtxt<'tcx> { 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() { 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() => { ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) if def_id.is_local() => {
let def_id = def_id.expect_local(); let def_id = def_id.expect_local();
let origin = match self.defining_use_anchor { match self.defining_use_anchor {
DefiningAnchor::Bind(_) => { DefiningAnchor::Bind(_) => {
// Check that this is `impl Trait` type is // Check that this is `impl Trait` type is
// declared by `parent_def_id` -- i.e., one whose // 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` // 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, DefiningAnchor::Error => return None,
}; };
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() { 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(), cause.clone(),
param_env, param_env,
b, b,
origin,
a_is_expected, a_is_expected,
)) ))
} }
@ -524,39 +522,18 @@ impl<'tcx> InferCtxt<'tcx> {
cause: ObligationCause<'tcx>, cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
hidden_ty: Ty<'tcx>, hidden_ty: Ty<'tcx>,
origin: hir::OpaqueTyOrigin,
a_is_expected: bool, a_is_expected: bool,
) -> InferResult<'tcx, ()> { ) -> InferResult<'tcx, ()> {
// Ideally, we'd get the span where *this specific `ty` came let mut obligations = Vec::new();
// from*, but right now we just use the span from the overall
// value being folded. In simple cases like `-> impl Foo`, self.insert_hidden_type(
// these are the same span, but not in cases like `-> (impl opaque_type_key,
// Foo, impl Bar)`. &cause,
let span = cause.span; param_env,
let mut obligations = if self.intercrate { hidden_ty,
// During intercrate we do not define opaque types but instead always a_is_expected,
// force ambiguity unless the hidden type is known to not implement &mut obligations,
// our trait. )?;
vec![traits::Obligation::new(
self.tcx,
cause.clone(),
param_env,
ty::PredicateKind::Ambiguous,
)]
} else {
let prev = self.inner.borrow_mut().opaque_types().register(
opaque_type_key,
OpaqueHiddenType { ty: hidden_ty, span },
origin,
);
if let Some(prev) = prev {
self.at(&cause, param_env)
.eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)?
.obligations
} else {
Vec::new()
}
};
self.add_item_bounds_for_hidden_type( self.add_item_bounds_for_hidden_type(
opaque_type_key, opaque_type_key,
@ -569,27 +546,54 @@ impl<'tcx> InferCtxt<'tcx> {
Ok(InferOk { value: (), obligations }) Ok(InferOk { value: (), obligations })
} }
/// Registers an opaque's hidden type -- only should be used when the opaque /// Insert a hidden type into the opaque type storage, equating it
/// can be defined. For something more fallible -- checks the anchors, tries /// with any previous entries if necessary.
/// to unify opaques in both dirs, etc. -- use `InferCtxt::handle_opaque_type`. ///
pub fn register_hidden_type_in_new_solver( /// 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, &self,
opaque_type_key: OpaqueTypeKey<'tcx>, opaque_type_key: OpaqueTypeKey<'tcx>,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
hidden_ty: Ty<'tcx>, hidden_ty: Ty<'tcx>,
) -> InferResult<'tcx, ()> { a_is_expected: bool,
assert!(self.next_trait_solver()); obligations: &mut Vec<PredicateObligation<'tcx>>,
let origin = self ) -> Result<(), TypeError<'tcx>> {
.opaque_type_origin(opaque_type_key.def_id) // Ideally, we'd get the span where *this specific `ty` came
.expect("should be called for defining usages only"); // from*, but right now we just use the span from the overall
self.register_hidden_type( // value being folded. In simple cases like `-> impl Foo`,
opaque_type_key, // these are the same span, but not in cases like `-> (impl
ObligationCause::dummy(), // Foo, impl Bar)`.
param_env, let span = cause.span;
hidden_ty, if self.intercrate {
origin, // During intercrate we do not define opaque types but instead always
true, // force ambiguity unless the hidden type is known to not implement
) // our trait.
obligations.push(traits::Obligation::new(
self.tcx,
cause.clone(),
param_env,
ty::PredicateKind::Ambiguous,
))
} else {
let prev = self
.inner
.borrow_mut()
.opaque_types()
.register(opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span });
if let Some(prev) = prev {
obligations.extend(
self.at(&cause, param_env)
.eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)?
.obligations,
);
}
};
Ok(())
} }
pub fn add_item_bounds_for_hidden_type( pub fn add_item_bounds_for_hidden_type(

View file

@ -1,5 +1,4 @@
use rustc_data_structures::undo_log::UndoLogs; use rustc_data_structures::undo_log::UndoLogs;
use rustc_hir::OpaqueTyOrigin;
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty}; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty};
use rustc_span::DUMMY_SP; use rustc_span::DUMMY_SP;
@ -60,14 +59,13 @@ impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> {
&mut self, &mut self,
key: OpaqueTypeKey<'tcx>, key: OpaqueTypeKey<'tcx>,
hidden_type: OpaqueHiddenType<'tcx>, hidden_type: OpaqueHiddenType<'tcx>,
origin: OpaqueTyOrigin,
) -> Option<Ty<'tcx>> { ) -> Option<Ty<'tcx>> {
if let Some(decl) = self.storage.opaque_types.get_mut(&key) { if let Some(decl) = self.storage.opaque_types.get_mut(&key) {
let prev = std::mem::replace(&mut decl.hidden_type, hidden_type); let prev = std::mem::replace(&mut decl.hidden_type, hidden_type);
self.undo_log.push(UndoLog::OpaqueTypes(key, Some(prev))); self.undo_log.push(UndoLog::OpaqueTypes(key, Some(prev)));
return Some(prev.ty); return Some(prev.ty);
} }
let decl = OpaqueTypeDecl { hidden_type, origin }; let decl = OpaqueTypeDecl { hidden_type };
self.storage.opaque_types.insert(key, decl); self.storage.opaque_types.insert(key, decl);
self.undo_log.push(UndoLog::OpaqueTypes(key, None)); self.undo_log.push(UndoLog::OpaqueTypes(key, None));
None None

View file

@ -15,8 +15,8 @@ use rustc_middle::traits::solve::{
}; };
use rustc_middle::traits::DefiningAnchor; use rustc_middle::traits::DefiningAnchor;
use rustc_middle::ty::{ use rustc_middle::ty::{
self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable,
TypeVisitor, TypeVisitableExt, TypeVisitor,
}; };
use rustc_span::DUMMY_SP; use rustc_span::DUMMY_SP;
use std::ops::ControlFlow; use std::ops::ControlFlow;
@ -191,16 +191,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
.with_opaque_type_inference(canonical_input.value.anchor) .with_opaque_type_inference(canonical_input.value.anchor)
.build_with_canonical(DUMMY_SP, &canonical_input); .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 { let mut ecx = EvalCtxt {
infcx, infcx,
var_values, var_values,
@ -211,6 +201,15 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
tainted: Ok(()), 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); let result = ecx.compute_goal(input.goal);
// When creating a query response we clone the opaque type constraints // 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() self.infcx.opaque_type_origin(def_id).is_some()
} }
pub(super) fn register_opaque_ty( pub(super) fn insert_hidden_type(
&mut self, &mut self,
a: ty::OpaqueTypeKey<'tcx>, opaque_type_key: OpaqueTypeKey<'tcx>,
b: Ty<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
hidden_ty: Ty<'tcx>,
) -> Result<(), NoSolution> { ) -> Result<(), NoSolution> {
let InferOk { value: (), obligations } = let mut obligations = Vec::new();
self.infcx.register_hidden_type_in_new_solver(a, param_env, b)?; self.infcx.insert_hidden_type(
self.add_goals(obligations.into_iter().map(|obligation| obligation.into())); opaque_type_key,
&ObligationCause::dummy(),
param_env,
hidden_ty,
true,
&mut obligations,
)?;
self.add_goals(obligations.into_iter().map(|o| o.into()));
Ok(()) 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 // Do something for each opaque/hidden pair defined with `def_id` in the
// current inference context. // current inference context.
pub(super) fn unify_existing_opaque_tys( 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, a, b)?;
} }
ecx.eq(param_env, candidate_ty, ty)?; ecx.eq(param_env, candidate_ty, ty)?;
let mut obl = vec![]; ecx.add_item_bounds_for_hidden_type(candidate_key, param_env, candidate_ty);
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.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})); }));
} }

View file

@ -16,7 +16,6 @@ use rustc_index::IndexVec;
use rustc_infer::infer::canonical::query_response::make_query_region_constraints; use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::canonical::CanonicalVarValues;
use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints}; use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints};
use rustc_infer::infer::InferOk;
use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::solve::{ use rustc_middle::traits::solve::{
ExternalConstraints, ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput, ExternalConstraints, ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput,
@ -321,12 +320,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)], opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)],
) -> Result<(), NoSolution> { ) -> Result<(), NoSolution> {
for &(a, b) in opaque_types { for &(key, ty) in opaque_types {
let InferOk { value: (), obligations } = self.insert_hidden_type(key, param_env, ty)?;
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;
} }
Ok(()) Ok(())
} }

View file

@ -50,7 +50,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
} }
} }
// Otherwise, define a new opaque type // 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) self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
} }
(Reveal::UserFacing, SolverMode::Coherence) => { (Reveal::UserFacing, SolverMode::Coherence) => {