Skip to content

Commit

Permalink
The only reason we had to replace opaque types in closures was due to…
Browse files Browse the repository at this point in the history
… async fn desugaring, make that explicit
  • Loading branch information
oli-obk committed Jun 29, 2022
1 parent 77e88a7 commit c33b127
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 67 deletions.
26 changes: 4 additions & 22 deletions compiler/rustc_infer/src/infer/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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,
Expand All @@ -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.
Expand Down
3 changes: 0 additions & 3 deletions compiler/rustc_typeck/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down
73 changes: 31 additions & 42 deletions compiler/rustc_typeck/src/check/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 _;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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(
Expand All @@ -646,31 +637,18 @@ 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
/// user specified. The "desugared" return type is an `impl
/// 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")
});
Expand Down Expand Up @@ -700,23 +678,34 @@ 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),
"async fn generator return type not an inference variable"
),
};

// 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
Expand Down

0 comments on commit c33b127

Please sign in to comment.