Skip to content

Commit

Permalink
Auto merge of rust-lang#112466 - lcnr:opaque-type-cleanup, r=compiler…
Browse files Browse the repository at this point in the history
…-errors

opaque type cleanup

the commits are pretty self-contained.

r? `@compiler-errors` cc `@oli-obk`
  • Loading branch information
bors committed Jun 11, 2023
2 parents 970058e + b62e20d commit 34d64ab
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 175 deletions.
150 changes: 77 additions & 73 deletions compiler/rustc_borrowck/src/region_infer/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
pub(crate) fn infer_opaque_types(
&self,
infcx: &InferCtxt<'tcx>,
opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
) -> FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> {
let mut result: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> = FxIndexMap::default();

Expand All @@ -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);

Expand Down Expand Up @@ -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<X, Y>` mapped to `(X, Y)`
Expand Down Expand Up @@ -215,7 +214,6 @@ pub trait InferCtxtExt<'tcx> {
&self,
opaque_type_key: OpaqueTypeKey<'tcx>,
instantiated_ty: OpaqueHiddenType<'tcx>,
origin: OpaqueTyOrigin,
) -> Ty<'tcx>;
}

Expand Down Expand Up @@ -248,109 +246,115 @@ 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);
}

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
.remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false)
.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,
opaque_type_key,
origin,
self.next_trait_solver(),
opaque_type_key.def_id,
instantiated_ty.span,
definition_ty,
) {
return self.tcx.ty_error(guar);
Ok(hidden_ty) => hidden_ty,
Err(guar) => 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);
/// 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 = 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,
) {
// 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))
}
}

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
Expand Down
34 changes: 23 additions & 11 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -28,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};
Expand Down Expand Up @@ -241,7 +241,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();

Expand Down Expand Up @@ -878,8 +878,7 @@ struct BorrowCheckContext<'a, 'tcx> {
pub(crate) struct MirTypeckResults<'tcx> {
pub(crate) constraints: MirTypeckRegionConstraints<'tcx>,
pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
pub(crate) opaque_type_values:
FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
pub(crate) opaque_type_values: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
}

/// A collection of region constraints that must be satisfied for the
Expand Down Expand Up @@ -1053,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",
Expand Down
Loading

0 comments on commit 34d64ab

Please sign in to comment.