mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
The only reason we had to replace opaque types in closures was due to async fn desugaring, make that explicit
This commit is contained in:
parent
77e88a7c7a
commit
c33b127d7c
@ -5,7 +5,7 @@ use hir::{HirId, OpaqueTyOrigin};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_data_structures::vec_map::VecMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::fold::BottomUpFolder;
|
||||
use rustc_middle::ty::subst::{GenericArgKind, Subst};
|
||||
use rustc_middle::ty::{
|
||||
@ -38,38 +38,19 @@ 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,
|
||||
ty: Ty<'tcx>,
|
||||
body_id: HirId,
|
||||
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 replace_opaque_type = |def_id| self.opaque_type_origin(def_id, span).is_some();
|
||||
let value = ty.fold_with(&mut ty::fold::BottomUpFolder {
|
||||
tcx: self.tcx,
|
||||
lt_op: |lt| lt,
|
||||
@ -78,7 +59,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
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());
|
||||
let code = traits::ObligationCauseCode::OpaqueReturnType(None);
|
||||
let cause = ObligationCause::new(span, body_id, code);
|
||||
// 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
|
||||
// that we see later on.
|
||||
|
@ -13,7 +13,6 @@ 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;
|
||||
@ -97,9 +96,7 @@ pub(super) fn check_fn<'a, 'tcx>(
|
||||
declared_ret_ty,
|
||||
body.value.hir_id,
|
||||
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,16 +7,13 @@ 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};
|
||||
use rustc_infer::traits::ObligationCauseCode;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::subst::InternalSubsts;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::traits::error_reporting::ArgKind;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
||||
@ -430,14 +427,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// in this binder we are creating.
|
||||
assert!(!expected_sig.sig.skip_binder().has_vars_bound_above(ty::INNERMOST));
|
||||
let bound_sig = expected_sig.sig.map_bound(|sig| {
|
||||
let output = self.hide_parent_opaque_types(
|
||||
sig.output(),
|
||||
expected_sig.cause_span.unwrap_or(DUMMY_SP),
|
||||
body.id().hir_id,
|
||||
);
|
||||
self.tcx.mk_fn_sig(
|
||||
sig.inputs().iter().cloned(),
|
||||
output,
|
||||
sig.output(),
|
||||
sig.c_variadic,
|
||||
hir::Unsafety::Normal,
|
||||
Abi::RustCall,
|
||||
@ -609,23 +601,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// function.
|
||||
Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn)) => {
|
||||
debug!("closure is async fn body");
|
||||
self.deduce_future_output_from_obligations(expr_def_id).unwrap_or_else(|| {
|
||||
// AFAIK, deducing the future output
|
||||
// always succeeds *except* in error cases
|
||||
// like #65159. I'd like to return Error
|
||||
// here, but I can't because I can't
|
||||
// easily (and locally) prove that we
|
||||
// *have* reported an
|
||||
// error. --nikomatsakis
|
||||
astconv.ty_infer(None, decl.output.span())
|
||||
})
|
||||
self.deduce_future_output_from_obligations(expr_def_id, body.id().hir_id)
|
||||
.unwrap_or_else(|| {
|
||||
// AFAIK, deducing the future output
|
||||
// always succeeds *except* in error cases
|
||||
// like #65159. I'd like to return Error
|
||||
// here, but I can't because I can't
|
||||
// easily (and locally) prove that we
|
||||
// *have* reported an
|
||||
// error. --nikomatsakis
|
||||
astconv.ty_infer(None, decl.output.span())
|
||||
})
|
||||
}
|
||||
|
||||
_ => astconv.ty_infer(None, decl.output.span()),
|
||||
},
|
||||
};
|
||||
let supplied_return =
|
||||
self.hide_parent_opaque_types(supplied_return, decl.output.span(), body.id().hir_id);
|
||||
|
||||
let result = ty::Binder::bind_with_vars(
|
||||
self.tcx.mk_fn_sig(
|
||||
@ -646,23 +637,6 @@ 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,
|
||||
body_id,
|
||||
span,
|
||||
ObligationCauseCode::MiscObligation,
|
||||
self.param_env,
|
||||
ReplaceOpaqueTypes::OnlyForRPIT,
|
||||
);
|
||||
self.register_predicates(obligations);
|
||||
value
|
||||
}
|
||||
|
||||
/// Invoked when we are translating the generator that results
|
||||
/// from desugaring an `async fn`. Returns the "sugared" return
|
||||
/// type of the `async fn` -- that is, the return type that the
|
||||
@ -670,7 +644,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
/// Future<Output = T>`, so we do this by searching through the
|
||||
/// obligations to extract the `T`.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn deduce_future_output_from_obligations(&self, expr_def_id: DefId) -> Option<Ty<'tcx>> {
|
||||
fn deduce_future_output_from_obligations(
|
||||
&self,
|
||||
expr_def_id: DefId,
|
||||
body_id: hir::HirId,
|
||||
) -> Option<Ty<'tcx>> {
|
||||
let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| {
|
||||
span_bug!(self.tcx.def_span(expr_def_id), "async fn generator outside of a fn")
|
||||
});
|
||||
@ -700,14 +678,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
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)),
|
||||
.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),
|
||||
@ -715,8 +693,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
),
|
||||
};
|
||||
|
||||
// async fn that have opaque types in their return type need to redo the conversion to inference variables
|
||||
// as they fetch the still opaque version from the signature.
|
||||
let InferOk { value: output_ty, obligations } = self
|
||||
.replace_opaque_types_with_inference_vars(
|
||||
output_ty,
|
||||
body_id,
|
||||
self.tcx.def_span(expr_def_id),
|
||||
self.param_env,
|
||||
);
|
||||
self.register_predicates(obligations);
|
||||
|
||||
debug!("deduce_future_output_from_obligations: output_ty={:?}", output_ty);
|
||||
output_ty
|
||||
Some(output_ty)
|
||||
}
|
||||
|
||||
/// Given a projection like
|
||||
|
Loading…
Reference in New Issue
Block a user