diff options
Diffstat (limited to '')
-rw-r--r-- | compiler/rustc_typeck/src/check/closure.rs | 90 |
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) } |