]> git.proxmox.com Git - rustc.git/blobdiff - src/librustc_typeck/check/closure.rs
New upstream version 1.41.1+dfsg1
[rustc.git] / src / librustc_typeck / check / closure.rs
index df83c92fde5b4361c25a1fd1ac1ef4c17be19c82..30cb0d4f96766925203bac150276f09279a7087a 100644 (file)
@@ -2,17 +2,17 @@
 
 use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
 
-use astconv::AstConv;
-use middle::region;
+use crate::astconv::AstConv;
+use crate::middle::{lang_items, region};
 use rustc::hir::def_id::DefId;
 use rustc::infer::{InferOk, InferResult};
 use rustc::infer::LateBoundRegionConversionTime;
-use rustc::infer::type_variable::TypeVariableOrigin;
+use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc::traits::Obligation;
 use rustc::traits::error_reporting::ArgKind;
 use rustc::ty::{self, Ty, GenericParamDefKind};
 use rustc::ty::fold::TypeFoldable;
-use rustc::ty::subst::Substs;
+use rustc::ty::subst::InternalSubsts;
 use std::cmp;
 use std::iter;
 use rustc_target::spec::abi::Abi;
@@ -32,14 +32,14 @@ struct ClosureSignatures<'tcx> {
     liberated_sig: ty::FnSig<'tcx>,
 }
 
-impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn check_expr_closure(
         &self,
         expr: &hir::Expr,
-        _capture: hir::CaptureClause,
-        decl: &'gcx hir::FnDecl,
+        _capture: hir::CaptureBy,
+        decl: &'tcx hir::FnDecl,
         body_id: hir::BodyId,
-        gen: Option<hir::GeneratorMovability>,
+        gen: Option<hir::Movability>,
         expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
         debug!(
@@ -62,9 +62,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         &self,
         expr: &hir::Expr,
         opt_kind: Option<ty::ClosureKind>,
-        decl: &'gcx hir::FnDecl,
-        body: &'gcx hir::Body,
-        gen: Option<hir::GeneratorMovability>,
+        decl: &'tcx hir::FnDecl,
+        body: &'tcx hir::Body,
+        gen: Option<hir::Movability>,
         expected_sig: Option<ExpectedSig<'tcx>>,
     ) -> Ty<'tcx> {
         debug!(
@@ -72,7 +72,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             opt_kind, expected_sig
         );
 
-        let expr_def_id = self.tcx.hir().local_def_id(expr.id);
+        let expr_def_id = self.tcx.hir().local_def_id(expr.hir_id);
 
         let ClosureSignatures {
             bound_sig,
@@ -86,7 +86,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.param_env,
             liberated_sig,
             decl,
-            expr.id,
+            expr.hir_id,
             body,
             gen,
         ).1;
@@ -95,44 +95,48 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // types of upvars. These will be unified during the upvar
         // inference phase (`upvar.rs`).
         let base_substs =
-            Substs::identity_for_item(self.tcx, self.tcx.closure_base_def_id(expr_def_id));
+            InternalSubsts::identity_for_item(self.tcx, self.tcx.closure_base_def_id(expr_def_id));
         let substs = base_substs.extend_to(self.tcx,expr_def_id, |param, _| {
             match param.kind {
                 GenericParamDefKind::Lifetime => {
-                    span_bug!(expr.span, "closure has region param")
+                    span_bug!(expr.span, "closure has lifetime param")
                 }
-                GenericParamDefKind::Type {..} => {
-                    self.infcx
-                        .next_ty_var(TypeVariableOrigin::ClosureSynthetic(expr.span)).into()
+                GenericParamDefKind::Type { .. } => {
+                    self.infcx.next_ty_var(TypeVariableOrigin {
+                        kind: TypeVariableOriginKind::ClosureSynthetic,
+                        span: expr.span,
+                    }).into()
+                }
+                GenericParamDefKind::Const => {
+                    span_bug!(expr.span, "closure has const param")
                 }
             }
         });
         if let Some(GeneratorTypes { yield_ty, interior, movability }) = generator_types {
-            let substs = ty::GeneratorSubsts { substs };
+            let generator_substs = substs.as_generator();
             self.demand_eqtype(
                 expr.span,
                 yield_ty,
-                substs.yield_ty(expr_def_id, self.tcx),
+                generator_substs.yield_ty(expr_def_id, self.tcx),
             );
             self.demand_eqtype(
                 expr.span,
                 liberated_sig.output(),
-                substs.return_ty(expr_def_id, self.tcx),
+                generator_substs.return_ty(expr_def_id, self.tcx),
             );
             self.demand_eqtype(
                 expr.span,
                 interior,
-                substs.witness(expr_def_id, self.tcx),
+                generator_substs.witness(expr_def_id, self.tcx),
             );
             return self.tcx.mk_generator(expr_def_id, substs, movability);
         }
 
-        let substs = ty::ClosureSubsts { substs };
         let closure_type = self.tcx.mk_closure(expr_def_id, substs);
 
         debug!(
-            "check_closure: expr.id={:?} closure_type={:?}",
-            expr.id, closure_type
+            "check_closure: expr.hir_id={:?} closure_type={:?}",
+            expr.hir_id, closure_type
         );
 
         // Tuple up the arguments and insert the resulting function type into
@@ -141,7 +145,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.tcx.mk_fn_sig(
                 iter::once(self.tcx.intern_tup(sig.inputs())),
                 sig.output(),
-                sig.variadic,
+                sig.c_variadic,
                 sig.unsafety,
                 sig.abi,
             )
@@ -156,14 +160,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.demand_eqtype(
             expr.span,
             sig_fn_ptr_ty,
-            substs.closure_sig_ty(expr_def_id, self.tcx),
+            substs.as_closure().sig_ty(expr_def_id, self.tcx),
         );
 
         if let Some(kind) = opt_kind {
             self.demand_eqtype(
                 expr.span,
                 kind.to_ty(self.tcx),
-                substs.closure_kind_ty(expr_def_id, self.tcx),
+                substs.as_closure().kind_ty(expr_def_id, self.tcx),
             );
         }
 
@@ -181,7 +185,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             expected_ty
         );
 
-        match expected_ty.sty {
+        match expected_ty.kind {
             ty::Dynamic(ref object_type, ..) => {
                 let sig = object_type
                     .projection_bounds()
@@ -244,7 +248,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     /// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
-    /// everything we need to know about a closure.
+    /// everything we need to know about a closure or generator.
     ///
     /// The `cause_span` should be the span that caused us to
     /// have this expected signature, or `None` if we can't readily
@@ -260,37 +264,50 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         let trait_ref = projection.to_poly_trait_ref(tcx);
 
-        if tcx.lang_items().fn_trait_kind(trait_ref.def_id()).is_none() {
+        let is_fn = tcx.lang_items().fn_trait_kind(trait_ref.def_id()).is_some();
+        let gen_trait = tcx.require_lang_item(lang_items::GeneratorTraitLangItem, cause_span);
+        let is_gen = gen_trait == trait_ref.def_id();
+        if !is_fn && !is_gen {
+            debug!("deduce_sig_from_projection: not fn or generator");
             return None;
         }
 
-        let arg_param_ty = trait_ref.skip_binder().substs.type_at(1);
-        let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty);
-        debug!(
-            "deduce_sig_from_projection: arg_param_ty {:?}",
-            arg_param_ty
-        );
+        if is_gen {
+            // Check that we deduce the signature from the `<_ as std::ops::Generator>::Return`
+            // associated item and not yield.
+            let return_assoc_item = self.tcx.associated_items(gen_trait).nth(1).unwrap().def_id;
+            if return_assoc_item != projection.projection_def_id() {
+                debug!("deduce_sig_from_projection: not return assoc item of generator");
+                return None;
+            }
+        }
+
+        let input_tys = if is_fn {
+            let arg_param_ty = trait_ref.skip_binder().substs.type_at(1);
+            let arg_param_ty = self.resolve_vars_if_possible(&arg_param_ty);
+            debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty);
 
-        let input_tys = match arg_param_ty.sty {
-            ty::Tuple(tys) => tys.into_iter(),
-            _ => return None
+            match arg_param_ty.kind {
+                ty::Tuple(tys) => tys.into_iter().map(|k| k.expect_ty()).collect::<Vec<_>>(),
+                _ => return None,
+            }
+        } else {
+            // Generators cannot have explicit arguments.
+            vec![]
         };
 
         let ret_param_ty = projection.skip_binder().ty;
-        let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty);
-        debug!(
-            "deduce_sig_from_projection: ret_param_ty {:?}",
-            ret_param_ty
-        );
+        let ret_param_ty = self.resolve_vars_if_possible(&ret_param_ty);
+        debug!("deduce_sig_from_projection: ret_param_ty={:?}", ret_param_ty);
 
         let sig = self.tcx.mk_fn_sig(
-            input_tys.cloned(),
-            ret_param_ty,
+            input_tys.iter(),
+            &ret_param_ty,
             false,
             hir::Unsafety::Normal,
             Abi::Rust,
         );
-        debug!("deduce_sig_from_projection: sig {:?}", sig);
+        debug!("deduce_sig_from_projection: sig={:?}", sig);
 
         Some(ExpectedSig { cause_span, sig })
     }
@@ -319,7 +336,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     ) -> ClosureSignatures<'tcx> {
         debug!("sig_of_closure_no_expectation()");
 
-        let bound_sig = self.supplied_sig_of_closure(expr_def_id, decl);
+        let bound_sig = self.supplied_sig_of_closure(expr_def_id, decl, body);
 
         self.closure_sigs(expr_def_id, body, bound_sig)
     }
