Make RPIT and TAIT work exactly the same
This commit is contained in:
parent
493c960a3e
commit
524d2b3178
57 changed files with 359 additions and 221 deletions
|
@ -38,6 +38,15 @@ pub struct OpaqueTypeDecl<'tcx> {
|
|||
pub origin: hir::OpaqueTyOrigin,
|
||||
}
|
||||
|
||||
pub enum ReplaceOpaqueTypes {
|
||||
/// Closures can't create hidden types for opaque types of their parent, as they
|
||||
/// do not have all the outlives information available. Also `type_of` looks for
|
||||
/// hidden types in the owner (so the closure's parent), so it would not find these
|
||||
/// definitions.
|
||||
OnlyForRPIT,
|
||||
All,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
pub fn replace_opaque_types_with_inference_vars(
|
||||
&self,
|
||||
|
@ -46,27 +55,29 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
span: Span,
|
||||
code: ObligationCauseCode<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
replace: ReplaceOpaqueTypes,
|
||||
) -> InferOk<'tcx, Ty<'tcx>> {
|
||||
if !ty.has_opaque_types() {
|
||||
return InferOk { value: ty, obligations: vec![] };
|
||||
}
|
||||
let mut obligations = vec![];
|
||||
let replace_opaque_type = |def_id| match self.opaque_type_origin(def_id, span) {
|
||||
None => false,
|
||||
Some(OpaqueTyOrigin::FnReturn(..)) => true,
|
||||
// Not using `==` or `matches!` here to make sure we exhaustively match variants.
|
||||
Some(_) => match replace {
|
||||
ReplaceOpaqueTypes::OnlyForRPIT => false,
|
||||
ReplaceOpaqueTypes::All => true,
|
||||
},
|
||||
};
|
||||
let value = ty.fold_with(&mut ty::fold::BottomUpFolder {
|
||||
tcx: self.tcx,
|
||||
lt_op: |lt| lt,
|
||||
ct_op: |ct| ct,
|
||||
ty_op: |ty| match *ty.kind() {
|
||||
// Closures can't create hidden types for opaque types of their parent, as they
|
||||
// do not have all the outlives information available. Also `type_of` looks for
|
||||
// hidden types in the owner (so the closure's parent), so it would not find these
|
||||
// definitions.
|
||||
ty::Opaque(def_id, _substs)
|
||||
if matches!(
|
||||
self.opaque_type_origin(def_id, span),
|
||||
Some(OpaqueTyOrigin::FnReturn(..))
|
||||
) =>
|
||||
{
|
||||
let span = if span.is_dummy() { self.tcx.def_span(def_id) } else { span };
|
||||
ty::Opaque(def_id, _substs) if replace_opaque_type(def_id) => {
|
||||
let def_span = self.tcx.def_span(def_id);
|
||||
let span = if span.contains(def_span) { def_span } else { span };
|
||||
let cause = ObligationCause::new(span, body_id, code.clone());
|
||||
// FIXME(compiler-errors): We probably should add a new TypeVariableOriginKind
|
||||
// for opaque types, and then use that kind to fix the spans for type errors
|
||||
|
|
|
@ -13,6 +13,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
|
|||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{ItemKind, Node, PathSegment};
|
||||
use rustc_infer::infer::opaque_types::ReplaceOpaqueTypes;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
|
||||
use rustc_infer::traits::Obligation;
|
||||
|
@ -95,9 +96,10 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||
fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars(
|
||||
declared_ret_ty,
|
||||
body.value.hir_id,
|
||||
DUMMY_SP,
|
||||
decl.output.span(),
|
||||
traits::ObligationCauseCode::OpaqueReturnType(None),
|
||||
param_env,
|
||||
ReplaceOpaqueTypes::All,
|
||||
));
|
||||
// If we replaced declared_ret_ty with infer vars, then we must be infering
|
||||
// an opaque type, so set a flag so we can improve diagnostics.
|
||||
|
|
|
@ -7,6 +7,7 @@ use crate::rustc_middle::ty::subst::Subst;
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_infer::infer::opaque_types::ReplaceOpaqueTypes;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::LateBoundRegionConversionTime;
|
||||
use rustc_infer::infer::{InferOk, InferResult};
|
||||
|
@ -645,6 +646,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
result
|
||||
}
|
||||
|
||||
/// Closures can't create hidden types for opaque types of their parent, as they
|
||||
/// do not have all the outlives information available. Also `type_of` looks for
|
||||
/// hidden types in the owner (so the closure's parent), so it would not find these
|
||||
/// definitions.
|
||||
fn hide_parent_opaque_types(&self, ty: Ty<'tcx>, span: Span, body_id: hir::HirId) -> Ty<'tcx> {
|
||||
let InferOk { value, obligations } = self.replace_opaque_types_with_inference_vars(
|
||||
ty,
|
||||
|
@ -652,6 +657,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
span,
|
||||
ObligationCauseCode::MiscObligation,
|
||||
self.param_env,
|
||||
ReplaceOpaqueTypes::OnlyForRPIT,
|
||||
);
|
||||
self.register_predicates(obligations);
|
||||
value
|
||||
|
@ -671,8 +677,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
let ret_ty = ret_coercion.borrow().expected_ty();
|
||||
let ret_ty = self.inh.infcx.shallow_resolve(ret_ty);
|
||||
let (def_id, substs) = match *ret_ty.kind() {
|
||||
ty::Opaque(def_id, substs) => (def_id, substs),
|
||||
|
||||
let get_future_output = |predicate: ty::Predicate<'tcx>, span| {
|
||||
// Search for a pending obligation like
|
||||
//
|
||||
// `<R as Future>::Output = T`
|
||||
//
|
||||
// where R is the return type we are expecting. This type `T`
|
||||
// will be our output.
|
||||
let bound_predicate = predicate.kind();
|
||||
if let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder() {
|
||||
self.deduce_future_output_from_projection(
|
||||
span,
|
||||
bound_predicate.rebind(proj_predicate),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let output_ty = match *ret_ty.kind() {
|
||||
ty::Infer(ty::TyVar(ret_vid)) => {
|
||||
self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| {
|
||||
get_future_output(obligation.predicate, obligation.cause.span)
|
||||
})
|
||||
}
|
||||
ty::Opaque(def_id, substs) => self
|
||||
.tcx
|
||||
.bound_explicit_item_bounds(def_id)
|
||||
.transpose_iter()
|
||||
.map(|e| e.map_bound(|e| *e).transpose_tuple2())
|
||||
.find_map(|(p, s)| get_future_output(p.subst(self.tcx, substs), s.0)),
|
||||
ty::Error(_) => return None,
|
||||
_ => span_bug!(
|
||||
self.tcx.def_span(expr_def_id),
|
||||
|
@ -680,30 +715,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
),
|
||||
};
|
||||
|
||||
let item_bounds = self.tcx.bound_explicit_item_bounds(def_id);
|
||||
|
||||
// Search for a pending obligation like
|
||||
//
|
||||
// `<R as Future>::Output = T`
|
||||
//
|
||||
// where R is the return type we are expecting. This type `T`
|
||||
// will be our output.
|
||||
let output_ty = item_bounds
|
||||
.transpose_iter()
|
||||
.map(|e| e.map_bound(|e| *e).transpose_tuple2())
|
||||
.find_map(|(predicate, span)| {
|
||||
let bound_predicate = predicate.subst(self.tcx, substs).kind();
|
||||
if let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder()
|
||||
{
|
||||
self.deduce_future_output_from_projection(
|
||||
span.0,
|
||||
bound_predicate.rebind(proj_predicate),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
debug!("deduce_future_output_from_obligations: output_ty={:?}", output_ty);
|
||||
output_ty
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue