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;
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!(
&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!(
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,
self.param_env,
liberated_sig,
decl,
- expr.id,
+ expr.hir_id,
body,
gen,
).1;
// 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
self.tcx.mk_fn_sig(
iter::once(self.tcx.intern_tup(sig.inputs())),
sig.output(),
- sig.variadic,
+ sig.c_variadic,
sig.unsafety,
sig.abi,
)
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),
);
}
expected_ty
);
- match expected_ty.sty {
+ match expected_ty.kind {
ty::Dynamic(ref object_type, ..) => {
let sig = object_type
.projection_bounds()
}
/// 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
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 })
}
) -> 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)
}
///
/// # 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
// 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(
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,
));
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(
//
// (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={:?}",
); // 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);
);
all_obligations.push(
Obligation::new(
- cause.clone(),
+ cause,
self.param_env,
ty::Predicate::TypeOutlives(
ty::Binder::dummy(
&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,
));
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.
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,
));
.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,
);