@@ -365,7 +382,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     ///
     /// # Arguments
     ///
-    /// - `expr_def_id`: the def-id of the closure expression
+    /// - `expr_def_id`: the `DefId` of the closure expression
     /// - `decl`: the HIR declaration of the closure
     /// - `body`: the body of the closure
     /// - `expected_sig`: the expected signature (if any). Note that
@@ -386,7 +403,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // Watch out for some surprises and just ignore the
         // expectation if things don't see to match up with what we
         // expect.
-        if expected_sig.sig.variadic != decl.variadic {
+        if expected_sig.sig.c_variadic != decl.c_variadic {
             return self.sig_of_closure_no_expectation(expr_def_id, decl, body);
         } else if expected_sig.sig.inputs_and_output.len() != decl.inputs.len() + 1 {
             return self.sig_of_closure_with_mismatched_number_of_arguments(
@@ -404,7 +421,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let bound_sig = ty::Binder::bind(self.tcx.mk_fn_sig(
             expected_sig.sig.inputs().iter().cloned(),
             expected_sig.sig.output(),
-            decl.variadic,
+            decl.c_variadic,
             hir::Unsafety::Normal,
             Abi::RustCall,
         ));
@@ -458,7 +475,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.closure_sigs(expr_def_id, body, error_sig)
     }
 
-    /// Enforce the user's types against the expectation.  See
+    /// 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(
@@ -472,7 +489,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         //
         // (See comment on `sig_of_closure_with_expectation` for the
         // meaning of these letters.)
-        let supplied_sig = self.supplied_sig_of_closure(expr_def_id, decl);
+        let supplied_sig = self.supplied_sig_of_closure(expr_def_id, decl, body);
 
         debug!(
             "check_supplied_sig_against_expectation: supplied_sig={:?}",
@@ -511,11 +528,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 ); // recreated from (*) above
 
                 // Check that E' = S'.
-                let cause = &self.misc(hir_ty.span);
+                let cause = self.misc(hir_ty.span);
                 let InferOk {
                     value: (),
                     obligations,
-                } = self.at(cause, self.param_env)
+                } = self.at(&cause, self.param_env)
                     .eq(*expected_ty, supplied_ty)?;
                 all_obligations.extend(obligations);
 
@@ -531,7 +548,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 );
                 all_obligations.push(
                     Obligation::new(
-                        cause.clone(),
+                        cause,
                         self.param_env,
                         ty::Predicate::TypeOutlives(
                             ty::Binder::dummy(
@@ -573,20 +590,47 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         &self,
         expr_def_id: DefId,
         decl: &hir::FnDecl,
+        body: &hir::Body,
     ) -> ty::PolyFnSig<'tcx> {
-        let astconv: &dyn AstConv = self;
+        let astconv: &dyn AstConv<'_> = self;
+
+        debug!(
+            "supplied_sig_of_closure(decl={:?}, body.generator_kind={:?})",
+            decl,
+            body.generator_kind,
+        );
 
         // First, convert the types that the user supplied (if any).
         let supplied_arguments = decl.inputs.iter().map(|a| astconv.ast_ty_to_ty(a));
         let supplied_return = match decl.output {
             hir::Return(ref output) => astconv.ast_ty_to_ty(&output),
-            hir::DefaultReturn(_) => astconv.ty_infer(decl.output.span()),
+            hir::DefaultReturn(_) => match body.generator_kind {
+                // In the case of the async block that we create for a function body,
+                // we expect the return type of the block to match that of the enclosing
+                // function.
+                Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn)) => {
+                    debug!("supplied_sig_of_closure: 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())
+                        })
+                }
+
+                _ => astconv.ty_infer(None, decl.output.span()),
+            }
         };
 
         let result = ty::Binder::bind(self.tcx.mk_fn_sig(
             supplied_arguments,
             supplied_return,
-            decl.variadic,
+            decl.c_variadic,
             hir::Unsafety::Normal,
             Abi::RustCall,
         ));
@@ -602,11 +646,121 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         result
     }
 
