summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_typeck/src/closure.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:21 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:21 +0000
commit4e8199b572f2035b7749cba276ece3a26630d23e (patch)
treef09feeed6a0fe39d027b1908aa63ea6b35e4b631 /compiler/rustc_hir_typeck/src/closure.rs
parentAdding upstream version 1.66.0+dfsg1. (diff)
downloadrustc-4e8199b572f2035b7749cba276ece3a26630d23e.tar.xz
rustc-4e8199b572f2035b7749cba276ece3a26630d23e.zip
Adding upstream version 1.67.1+dfsg1.upstream/1.67.1+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_hir_typeck/src/closure.rs')
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs250
1 files changed, 115 insertions, 135 deletions
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index a5a45f75e..429cb60ba 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -4,24 +4,26 @@ use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
use hir::def::DefKind;
use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::LocalDefId;
use rustc_hir::lang_items::LangItem;
use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_infer::infer::{InferOk, InferResult};
+use rustc_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{self, Ty};
use rustc_span::source_map::Span;
use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::traits;
use rustc_trait_selection::traits::error_reporting::ArgKind;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use std::cmp;
use std::iter;
/// What signature do we *expect* the closure to have from context?
-#[derive(Debug)]
+#[derive(Debug, Clone, TypeFoldable, TypeVisitable)]
struct ExpectedSig<'tcx> {
/// Span that gave us this expectation, if we know that.
cause_span: Option<Span>,
@@ -33,24 +35,20 @@ struct ClosureSignatures<'tcx> {
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
+ /// opaque types from the signature expectation are overridden in case there are
/// explicit hidden types written by the user in the closure signature.
liberated_sig: ty::FnSig<'tcx>,
}
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
- #[instrument(skip(self, expr, _capture, decl, body_id), level = "debug")]
+ #[instrument(skip(self, closure), level = "debug")]
pub fn check_expr_closure(
&self,
- expr: &hir::Expr<'_>,
- _capture: hir::CaptureBy,
- decl: &'tcx hir::FnDecl<'tcx>,
- body_id: hir::BodyId,
- gen: Option<hir::Movability>,
+ closure: &hir::Closure<'tcx>,
+ expr_span: Span,
expected: Expectation<'tcx>,
) -> Ty<'tcx> {
- trace!("decl = {:#?}", decl);
- trace!("expr = {:#?}", expr);
+ trace!("decl = {:#?}", closure.fn_decl);
// It's always helpful for inference if we know the kind of
// closure sooner rather than later, so first examine the expected
@@ -59,42 +57,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Some(ty) => self.deduce_expectations_from_expected_type(ty),
None => (None, None),
};
- let body = self.tcx.hir().body(body_id);
- self.check_closure(expr, expected_kind, decl, body, gen, expected_sig)
+ let body = self.tcx.hir().body(closure.body);
+ self.check_closure(closure, expr_span, expected_kind, body, expected_sig)
}
- #[instrument(skip(self, expr, body, decl), level = "debug", ret)]
+ #[instrument(skip(self, closure, body), level = "debug", ret)]
fn check_closure(
&self,
- expr: &hir::Expr<'_>,
+ closure: &hir::Closure<'tcx>,
+ expr_span: Span,
opt_kind: Option<ty::ClosureKind>,
- decl: &'tcx hir::FnDecl<'tcx>,
body: &'tcx hir::Body<'tcx>,
- gen: Option<hir::Movability>,
expected_sig: Option<ExpectedSig<'tcx>>,
) -> Ty<'tcx> {
- trace!("decl = {:#?}", decl);
- let expr_def_id = self.tcx.hir().local_def_id(expr.hir_id);
+ trace!("decl = {:#?}", closure.fn_decl);
+ let expr_def_id = closure.def_id;
debug!(?expr_def_id);
let ClosureSignatures { bound_sig, liberated_sig } =
- self.sig_of_closure(expr.hir_id, expr_def_id.to_def_id(), decl, body, expected_sig);
+ self.sig_of_closure(expr_def_id, closure.fn_decl, body, expected_sig);
debug!(?bound_sig, ?liberated_sig);
- let return_type_pre_known = !liberated_sig.output().is_ty_infer();
-
+ let mut fcx = FnCtxt::new(self, self.param_env.without_const(), body.value.hir_id);
let generator_types = check_fn(
- self,
- self.param_env.without_const(),
+ &mut fcx,
liberated_sig,
- decl,
- expr.hir_id,
+ closure.fn_decl,
+ expr_def_id,
body,
- gen,
- return_type_pre_known,
- )
- .1;
+ closure.movability,
+ );
let parent_substs = InternalSubsts::identity_for_item(
self.tcx,
@@ -103,7 +96,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let tupled_upvars_ty = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::ClosureSynthetic,
- span: self.tcx.hir().span(expr.hir_id),
+ span: self.tcx.def_span(expr_def_id),
});
if let Some(GeneratorTypes { resume_ty, yield_ty, interior, movability }) = generator_types
@@ -149,7 +142,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
None => self.next_ty_var(TypeVariableOrigin {
// FIXME(eddyb) distinguish closure kind inference variables from the rest.
kind: TypeVariableOriginKind::ClosureSynthetic,
- span: expr.span,
+ span: expr_span,
}),
};
@@ -174,34 +167,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected_ty: Ty<'tcx>,
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
match *expected_ty.kind() {
- ty::Opaque(def_id, substs) => {
- let bounds = self.tcx.bound_explicit_item_bounds(def_id);
- let sig =
- bounds.subst_iter_copied(self.tcx, substs).find_map(|(pred, span)| match pred
- .kind()
- .skip_binder()
- {
- ty::PredicateKind::Projection(proj_predicate) => self
- .deduce_sig_from_projection(
- Some(span),
- pred.kind().rebind(proj_predicate),
- ),
- _ => None,
- });
-
- let kind = bounds
- .0
- .iter()
- .filter_map(|(pred, _)| match pred.kind().skip_binder() {
- ty::PredicateKind::Trait(tp) => {
- self.tcx.fn_trait_kind_from_lang_item(tp.def_id())
- }
- _ => None,
- })
- .fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));
- trace!(?sig, ?kind);
- (sig, kind)
- }
+ ty::Opaque(def_id, substs) => self.deduce_signature_from_predicates(
+ self.tcx.bound_explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs),
+ ),
ty::Dynamic(ref object_type, ..) => {
let sig = object_type.projection_bounds().find_map(|pb| {
let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self);
@@ -209,10 +177,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
});
let kind = object_type
.principal_def_id()
- .and_then(|did| self.tcx.fn_trait_kind_from_lang_item(did));
+ .and_then(|did| self.tcx.fn_trait_kind_from_def_id(did));
(sig, kind)
}
- ty::Infer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid),
+ ty::Infer(ty::TyVar(vid)) => self.deduce_signature_from_predicates(
+ self.obligations_for_self_ty(vid).map(|obl| (obl.predicate, obl.cause.span)),
+ ),
ty::FnPtr(sig) => {
let expected_sig = ExpectedSig { cause_span: None, sig };
(Some(expected_sig), Some(ty::ClosureKind::Fn))
@@ -221,37 +191,57 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- fn deduce_expectations_from_obligations(
+ fn deduce_signature_from_predicates(
&self,
- expected_vid: ty::TyVid,
+ predicates: impl DoubleEndedIterator<Item = (ty::Predicate<'tcx>, Span)>,
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
- let expected_sig =
- self.obligations_for_self_ty(expected_vid).find_map(|(_, obligation)| {
- debug!(?obligation.predicate);
-
- let bound_predicate = obligation.predicate.kind();
- if let ty::PredicateKind::Projection(proj_predicate) =
- obligation.predicate.kind().skip_binder()
- {
- // Given a Projection predicate, we can potentially infer
- // the complete signature.
+ let mut expected_sig = None;
+ let mut expected_kind = None;
+
+ for obligation in traits::elaborate_predicates_with_span(
+ self.tcx,
+ // Reverse the obligations here, since `elaborate_*` uses a stack,
+ // and we want to keep inference generally in the same order of
+ // the registered obligations.
+ predicates.rev(),
+ ) {
+ debug!(?obligation.predicate);
+ let bound_predicate = obligation.predicate.kind();
+
+ // Given a Projection predicate, we can potentially infer
+ // the complete signature.
+ if expected_sig.is_none()
+ && let ty::PredicateKind::Clause(ty::Clause::Projection(proj_predicate)) = bound_predicate.skip_binder()
+ {
+ expected_sig = self.normalize(
+ obligation.cause.span,
self.deduce_sig_from_projection(
- Some(obligation.cause.span),
+ Some(obligation.cause.span),
bound_predicate.rebind(proj_predicate),
- )
- } else {
- None
- }
- });
+ ),
+ );
+ }
- // Even if we can't infer the full signature, we may be able to
- // infer the kind. This can occur when we elaborate a predicate
- // like `F : Fn<A>`. Note that due to subtyping we could encounter
- // many viable options, so pick the most restrictive.
- let expected_kind = self
- .obligations_for_self_ty(expected_vid)
- .filter_map(|(tr, _)| self.tcx.fn_trait_kind_from_lang_item(tr.def_id()))
- .fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));
+ // Even if we can't infer the full signature, we may be able to
+ // infer the kind. This can occur when we elaborate a predicate
+ // like `F : Fn<A>`. Note that due to subtyping we could encounter
+ // many viable options, so pick the most restrictive.
+ let trait_def_id = match bound_predicate.skip_binder() {
+ ty::PredicateKind::Clause(ty::Clause::Projection(data)) => {
+ Some(data.projection_ty.trait_def_id(self.tcx))
+ }
+ ty::PredicateKind::Clause(ty::Clause::Trait(data)) => Some(data.def_id()),
+ _ => None,
+ };
+ if let Some(closure_kind) =
+ trait_def_id.and_then(|def_id| self.tcx.fn_trait_kind_from_def_id(def_id))
+ {
+ expected_kind = Some(
+ expected_kind
+ .map_or_else(|| closure_kind, |current| cmp::min(current, closure_kind)),
+ );
+ }
+ }
(expected_sig, expected_kind)
}
@@ -272,7 +262,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let trait_def_id = projection.trait_def_id(tcx);
- let is_fn = tcx.fn_trait_kind_from_lang_item(trait_def_id).is_some();
+ let is_fn = tcx.is_fn_trait(trait_def_id);
let gen_trait = tcx.require_lang_item(LangItem::Generator, cause_span);
let is_gen = gen_trait == trait_def_id;
if !is_fn && !is_gen {
@@ -323,30 +313,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn sig_of_closure(
&self,
- hir_id: hir::HirId,
- expr_def_id: DefId,
+ expr_def_id: LocalDefId,
decl: &hir::FnDecl<'_>,
body: &hir::Body<'_>,
expected_sig: Option<ExpectedSig<'tcx>>,
) -> ClosureSignatures<'tcx> {
if let Some(e) = expected_sig {
- self.sig_of_closure_with_expectation(hir_id, expr_def_id, decl, body, e)
+ self.sig_of_closure_with_expectation(expr_def_id, decl, body, e)
} else {
- self.sig_of_closure_no_expectation(hir_id, expr_def_id, decl, body)
+ self.sig_of_closure_no_expectation(expr_def_id, decl, body)
}
}
/// If there is no expected signature, then we will convert the
/// types that the user gave into a signature.
- #[instrument(skip(self, hir_id, expr_def_id, decl, body), level = "debug")]
+ #[instrument(skip(self, expr_def_id, decl, body), level = "debug")]
fn sig_of_closure_no_expectation(
&self,
- hir_id: hir::HirId,
- expr_def_id: DefId,
+ expr_def_id: LocalDefId,
decl: &hir::FnDecl<'_>,
body: &hir::Body<'_>,
) -> ClosureSignatures<'tcx> {
- let bound_sig = self.supplied_sig_of_closure(hir_id, expr_def_id, decl, body);
+ let bound_sig = self.supplied_sig_of_closure(expr_def_id, decl, body);
self.closure_sigs(expr_def_id, body, bound_sig)
}
@@ -392,17 +380,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
///
/// # Arguments
///
- /// - `expr_def_id`: the `DefId` of the closure expression
+ /// - `expr_def_id`: the `LocalDefId` 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
/// this is missing a binder: that is, there may be late-bound
/// regions with depth 1, which are bound then by the closure.
- #[instrument(skip(self, hir_id, expr_def_id, decl, body), level = "debug")]
+ #[instrument(skip(self, expr_def_id, decl, body), level = "debug")]
fn sig_of_closure_with_expectation(
&self,
- hir_id: hir::HirId,
- expr_def_id: DefId,
+ expr_def_id: LocalDefId,
decl: &hir::FnDecl<'_>,
body: &hir::Body<'_>,
expected_sig: ExpectedSig<'tcx>,
@@ -411,7 +398,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// expectation if things don't see to match up with what we
// expect.
if expected_sig.sig.c_variadic() != decl.c_variadic {
- return self.sig_of_closure_no_expectation(hir_id, expr_def_id, decl, body);
+ return self.sig_of_closure_no_expectation(expr_def_id, decl, body);
} else if expected_sig.sig.skip_binder().inputs_and_output.len() != decl.inputs.len() + 1 {
return self.sig_of_closure_with_mismatched_number_of_arguments(
expr_def_id,
@@ -447,27 +434,21 @@ 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.merge_supplied_sig_with_expectation(
- hir_id,
- expr_def_id,
- decl,
- body,
- closure_sigs,
- ) {
+ match self.merge_supplied_sig_with_expectation(expr_def_id, decl, body, closure_sigs) {
Ok(infer_ok) => self.register_infer_ok_obligations(infer_ok),
- Err(_) => self.sig_of_closure_no_expectation(hir_id, expr_def_id, decl, body),
+ Err(_) => self.sig_of_closure_no_expectation(expr_def_id, decl, body),
}
}
fn sig_of_closure_with_mismatched_number_of_arguments(
&self,
- expr_def_id: DefId,
+ expr_def_id: LocalDefId,
decl: &hir::FnDecl<'_>,
body: &hir::Body<'_>,
expected_sig: ExpectedSig<'tcx>,
) -> ClosureSignatures<'tcx> {
let hir = self.tcx.hir();
- let expr_map_node = hir.get_if_local(expr_def_id).unwrap();
+ let expr_map_node = hir.get_by_def_id(expr_def_id);
let expected_args: Vec<_> = expected_sig
.sig
.skip_binder()
@@ -475,18 +456,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.iter()
.map(|ty| ArgKind::from_expected_ty(*ty, None))
.collect();
- let (closure_span, found_args) = match self.get_fn_like_arguments(expr_map_node) {
- Some((sp, args)) => (Some(sp), args),
- None => (None, Vec::new()),
- };
+ let (closure_span, closure_arg_span, found_args) =
+ match self.get_fn_like_arguments(expr_map_node) {
+ Some((sp, arg_sp, args)) => (Some(sp), arg_sp, args),
+ None => (None, None, Vec::new()),
+ };
let expected_span =
- expected_sig.cause_span.unwrap_or_else(|| hir.span_if_local(expr_def_id).unwrap());
+ expected_sig.cause_span.unwrap_or_else(|| self.tcx.def_span(expr_def_id));
self.report_arg_count_mismatch(
expected_span,
closure_span,
expected_args,
found_args,
true,
+ closure_arg_span,
)
.emit();
@@ -498,11 +481,10 @@ 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.
- #[instrument(level = "debug", skip(self, hir_id, expr_def_id, decl, body, expected_sigs))]
+ #[instrument(level = "debug", skip(self, expr_def_id, decl, body, expected_sigs))]
fn merge_supplied_sig_with_expectation(
&self,
- hir_id: hir::HirId,
- expr_def_id: DefId,
+ expr_def_id: LocalDefId,
decl: &hir::FnDecl<'_>,
body: &hir::Body<'_>,
mut expected_sigs: ClosureSignatures<'tcx>,
@@ -511,7 +493,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
//
// (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);
+ let supplied_sig = self.supplied_sig_of_closure(expr_def_id, decl, body);
debug!(?supplied_sig);
@@ -591,8 +573,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
#[instrument(skip(self, decl, body), level = "debug", ret)]
fn supplied_sig_of_closure(
&self,
- hir_id: hir::HirId,
- expr_def_id: DefId,
+ expr_def_id: LocalDefId,
decl: &hir::FnDecl<'_>,
body: &hir::Body<'_>,
) -> ty::PolyFnSig<'tcx> {
@@ -601,6 +582,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
trace!("decl = {:#?}", decl);
debug!(?body.generator_kind);
+ let hir_id = self.tcx.hir().local_def_id_to_hir_id(expr_def_id);
let bound_vars = self.tcx.late_bound_vars(hir_id);
// First, convert the types that the user supplied (if any).
@@ -642,7 +624,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
// Astconv can't normalize inputs or outputs with escaping bound vars,
// so normalize them here, after we've wrapped them in a binder.
- let result = self.normalize_associated_types_in(self.tcx.hir().span(hir_id), result);
+ let result = self.normalize(self.tcx.hir().span(hir_id), result);
let c_result = self.inh.infcx.canonicalize_response(result);
self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result);
@@ -659,7 +641,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
#[instrument(skip(self), level = "debug", ret)]
fn deduce_future_output_from_obligations(
&self,
- expr_def_id: DefId,
+ expr_def_id: LocalDefId,
body_id: hir::HirId,
) -> Option<Ty<'tcx>> {
let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| {
@@ -677,7 +659,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// where R is the return type we are expecting. This type `T`
// will be our output.
let bound_predicate = predicate.kind();
- if let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder() {
+ if let ty::PredicateKind::Clause(ty::Clause::Projection(proj_predicate)) =
+ bound_predicate.skip_binder()
+ {
self.deduce_future_output_from_projection(
span,
bound_predicate.rebind(proj_predicate),
@@ -689,7 +673,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let output_ty = match *ret_ty.kind() {
ty::Infer(ty::TyVar(ret_vid)) => {
- self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| {
+ self.obligations_for_self_ty(ret_vid).find_map(|obligation| {
get_future_output(obligation.predicate, obligation.cause.span)
})?
}
@@ -808,17 +792,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn closure_sigs(
&self,
- expr_def_id: DefId,
+ expr_def_id: LocalDefId,
body: &hir::Body<'_>,
bound_sig: ty::PolyFnSig<'tcx>,
) -> ClosureSignatures<'tcx> {
- let liberated_sig = self.tcx().liberate_late_bound_regions(expr_def_id, bound_sig);
- let liberated_sig = self.inh.normalize_associated_types_in(
- body.value.span,
- body.value.hir_id,
- self.param_env,
- liberated_sig,
- );
+ let liberated_sig =
+ self.tcx().liberate_late_bound_regions(expr_def_id.to_def_id(), bound_sig);
+ let liberated_sig = self.normalize(body.value.span, liberated_sig);
ClosureSignatures { bound_sig, liberated_sig }
}
}