summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_typeck/src/check/closure.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_typeck/src/check/closure.rs')
-rw-r--r--compiler/rustc_typeck/src/check/closure.rs90
1 files changed, 55 insertions, 35 deletions
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index fee872155..9b943b160 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -4,6 +4,7 @@ use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
use crate::astconv::AstConv;
use crate::rustc_middle::ty::subst::Subst;
+use hir::def::DefKind;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
@@ -29,7 +30,12 @@ struct ExpectedSig<'tcx> {
}
struct ClosureSignatures<'tcx> {
+ /// The signature users of the closure see.
bound_sig: ty::PolyFnSig<'tcx>,
+ /// The signature within the function body.
+ /// This mostly differs in the sense that lifetimes are now early bound and any
+ /// opaque types from the signature expectation are overriden in case there are
+ /// explicit hidden types written by the user in the closure signature.
liberated_sig: ty::FnSig<'tcx>,
}
@@ -58,7 +64,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.check_closure(expr, expected_kind, decl, body, gen, expected_sig)
}
- #[instrument(skip(self, expr, body, decl), level = "debug")]
+ #[instrument(skip(self, expr, body, decl), level = "debug", ret)]
fn check_closure(
&self,
expr: &hir::Expr<'_>,
@@ -158,11 +164,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
},
);
- let closure_type = self.tcx.mk_closure(expr_def_id.to_def_id(), closure_substs.substs);
-
- debug!(?expr.hir_id, ?closure_type);
-
- closure_type
+ self.tcx.mk_closure(expr_def_id.to_def_id(), closure_substs.substs)
}
/// Given the expected type, figures out what it can about this closure we
@@ -262,7 +264,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// The `cause_span` should be the span that caused us to
/// have this expected signature, or `None` if we can't readily
/// know that.
- #[instrument(level = "debug", skip(self, cause_span))]
+ #[instrument(level = "debug", skip(self, cause_span), ret)]
fn deduce_sig_from_projection(
&self,
cause_span: Option<Span>,
@@ -317,7 +319,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
hir::Unsafety::Normal,
Abi::Rust,
));
- debug!(?sig);
Some(ExpectedSig { cause_span, sig })
}
@@ -448,18 +449,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Along the way, it also writes out entries for types that the user
// wrote into our typeck results, which are then later used by the privacy
// check.
- match self.check_supplied_sig_against_expectation(
+ match self.merge_supplied_sig_with_expectation(
hir_id,
expr_def_id,
decl,
body,
- &closure_sigs,
+ closure_sigs,
) {
Ok(infer_ok) => self.register_infer_ok_obligations(infer_ok),
- Err(_) => return self.sig_of_closure_no_expectation(hir_id, expr_def_id, decl, body),
+ Err(_) => self.sig_of_closure_no_expectation(hir_id, expr_def_id, decl, body),
}
-
- closure_sigs
}
fn sig_of_closure_with_mismatched_number_of_arguments(
@@ -501,21 +500,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Enforce the user's types against the expectation. See
/// `sig_of_closure_with_expectation` for details on the overall
/// strategy.
- fn check_supplied_sig_against_expectation(
+ #[instrument(level = "debug", skip(self, hir_id, expr_def_id, decl, body, expected_sigs))]
+ fn merge_supplied_sig_with_expectation(
&self,
hir_id: hir::HirId,
expr_def_id: DefId,
decl: &hir::FnDecl<'_>,
body: &hir::Body<'_>,
- expected_sigs: &ClosureSignatures<'tcx>,
- ) -> InferResult<'tcx, ()> {
+ mut expected_sigs: ClosureSignatures<'tcx>,
+ ) -> InferResult<'tcx, ClosureSignatures<'tcx>> {
// Get the signature S that the user gave.
//
// (See comment on `sig_of_closure_with_expectation` for the
// meaning of these letters.)
let supplied_sig = self.supplied_sig_of_closure(hir_id, expr_def_id, decl, body);
- debug!("check_supplied_sig_against_expectation: supplied_sig={:?}", supplied_sig);
+ debug!(?supplied_sig);
// FIXME(#45727): As discussed in [this comment][c1], naively
// forcing equality here actually results in suboptimal error
@@ -533,23 +533,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// [c2]: https://github.com/rust-lang/rust/pull/45072#issuecomment-341096796
self.commit_if_ok(|_| {
let mut all_obligations = vec![];
+ let inputs: Vec<_> = iter::zip(
+ decl.inputs,
+ supplied_sig.inputs().skip_binder(), // binder moved to (*) below
+ )
+ .map(|(hir_ty, &supplied_ty)| {
+ // Instantiate (this part of..) S to S', i.e., with fresh variables.
+ self.replace_bound_vars_with_fresh_vars(
+ hir_ty.span,
+ LateBoundRegionConversionTime::FnCall,
+ // (*) binder moved to here
+ supplied_sig.inputs().rebind(supplied_ty),
+ )
+ })
+ .collect();
// The liberated version of this signature should be a subtype
// of the liberated form of the expectation.
for ((hir_ty, &supplied_ty), expected_ty) in iter::zip(
- iter::zip(
- decl.inputs,
- supplied_sig.inputs().skip_binder(), // binder moved to (*) below
- ),
+ iter::zip(decl.inputs, &inputs),
expected_sigs.liberated_sig.inputs(), // `liberated_sig` is E'.
) {
- // Instantiate (this part of..) S to S', i.e., with fresh variables.
- let supplied_ty = self.replace_bound_vars_with_fresh_vars(
- hir_ty.span,
- LateBoundRegionConversionTime::FnCall,
- supplied_sig.inputs().rebind(supplied_ty),
- ); // recreated from (*) above
-
// Check that E' = S'.
let cause = self.misc(hir_ty.span);
let InferOk { value: (), obligations } =
@@ -568,7 +572,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.eq(expected_sigs.liberated_sig.output(), supplied_output_ty)?;
all_obligations.extend(obligations);
- Ok(InferOk { value: (), obligations: all_obligations })
+ let inputs = inputs.into_iter().map(|ty| self.resolve_vars_if_possible(ty));
+
+ expected_sigs.liberated_sig = self.tcx.mk_fn_sig(
+ inputs,
+ supplied_output_ty,
+ expected_sigs.liberated_sig.c_variadic,
+ hir::Unsafety::Normal,
+ Abi::RustCall,
+ );
+
+ Ok(InferOk { value: expected_sigs, obligations: all_obligations })
})
}
@@ -576,7 +590,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// types that the user gave into a signature.
///
/// Also, record this closure signature for later.
- #[instrument(skip(self, decl, body), level = "debug")]
+ #[instrument(skip(self, decl, body), level = "debug", ret)]
fn supplied_sig_of_closure(
&self,
hir_id: hir::HirId,
@@ -629,8 +643,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
bound_vars,
);
- debug!(?result);
-
let c_result = self.inh.infcx.canonicalize_response(result);
self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result);
@@ -643,7 +655,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// 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")]
+ #[instrument(skip(self), level = "debug", ret)]
fn deduce_future_output_from_obligations(
&self,
expr_def_id: DefId,
@@ -687,9 +699,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.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,
+ ty::Projection(proj)
+ if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder =>
+ {
+ self.tcx
+ .bound_explicit_item_bounds(proj.item_def_id)
+ .transpose_iter()
+ .map(|e| e.map_bound(|e| *e).transpose_tuple2())
+ .find_map(|(p, s)| get_future_output(p.subst(self.tcx, proj.substs), s.0))?
+ }
_ => span_bug!(
self.tcx.def_span(expr_def_id),
- "async fn generator return type not an inference variable"
+ "async fn generator return type not an inference variable: {ret_ty}"
),
};
@@ -704,7 +725,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
self.register_predicates(obligations);
- debug!("deduce_future_output_from_obligations: output_ty={:?}", output_ty);
Some(output_ty)
}