+    /// 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 a `impl
+    /// Future<Output = T>`, so we do this by searching through the
+    /// obligations to extract the `T`.
+    fn deduce_future_output_from_obligations(
+        &self,
+        expr_def_id: DefId,
+    ) -> Option<Ty<'tcx>> {
+        debug!("deduce_future_output_from_obligations(expr_def_id={:?})", expr_def_id);
+
+        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"
+            ));
+
+        // In practice, the return type of the surrounding function is
+        // always a (not yet resolved) inference variable, because it
+        // is the hidden type for an `impl Trait` that we are going to
+        // be inferring.
+        let ret_ty = ret_coercion.borrow().expected_ty();
+        let ret_ty = self.inh.infcx.shallow_resolve(ret_ty);
+        let ret_vid = match ret_ty.kind {
+            ty::Infer(ty::TyVar(ret_vid)) => ret_vid,
+            _ => {
+                span_bug!(
+                    self.tcx.def_span(expr_def_id),
+                    "async fn generator return type not an inference variable"
+                )
+            }
+        };
+
+        // 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 = self.obligations_for_self_ty(ret_vid)
+            .find_map(|(_, obligation)| {
+                if let ty::Predicate::Projection(ref proj_predicate) = obligation.predicate {
+                    self.deduce_future_output_from_projection(
+                        obligation.cause.span,
+                        proj_predicate
+                    )
+                } else {
+                    None
+                }
+            });
+
+        debug!("deduce_future_output_from_obligations: output_ty={:?}", output_ty);
+        output_ty
+    }
+
+    /// Given a projection like
+    ///
+    /// `<X as Future>::Output = T`
+    ///
+    /// where `X` is some type that has no late-bound regions, returns
+    /// `Some(T)`. If the projection is for some other trait, returns
+    /// `None`.
+    fn deduce_future_output_from_projection(
+        &self,
+        cause_span: Span,
+        predicate: &ty::PolyProjectionPredicate<'tcx>,
+    ) -> Option<Ty<'tcx>> {
+        debug!("deduce_future_output_from_projection(predicate={:?})", predicate);
+
+        // We do not expect any bound regions in our predicate, so
+        // skip past the bound vars.
+        let predicate = match predicate.no_bound_vars() {
+            Some(p) => p,
+            None => {
+                debug!("deduce_future_output_from_projection: has late-bound regions");
+                return None;
+            }
+        };
+
+        // Check that this is a projection from the `Future` trait.
+        let trait_ref = predicate.projection_ty.trait_ref(self.tcx);
+        let future_trait = self.tcx.lang_items().future_trait().unwrap();
+        if trait_ref.def_id != future_trait {
+            debug!("deduce_future_output_from_projection: not a future");
+            return None;
+        }
+
+        // The `Future` trait has only one associted item, `Output`,
+        // so check that this is what we see.
+        let output_assoc_item = self.tcx.associated_items(future_trait).nth(0).unwrap().def_id;
+        if output_assoc_item != predicate.projection_ty.item_def_id {
+            span_bug!(
+                cause_span,
+                "projecting associated item `{:?}` from future, which is not Output `{:?}`",
+                predicate.projection_ty.item_def_id,
+                output_assoc_item,
+            );
+        }
+
+        // Extract the type from the projection. Note that there can
+        // be no bound variables in this type because the "self type"
+        // does not have any regions in it.
+        let output_ty = self.resolve_vars_if_possible(&predicate.ty);
+        debug!("deduce_future_output_from_projection: output_ty={:?}", output_ty);
+        Some(output_ty)
+    }
+
     /// Converts the types that the user supplied, in case that doing
     /// so should yield an error, but returns back a signature where
     /// all parameters are of type `TyErr`.
     fn error_sig_of_closure(&self, decl: &hir::FnDecl) -> ty::PolyFnSig<'tcx> {
-        let astconv: &dyn AstConv = self;
+        let astconv: &dyn AstConv<'_> = self;
 
         let supplied_arguments = decl.inputs.iter().map(|a| {
             // Convert the types that the user supplied (if any), but ignore them.
@@ -621,7 +775,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let result = ty::Binder::bind(self.tcx.mk_fn_sig(
             supplied_arguments,
             self.tcx.types.err,
-            decl.variadic,
+            decl.c_variadic,
             hir::Unsafety::Normal,
             Abi::RustCall,
         ));
@@ -641,7 +795,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             .liberate_late_bound_regions(expr_def_id, &bound_sig);
         let liberated_sig = self.inh.normalize_associated_types_in(
             body.value.span,
-            body.value.id,
+            body.value.hir_id,
             self.param_env,
             &liberated_sig,
         );