summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_typeck
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:20:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:20:39 +0000
commit1376c5a617be5c25655d0d7cb63e3beaa5a6e026 (patch)
tree3bb8d61aee02bc7a15eab3f36e3b921afc2075d0 /compiler/rustc_hir_typeck
parentReleasing progress-linux version 1.69.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-1376c5a617be5c25655d0d7cb63e3beaa5a6e026.tar.xz
rustc-1376c5a617be5c25655d0d7cb63e3beaa5a6e026.zip
Merging upstream version 1.70.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_hir_typeck')
-rw-r--r--compiler/rustc_hir_typeck/messages.ftl (renamed from compiler/rustc_hir_typeck/locales/en-US.ftl)4
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs18
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs51
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs75
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs421
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs83
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs18
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs216
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs121
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs91
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs91
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/mod.rs36
-rw-r--r--compiler/rustc_hir_typeck/src/inherited.rs50
-rw-r--r--compiler/rustc_hir_typeck/src/intrinsicck.rs11
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs236
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs20
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs14
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs102
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs132
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs43
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs44
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs31
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs5
27 files changed, 1033 insertions, 909 deletions
diff --git a/compiler/rustc_hir_typeck/locales/en-US.ftl b/compiler/rustc_hir_typeck/messages.ftl
index adfcbc36a..2c537bf40 100644
--- a/compiler/rustc_hir_typeck/locales/en-US.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -4,14 +4,14 @@ hir_typeck_field_multiply_specified_in_initializer =
.previous_use_label = first use of `{$ident}`
hir_typeck_copy_impl_on_type_with_dtor =
- the trait `Copy` may not be implemented for this type; the type has a destructor
+ the trait `Copy` cannot be implemented for this type; the type has a destructor
.label = `Copy` not allowed on types with destructors
hir_typeck_multiple_relaxed_default_bounds =
type parameter has more than one relaxed default bound, only one is supported
hir_typeck_copy_impl_on_non_adt =
- the trait `Copy` may not be implemented for this type
+ the trait `Copy` cannot be implemented for this type
.label = type is not a structure or enumeration
hir_typeck_trait_object_declared_with_no_traits =
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index e19ef2ff3..6c2ce6272 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -299,7 +299,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
// check that the `if` expr without `else` is the fn body's expr
if expr.span == sp {
- return self.get_fn_decl(hir_id).and_then(|(fn_decl, _)| {
+ return self.get_fn_decl(hir_id).and_then(|(_, fn_decl, _)| {
let span = fn_decl.output.span();
let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok()?;
Some((span, format!("expected `{snippet}` because of this return type")))
@@ -538,8 +538,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// FIXME(rpitit): This will need to be fixed when we move to associated types
assert!(matches!(
*trait_pred.trait_ref.self_ty().kind(),
- ty::Alias(_, ty::AliasTy { def_id, substs, .. })
- if def_id == rpit_def_id && substs == substs
+ ty::Alias(_, ty::AliasTy { def_id, substs: alias_substs, .. })
+ if def_id == rpit_def_id && substs == alias_substs
));
ty::PredicateKind::Clause(ty::Clause::Trait(
trait_pred.with_self_ty(self.tcx, ty),
@@ -548,8 +548,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::PredicateKind::Clause(ty::Clause::Projection(mut proj_pred)) => {
assert!(matches!(
*proj_pred.projection_ty.self_ty().kind(),
- ty::Alias(_, ty::AliasTy { def_id, substs, .. })
- if def_id == rpit_def_id && substs == substs
+ ty::Alias(_, ty::AliasTy { def_id, substs: alias_substs, .. })
+ if def_id == rpit_def_id && substs == alias_substs
));
proj_pred = proj_pred.with_self_ty(self.tcx, ty);
ty::PredicateKind::Clause(ty::Clause::Projection(proj_pred))
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 6a0d5c011..5235710a2 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -311,9 +311,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let fn_decl_span = if hir.body(body).generator_kind
== Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure))
{
- // Actually need to unwrap a few more layers of HIR to get to
+ // Actually need to unwrap one more layer of HIR to get to
// the _real_ closure...
- let async_closure = hir.parent_id(hir.parent_id(parent_hir_id));
+ let async_closure = hir.parent_id(parent_hir_id);
if let hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
..
@@ -668,7 +668,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_ty)
- && !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span)
+ && !self.type_is_sized_modulo_regions(self.param_env, output_ty)
{
let descr = match maybe_def {
DefIdOrName::DefId(def_id) => self.tcx.def_descr(def_id),
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 316c2a7ee..1481c038c 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -96,20 +96,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let t = self.resolve_vars_if_possible(t);
t.error_reported()?;
- if self.type_is_sized_modulo_regions(self.param_env, t, span) {
+ if self.type_is_sized_modulo_regions(self.param_env, t) {
return Ok(Some(PointerKind::Thin));
}
Ok(match *t.kind() {
ty::Slice(_) | ty::Str => Some(PointerKind::Length),
ty::Dynamic(ref tty, _, ty::Dyn) => Some(PointerKind::VTable(tty.principal_def_id())),
- ty::Adt(def, substs) if def.is_struct() => match def.non_enum_variant().fields.last() {
- None => Some(PointerKind::Thin),
- Some(f) => {
- let field_ty = self.field_ty(span, f, substs);
- self.pointer_kind(field_ty, span)?
+ ty::Adt(def, substs) if def.is_struct() => {
+ match def.non_enum_variant().fields.raw.last() {
+ None => Some(PointerKind::Thin),
+ Some(f) => {
+ let field_ty = self.field_ty(span, f, substs);
+ self.pointer_kind(field_ty, span)?
+ }
}
- },
+ }
ty::Tuple(fields) => match fields.last() {
None => Some(PointerKind::Thin),
Some(&f) => self.pointer_kind(f, span)?,
@@ -722,7 +724,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty);
- if !fcx.type_is_sized_modulo_regions(fcx.param_env, self.cast_ty, self.span)
+ if !fcx.type_is_sized_modulo_regions(fcx.param_env, self.cast_ty)
&& !self.cast_ty.has_infer_types()
{
self.report_cast_to_unsized_type(fcx);
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index d84fabb78..8c2495e1d 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -2,13 +2,12 @@
use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
-use hir::def::DefKind;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
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::{DefineOpaqueTypes, LateBoundRegionConversionTime};
use rustc_infer::infer::{InferOk, InferResult};
use rustc_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::ty::subst::InternalSubsts;
@@ -205,15 +204,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut expected_sig = None;
let mut expected_kind = None;
- for obligation in traits::elaborate_predicates_with_span(
+ for (pred, span) in traits::elaborate(
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();
+ )
+ // We only care about self bounds
+ .filter_only_self()
+ {
+ debug!(?pred);
+ let bound_predicate = pred.kind();
// Given a Projection predicate, we can potentially infer
// the complete signature.
@@ -221,9 +223,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& let ty::PredicateKind::Clause(ty::Clause::Projection(proj_predicate)) = bound_predicate.skip_binder()
{
let inferred_sig = self.normalize(
- obligation.cause.span,
+ span,
self.deduce_sig_from_projection(
- Some(obligation.cause.span),
+ Some(span),
bound_predicate.rebind(proj_predicate),
),
);
@@ -398,7 +400,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
///
/// Here:
/// - E would be `fn(&u32) -> &u32`.
- /// - S would be `fn(&u32) ->
+ /// - S would be `fn(&u32) -> ?T`
/// - E' is `&'!0 u32 -> &'!0 u32`
/// - S' is `&'?0 u32 -> ?T`
///
@@ -563,10 +565,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) {
// Check that E' = S'.
let cause = self.misc(hir_ty.span);
- let InferOk { value: (), obligations } = self
- .at(&cause, self.param_env)
- .define_opaque_types(true)
- .eq(*expected_ty, supplied_ty)?;
+ let InferOk { value: (), obligations } = self.at(&cause, self.param_env).eq(
+ DefineOpaqueTypes::Yes,
+ *expected_ty,
+ supplied_ty,
+ )?;
all_obligations.extend(obligations);
}
@@ -576,10 +579,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
supplied_sig.output(),
);
let cause = &self.misc(decl.output.span());
- let InferOk { value: (), obligations } = self
- .at(cause, self.param_env)
- .define_opaque_types(true)
- .eq(expected_sigs.liberated_sig.output(), supplied_output_ty)?;
+ let InferOk { value: (), obligations } = self.at(cause, self.param_env).eq(
+ DefineOpaqueTypes::Yes,
+ expected_sigs.liberated_sig.output(),
+ supplied_output_ty,
+ )?;
all_obligations.extend(obligations);
let inputs = inputs.into_iter().map(|ty| self.resolve_vars_if_possible(ty));
@@ -713,14 +717,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.subst_iter_copied(self.tcx, substs)
.find_map(|(p, s)| get_future_output(p, s))?,
ty::Error(_) => return None,
- ty::Alias(ty::Projection, proj)
- if self.tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder =>
- {
- self.tcx
- .bound_explicit_item_bounds(proj.def_id)
- .subst_iter_copied(self.tcx, proj.substs)
- .find_map(|(p, s)| get_future_output(p, s))?
- }
+ ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => self
+ .tcx
+ .bound_explicit_item_bounds(proj.def_id)
+ .subst_iter_copied(self.tcx, proj.substs)
+ .find_map(|(p, s)| get_future_output(p, s))?,
_ => span_bug!(
self.tcx.def_span(expr_def_id),
"async fn generator return type not an inference variable: {ret_ty}"
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 00b86890b..8fa3bcd68 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -45,8 +45,8 @@ use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::Expr;
use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::{Coercion, InferOk, InferResult};
-use rustc_infer::traits::Obligation;
+use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult};
+use rustc_infer::traits::{Obligation, PredicateObligation};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
@@ -143,11 +143,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub);
self.commit_if_ok(|_| {
- let at = self.at(&self.cause, self.fcx.param_env).define_opaque_types(true);
+ let at = self.at(&self.cause, self.fcx.param_env);
if self.use_lub {
- at.lub(b, a)
+ at.lub(DefineOpaqueTypes::Yes, b, a)
} else {
- at.sup(b, a)
+ at.sup(DefineOpaqueTypes::Yes, b, a)
.map(|InferOk { value: (), obligations }| InferOk { value: a, obligations })
}
})
@@ -175,7 +175,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// so this will have the side-effect of making sure we have no ambiguities
// due to `[type error]` and `_` not coercing together.
let _ = self.commit_if_ok(|_| {
- self.at(&self.cause, self.param_env).define_opaque_types(true).eq(a, b)
+ self.at(&self.cause, self.param_env).eq(DefineOpaqueTypes::Yes, a, b)
});
return success(vec![], self.fcx.tcx.ty_error(guar), vec![]);
}
@@ -597,13 +597,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// and almost never more than 3. By using a SmallVec we avoid an
// allocation, at the (very small) cost of (occasionally) having to
// shift subsequent elements down when removing the front element.
- let mut queue: SmallVec<[_; 4]> = smallvec![traits::predicate_for_trait_def(
+ let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![Obligation::new(
self.tcx,
- self.fcx.param_env,
cause,
- coerce_unsized_did,
- 0,
- [coerce_source, coerce_target]
+ self.fcx.param_env,
+ self.tcx.mk_trait_ref(coerce_unsized_did, [coerce_source, coerce_target])
)];
let mut has_unsized_tuple_coercion = false;
@@ -651,9 +649,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
let self_ty = trait_pred.skip_binder().self_ty();
let unsize_ty = trait_pred.skip_binder().trait_ref.substs[1].expect_ty();
debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred);
- match (&self_ty.kind(), &unsize_ty.kind()) {
- (ty::Infer(ty::TyVar(v)), ty::Dynamic(..))
- if self.type_var_is_sized(*v) =>
+ match (self_ty.kind(), unsize_ty.kind()) {
+ (&ty::Infer(ty::TyVar(v)), ty::Dynamic(..))
+ if self.type_var_is_sized(v) =>
{
debug!("coerce_unsized: have sized infer {:?}", v);
coercion.obligations.push(obligation);
@@ -1101,9 +1099,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(ty::FnDef(..), ty::FnDef(..)) => {
// Don't reify if the function types have a LUB, i.e., they
// are the same function and their parameters have a LUB.
- match self
- .commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty))
- {
+ match self.commit_if_ok(|_| {
+ self.at(cause, self.param_env).lub(
+ DefineOpaqueTypes::No,
+ prev_ty,
+ new_ty,
+ )
+ }) {
// We have a LUB of prev_ty and new_ty, just return it.
Ok(ok) => return Ok(self.register_infer_ok_obligations(ok)),
Err(_) => {
@@ -1153,7 +1155,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let sig = self
.at(cause, self.param_env)
.trace(prev_ty, new_ty)
- .lub(a_sig, b_sig)
+ .lub(DefineOpaqueTypes::No, a_sig, b_sig)
.map(|ok| self.register_infer_ok_obligations(ok))?;
// Reify both sides and return the reified fn pointer type.
@@ -1237,7 +1239,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
return self
- .commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty))
+ .commit_if_ok(|_| {
+ self.at(cause, self.param_env).lub(DefineOpaqueTypes::No, prev_ty, new_ty)
+ })
.map(|ok| self.register_infer_ok_obligations(ok));
}
}
@@ -1248,8 +1252,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some(e) = first_error {
Err(e)
} else {
- self.commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty))
- .map(|ok| self.register_infer_ok_obligations(ok))
+ self.commit_if_ok(|_| {
+ self.at(cause, self.param_env).lub(DefineOpaqueTypes::No, prev_ty, new_ty)
+ })
+ .map(|ok| self.register_infer_ok_obligations(ok))
}
}
Ok(ok) => {
@@ -1487,8 +1493,12 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
assert!(expression_ty.is_unit(), "if let hack without unit type");
fcx.at(cause, fcx.param_env)
// needed for tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs
- .define_opaque_types(true)
- .eq_exp(label_expression_as_expected, expression_ty, self.merged_ty())
+ .eq_exp(
+ DefineOpaqueTypes::Yes,
+ label_expression_as_expected,
+ expression_ty,
+ self.merged_ty(),
+ )
.map(|infer_ok| {
fcx.register_infer_ok_obligations(infer_ok);
expression_ty
@@ -1710,12 +1720,13 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
fcx.suggest_semicolon_at_end(cond_expr.span, &mut err);
}
}
- fcx.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
+ fcx.get_node_fn_decl(parent)
+ .map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main))
} else {
fcx.get_fn_decl(parent_id)
};
- if let Some((fn_decl, can_suggest)) = fn_decl {
+ if let Some((fn_id, fn_decl, can_suggest)) = fn_decl {
if blk_id.is_none() {
pointing_at_return_type |= fcx.suggest_missing_return_type(
&mut err,
@@ -1723,7 +1734,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
expected,
found,
can_suggest,
- fcx.tcx.hir().get_parent_item(id).into(),
+ fn_id,
);
}
if !pointing_at_return_type {
@@ -1734,17 +1745,11 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
let parent_id = fcx.tcx.hir().get_parent_item(id);
let parent_item = fcx.tcx.hir().get_by_def_id(parent_id.def_id);
- if let (Some(expr), Some(_), Some((fn_decl, _, _))) =
+ if let (Some(expr), Some(_), Some((fn_id, fn_decl, _, _))) =
(expression, blk_id, fcx.get_node_fn_decl(parent_item))
{
fcx.suggest_missing_break_or_return_expr(
- &mut err,
- expr,
- fn_decl,
- expected,
- found,
- id,
- parent_id.into(),
+ &mut err, expr, fn_decl, expected, found, id, fn_id,
);
}
@@ -1870,7 +1875,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
}
fn is_return_ty_unsized<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool {
- if let Some((fn_decl, _)) = fcx.get_fn_decl(blk_id)
+ if let Some((_, fn_decl, _)) = fcx.get_fn_decl(blk_id)
&& let hir::FnRetTy::Return(ty) = fn_decl.output
&& let ty = fcx.astconv().ast_ty_to_ty( ty)
&& let ty::Dynamic(..) = ty.kind()
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 7ba57b3b7..13442c316 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -1,6 +1,5 @@
use crate::FnCtxt;
use rustc_ast::util::parser::PREC_POSTFIX;
-use rustc_data_structures::fx::FxHashMap;
use rustc_errors::MultiSpan;
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
@@ -8,19 +7,18 @@ use rustc_hir::def::CtorKind;
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{is_range_literal, Node};
-use rustc_infer::infer::InferOk;
+use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
use rustc_middle::lint::in_external_macro;
use rustc_middle::middle::stability::EvalResult;
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::fold::{BottomUpFolder, TypeFolder};
-use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths};
-use rustc_middle::ty::relate::TypeRelation;
-use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut, TypeVisitableExt};
+use rustc_middle::ty::fold::BottomUpFolder;
+use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut, TypeFoldable};
use rustc_span::symbol::{sym, Symbol};
-use rustc_span::{BytePos, Span};
+use rustc_span::{BytePos, Span, DUMMY_SP};
+use rustc_target::abi::FieldIdx;
use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::traits::error_reporting::method_chain::CollectAllMismatches;
use rustc_trait_selection::traits::ObligationCause;
use super::method::probe;
@@ -61,9 +59,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|| self.suggest_into(err, expr, expr_ty, expected)
|| self.suggest_floating_point_literal(err, expr, expected)
|| self.suggest_null_ptr_for_literal_zero_given_to_ptr_arg(err, expr, expected)
- || self.note_result_coercion(err, expr, expected, expr_ty);
+ || self.suggest_coercing_result_via_try_operator(err, expr, expected, expr_ty);
+
if !suggested {
- self.point_at_expr_source_of_inferred_type(err, expr, expr_ty, expected, expr.span);
+ self.note_source_of_type_mismatch_constraint(
+ err,
+ expr,
+ TypeMismatchSource::Ty(expected),
+ );
}
}
@@ -83,7 +86,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.annotate_expected_due_to_let_ty(err, expr, error);
self.emit_type_mismatch_suggestions(err, expr, expr_ty, expected, expected_ty_expr, error);
self.note_type_is_not_clone(err, expected, expr_ty, expr);
- self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
+ self.note_internal_mutation_in_method(err, expr, Some(expected), expr_ty);
self.check_for_range_as_method_call(err, expr, expr_ty, expected);
self.check_for_binding_assigned_block_without_tail_expression(err, expr, expr_ty, expected);
self.check_wrong_return_type_due_to_generic_arg(err, expr, expr_ty);
@@ -113,7 +116,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Ty<'tcx>,
actual: Ty<'tcx>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
- match self.at(cause, self.param_env).define_opaque_types(true).sup(expected, actual) {
+ match self.at(cause, self.param_env).sup(DefineOpaqueTypes::Yes, expected, actual) {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
None
@@ -143,7 +146,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Ty<'tcx>,
actual: Ty<'tcx>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
- match self.at(cause, self.param_env).define_opaque_types(true).eq(expected, actual) {
+ match self.at(cause, self.param_env).eq(DefineOpaqueTypes::Yes, expected, actual) {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
None
@@ -217,37 +220,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(expected, Some(err))
}
- pub fn point_at_expr_source_of_inferred_type(
+ /// Notes the point at which a variable is constrained to some type incompatible
+ /// with some expectation given by `source`.
+ pub fn note_source_of_type_mismatch_constraint(
&self,
err: &mut Diagnostic,
expr: &hir::Expr<'_>,
- found: Ty<'tcx>,
- expected: Ty<'tcx>,
- mismatch_span: Span,
+ source: TypeMismatchSource<'tcx>,
) -> bool {
- let map = self.tcx.hir();
+ let hir = self.tcx.hir();
let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind else { return false; };
let [hir::PathSegment { ident, args: None, .. }] = p.segments else { return false; };
- let hir::def::Res::Local(hir_id) = p.res else { return false; };
- let Some(hir::Node::Pat(pat)) = map.find(hir_id) else { return false; };
- let Some(hir::Node::Local(hir::Local {
- ty: None,
- init: Some(init),
- ..
- })) = map.find_parent(pat.hir_id) else { return false; };
- let Some(ty) = self.node_ty_opt(init.hir_id) else { return false; };
- if ty.is_closure() || init.span.overlaps(expr.span) || pat.span.from_expansion() {
- return false;
- }
+ let hir::def::Res::Local(local_hir_id) = p.res else { return false; };
+ let hir::Node::Pat(pat) = hir.get(local_hir_id) else { return false; };
+ let (init_ty_hir_id, init) = match hir.get_parent(pat.hir_id) {
+ hir::Node::Local(hir::Local { ty: Some(ty), init, .. }) => (ty.hir_id, *init),
+ hir::Node::Local(hir::Local { init: Some(init), .. }) => (init.hir_id, Some(*init)),
+ _ => return false,
+ };
+ let Some(init_ty) = self.node_ty_opt(init_ty_hir_id) else { return false; };
// Locate all the usages of the relevant binding.
- struct FindExprs<'hir> {
+ struct FindExprs<'tcx> {
hir_id: hir::HirId,
- uses: Vec<&'hir hir::Expr<'hir>>,
+ uses: Vec<&'tcx hir::Expr<'tcx>>,
}
- impl<'v> Visitor<'v> for FindExprs<'v> {
- fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
+ impl<'tcx> Visitor<'tcx> for FindExprs<'tcx> {
+ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = ex.kind
&& let hir::def::Res::Local(hir_id) = path.res
&& hir_id == self.hir_id
@@ -258,180 +258,205 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- let mut expr_finder = FindExprs { hir_id, uses: vec![] };
- let id = map.get_parent_item(hir_id);
- let hir_id: hir::HirId = id.into();
-
- let Some(node) = map.find(hir_id) else { return false; };
- let Some(body_id) = node.body_id() else { return false; };
- let body = map.body(body_id);
+ let mut expr_finder = FindExprs { hir_id: local_hir_id, uses: init.into_iter().collect() };
+ let body =
+ hir.body(hir.maybe_body_owned_by(self.body_id).expect("expected item to have body"));
expr_finder.visit_expr(body.value);
- // Hack to make equality checks on types with inference variables and regions useful.
- let mut eraser = BottomUpFolder {
+
+ use rustc_infer::infer::type_variable::*;
+ use rustc_middle::infer::unify_key::*;
+ // Replaces all of the variables in the given type with a fresh inference variable.
+ let mut fudger = BottomUpFolder {
tcx: self.tcx,
+ ty_op: |ty| {
+ if let ty::Infer(infer) = ty.kind() {
+ match infer {
+ ty::InferTy::TyVar(_) => self.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::MiscVariable,
+ span: DUMMY_SP,
+ }),
+ ty::InferTy::IntVar(_) => self.next_int_var(),
+ ty::InferTy::FloatVar(_) => self.next_float_var(),
+ _ => bug!(),
+ }
+ } else {
+ ty
+ }
+ },
lt_op: |_| self.tcx.lifetimes.re_erased,
- ct_op: |c| c,
- ty_op: |t| match *t.kind() {
- ty::Infer(ty::TyVar(_)) => self.tcx.mk_ty_var(ty::TyVid::from_u32(0)),
- ty::Infer(ty::IntVar(_)) => self.tcx.mk_int_var(ty::IntVid { index: 0 }),
- ty::Infer(ty::FloatVar(_)) => self.tcx.mk_float_var(ty::FloatVid { index: 0 }),
- _ => t,
+ ct_op: |ct| {
+ if let ty::ConstKind::Infer(_) = ct.kind() {
+ self.next_const_var(
+ ct.ty(),
+ ConstVariableOrigin {
+ kind: ConstVariableOriginKind::MiscVariable,
+ span: DUMMY_SP,
+ },
+ )
+ } else {
+ ct
+ }
},
};
- let mut prev = eraser.fold_ty(ty);
- let mut prev_span: Option<Span> = None;
-
- for binding in expr_finder.uses {
- // In every expression where the binding is referenced, we will look at that
- // expression's type and see if it is where the incorrect found type was fully
- // "materialized" and point at it. We will also try to provide a suggestion there.
- if let Some(hir::Node::Expr(expr)
- | hir::Node::Stmt(hir::Stmt {
- kind: hir::StmtKind::Expr(expr) | hir::StmtKind::Semi(expr),
- ..
- })) = &map.find_parent(binding.hir_id)
- && let hir::ExprKind::MethodCall(segment, rcvr, args, _span) = expr.kind
- && rcvr.hir_id == binding.hir_id
- && let Some(def_id) = self.typeck_results.borrow().type_dependent_def_id(expr.hir_id)
- {
- // We special case methods, because they can influence inference through the
- // call's arguments and we can provide a more explicit span.
- let sig = self.tcx.fn_sig(def_id).subst_identity();
- let def_self_ty = sig.input(0).skip_binder();
- let param_tys = sig.inputs().skip_binder().iter().skip(1);
- // If there's an arity mismatch, pointing out the call as the source of an inference
- // can be misleading, so we skip it.
- if param_tys.len() != args.len() {
- continue;
- }
- let rcvr_ty = self.node_ty(rcvr.hir_id);
- // Get the evaluated type *after* calling the method call, so that the influence
- // of the arguments can be reflected in the receiver type. The receiver
- // expression has the type *before* theis analysis is done.
- let ty = match self.lookup_probe_for_diagnostic(
- segment.ident,
- rcvr_ty,
- expr,
- probe::ProbeScope::TraitsInScope,
- None,
- ) {
- Ok(pick) => eraser.fold_ty(pick.self_ty),
- Err(_) => rcvr_ty,
+
+ let expected_ty = match source {
+ TypeMismatchSource::Ty(expected_ty) => expected_ty,
+ // Try to deduce what the possible value of `expr` would be if the
+ // incompatible arg were compatible. For example, given `Vec<i32>`
+ // and `vec.push(1u32)`, we ideally want to deduce that the type of
+ // `vec` *should* have been `Vec<u32>`. This will allow us to then
+ // run the subsequent code with this expectation, finding out exactly
+ // when this type diverged from our expectation.
+ TypeMismatchSource::Arg { call_expr, incompatible_arg: idx } => {
+ let hir::ExprKind::MethodCall(segment, _, args, _) = call_expr.kind else {
+ return false;
};
- // Remove one layer of references to account for `&mut self` and
- // `&self`, so that we can compare it against the binding.
- let (ty, def_self_ty) = match (ty.kind(), def_self_ty.kind()) {
- (ty::Ref(_, ty, a), ty::Ref(_, self_ty, b)) if a == b => (*ty, *self_ty),
- _ => (ty, def_self_ty),
+ let Some(arg_ty) = self.node_ty_opt(args[idx].hir_id) else {
+ return false;
};
- let mut param_args = FxHashMap::default();
- let mut param_expected = FxHashMap::default();
- let mut param_found = FxHashMap::default();
- if self.can_eq(self.param_env, ty, found) {
- // We only point at the first place where the found type was inferred.
- for (param_ty, arg) in param_tys.zip(args) {
- if def_self_ty.contains(*param_ty) && let ty::Param(_) = param_ty.kind() {
- // We found an argument that references a type parameter in `Self`,
- // so we assume that this is the argument that caused the found
- // type, which we know already because of `can_eq` above was first
- // inferred in this method call.
- let arg_ty = self.node_ty(arg.hir_id);
- if !arg.span.overlaps(mismatch_span) {
- err.span_label(
- arg.span,
- &format!(
- "this is of type `{arg_ty}`, which causes `{ident}` to be \
- inferred as `{ty}`",
- ),
- );
- }
- param_args.insert(param_ty, (arg, arg_ty));
- }
- }
+ let possible_rcvr_ty = expr_finder.uses.iter().find_map(|binding| {
+ let possible_rcvr_ty = self.node_ty_opt(binding.hir_id)?;
+ // Fudge the receiver, so we can do new inference on it.
+ let possible_rcvr_ty = possible_rcvr_ty.fold_with(&mut fudger);
+ let method = self
+ .lookup_method(
+ possible_rcvr_ty,
+ segment,
+ DUMMY_SP,
+ call_expr,
+ binding,
+ args,
+ )
+ .ok()?;
+ // Unify the method signature with our incompatible arg, to
+ // do inference in the *opposite* direction and to find out
+ // what our ideal rcvr ty would look like.
+ let _ = self
+ .at(&ObligationCause::dummy(), self.param_env)
+ .eq(DefineOpaqueTypes::No, method.sig.inputs()[idx + 1], arg_ty)
+ .ok()?;
+ self.select_obligations_where_possible(|errs| {
+ // Yeet the errors, we're already reporting errors.
+ errs.clear();
+ });
+ Some(self.resolve_vars_if_possible(possible_rcvr_ty))
+ });
+ if let Some(rcvr_ty) = possible_rcvr_ty {
+ rcvr_ty
+ } else {
+ return false;
}
+ }
+ };
- // Here we find, for a type param `T`, the type that `T` is in the current
- // method call *and* in the original expected type. That way, we can see if we
- // can give any structured suggestion for the function argument.
- let mut c = CollectAllMismatches {
- infcx: &self.infcx,
- param_env: self.param_env,
- errors: vec![],
+ // If our expected_ty does not equal init_ty, then it *began* as incompatible.
+ // No need to note in this case...
+ if !self.can_eq(self.param_env, expected_ty, init_ty.fold_with(&mut fudger)) {
+ return false;
+ }
+
+ for window in expr_finder.uses.windows(2) {
+ // Bindings always update their recorded type after the fact, so we
+ // need to look at the *following* usage's type to see when the
+ // binding became incompatible.
+ let [binding, next_usage] = *window else { continue; };
+
+ // Don't go past the binding (always gonna be a nonsense label if so)
+ if binding.hir_id == expr.hir_id {
+ break;
+ }
+
+ let Some(next_use_ty) = self.node_ty_opt(next_usage.hir_id) else { continue; };
+
+ // If the type is not constrained in a way making it not possible to
+ // equate with `expected_ty` by this point, skip.
+ if self.can_eq(self.param_env, expected_ty, next_use_ty.fold_with(&mut fudger)) {
+ continue;
+ }
+
+ if let hir::Node::Expr(parent_expr) = hir.get_parent(binding.hir_id)
+ && let hir::ExprKind::MethodCall(segment, rcvr, args, _) = parent_expr.kind
+ && rcvr.hir_id == binding.hir_id
+ {
+ // If our binding became incompatible while it was a receiver
+ // to a method call, we may be able to make a better guess to
+ // the source of a type mismatch.
+ let Some(rcvr_ty) = self.node_ty_opt(rcvr.hir_id) else { continue; };
+ let rcvr_ty = rcvr_ty.fold_with(&mut fudger);
+ let Ok(method) =
+ self.lookup_method(rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr, args)
+ else {
+ continue;
};
- let _ = c.relate(def_self_ty, ty);
- for error in c.errors {
- if let TypeError::Sorts(error) = error {
- param_found.insert(error.expected, error.found);
- }
- }
- c.errors = vec![];
- let _ = c.relate(def_self_ty, expected);
- for error in c.errors {
- if let TypeError::Sorts(error) = error {
- param_expected.insert(error.expected, error.found);
- }
- }
- for (param, (arg, arg_ty)) in param_args.iter() {
- let Some(expected) = param_expected.get(param) else { continue; };
- let Some(found) = param_found.get(param) else { continue; };
- if !self.can_eq(self.param_env, *arg_ty, *found) { continue; }
- self.emit_coerce_suggestions(err, arg, *found, *expected, None, None);
- }
- let ty = eraser.fold_ty(ty);
- if ty.references_error() {
- break;
- }
- if ty != prev
- && param_args.is_empty()
- && self.can_eq(self.param_env, ty, found)
+ let ideal_rcvr_ty = rcvr_ty.fold_with(&mut fudger);
+ let ideal_method = self
+ .lookup_method(ideal_rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr, args)
+ .ok()
+ .and_then(|method| {
+ let _ = self.at(&ObligationCause::dummy(), self.param_env)
+ .eq(DefineOpaqueTypes::No, ideal_rcvr_ty, expected_ty)
+ .ok()?;
+ Some(method)
+ });
+
+ // Find what argument caused our rcvr to become incompatible
+ // with the expected ty.
+ for (idx, (expected_arg_ty, arg_expr)) in
+ std::iter::zip(&method.sig.inputs()[1..], args).enumerate()
{
- // We only point at the first place where the found type was inferred.
- if !segment.ident.span.overlaps(mismatch_span) {
+ let Some(arg_ty) = self.node_ty_opt(arg_expr.hir_id) else { continue; };
+ let arg_ty = arg_ty.fold_with(&mut fudger);
+ let _ = self.try_coerce(
+ arg_expr,
+ arg_ty,
+ *expected_arg_ty,
+ AllowTwoPhase::No,
+ None,
+ );
+ self.select_obligations_where_possible(|errs| {
+ // Yeet the errors, we're already reporting errors.
+ errs.clear();
+ });
+ // If our rcvr, after inference due to unifying the signature
+ // with the expected argument type, is still compatible with
+ // the rcvr, then it must've not been the source of blame.
+ if self.can_eq(self.param_env, rcvr_ty, expected_ty) {
+ continue;
+ }
+ err.span_label(arg_expr.span, format!("this argument has type `{arg_ty}`..."));
err.span_label(
- segment.ident.span,
- with_forced_trimmed_paths!(format!(
- "here the type of `{ident}` is inferred to be `{ty}`",
- )),
- );}
- break;
- } else if !param_args.is_empty() {
- break;
- }
- prev = ty;
- } else {
- let ty = eraser.fold_ty(self.node_ty(binding.hir_id));
- if ty.references_error() {
- break;
- }
- if ty != prev
- && let Some(span) = prev_span
- && self.can_eq(self.param_env, ty, found)
- {
- // We only point at the first place where the found type was inferred.
- // We use the *previous* span because if the type is known *here* it means
- // it was *evaluated earlier*. We don't do this for method calls because we
- // evaluate the method's self type eagerly, but not in any other case.
- if !span.overlaps(mismatch_span) {
- err.span_label(
- span,
- with_forced_trimmed_paths!(format!(
- "here the type of `{ident}` is inferred to be `{ty}`",
- )),
+ binding.span,
+ format!("... which causes `{ident}` to have type `{next_use_ty}`"),
+ );
+ // Using our "ideal" method signature, suggest a fix to this
+ // blame arg, if possible. Don't do this if we're coming from
+ // arg mismatch code, because we'll possibly suggest a mutually
+ // incompatible fix at the original mismatch site.
+ if matches!(source, TypeMismatchSource::Ty(_))
+ && let Some(ideal_method) = ideal_method
+ {
+ self.emit_type_mismatch_suggestions(
+ err,
+ arg_expr,
+ arg_ty,
+ self.resolve_vars_if_possible(ideal_method.sig.inputs()[idx + 1]),
+ None,
+ None,
);
}
- break;
+ return true;
}
- prev = ty;
- }
- if binding.hir_id == expr.hir_id {
- // Do not look at expressions that come after the expression we were originally
- // evaluating and had a type error.
- break;
}
- prev_span = Some(binding.span);
+ err.span_label(
+ binding.span,
+ format!("here the type of `{ident}` is inferred to be `{next_use_ty}`"),
+ );
+ return true;
}
- true
+
+ // We must've not found something that constrained the expr.
+ false
}
fn annotate_expected_due_to_let_ty(
@@ -707,7 +732,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
- pub(crate) fn note_result_coercion(
+ pub(crate) fn suggest_coercing_result_via_try_operator(
&self,
err: &mut Diagnostic,
expr: &hir::Expr<'tcx>,
@@ -850,7 +875,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
variant.fields.len() == 1
})
.filter_map(|variant| {
- let sole_field = &variant.fields[0];
+ let sole_field = &variant.fields[FieldIdx::from_u32(0)];
let field_is_local = sole_field.did.is_local();
let field_is_accessible =
@@ -1480,14 +1505,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// For this suggestion to make sense, the type would need to be `Copy`,
// or we have to be moving out of a `Box<T>`
- if self.type_is_copy_modulo_regions(self.param_env, expected, sp)
+ if self.type_is_copy_modulo_regions(self.param_env, expected)
// FIXME(compiler-errors): We can actually do this if the checked_ty is
// `steps` layers of boxes, not just one, but this is easier and most likely.
|| (checked_ty.is_box() && steps == 1)
{
let deref_kind = if checked_ty.is_box() {
"unboxing the value"
- } else if checked_ty.is_region_ptr() {
+ } else if checked_ty.is_ref() {
"dereferencing the borrow"
} else {
"dereferencing the type"
@@ -2093,3 +2118,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
}
+
+pub enum TypeMismatchSource<'tcx> {
+ /// Expected the binding to have the given type, but it was found to have
+ /// a different type. Find out when that type first became incompatible.
+ Ty(Ty<'tcx>),
+ /// When we fail during method argument checking, try to find out if a previous
+ /// expression has constrained the method's receiver in a way that makes the
+ /// argument's type incompatible.
+ Arg { call_expr: &'tcx hir::Expr<'tcx>, incompatible_arg: usize },
+}
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 7fc4ccb04..6ffa0134f 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -36,6 +36,7 @@ use rustc_hir_analysis::astconv::AstConv as _;
use rustc_hir_analysis::check::ty_kind_suggestion;
use rustc_infer::infer;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::infer::InferOk;
use rustc_infer::traits::ObligationCause;
use rustc_middle::middle::stability;
@@ -49,6 +50,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::source_map::{Span, Spanned};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_target::abi::FieldIdx;
use rustc_target::spec::abi::Abi::RustIntrinsic;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::{self, ObligationCauseCode};
@@ -118,7 +120,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty
}
- pub(super) fn check_expr_coercable_to_type(
+ pub(super) fn check_expr_coercible_to_type(
&self,
expr: &'tcx hir::Expr<'tcx>,
expected: Ty<'tcx>,
@@ -230,7 +232,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ty = ensure_sufficient_stack(|| match &expr.kind {
hir::ExprKind::Path(
- qpath @ hir::QPath::Resolved(..) | qpath @ hir::QPath::TypeRelative(..),
+ qpath @ (hir::QPath::Resolved(..) | hir::QPath::TypeRelative(..)),
) => self.check_expr_path(qpath, expr, args),
_ => self.check_expr_kind(expr, expected),
});
@@ -283,7 +285,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let tcx = self.tcx;
match expr.kind {
- ExprKind::Box(subexpr) => self.check_expr_box(subexpr, expected),
ExprKind::Lit(ref lit) => self.check_lit(&lit, expected),
ExprKind::Binary(op, lhs, rhs) => self.check_binop(expr, op, lhs, rhs, expected),
ExprKind::Assign(lhs, rhs, span) => {
@@ -358,16 +359,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- fn check_expr_box(&self, expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>) -> Ty<'tcx> {
- let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| match ty.kind() {
- ty::Adt(def, _) if def.is_box() => Expectation::rvalue_hint(self, ty.boxed_ty()),
- _ => NoExpectation,
- });
- let referent_ty = self.check_expr_with_expectation(expr, expected_inner);
- self.require_type_is_sized(referent_ty, expr.span, traits::SizedBoxType);
- self.tcx.mk_box(referent_ty)
- }
-
fn check_expr_unary(
&self,
unop: hir::UnOp,
@@ -798,7 +789,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.ret_coercion_span.set(Some(expr.span));
}
let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression);
- if let Some((fn_decl, _)) = self.get_fn_decl(expr.hir_id) {
+ if let Some((_, fn_decl, _)) = self.get_fn_decl(expr.hir_id) {
coercion.coerce_forced_unit(
self,
&cause,
@@ -1137,7 +1128,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
};
- // This is (basically) inlined `check_expr_coercable_to_type`, but we want
+ // This is (basically) inlined `check_expr_coercible_to_type`, but we want
// to suggest an additional fixup here in `suggest_deref_binop`.
let rhs_ty = self.check_expr_with_hint(&rhs, lhs_ty);
if let (_, Some(mut diag)) =
@@ -1410,7 +1401,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let (element_ty, t) = match uty {
Some(uty) => {
- self.check_expr_coercable_to_type(&element, uty, None);
+ self.check_expr_coercible_to_type(&element, uty, None);
(uty, uty)
}
None => {
@@ -1487,7 +1478,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let elt_ts_iter = elts.iter().enumerate().map(|(i, e)| match flds {
Some(fs) if i < fs.len() => {
let ety = fs[i];
- self.check_expr_coercable_to_type(&e, ety, None);
+ self.check_expr_coercible_to_type(&e, ety, None);
ety
}
_ => self.check_expr_with_expectation(&e, NoExpectation),
@@ -1571,8 +1562,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut remaining_fields = variant
.fields
- .iter()
- .enumerate()
+ .iter_enumerated()
.map(|(i, field)| (field.ident(tcx).normalize_to_macros_2_0(), (i, field)))
.collect::<FxHashMap<_, _>>();
@@ -1683,7 +1673,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some(_) = remaining_fields.remove(&ident) {
let target_ty = self.field_ty(base_expr.span, f, substs);
let cause = self.misc(base_expr.span);
- match self.at(&cause, self.param_env).sup(target_ty, fru_ty) {
+ match self.at(&cause, self.param_env).sup(
+ DefineOpaqueTypes::No,
+ target_ty,
+ fru_ty,
+ ) {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations)
}
@@ -1821,7 +1815,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
adt_ty: Ty<'tcx>,
span: Span,
- remaining_fields: FxHashMap<Ident, (usize, &ty::FieldDef)>,
+ remaining_fields: FxHashMap<Ident, (FieldIdx, &ty::FieldDef)>,
variant: &'tcx ty::VariantDef,
ast_fields: &'tcx [hir::ExprField<'tcx>],
substs: SubstsRef<'tcx>,
@@ -2215,11 +2209,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let (ident, def_scope) =
self.tcx.adjust_ident_and_get_scope(field, base_def.did(), body_hir_id);
let fields = &base_def.non_enum_variant().fields;
- if let Some(index) = fields
- .iter()
- .position(|f| f.ident(self.tcx).normalize_to_macros_2_0() == ident)
+ if let Some((index, field)) = fields
+ .iter_enumerated()
+ .find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == ident)
{
- let field = &fields[index];
let field_ty = self.field_ty(expr.span, field, substs);
// Save the index of all fields regardless of their visibility in case
// of error recovery.
@@ -2236,15 +2229,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
ty::Tuple(tys) => {
- let fstr = field.as_str();
- if let Ok(index) = fstr.parse::<usize>() {
- if fstr == index.to_string() {
+ if let Ok(index) = field.as_str().parse::<usize>() {
+ if field.name == sym::integer(index) {
if let Some(&field_ty) = tys.get(index) {
let adjustments = self.adjust_steps(&autoderef);
self.apply_adjustments(base, adjustments);
self.register_predicates(autoderef.into_obligations());
- self.write_field_index(expr.hir_id, index);
+ self.write_field_index(expr.hir_id, FieldIdx::from_usize(index));
return field_ty;
}
}
@@ -2818,23 +2810,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"cannot index into a value of type `{base_t}`",
);
// Try to give some advice about indexing tuples.
- if let ty::Tuple(..) = base_t.kind() {
+ if let ty::Tuple(types) = base_t.kind() {
let mut needs_note = true;
// If the index is an integer, we can show the actual
// fixed expression:
- if let ExprKind::Lit(ref lit) = idx.kind {
- if let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node {
- let snip = self.tcx.sess.source_map().span_to_snippet(base.span);
- if let Ok(snip) = snip {
- err.span_suggestion(
- expr.span,
- "to access tuple elements, use",
- format!("{snip}.{i}"),
- Applicability::MachineApplicable,
- );
- needs_note = false;
- }
+ if let ExprKind::Lit(ref lit) = idx.kind
+ && let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node
+ && i < types.len().try_into().expect("expected tuple index to be < usize length")
+ {
+ let snip = self.tcx.sess.source_map().span_to_snippet(base.span);
+ if let Ok(snip) = snip {
+ err.span_suggestion(
+ expr.span,
+ "to access tuple elements, use",
+ format!("{snip}.{i}"),
+ Applicability::MachineApplicable,
+ );
+ needs_note = false;
}
+ } else if let ExprKind::Path(..) = idx.peel_borrows().kind {
+ err.span_label(idx.span, "cannot access tuple elements at a variable index");
}
if needs_note {
err.help(
@@ -2874,7 +2869,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> Ty<'tcx> {
match self.resume_yield_tys {
Some((resume_ty, yield_ty)) => {
- self.check_expr_coercable_to_type(&value, yield_ty, None);
+ self.check_expr_coercible_to_type(&value, yield_ty, None);
resume_ty
}
@@ -2883,7 +2878,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// information. Hence, we check the source of the yield expression here and check its
// value's type against `()` (this check should always hold).
None if src.is_await() => {
- self.check_expr_coercable_to_type(&value, self.tcx.mk_unit(), None);
+ self.check_expr_coercible_to_type(&value, self.tcx.mk_unit(), None);
self.tcx.mk_unit()
}
_ => {
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index b9a058d6b..ee1c6fbfd 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -14,12 +14,11 @@ use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::PatKind;
-use rustc_index::vec::Idx;
use rustc_infer::infer::InferCtxt;
use rustc_middle::hir::place::ProjectionKind;
use rustc_middle::mir::FakeReadCause;
use rustc_middle::ty::{self, adjustment, AdtKind, Ty, TyCtxt};
-use rustc_target::abi::VariantIdx;
+use rustc_target::abi::FIRST_VARIANT;
use ty::BorrowKind::ImmBorrow;
use crate::mem_categorization as mc;
@@ -356,10 +355,6 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
self.walk_captures(closure);
}
- hir::ExprKind::Box(ref base) => {
- self.consume_expr(base);
- }
-
hir::ExprKind::Yield(value, _) => {
self.consume_expr(value);
}
@@ -544,7 +539,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
match with_place.place.ty().kind() {
ty::Adt(adt, substs) if adt.is_struct() => {
// Consume those fields of the with expression that are needed.
- for (f_index, with_field) in adt.non_enum_variant().fields.iter().enumerate() {
+ for (f_index, with_field) in adt.non_enum_variant().fields.iter_enumerated() {
let is_mentioned = fields
.iter()
.any(|f| self.mc.typeck_results.opt_field_index(f.hir_id) == Some(f_index));
@@ -553,7 +548,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
&*with_expr,
with_place.clone(),
with_field.ty(self.tcx(), substs),
- ProjectionKind::Field(f_index as u32, VariantIdx::new(0)),
+ ProjectionKind::Field(f_index, FIRST_VARIANT),
);
self.delegate_consume(&field_place, field_place.hir_id);
}
@@ -564,7 +559,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
// struct; however, when EUV is run during typeck, it
// may not. This will generate an error earlier in typeck,
// so we can just ignore it.
- if !self.tcx().sess.has_errors().is_some() {
+ if self.tcx().sess.has_errors().is_none() {
span_bug!(with_expr.span, "with expression doesn't evaluate to a struct");
}
}
@@ -871,10 +866,7 @@ fn copy_or_move<'a, 'tcx>(
mc: &mc::MemCategorizationContext<'a, 'tcx>,
place_with_id: &PlaceWithHirId<'tcx>,
) -> ConsumeMode {
- if !mc.type_is_copy_modulo_regions(
- place_with_id.place.ty(),
- mc.tcx().hir().span(place_with_id.hir_id),
- ) {
+ if !mc.type_is_copy_modulo_regions(place_with_id.place.ty()) {
ConsumeMode::Move
} else {
ConsumeMode::Copy
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 60e55c7b0..f736f7a96 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -19,13 +19,13 @@ use rustc_hir_analysis::astconv::{
};
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
-use rustc_infer::infer::InferResult;
+use rustc_infer::infer::{DefineOpaqueTypes, InferResult};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
use rustc_middle::ty::{
- self, AdtKind, CanonicalUserType, DefIdTree, GenericParamDefKind, Ty, TyCtxt, UserType,
+ self, AdtKind, CanonicalUserType, GenericParamDefKind, Ty, TyCtxt, UserType,
};
use rustc_middle::ty::{GenericArgKind, SubstsRef, UserSelfTy, UserSubsts};
use rustc_session::lint;
@@ -33,6 +33,7 @@ use rustc_span::def_id::LocalDefId;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Span;
+use rustc_target::abi::FieldIdx;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::{self, NormalizeExt, ObligationCauseCode, ObligationCtxt};
@@ -147,7 +148,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- pub fn write_field_index(&self, hir_id: hir::HirId, index: usize) {
+ pub fn write_field_index(&self, hir_id: hir::HirId, index: FieldIdx) {
self.typeck_results.borrow_mut().field_indices_mut().insert(hir_id, index);
}
@@ -301,16 +302,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: Span,
def_id: DefId,
substs: SubstsRef<'tcx>,
- ) -> (ty::InstantiatedPredicates<'tcx>, Vec<Span>) {
+ ) -> ty::InstantiatedPredicates<'tcx> {
let bounds = self.tcx.predicates_of(def_id);
- let spans: Vec<Span> = bounds.predicates.iter().map(|(_, span)| *span).collect();
let result = bounds.instantiate(self.tcx, substs);
let result = self.normalize(span, result);
- debug!(
- "instantiate_bounds(bounds={:?}, substs={:?}) = {:?}, {:?}",
- bounds, substs, result, spans,
- );
- (result, spans)
+ debug!("instantiate_bounds(bounds={:?}, substs={:?}) = {:?}", bounds, substs, result);
+ result
}
pub(in super::super) fn normalize<T>(&self, span: Span, value: T) -> T
@@ -562,7 +559,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let span = self.tcx.hir().body(body_id).value.span;
let ok = self
.at(&self.misc(span), self.param_env)
- .eq(interior, witness)
+ .eq(DefineOpaqueTypes::No, interior, witness)
.expect("Failed to unify generator interior type");
let mut obligations = ok.obligations;
@@ -581,11 +578,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
#[instrument(skip(self), level = "debug")]
pub(in super::super) fn report_ambiguity_errors(&self) {
- let mut errors = self.fulfillment_cx.borrow_mut().collect_remaining_errors();
+ let mut errors = self.fulfillment_cx.borrow_mut().collect_remaining_errors(self);
if !errors.is_empty() {
self.adjust_fulfillment_errors_for_expr_obligation(&mut errors);
- self.err_ctxt().report_fulfillment_errors(&errors, self.inh.body_id);
+ self.err_ctxt().report_fulfillment_errors(&errors);
}
}
@@ -598,7 +595,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if !result.is_empty() {
mutate_fulfillment_errors(&mut result);
self.adjust_fulfillment_errors_for_expr_obligation(&mut result);
- self.err_ctxt().report_fulfillment_errors(&result, self.inh.body_id);
+ self.err_ctxt().report_fulfillment_errors(&result);
}
}
@@ -670,7 +667,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
| ty::PredicateKind::WellFormed(..)
| ty::PredicateKind::ObjectSafe(..)
- | ty::PredicateKind::AliasEq(..)
+ | ty::PredicateKind::AliasRelate(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
// N.B., this predicate is created by breaking down a
@@ -902,56 +899,74 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
}
- /// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise.
+ /// Given a function `Node`, return its `HirId` and `FnDecl` if it exists. Given a closure
+ /// that is the child of a function, return that function's `HirId` and `FnDecl` instead.
+ /// This may seem confusing at first, but this is used in diagnostics for `async fn`,
+ /// for example, where most of the type checking actually happens within a nested closure,
+ /// but we often want access to the parent function's signature.
+ ///
+ /// Otherwise, return false.
pub(in super::super) fn get_node_fn_decl(
&self,
node: Node<'tcx>,
- ) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident, bool)> {
+ ) -> Option<(hir::HirId, &'tcx hir::FnDecl<'tcx>, Ident, bool)> {
match node {
- Node::Item(&hir::Item { ident, kind: hir::ItemKind::Fn(ref sig, ..), .. }) => {
+ Node::Item(&hir::Item {
+ ident,
+ kind: hir::ItemKind::Fn(ref sig, ..),
+ owner_id,
+ ..
+ }) => {
// This is less than ideal, it will not suggest a return type span on any
// method called `main`, regardless of whether it is actually the entry point,
// but it will still present it as the reason for the expected type.
- Some((&sig.decl, ident, ident.name != sym::main))
+ Some((
+ hir::HirId::make_owner(owner_id.def_id),
+ &sig.decl,
+ ident,
+ ident.name != sym::main,
+ ))
}
Node::TraitItem(&hir::TraitItem {
ident,
kind: hir::TraitItemKind::Fn(ref sig, ..),
+ owner_id,
..
- }) => Some((&sig.decl, ident, true)),
+ }) => Some((hir::HirId::make_owner(owner_id.def_id), &sig.decl, ident, true)),
Node::ImplItem(&hir::ImplItem {
ident,
kind: hir::ImplItemKind::Fn(ref sig, ..),
+ owner_id,
..
- }) => Some((&sig.decl, ident, false)),
- Node::Expr(&hir::Expr {
- hir_id,
- kind: hir::ExprKind::Closure(..),
- ..
- }) if let Some(Node::Expr(&hir::Expr {
- hir_id,
- kind: hir::ExprKind::Call(..),
- ..
- })) = self.tcx.hir().find_parent(hir_id) &&
- let Some(Node::Item(&hir::Item {
+ }) => Some((hir::HirId::make_owner(owner_id.def_id), &sig.decl, ident, false)),
+ Node::Expr(&hir::Expr { hir_id, kind: hir::ExprKind::Closure(..), .. })
+ if let Some(Node::Item(&hir::Item {
+ ident,
+ kind: hir::ItemKind::Fn(ref sig, ..),
+ owner_id,
+ ..
+ })) = self.tcx.hir().find_parent(hir_id) => Some((
+ hir::HirId::make_owner(owner_id.def_id),
+ &sig.decl,
ident,
- kind: hir::ItemKind::Fn(ref sig, ..),
- ..
- })) = self.tcx.hir().find_parent(hir_id) => {
- Some((&sig.decl, ident, ident.name != sym::main))
- },
+ ident.name != sym::main,
+ )),
_ => None,
}
}
- /// Given a `HirId`, return the `FnDecl` of the method it is enclosed by and whether a
+ /// Given a `HirId`, return the `HirId` of the enclosing function, its `FnDecl`, and whether a
/// suggestion can be made, `None` otherwise.
- pub fn get_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, bool)> {
+ pub fn get_fn_decl(
+ &self,
+ blk_id: hir::HirId,
+ ) -> Option<(hir::HirId, &'tcx hir::FnDecl<'tcx>, bool)> {
// Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
// `while` before reaching it, as block tail returns are not available in them.
self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| {
let parent = self.tcx.hir().get(blk_id);
- self.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
+ self.get_node_fn_decl(parent)
+ .map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main))
})
}
@@ -959,44 +974,75 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
err: &mut Diagnostic,
expr: &hir::Expr<'_>,
- expected: Ty<'tcx>,
+ expected: Option<Ty<'tcx>>,
found: Ty<'tcx>,
) {
if found != self.tcx.types.unit {
return;
}
- if let ExprKind::MethodCall(path_segment, rcvr, ..) = expr.kind {
- if self
- .typeck_results
+
+ let ExprKind::MethodCall(path_segment, rcvr, ..) = expr.kind else {
+ return;
+ };
+
+ let rcvr_has_the_expected_type = self
+ .typeck_results
+ .borrow()
+ .expr_ty_adjusted_opt(rcvr)
+ .and_then(|ty| expected.map(|expected_ty| expected_ty.peel_refs() == ty.peel_refs()))
+ .unwrap_or(false);
+
+ let prev_call_mutates_and_returns_unit = || {
+ self.typeck_results
.borrow()
- .expr_ty_adjusted_opt(rcvr)
- .map_or(true, |ty| expected.peel_refs() != ty.peel_refs())
- {
- return;
- }
- let mut sp = MultiSpan::from_span(path_segment.ident.span);
- sp.push_span_label(
- path_segment.ident.span,
- format!(
- "this call modifies {} in-place",
- match rcvr.kind {
- ExprKind::Path(QPath::Resolved(
- None,
- hir::Path { segments: [segment], .. },
- )) => format!("`{}`", segment.ident),
- _ => "its receiver".to_string(),
- }
- ),
- );
+ .type_dependent_def_id(expr.hir_id)
+ .map(|def_id| self.tcx.fn_sig(def_id).skip_binder().skip_binder())
+ .and_then(|sig| sig.inputs_and_output.split_last())
+ .map(|(output, inputs)| {
+ output.is_unit()
+ && inputs
+ .get(0)
+ .and_then(|self_ty| self_ty.ref_mutability())
+ .map_or(false, rustc_ast::Mutability::is_mut)
+ })
+ .unwrap_or(false)
+ };
+
+ if !(rcvr_has_the_expected_type || prev_call_mutates_and_returns_unit()) {
+ return;
+ }
+
+ let mut sp = MultiSpan::from_span(path_segment.ident.span);
+ sp.push_span_label(
+ path_segment.ident.span,
+ format!(
+ "this call modifies {} in-place",
+ match rcvr.kind {
+ ExprKind::Path(QPath::Resolved(
+ None,
+ hir::Path { segments: [segment], .. },
+ )) => format!("`{}`", segment.ident),
+ _ => "its receiver".to_string(),
+ }
+ ),
+ );
+
+ let modifies_rcvr_note =
+ format!("method `{}` modifies its receiver in-place", path_segment.ident);
+ if rcvr_has_the_expected_type {
sp.push_span_label(
rcvr.span,
"you probably want to use this value after calling the method...",
);
+ err.span_note(sp, &modifies_rcvr_note);
+ err.note(&format!("...instead of the `()` output of method `{}`", path_segment.ident));
+ } else if let ExprKind::MethodCall(..) = rcvr.kind {
err.span_note(
sp,
- &format!("method `{}` modifies its receiver in-place", path_segment.ident),
+ modifies_rcvr_note.clone() + ", it is not meant to be used in method chains.",
);
- err.note(&format!("...instead of the `()` output of method `{}`", path_segment.ident));
+ } else {
+ err.span_note(sp, &modifies_rcvr_note);
}
}
@@ -1319,7 +1365,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// This also occurs for an enum variant on a type alias.
let impl_ty = self.normalize(span, tcx.type_of(impl_def_id).subst(tcx, substs));
let self_ty = self.normalize(span, self_ty);
- match self.at(&self.misc(span), self.param_env).eq(impl_ty, self_ty) {
+ match self.at(&self.misc(span), self.param_env).eq(
+ DefineOpaqueTypes::No,
+ impl_ty,
+ self_ty,
+ ) {
Ok(ok) => self.register_infer_ok_obligations(ok),
Err(_) => {
self.tcx.sess.delay_span_bug(
@@ -1367,41 +1417,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) {
let param_env = self.param_env;
- let remap = match self.tcx.def_kind(def_id) {
- // Associated consts have `Self: ~const Trait` bounds that should be satisfiable when
- // `Self: Trait` is satisfied because it does not matter whether the impl is `const`.
- // Therefore we have to remap the param env here to be non-const.
- hir::def::DefKind::AssocConst => true,
- hir::def::DefKind::AssocFn
- if self.tcx.def_kind(self.tcx.parent(def_id)) == hir::def::DefKind::Trait =>
- {
- // N.B.: All callsites to this function involve checking a path expression.
- //
- // When instantiating a trait method as a function item, it does not actually matter whether
- // the trait is `const` or not, or whether `where T: ~const Tr` needs to be satisfied as
- // `const`. If we were to introduce instantiating trait methods as `const fn`s, we would
- // check that after this, either via a bound `where F: ~const FnOnce` or when coercing to a
- // `const fn` pointer.
- //
- // FIXME(fee1-dead) FIXME(const_trait_impl): update this doc when trait methods can satisfy
- // `~const FnOnce` or can be coerced to `const fn` pointer.
- true
- }
- _ => false,
- };
- let (bounds, _) = self.instantiate_bounds(span, def_id, &substs);
+ let bounds = self.instantiate_bounds(span, def_id, &substs);
- for mut obligation in traits::predicates_for_generics(
+ for obligation in traits::predicates_for_generics(
|idx, predicate_span| {
traits::ObligationCause::new(span, self.body_id, code(idx, predicate_span))
},
param_env,
bounds,
) {
- if remap {
- obligation = obligation.without_const(self.tcx);
- }
- self.register_predicate(obligation);
+ // N.B. We are remapping all predicates to non-const since we don't know if we just
+ // want them as function pointers or we are calling them from a const-context. The
+ // actual checking will occur in `rustc_const_eval::transform::check_consts`.
+ self.register_predicate(obligation.without_const(self.tcx));
}
}
@@ -1415,7 +1443,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
let e = self.tainted_by_errors().unwrap_or_else(|| {
self.err_ctxt()
- .emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282, true)
+ .emit_inference_failure_err(self.body_id, sp, ty.into(), E0282, true)
.emit()
});
let err = self.tcx.ty_error(e);
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
index b09886fe3..f879ccbb3 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
@@ -3,10 +3,8 @@ use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def_id::DefId;
use rustc_infer::traits::ObligationCauseCode;
-use rustc_middle::ty::{
- self, DefIdTree, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
-};
-use rustc_span::{self, Span};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use rustc_span::{self, symbol::kw, Span};
use rustc_trait_selection::traits;
use std::ops::ControlFlow;
@@ -27,17 +25,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let generics = self.tcx.generics_of(def_id);
let predicate_substs = match unsubstituted_pred.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs,
- ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => pred.projection_ty.substs,
- _ => ty::List::empty(),
+ ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs.to_vec(),
+ ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => {
+ pred.projection_ty.substs.to_vec()
+ }
+ ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(arg, ty)) => {
+ vec![ty.into(), arg.into()]
+ }
+ ty::PredicateKind::ConstEvaluatable(e) => vec![e.into()],
+ _ => return false,
};
- let find_param_matching = |matches: &dyn Fn(&ty::ParamTy) -> bool| {
- predicate_substs.types().find_map(|ty| {
- ty.walk().find_map(|arg| {
+ let find_param_matching = |matches: &dyn Fn(ty::ParamTerm) -> bool| {
+ predicate_substs.iter().find_map(|arg| {
+ arg.walk().find_map(|arg| {
if let ty::GenericArgKind::Type(ty) = arg.unpack()
- && let ty::Param(param_ty) = ty.kind()
- && matches(param_ty)
+ && let ty::Param(param_ty) = *ty.kind()
+ && matches(ty::ParamTerm::Ty(param_ty))
+ {
+ Some(arg)
+ } else if let ty::GenericArgKind::Const(ct) = arg.unpack()
+ && let ty::ConstKind::Param(param_ct) = ct.kind()
+ && matches(ty::ParamTerm::Const(param_ct))
{
Some(arg)
} else {
@@ -49,26 +58,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Prefer generics that are local to the fn item, since these are likely
// to be the cause of the unsatisfied predicate.
- let mut param_to_point_at = find_param_matching(&|param_ty| {
- self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) == def_id
+ let mut param_to_point_at = find_param_matching(&|param_term| {
+ self.tcx.parent(generics.param_at(param_term.index(), self.tcx).def_id) == def_id
});
// Fall back to generic that isn't local to the fn item. This will come
// from a trait or impl, for example.
- let mut fallback_param_to_point_at = find_param_matching(&|param_ty| {
- self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) != def_id
- && param_ty.name != rustc_span::symbol::kw::SelfUpper
+ let mut fallback_param_to_point_at = find_param_matching(&|param_term| {
+ self.tcx.parent(generics.param_at(param_term.index(), self.tcx).def_id) != def_id
+ && !matches!(param_term, ty::ParamTerm::Ty(ty) if ty.name == kw::SelfUpper)
});
// Finally, the `Self` parameter is possibly the reason that the predicate
// is unsatisfied. This is less likely to be true for methods, because
// method probe means that we already kinda check that the predicates due
// to the `Self` type are true.
- let mut self_param_to_point_at =
- find_param_matching(&|param_ty| param_ty.name == rustc_span::symbol::kw::SelfUpper);
+ let mut self_param_to_point_at = find_param_matching(
+ &|param_term| matches!(param_term, ty::ParamTerm::Ty(ty) if ty.name == kw::SelfUpper),
+ );
// Finally, for ambiguity-related errors, we actually want to look
// for a parameter that is the source of the inference type left
// over in this predicate.
- if let traits::FulfillmentErrorCode::CodeAmbiguity = error.code {
+ if let traits::FulfillmentErrorCode::CodeAmbiguity { .. } = error.code {
fallback_param_to_point_at = None;
self_param_to_point_at = None;
param_to_point_at =
@@ -227,15 +237,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.own_substs(ty::InternalSubsts::identity_for_item(self.tcx, def_id));
let Some((index, _)) = own_substs
.iter()
- .filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_)))
.enumerate()
.find(|(_, arg)| **arg == param_to_point_at) else { return false };
let Some(arg) = segment
.args()
.args
- .iter()
- .filter(|arg| matches!(arg, hir::GenericArg::Type(_)))
- .nth(index) else { return false; };
+ .get(index) else { return false; };
error.obligation.cause.span = arg
.span()
.find_ancestor_in_same_ctxt(error.obligation.cause.span)
@@ -302,7 +309,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.iter()
.filter(|field| {
let field_ty = field.ty(self.tcx, identity_substs);
- Self::find_param_in_ty(field_ty.into(), param_to_point_at)
+ find_param_in_ty(field_ty.into(), param_to_point_at)
})
.collect();
@@ -348,7 +355,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.inputs()
.iter()
.enumerate()
- .filter(|(_, ty)| Self::find_param_in_ty((**ty).into(), param_to_point_at))
+ .filter(|(_, ty)| find_param_in_ty((**ty).into(), param_to_point_at))
.collect();
// If there's one field that references the given generic, great!
if let [(idx, _)] = args_referencing_param.as_slice()
@@ -459,7 +466,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// obligation. Hence we refine the `expr` "outwards-in" and bail at the first kind of expression/impl we don't recognize.
///
/// This function returns a `Result<&Expr, &Expr>` - either way, it returns the `Expr` whose span should be
- /// reported as an error. If it is `Ok`, then it means it refined successfull. If it is `Err`, then it may be
+ /// reported as an error. If it is `Ok`, then it means it refined successful. If it is `Err`, then it may be
/// only a partial success - but it cannot be refined even further.
fn blame_specific_expr_if_possible_for_derived_predicate_obligation(
&self,
@@ -527,7 +534,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// - in_ty: `(Option<Vec<T>, bool)`
/// we would drill until we arrive at `vec![1, 2, 3]`.
///
- /// If successful, we return `Ok(refined_expr)`. If unsuccesful, we return `Err(partially_refined_expr`),
+ /// If successful, we return `Ok(refined_expr)`. If unsuccessful, we return `Err(partially_refined_expr`),
/// which will go as far as possible. For example, given `(foo(), false)` instead, we would drill to
/// `foo()` and then return `Err("foo()")`.
///
@@ -571,8 +578,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Find out which of `in_ty_elements` refer to `param`.
// FIXME: It may be better to take the first if there are multiple,
// just so that the error points to a smaller expression.
- let Some((drill_expr, drill_ty)) = Self::is_iterator_singleton(expr_elements.iter().zip( in_ty_elements.iter()).filter(|(_expr_elem, in_ty_elem)| {
- Self::find_param_in_ty((*in_ty_elem).into(), param)
+ let Some((drill_expr, drill_ty)) = is_iterator_singleton(expr_elements.iter().zip( in_ty_elements.iter()).filter(|(_expr_elem, in_ty_elem)| {
+ find_param_in_ty((*in_ty_elem).into(), param)
})) else {
// The param is not mentioned, or it is mentioned in multiple indexes.
return Err(expr);
@@ -620,10 +627,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// We need to know which of the generic parameters mentions our target param.
// We expect that at least one of them does, since it is expected to be mentioned.
let Some((drill_generic_index, generic_argument_type)) =
- Self::is_iterator_singleton(
+ is_iterator_singleton(
in_ty_adt_generic_args.iter().enumerate().filter(
|(_index, in_ty_generic)| {
- Self::find_param_in_ty(*in_ty_generic, param)
+ find_param_in_ty(*in_ty_generic, param)
},
),
) else {
@@ -743,10 +750,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// We need to know which of the generic parameters mentions our target param.
// We expect that at least one of them does, since it is expected to be mentioned.
let Some((drill_generic_index, generic_argument_type)) =
- Self::is_iterator_singleton(
+ is_iterator_singleton(
in_ty_adt_generic_args.iter().enumerate().filter(
|(_index, in_ty_generic)| {
- Self::find_param_in_ty(*in_ty_generic, param)
+ find_param_in_ty(*in_ty_generic, param)
},
),
) else {
@@ -785,14 +792,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// outer contextual information.
// (1) Find the (unique) field index which mentions the type in our constraint:
- let Some((field_index, field_type)) = Self::is_iterator_singleton(
+ let Some((field_index, field_type)) = is_iterator_singleton(
in_ty_adt
.variant_with_id(variant_def_id)
.fields
.iter()
.map(|field| field.ty(self.tcx, *in_ty_adt_generic_args))
.enumerate()
- .filter(|(_index, field_type)| Self::find_param_in_ty((*field_type).into(), param))
+ .filter(|(_index, field_type)| find_param_in_ty((*field_type).into(), param))
) else {
return Err(expr);
};
@@ -825,20 +832,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Err(expr)
}
+}
- // FIXME: This can be made into a private, non-impl function later.
- /// Traverses the given ty (either a `ty::Ty` or a `ty::GenericArg`) and searches for references
- /// to the given `param_to_point_at`. Returns `true` if it finds any use of the param.
- pub fn find_param_in_ty(
- ty: ty::GenericArg<'tcx>,
- param_to_point_at: ty::GenericArg<'tcx>,
- ) -> bool {
- let mut walk = ty.walk();
- while let Some(arg) = walk.next() {
- if arg == param_to_point_at {
- return true;
- }
- if let ty::GenericArgKind::Type(ty) = arg.unpack()
+/// Traverses the given ty (either a `ty::Ty` or a `ty::GenericArg`) and searches for references
+/// to the given `param_to_point_at`. Returns `true` if it finds any use of the param.
+fn find_param_in_ty<'tcx>(
+ ty: ty::GenericArg<'tcx>,
+ param_to_point_at: ty::GenericArg<'tcx>,
+) -> bool {
+ let mut walk = ty.walk();
+ while let Some(arg) = walk.next() {
+ if arg == param_to_point_at {
+ return true;
+ }
+ if let ty::GenericArgKind::Type(ty) = arg.unpack()
&& let ty::Alias(ty::Projection, ..) = ty.kind()
{
// This logic may seem a bit strange, but typically when
@@ -849,16 +856,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// in some UI tests.
walk.skip_current_subtree();
}
- }
- false
}
+ false
+}
- // FIXME: This can be made into a private, non-impl function later.
- /// Returns `Some(iterator.next())` if it has exactly one item, and `None` otherwise.
- pub fn is_iterator_singleton<T>(mut iterator: impl Iterator<Item = T>) -> Option<T> {
- match (iterator.next(), iterator.next()) {
- (_, Some(_)) => None,
- (first, _) => first,
- }
+/// Returns `Some(iterator.next())` if it has exactly one item, and `None` otherwise.
+fn is_iterator_singleton<T>(mut iterator: impl Iterator<Item = T>) -> Option<T> {
+ match (iterator.next(), iterator.next()) {
+ (_, Some(_)) => None,
+ (first, _) => first,
}
}
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index a46bdeb41..ea1b52daa 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -24,14 +24,14 @@ use rustc_hir_analysis::structured_errors::StructuredDiagnostic;
use rustc_index::vec::IndexVec;
use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::InferOk;
use rustc_infer::infer::TypeTrace;
+use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::visit::TypeVisitableExt;
-use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty};
+use rustc_middle::ty::{self, IsSuggestable, Ty};
use rustc_session::Session;
use rustc_span::symbol::{kw, Ident};
-use rustc_span::{self, sym, Span};
+use rustc_span::{self, sym, BytePos, Span};
use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext};
use std::iter;
@@ -301,9 +301,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// 3. Check if the formal type is a supertype of the checked one
// and register any such obligations for future type checks
- let supertype_error = self
- .at(&self.misc(provided_arg.span), self.param_env)
- .sup(formal_input_ty, coerced_ty);
+ let supertype_error = self.at(&self.misc(provided_arg.span), self.param_env).sup(
+ DefineOpaqueTypes::No,
+ formal_input_ty,
+ coerced_ty,
+ );
let subtyping_error = match supertype_error {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
@@ -470,7 +472,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err_code: &str,
fn_def_id: Option<DefId>,
call_span: Span,
- call_expr: &hir::Expr<'tcx>,
+ call_expr: &'tcx hir::Expr<'tcx>,
) {
// Next, let's construct the error
let (error_span, full_call_span, call_name, is_method) = match &call_expr.kind {
@@ -585,7 +587,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Using probe here, since we don't want this subtyping to affect inference.
let subtyping_error = self.probe(|_| {
- self.at(&self.misc(arg_span), self.param_env).sup(formal_input_ty, coerced_ty).err()
+ self.at(&self.misc(arg_span), self.param_env)
+ .sup(DefineOpaqueTypes::No, formal_input_ty, coerced_ty)
+ .err()
});
// Same as above: if either the coerce type or the checked type is an error type,
@@ -764,7 +768,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let (provided_ty, provided_span) = provided_arg_tys[*provided_idx];
let trace =
mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty);
- if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308(_)) {
+ if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) {
self.err_ctxt().report_and_explain_type_error(trace, *e).emit();
return true;
}
@@ -803,24 +807,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
full_call_span,
format!("arguments to this {} are incorrect", call_name),
);
- if let (Some(callee_ty), hir::ExprKind::MethodCall(_, rcvr, _, _)) =
- (callee_ty, &call_expr.kind)
+
+ if let hir::ExprKind::MethodCall(_, rcvr, _, _) = call_expr.kind
+ && provided_idx.as_usize() == expected_idx.as_usize()
{
- // Type that would have accepted this argument if it hadn't been inferred earlier.
- // FIXME: We leave an inference variable for now, but it'd be nice to get a more
- // specific type to increase the accuracy of the diagnostic.
- let expected = self.infcx.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::MiscVariable,
- span: full_call_span,
- });
- self.point_at_expr_source_of_inferred_type(
+ self.note_source_of_type_mismatch_constraint(
&mut err,
rcvr,
- expected,
- callee_ty,
- provided_arg_span,
+ crate::demand::TypeMismatchSource::Arg {
+ call_expr,
+ incompatible_arg: provided_idx.as_usize(),
+ },
);
}
+
// Call out where the function is defined
self.label_fn_like(
&mut err,
@@ -890,8 +890,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let mut errors = errors.into_iter().peekable();
+ let mut only_extras_so_far = errors
+ .peek()
+ .map_or(false, |first| matches!(first, Error::Extra(arg_idx) if arg_idx.index() == 0));
let mut suggestions = vec![];
while let Some(error) = errors.next() {
+ only_extras_so_far &= matches!(error, Error::Extra(_));
+
match error {
Error::Invalid(provided_idx, expected_idx, compatibility) => {
let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx];
@@ -937,10 +942,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if arg_idx.index() > 0
&& let Some((_, prev)) = provided_arg_tys
.get(ProvidedIdx::from_usize(arg_idx.index() - 1)
- ) {
- // Include previous comma
- span = prev.shrink_to_hi().to(span);
- }
+ ) {
+ // Include previous comma
+ span = prev.shrink_to_hi().to(span);
+ }
+
+ // Is last argument for deletion in a row starting from the 0-th argument?
+ // Then delete the next comma, so we are not left with `f(, ...)`
+ //
+ // fn f() {}
+ // - f(0, 1,)
+ // + f()
+ if only_extras_so_far
+ && errors
+ .peek()
+ .map_or(true, |next_error| !matches!(next_error, Error::Extra(_)))
+ {
+ let next = provided_arg_tys
+ .get(arg_idx + 1)
+ .map(|&(_, sp)| sp)
+ .unwrap_or_else(|| {
+ // Subtract one to move before `)`
+ call_expr.span.with_lo(call_expr.span.hi() - BytePos(1))
+ });
+
+ // Include next comma
+ span = span.until(next);
+ }
+
suggestions.push((span, String::new()));
suggestion_text = match suggestion_text {
@@ -1158,11 +1187,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// index position where it *should have been*, which is *after* the previous one.
if let Some(provided_idx) = provided_idx {
prev = provided_idx.index() as i64;
+ continue;
}
let idx = ProvidedIdx::from_usize((prev + 1) as usize);
- if let None = provided_idx
- && let Some((_, arg_span)) = provided_arg_tys.get(idx)
- {
+ if let Some((_, arg_span)) = provided_arg_tys.get(idx) {
+ prev += 1;
// There is a type that was *not* found anywhere, so it isn't a move, but a
// replacement and we look at what type it should have been. This will allow us
// To suggest a multipart suggestion when encountering `foo(1, "")` where the def
@@ -1380,7 +1409,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.demand_eqtype(init.span, local_ty, init_ty);
init_ty
} else {
- self.check_expr_coercable_to_type(init, local_ty, None)
+ self.check_expr_coercible_to_type(init, local_ty, None)
}
}
@@ -1665,7 +1694,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise.
fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> {
let parent = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(blk_id).def_id);
- self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident))
+ self.get_node_fn_decl(parent).map(|(_, fn_decl, ident, _)| (fn_decl, ident))
}
/// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 1dea3e6f9..c6fd0b610 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -211,13 +211,13 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
fn get_type_parameter_bounds(
&self,
_: Span,
- def_id: DefId,
+ def_id: LocalDefId,
_: Ident,
) -> ty::GenericPredicates<'tcx> {
let tcx = self.tcx;
- let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local());
+ let item_def_id = tcx.hir().ty_param_owner(def_id);
let generics = tcx.generics_of(item_def_id);
- let index = generics.param_def_id_to_index[&def_id];
+ let index = generics.param_def_id_to_index[&def_id.to_def_id()];
ty::GenericPredicates {
parent: None,
predicates: tcx.arena.alloc_from_iter(
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index c49621b7c..5fda4e191 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -16,7 +16,7 @@ use rustc_infer::traits::{self, StatementAsExpression};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{
- self, suggest_constraining_type_params, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty,
+ self, suggest_constraining_type_params, Binder, IsSuggestable, ToPredicate, Ty,
TypeVisitableExt,
};
use rustc_session::errors::ExprParenthesesNeeded;
@@ -64,8 +64,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let expr = expr.peel_drop_temps();
self.suggest_missing_semicolon(err, expr, expected, false);
let mut pointing_at_return_type = false;
- if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
- let fn_id = self.tcx.hir().get_return_block(blk_id).unwrap();
+ if let Some((fn_id, fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
pointing_at_return_type = self.suggest_missing_return_type(
err,
&fn_decl,
@@ -166,8 +165,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
ty: Ty<'tcx>,
) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {
- let body_hir_id = self.tcx.hir().local_def_id_to_hir_id(self.body_id);
- self.err_ctxt().extract_callable_info(body_hir_id, self.param_env, ty)
+ self.err_ctxt().extract_callable_info(self.body_id, self.param_env, ty)
}
pub fn suggest_two_fn_call(
@@ -669,6 +667,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// This routine checks if the return type is left as default, the method is not part of an
/// `impl` block and that it isn't the `main` method. If so, it suggests setting the return
/// type.
+ #[instrument(level = "trace", skip(self, err))]
pub(in super::super) fn suggest_missing_return_type(
&self,
err: &mut Diagnostic,
@@ -705,28 +704,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return true
}
}
- hir::FnRetTy::Return(ty) => {
- let span = ty.span;
-
- if let hir::TyKind::OpaqueDef(item_id, ..) = ty.kind
- && let hir::Node::Item(hir::Item {
- kind: hir::ItemKind::OpaqueTy(op_ty),
- ..
- }) = self.tcx.hir().get(item_id.hir_id())
- && let hir::OpaqueTy {
- bounds: [bound], ..
- } = op_ty
- && let hir::GenericBound::LangItemTrait(
- hir::LangItem::Future, _, _, generic_args) = bound
- && let hir::GenericArgs { bindings: [ty_binding], .. } = generic_args
- && let hir::TypeBinding { kind, .. } = ty_binding
- && let hir::TypeBindingKind::Equality { term } = kind
- && let hir::Term::Ty(term_ty) = term {
+ hir::FnRetTy::Return(hir_ty) => {
+ let span = hir_ty.span;
+
+ if let hir::TyKind::OpaqueDef(item_id, ..) = hir_ty.kind
+ && let hir::Node::Item(hir::Item {
+ kind: hir::ItemKind::OpaqueTy(op_ty),
+ ..
+ }) = self.tcx.hir().get(item_id.hir_id())
+ && let [hir::GenericBound::LangItemTrait(
+ hir::LangItem::Future, _, _, generic_args)] = op_ty.bounds
+ && let hir::GenericArgs { bindings: [ty_binding], .. } = generic_args
+ && let hir::TypeBindingKind::Equality { term: hir::Term::Ty(term) } = ty_binding.kind
+ {
// Check if async function's return type was omitted.
// Don't emit suggestions if the found type is `impl Future<...>`.
- debug!("suggest_missing_return_type: found = {:?}", found);
+ debug!(?found);
if found.is_suggestable(self.tcx, false) {
- if term_ty.span.is_empty() {
+ if term.span.is_empty() {
err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found: found.to_string() });
return true;
} else {
@@ -737,11 +732,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Only point to return type if the expected type is the return type, as if they
// are not, the expectation must have been caused by something else.
- debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind);
- let ty = self.astconv().ast_ty_to_ty(ty);
- debug!("suggest_missing_return_type: return type {:?}", ty);
- debug!("suggest_missing_return_type: expected type {:?}", ty);
- let bound_vars = self.tcx.late_bound_vars(fn_id);
+ debug!("return type {:?}", hir_ty);
+ let ty = self.astconv().ast_ty_to_ty(hir_ty);
+ debug!("return type {:?}", ty);
+ debug!("expected type {:?}", expected);
+ let bound_vars = self.tcx.late_bound_vars(hir_ty.hir_id.owner.into());
let ty = Binder::bind_with_vars(ty, bound_vars);
let ty = self.normalize(span, ty);
let ty = self.tcx.erase_late_bound_regions(ty);
@@ -988,13 +983,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
.must_apply_modulo_regions()
{
- diag.span_suggestion_verbose(
- expr.span.shrink_to_hi(),
- "consider using clone here",
- ".clone()",
- Applicability::MachineApplicable,
- );
- return true;
+ let suggestion = match self.maybe_get_struct_pattern_shorthand_field(expr) {
+ Some(ident) => format!(": {}.clone()", ident),
+ None => ".clone()".to_string()
+ };
+
+ diag.span_suggestion_verbose(
+ expr.span.shrink_to_hi(),
+ "consider using clone here",
+ suggestion,
+ Applicability::MachineApplicable,
+ );
+ return true;
}
false
}
@@ -1015,11 +1015,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut suggest_copied_or_cloned = || {
let expr_inner_ty = substs.type_at(0);
let expected_inner_ty = expected_substs.type_at(0);
- if let ty::Ref(_, ty, hir::Mutability::Not) = expr_inner_ty.kind()
- && self.can_eq(self.param_env, *ty, expected_inner_ty)
+ if let &ty::Ref(_, ty, hir::Mutability::Not) = expr_inner_ty.kind()
+ && self.can_eq(self.param_env, ty, expected_inner_ty)
{
let def_path = self.tcx.def_path_str(adt_def.did());
- if self.type_is_copy_modulo_regions(self.param_env, *ty, expr.span) {
+ if self.type_is_copy_modulo_regions(self.param_env, ty) {
diag.span_suggestion_verbose(
expr.span.shrink_to_hi(),
format!(
@@ -1033,9 +1033,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions(
self,
self.param_env,
- *ty,
+ ty,
clone_did,
- expr.span
)
{
diag.span_suggestion_verbose(
@@ -1156,13 +1155,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return false;
}
- diag.span_suggestion(
+ let suggestion = match self.maybe_get_struct_pattern_shorthand_field(expr) {
+ Some(ident) => format!(": {}.is_some()", ident),
+ None => ".is_some()".to_string(),
+ };
+
+ diag.span_suggestion_verbose(
expr.span.shrink_to_hi(),
"use `Option::is_some` to test if the `Option` has a value",
- ".is_some()",
+ suggestion,
Applicability::MachineApplicable,
);
-
true
}
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
index 7c0402b1c..3e9a9ce1b 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
@@ -190,7 +190,6 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
//
// Some of these may be interesting in the future
ExprKind::Path(..)
- | ExprKind::Box(..)
| ExprKind::ConstBlock(..)
| ExprKind::Array(..)
| ExprKind::Call(..)
@@ -478,7 +477,6 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
| ExprKind::AssignOp(..)
| ExprKind::Binary(..)
| ExprKind::Block(..)
- | ExprKind::Box(..)
| ExprKind::Cast(..)
| ExprKind::Closure { .. }
| ExprKind::ConstBlock(..)
@@ -528,8 +526,9 @@ impl DropRangesBuilder {
let mut next = <_>::from(0u32);
for value in tracked_values {
for_each_consumable(hir, value, |value| {
- if !tracked_value_map.contains_key(&value) {
- tracked_value_map.insert(value, next);
+ if let std::collections::hash_map::Entry::Vacant(e) = tracked_value_map.entry(value)
+ {
+ e.insert(next);
next = next + 1;
}
});
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
index 2e41c2041..f39710804 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
@@ -13,7 +13,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::hir_id::HirIdSet;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
-use rustc_infer::infer::RegionVariableOrigin;
+use rustc_infer::infer::{DefineOpaqueTypes, RegionVariableOrigin};
use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData};
use rustc_middle::ty::fold::FnMutDelegate;
use rustc_middle::ty::{self, BoundVariableKind, RvalueScopes, Ty, TyCtxt, TypeVisitableExt};
@@ -239,8 +239,7 @@ pub fn resolve_interior<'a, 'tcx>(
// typeck had previously found constraints that would cause them to be related.
let mut counter = 0;
- let mut mk_bound_region = |span| {
- let kind = ty::BrAnon(counter, span);
+ let mut mk_bound_region = |kind| {
let var = ty::BoundVar::from_u32(counter);
counter += 1;
ty::BoundRegion { var, kind }
@@ -252,24 +251,23 @@ pub fn resolve_interior<'a, 'tcx>(
let origin = fcx.region_var_origin(vid);
match origin {
RegionVariableOrigin::EarlyBoundRegion(span, _) => {
- mk_bound_region(Some(span))
+ mk_bound_region(ty::BrAnon(Some(span)))
}
- _ => mk_bound_region(None),
+ _ => mk_bound_region(ty::BrAnon(None)),
}
}
- // FIXME: these should use `BrNamed`
ty::ReEarlyBound(region) => {
- mk_bound_region(Some(fcx.tcx.def_span(region.def_id)))
+ mk_bound_region(ty::BrNamed(region.def_id, region.name))
}
ty::ReLateBound(_, ty::BoundRegion { kind, .. })
| ty::ReFree(ty::FreeRegion { bound_region: kind, .. }) => match kind {
- ty::BoundRegionKind::BrAnon(_, span) => mk_bound_region(span),
- ty::BoundRegionKind::BrNamed(def_id, _) => {
- mk_bound_region(Some(fcx.tcx.def_span(def_id)))
+ ty::BoundRegionKind::BrAnon(span) => mk_bound_region(ty::BrAnon(span)),
+ ty::BoundRegionKind::BrNamed(def_id, sym) => {
+ mk_bound_region(ty::BrNamed(def_id, sym))
}
- ty::BoundRegionKind::BrEnv => mk_bound_region(None),
+ ty::BoundRegionKind::BrEnv => mk_bound_region(ty::BrAnon(None)),
},
- _ => mk_bound_region(None),
+ _ => mk_bound_region(ty::BrAnon(None)),
};
let r = fcx.tcx.mk_re_late_bound(current_depth, br);
r
@@ -293,10 +291,7 @@ pub fn resolve_interior<'a, 'tcx>(
type_causes,
FnMutDelegate {
regions: &mut |br| {
- let kind = match br.kind {
- ty::BrAnon(_, span) => ty::BrAnon(counter, span),
- _ => br.kind,
- };
+ let kind = br.kind;
let var = ty::BoundVar::from_usize(bound_vars.len());
bound_vars.push(ty::BoundVariableKind::Region(kind));
counter += 1;
@@ -313,8 +308,7 @@ pub fn resolve_interior<'a, 'tcx>(
// Extract type components to build the witness type.
let type_list = fcx.tcx.mk_type_list_from_iter(type_causes.iter().map(|cause| cause.ty));
let bound_vars = fcx.tcx.mk_bound_variable_kinds(&bound_vars);
- let witness =
- fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars.clone()));
+ let witness = fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars));
drop(typeck_results);
// Store the generator types and spans into the typeck results for this generator.
@@ -327,7 +321,11 @@ pub fn resolve_interior<'a, 'tcx>(
);
// Unify the type variable inside the generator with the new witness
- match fcx.at(&fcx.misc(body.value.span), fcx.param_env).eq(interior, witness) {
+ match fcx.at(&fcx.misc(body.value.span), fcx.param_env).eq(
+ DefineOpaqueTypes::No,
+ interior,
+ witness,
+ ) {
Ok(ok) => fcx.register_infer_ok_obligations(ok),
_ => bug!("failed to relate {interior} and {witness}"),
}
diff --git a/compiler/rustc_hir_typeck/src/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs
index 26020382d..4110b176b 100644
--- a/compiler/rustc_hir_typeck/src/inherited.rs
+++ b/compiler/rustc_hir_typeck/src/inherited.rs
@@ -4,7 +4,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::HirIdMap;
-use rustc_infer::infer;
use rustc_infer::infer::{DefiningAnchor, InferCtxt, InferOk, TyCtxtInferExt};
use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -58,8 +57,6 @@ pub struct Inherited<'tcx> {
pub(super) deferred_generator_interiors:
RefCell<Vec<(LocalDefId, hir::BodyId, Ty<'tcx>, hir::GeneratorKind)>>,
- pub(super) body_id: Option<hir::BodyId>,
-
/// Whenever we introduce an adjustment from `!` into a type variable,
/// we record that type variable here. This is later used to inform
/// fallback. See the `fallback` module for details.
@@ -75,48 +72,16 @@ impl<'tcx> Deref for Inherited<'tcx> {
}
}
-/// A temporary returned by `Inherited::build(...)`. This is necessary
-/// for multiple `InferCtxt` to share the same `typeck_results`
-/// without using `Rc` or something similar.
-pub struct InheritedBuilder<'tcx> {
- infcx: infer::InferCtxtBuilder<'tcx>,
- def_id: LocalDefId,
- typeck_results: RefCell<ty::TypeckResults<'tcx>>,
-}
-
impl<'tcx> Inherited<'tcx> {
- pub fn build(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> InheritedBuilder<'tcx> {
+ pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner;
- InheritedBuilder {
- infcx: tcx
- .infer_ctxt()
- .ignoring_regions()
- .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id)),
- def_id,
- typeck_results: RefCell::new(ty::TypeckResults::new(hir_owner)),
- }
- }
-}
-
-impl<'tcx> InheritedBuilder<'tcx> {
- pub fn enter<F, R>(mut self, f: F) -> R
- where
- F: FnOnce(&Inherited<'tcx>) -> R,
- {
- let def_id = self.def_id;
- f(&Inherited::new(self.infcx.build(), def_id, self.typeck_results))
- }
-}
-
-impl<'tcx> Inherited<'tcx> {
- fn new(
- infcx: InferCtxt<'tcx>,
- def_id: LocalDefId,
- typeck_results: RefCell<ty::TypeckResults<'tcx>>,
- ) -> Self {
- let tcx = infcx.tcx;
- let body_id = tcx.hir().maybe_body_owned_by(def_id);
+ let infcx = tcx
+ .infer_ctxt()
+ .ignoring_regions()
+ .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id))
+ .build();
+ let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner));
Inherited {
typeck_results,
@@ -130,7 +95,6 @@ impl<'tcx> Inherited<'tcx> {
deferred_asm_checks: RefCell::new(Vec::new()),
deferred_generator_interiors: RefCell::new(Vec::new()),
diverging_type_vars: RefCell::new(Default::default()),
- body_id,
infer_var_info: RefCell::new(Default::default()),
}
}
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
index 19d2befc4..106f5bcd7 100644
--- a/compiler/rustc_hir_typeck/src/intrinsicck.rs
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -4,7 +4,7 @@ use rustc_hir as hir;
use rustc_index::vec::Idx;
use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
-use rustc_target::abi::{Pointer, VariantIdx};
+use rustc_target::abi::{FieldIdx, Pointer, VariantIdx};
use super::FnCtxt;
@@ -28,7 +28,7 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
}
if def.variant(data_idx).fields.len() == 1 {
- return def.variant(data_idx).fields[0].ty(tcx, substs);
+ return def.variant(data_idx).fields[FieldIdx::from_u32(0)].ty(tcx, substs);
}
}
@@ -84,6 +84,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let skeleton_string = |ty: Ty<'tcx>, sk| match sk {
Ok(SizeSkeleton::Known(size)) => format!("{} bits", size.bits()),
Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"),
+ Ok(SizeSkeleton::Generic(size)) => {
+ if let Some(size) = size.try_eval_target_usize(tcx, self.param_env) {
+ format!("{size} bytes")
+ } else {
+ format!("generic size {size}")
+ }
+ }
Err(LayoutError::Unknown(bad)) => {
if bad == ty {
"this type does not have a fixed size".to_owned()
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index e397dfd45..45890abad 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -45,13 +45,14 @@ mod rvalue_scopes;
mod upvar;
mod writeback;
-pub use diverges::Diverges;
-pub use expectation::Expectation;
-pub use fn_ctxt::*;
-pub use inherited::{Inherited, InheritedBuilder};
+pub use fn_ctxt::FnCtxt;
+pub use inherited::Inherited;
use crate::check::check_fn;
use crate::coercion::DynamicCoerceMany;
+use crate::diverges::Diverges;
+use crate::expectation::Expectation;
+use crate::fn_ctxt::RawTy;
use crate::gather_locals::GatherLocalsVisitor;
use rustc_data_structures::unord::UnordSet;
use rustc_errors::{
@@ -74,7 +75,7 @@ use rustc_session::Session;
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::{sym, Span};
-fluent_messages! { "../locales/en-US.ftl" }
+fluent_messages! { "../messages.ftl" }
#[macro_export]
macro_rules! type_error_struct {
@@ -105,10 +106,9 @@ pub struct LocalTy<'tcx> {
/// (notably closures), `typeck_results(def_id)` would wind up
/// redirecting to the owning function.
fn primary_body_of(
- tcx: TyCtxt<'_>,
- id: hir::HirId,
+ node: Node<'_>,
) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
- match tcx.hir().get(id) {
+ match node {
Node::Item(item) => match item.kind {
hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
Some((body, Some(ty), None))
@@ -142,8 +142,7 @@ fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
}
if let Some(def_id) = def_id.as_local() {
- let id = tcx.hir().local_def_id_to_hir_id(def_id);
- primary_body_of(tcx, id).is_some()
+ primary_body_of(tcx.hir().get_by_def_id(def_id)).is_some()
} else {
false
}
@@ -198,143 +197,140 @@ fn typeck_with_fallback<'tcx>(
}
let id = tcx.hir().local_def_id_to_hir_id(def_id);
+ let node = tcx.hir().get(id);
let span = tcx.hir().span(id);
// Figure out what primary body this item has.
- let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| {
+ let (body_id, body_ty, fn_sig) = primary_body_of(node).unwrap_or_else(|| {
span_bug!(span, "can't type-check body of {:?}", def_id);
});
let body = tcx.hir().body(body_id);
- let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
- let param_env = tcx.param_env(def_id);
- let param_env = if tcx.has_attr(def_id.to_def_id(), sym::rustc_do_not_const_check) {
- param_env.without_const()
+ let param_env = tcx.param_env(def_id);
+ let param_env = if tcx.has_attr(def_id, sym::rustc_do_not_const_check) {
+ param_env.without_const()
+ } else {
+ param_env
+ };
+ let inh = Inherited::new(tcx, def_id);
+ let mut fcx = FnCtxt::new(&inh, param_env, def_id);
+
+ if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
+ let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() {
+ fcx.astconv().ty_of_fn(id, header.unsafety, header.abi, decl, None, None)
} else {
- param_env
+ tcx.fn_sig(def_id).subst_identity()
};
- let mut fcx = FnCtxt::new(&inh, param_env, def_id);
-
- if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
- let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() {
- fcx.astconv().ty_of_fn(id, header.unsafety, header.abi, decl, None, None)
- } else {
- tcx.fn_sig(def_id).subst_identity()
- };
- check_abi(tcx, id, span, fn_sig.abi());
+ check_abi(tcx, id, span, fn_sig.abi());
- // Compute the function signature from point of view of inside the fn.
- let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
- let fn_sig = fcx.normalize(body.value.span, fn_sig);
+ // Compute the function signature from point of view of inside the fn.
+ let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
+ let fn_sig = fcx.normalize(body.value.span, fn_sig);
- check_fn(&mut fcx, fn_sig, decl, def_id, body, None);
- } else {
- let expected_type = body_ty
- .and_then(|ty| match ty.kind {
- hir::TyKind::Infer => Some(fcx.astconv().ast_ty_to_ty(ty)),
- _ => None,
- })
- .unwrap_or_else(|| match tcx.hir().get(id) {
- Node::AnonConst(_) => match tcx.hir().get(tcx.hir().parent_id(id)) {
- Node::Expr(&hir::Expr {
- kind: hir::ExprKind::ConstBlock(ref anon_const),
- ..
- }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::TypeInference,
- span,
- }),
- Node::Ty(&hir::Ty {
- kind: hir::TyKind::Typeof(ref anon_const), ..
- }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::TypeInference,
- span,
- }),
- Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
- | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
- let operand_ty =
- asm.operands.iter().find_map(|(op, _op_sp)| match op {
- hir::InlineAsmOperand::Const { anon_const }
- if anon_const.hir_id == id =>
- {
- // Inline assembly constants must be integers.
- Some(fcx.next_int_var())
- }
- hir::InlineAsmOperand::SymFn { anon_const }
- if anon_const.hir_id == id =>
- {
- Some(fcx.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::MiscVariable,
- span,
- }))
- }
- _ => None,
- });
- operand_ty.unwrap_or_else(fallback)
+ check_fn(&mut fcx, fn_sig, decl, def_id, body, None);
+ } else {
+ let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer, span, .. }) = body_ty {
+ Some(fcx.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::TypeInference,
+ span,
+ }))
+ } else if let Node::AnonConst(_) = node {
+ match tcx.hir().get(tcx.hir().parent_id(id)) {
+ Node::Expr(&hir::Expr {
+ kind: hir::ExprKind::ConstBlock(ref anon_const), ..
+ }) if anon_const.hir_id == id => Some(fcx.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::TypeInference,
+ span,
+ })),
+ Node::Ty(&hir::Ty { kind: hir::TyKind::Typeof(ref anon_const), .. })
+ if anon_const.hir_id == id =>
+ {
+ Some(fcx.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::TypeInference,
+ span,
+ }))
+ }
+ Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
+ | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
+ asm.operands.iter().find_map(|(op, _op_sp)| match op {
+ hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == id => {
+ // Inline assembly constants must be integers.
+ Some(fcx.next_int_var())
+ }
+ hir::InlineAsmOperand::SymFn { anon_const } if anon_const.hir_id == id => {
+ Some(fcx.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::MiscVariable,
+ span,
+ }))
}
- _ => fallback(),
- },
- _ => fallback(),
- });
+ _ => None,
+ })
+ }
+ _ => None,
+ }
+ } else {
+ None
+ };
+ let expected_type = expected_type.unwrap_or_else(fallback);
- let expected_type = fcx.normalize(body.value.span, expected_type);
- fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
+ let expected_type = fcx.normalize(body.value.span, expected_type);
+ fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
- // Gather locals in statics (because of block expressions).
- GatherLocalsVisitor::new(&fcx).visit_body(body);
+ // Gather locals in statics (because of block expressions).
+ GatherLocalsVisitor::new(&fcx).visit_body(body);
- fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
+ fcx.check_expr_coercible_to_type(&body.value, expected_type, None);
- fcx.write_ty(id, expected_type);
- };
+ fcx.write_ty(id, expected_type);
+ };
- fcx.type_inference_fallback();
-
- // Even though coercion casts provide type hints, we check casts after fallback for
- // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
- fcx.check_casts();
- fcx.select_obligations_where_possible(|_| {});
-
- // Closure and generator analysis may run after fallback
- // because they don't constrain other type variables.
- // Closure analysis only runs on closures. Therefore they only need to fulfill non-const predicates (as of now)
- let prev_constness = fcx.param_env.constness();
- fcx.param_env = fcx.param_env.without_const();
- fcx.closure_analyze(body);
- fcx.param_env = fcx.param_env.with_constness(prev_constness);
- assert!(fcx.deferred_call_resolutions.borrow().is_empty());
- // Before the generator analysis, temporary scopes shall be marked to provide more
- // precise information on types to be captured.
- fcx.resolve_rvalue_scopes(def_id.to_def_id());
-
- for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
- let ty = fcx.normalize(span, ty);
- fcx.require_type_is_sized(ty, span, code);
- }
+ fcx.type_inference_fallback();
+
+ // Even though coercion casts provide type hints, we check casts after fallback for
+ // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
+ fcx.check_casts();
+ fcx.select_obligations_where_possible(|_| {});
+
+ // Closure and generator analysis may run after fallback
+ // because they don't constrain other type variables.
+ // Closure analysis only runs on closures. Therefore they only need to fulfill non-const predicates (as of now)
+ let prev_constness = fcx.param_env.constness();
+ fcx.param_env = fcx.param_env.without_const();
+ fcx.closure_analyze(body);
+ fcx.param_env = fcx.param_env.with_constness(prev_constness);
+ assert!(fcx.deferred_call_resolutions.borrow().is_empty());
+ // Before the generator analysis, temporary scopes shall be marked to provide more
+ // precise information on types to be captured.
+ fcx.resolve_rvalue_scopes(def_id.to_def_id());
+
+ for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
+ let ty = fcx.normalize(span, ty);
+ fcx.require_type_is_sized(ty, span, code);
+ }
- fcx.select_obligations_where_possible(|_| {});
+ fcx.select_obligations_where_possible(|_| {});
- debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations());
+ debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations());
- // This must be the last thing before `report_ambiguity_errors`.
- fcx.resolve_generator_interiors(def_id.to_def_id());
+ // This must be the last thing before `report_ambiguity_errors`.
+ fcx.resolve_generator_interiors(def_id.to_def_id());
- debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations());
+ debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations());
- if let None = fcx.infcx.tainted_by_errors() {
- fcx.report_ambiguity_errors();
- }
+ if let None = fcx.infcx.tainted_by_errors() {
+ fcx.report_ambiguity_errors();
+ }
- if let None = fcx.infcx.tainted_by_errors() {
- fcx.check_transmutes();
- }
+ if let None = fcx.infcx.tainted_by_errors() {
+ fcx.check_transmutes();
+ }
- fcx.check_asms();
+ fcx.check_asms();
- fcx.infcx.skip_region_resolution();
+ fcx.infcx.skip_region_resolution();
- fcx.resolve_type_vars_in_body(body)
- });
+ let typeck_results = fcx.resolve_type_vars_in_body(body);
// Consistency check our TypeckResults instance can hold all ItemLocalIds
// it will need to hold.
diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index 4d3969d28..6c861b593 100644
--- a/compiler/rustc_hir_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -59,10 +59,9 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::LocalDefId;
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
use rustc_hir::PatKind;
-use rustc_index::vec::Idx;
use rustc_infer::infer::InferCtxt;
use rustc_span::Span;
-use rustc_target::abi::VariantIdx;
+use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};
use rustc_trait_selection::infer::InferCtxtExt;
pub(crate) trait HirNode {
@@ -120,8 +119,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
self.infcx.tcx
}
- pub(crate) fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool {
- self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span)
+ pub(crate) fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
+ self.infcx.type_is_copy_modulo_regions(self.param_env, ty)
}
fn resolve_vars_if_possible<T>(&self, value: T) -> T
@@ -331,7 +330,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
expr,
base,
expr_ty,
- ProjectionKind::Field(field_idx as u32, VariantIdx::new(0)),
+ ProjectionKind::Field(field_idx, FIRST_VARIANT),
))
}
@@ -382,7 +381,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
| hir::ExprKind::Struct(..)
| hir::ExprKind::Repeat(..)
| hir::ExprKind::InlineAsm(..)
- | hir::ExprKind::Box(..)
| hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr.span, expr_ty)),
}
}
@@ -562,7 +560,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
| Res::SelfTyParam { .. }
| Res::SelfTyAlias { .. } => {
// Structs and Unions have only have one variant.
- Ok(VariantIdx::new(0))
+ Ok(FIRST_VARIANT)
}
_ => bug!("expected ADT path, found={:?}", res),
}
@@ -676,7 +674,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) {
let subpat_ty = self.pat_ty_adjusted(subpat)?;
- let projection_kind = ProjectionKind::Field(i as u32, VariantIdx::new(0));
+ let projection_kind =
+ ProjectionKind::Field(FieldIdx::from_usize(i), FIRST_VARIANT);
let sub_place =
self.cat_projection(pat, place_with_id.clone(), subpat_ty, projection_kind);
self.cat_pattern_(sub_place, subpat, op)?;
@@ -691,7 +690,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) {
let subpat_ty = self.pat_ty_adjusted(subpat)?;
- let projection_kind = ProjectionKind::Field(i as u32, variant_index);
+ let projection_kind =
+ ProjectionKind::Field(FieldIdx::from_usize(i), variant_index);
let sub_place =
self.cat_projection(pat, place_with_id.clone(), subpat_ty, projection_kind);
self.cat_pattern_(sub_place, subpat, op)?;
@@ -716,7 +716,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
pat,
place_with_id.clone(),
field_ty,
- ProjectionKind::Field(field_index as u32, variant_index),
+ ProjectionKind::Field(field_index, variant_index),
);
self.cat_pattern_(field_place, fp.pat, op)?;
}
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 169f128e0..9155a3d8d 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -8,7 +8,7 @@ use rustc_hir_analysis::astconv::generics::{
check_generic_arg_count_for_call, create_substs_for_generic_args,
};
use rustc_hir_analysis::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
-use rustc_infer::infer::{self, InferOk};
+use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk};
use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
@@ -478,7 +478,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
substs,
})),
);
- match self.at(&cause, self.param_env).sup(method_self_ty, self_ty) {
+ match self.at(&cause, self.param_env).sup(DefineOpaqueTypes::No, method_self_ty, self_ty) {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
}
@@ -574,19 +574,15 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
) -> Option<Span> {
let sized_def_id = self.tcx.lang_items().sized_trait()?;
- traits::elaborate_predicates(self.tcx, predicates.predicates.iter().copied())
+ traits::elaborate(self.tcx, predicates.predicates.iter().copied())
// We don't care about regions here.
- .filter_map(|obligation| match obligation.predicate.kind().skip_binder() {
+ .filter_map(|pred| match pred.kind().skip_binder() {
ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred))
if trait_pred.def_id() == sized_def_id =>
{
let span = predicates
.iter()
- .find_map(
- |(p, span)| {
- if p == obligation.predicate { Some(span) } else { None }
- },
- )
+ .find_map(|(p, span)| if p == pred { Some(span) } else { None })
.unwrap_or(rustc_span::DUMMY_SP);
Some((trait_pred, span))
}
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 3bef5cfcd..4fd778910 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -13,6 +13,7 @@ use rustc_hir_analysis::astconv::InferCtxtExt as _;
use rustc_hir_analysis::autoderef::{self, Autoderef};
use rustc_infer::infer::canonical::OriginalQueryValues;
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
+use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
use rustc_middle::middle::stability;
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
@@ -699,7 +700,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
fn assemble_inherent_candidates_for_incoherent_ty(&mut self, self_ty: Ty<'tcx>) {
- let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsInfer) else {
+ let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsCandidateKey) else {
bug!("unexpected incoherent type: {:?}", self_ty)
};
for &impl_def_id in self.tcx.incoherent_impls(simp) {
@@ -792,6 +793,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// a `&self` method will wind up with an argument type like `&dyn Trait`.
let trait_ref = principal.with_self_ty(self.tcx, self_ty);
self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| {
+ if new_trait_ref.has_non_region_late_bound() {
+ this.tcx.sess.delay_span_bug(
+ this.span,
+ "tried to select method from HRTB with non-lifetime bound vars",
+ );
+ return;
+ }
+
let new_trait_ref = this.erase_late_bound_regions(new_trait_ref);
let (xform_self_ty, xform_ret_ty) =
@@ -836,24 +845,21 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::Ambiguous
- | ty::PredicateKind::AliasEq(..)
+ | ty::PredicateKind::AliasRelate(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
}
});
self.elaborate_bounds(bounds, |this, poly_trait_ref, item| {
- let trait_ref = this.erase_late_bound_regions(poly_trait_ref);
+ let trait_ref = this.instantiate_binder_with_fresh_vars(
+ this.span,
+ infer::LateBoundRegionConversionTime::FnCall,
+ poly_trait_ref,
+ );
let (xform_self_ty, xform_ret_ty) =
this.xform_self_ty(item, trait_ref.self_ty(), trait_ref.substs);
- // Because this trait derives from a where-clause, it
- // should not contain any inference variables or other
- // artifacts. This means it is safe to put into the
- // `WhereClauseCandidate` and (eventually) into the
- // `WhereClausePick`.
- assert!(!trait_ref.substs.needs_infer());
-
this.push_candidate(
Candidate {
xform_self_ty,
@@ -929,7 +935,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
if let Some(self_ty) = self_ty {
if self
.at(&ObligationCause::dummy(), self.param_env)
- .sup(fty.inputs()[0], self_ty)
+ .sup(DefineOpaqueTypes::No, fty.inputs()[0], self_ty)
.is_err()
{
return false;
@@ -963,7 +969,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
bound_trait_ref.def_id(),
));
} else {
- let new_trait_ref = self.erase_late_bound_regions(bound_trait_ref);
+ let new_trait_ref = self.instantiate_binder_with_fresh_vars(
+ self.span,
+ infer::LateBoundRegionConversionTime::FnCall,
+ bound_trait_ref,
+ );
let (xform_self_ty, xform_ret_ty) =
self.xform_self_ty(item, new_trait_ref.self_ty(), new_trait_ref.substs);
@@ -1026,12 +1036,21 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
true
}
})
+ // ensure that we don't suggest unstable methods
+ .filter(|candidate| {
+ // note that `DUMMY_SP` is ok here because it is only used for
+ // suggestions and macro stuff which isn't applicable here.
+ !matches!(
+ self.tcx.eval_stability(candidate.item.def_id, None, DUMMY_SP, None),
+ stability::EvalResult::Deny { .. }
+ )
+ })
.map(|candidate| candidate.item.ident(self.tcx))
.filter(|&name| set.insert(name))
.collect();
// Sort them by the name so we have a stable result.
- names.sort_by(|a, b| a.as_str().partial_cmp(b.as_str()).unwrap());
+ names.sort_by(|a, b| a.as_str().cmp(b.as_str()));
names
}
@@ -1338,6 +1357,7 @@ impl<'tcx> Pick<'tcx> {
container: _,
trait_item_def_id: _,
fn_has_self_parameter: _,
+ opt_rpitit_info: _,
},
kind: _,
import_ids: _,
@@ -1434,9 +1454,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
CandidateSource::Trait(candidate.item.container_id(self.tcx))
}
TraitCandidate(trait_ref) => self.probe(|_| {
- let _ = self
- .at(&ObligationCause::dummy(), self.param_env)
- .sup(candidate.xform_self_ty, self_ty);
+ let _ = self.at(&ObligationCause::dummy(), self.param_env).sup(
+ DefineOpaqueTypes::No,
+ candidate.xform_self_ty,
+ self_ty,
+ );
match self.select_trait_candidate(trait_ref) {
Ok(Some(traits::ImplSource::UserDefined(ref impl_data))) => {
// If only a single impl matches, make the error message point
@@ -1463,10 +1485,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self.probe(|_| {
// First check that the self type can be related.
- let sub_obligations = match self
- .at(&ObligationCause::dummy(), self.param_env)
- .sup(probe.xform_self_ty, self_ty)
- {
+ let sub_obligations = match self.at(&ObligationCause::dummy(), self.param_env).sup(
+ DefineOpaqueTypes::No,
+ probe.xform_self_ty,
+ self_ty,
+ ) {
Ok(InferOk { obligations, value: () }) => obligations,
Err(err) => {
debug!("--> cannot relate self-types {:?}", err);
@@ -1508,23 +1531,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// Convert the bounds into obligations.
let impl_obligations = traits::predicates_for_generics(
- |_idx, span| {
- let misc = traits::ObligationCause::misc(span, self.body_id);
- let parent_trait_pred = ty::Binder::dummy(ty::TraitPredicate {
- trait_ref: ty::TraitRef::from_method(self.tcx, impl_def_id, substs),
- constness: ty::BoundConstness::NotConst,
- polarity: ty::ImplPolarity::Positive,
- });
- misc.derived_cause(parent_trait_pred, |derived| {
- traits::ImplDerivedObligation(Box::new(
- traits::ImplDerivedObligationCause {
- derived,
- impl_or_alias_def_id: impl_def_id,
- impl_def_predicate_index: None,
- span,
- },
- ))
- })
+ |idx, span| {
+ let code = if span.is_dummy() {
+ traits::ExprItemObligation(impl_def_id, self.scope_expr_id, idx)
+ } else {
+ traits::ExprBindingObligation(
+ impl_def_id,
+ span,
+ self.scope_expr_id,
+ idx,
+ )
+ };
+ ObligationCause::new(self.span, self.body_id, code)
},
self.param_env,
impl_bounds,
@@ -1541,8 +1559,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
if !self.predicate_may_hold(&o) {
result = ProbeResult::NoMatch;
let parent_o = o.clone();
- let implied_obligations =
- traits::elaborate_obligations(self.tcx, vec![o]);
+ let implied_obligations = traits::elaborate(self.tcx, vec![o]);
for o in implied_obligations {
let parent = if o == parent_o {
None
@@ -1681,7 +1698,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
if let ProbeResult::Match = result
&& self
.at(&ObligationCause::dummy(), self.param_env)
- .sup(return_ty, xform_ret_ty)
+ .sup(DefineOpaqueTypes::No, return_ty, xform_ret_ty)
.is_err()
{
result = ProbeResult::BadReturnType;
@@ -1742,7 +1759,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
fn probe_for_similar_candidate(&mut self) -> Result<Option<ty::AssocItem>, MethodError<'tcx>> {
debug!("probing for method names similar to {:?}", self.method_name);
- let steps = self.steps.clone();
self.probe(|_| {
let mut pcx = ProbeContext::new(
self.fcx,
@@ -1750,8 +1766,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self.mode,
self.method_name,
self.return_type,
- &self.orig_steps_var_values,
- steps,
+ self.orig_steps_var_values,
+ self.steps,
self.scope_expr_id,
);
pcx.allow_similar_names = true;
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 60d56263d..900a6fa0d 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -27,7 +27,7 @@ use rustc_middle::traits::util::supertraits;
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
use rustc_middle::ty::print::{with_crate_prefix, with_forced_trimmed_paths};
-use rustc_middle::ty::{self, DefIdTree, GenericArgKind, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Symbol;
@@ -42,7 +42,7 @@ use rustc_trait_selection::traits::{
use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope};
use super::{CandidateSource, MethodError, NoMatchData};
use rustc_hir::intravisit::Visitor;
-use std::cmp::Ordering;
+use std::cmp::{self, Ordering};
use std::iter;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -245,6 +245,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
None
}
+ fn suggest_missing_writer(
+ &self,
+ rcvr_ty: Ty<'tcx>,
+ args: (&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>]),
+ ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+ let (ty_str, _ty_file) = self.tcx.short_ty_string(rcvr_ty);
+ let mut err =
+ struct_span_err!(self.tcx.sess, args.0.span, E0599, "cannot write into `{}`", ty_str);
+ err.span_note(
+ args.0.span,
+ "must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method",
+ );
+ if let ExprKind::Lit(_) = args.0.kind {
+ err.span_help(
+ args.0.span.shrink_to_lo(),
+ "a writer is needed before this format string",
+ );
+ };
+
+ err
+ }
+
pub fn report_no_match_method_error(
&self,
mut span: Span,
@@ -278,7 +300,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
// We could pass the file for long types into these two, but it isn't strictly necessary
- // given how targetted they are.
+ // given how targeted they are.
if self.suggest_wrapping_range_with_parens(
tcx,
rcvr_ty,
@@ -323,16 +345,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- let mut err = struct_span_err!(
- tcx.sess,
- span,
- E0599,
- "no {} named `{}` found for {} `{}` in the current scope",
- item_kind,
- item_name,
- rcvr_ty.prefix_string(self.tcx),
- ty_str_reported,
- );
+ let is_write = sugg_span.ctxt().outer_expn_data().macro_def_id.map_or(false, |def_id| {
+ tcx.is_diagnostic_item(sym::write_macro, def_id)
+ || tcx.is_diagnostic_item(sym::writeln_macro, def_id)
+ }) && item_name.name == Symbol::intern("write_fmt");
+ let mut err = if is_write
+ && let Some(args) = args
+ {
+ self.suggest_missing_writer(rcvr_ty, args)
+ } else {
+ struct_span_err!(
+ tcx.sess,
+ span,
+ E0599,
+ "no {} named `{}` found for {} `{}` in the current scope",
+ item_kind,
+ item_name,
+ rcvr_ty.prefix_string(self.tcx),
+ ty_str_reported,
+ )
+ };
if tcx.sess.source_map().is_multiline(sugg_span) {
err.span_label(sugg_span.with_hi(span.lo()), "");
}
@@ -348,6 +380,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.downgrade_to_delayed_bug();
}
+ if tcx.ty_is_opaque_future(rcvr_ty) && item_name.name == sym::poll {
+ err.help(&format!(
+ "method `poll` found on `Pin<&mut {ty_str}>`, \
+ see documentation for `std::pin::Pin`"
+ ));
+ err.help("self type must be pinned to call `Future::poll`, \
+ see https://rust-lang.github.io/async-book/04_pinning/01_chapter.html#pinning-in-practice"
+ );
+ }
+
if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
self.suggest_await_before_method(
&mut err, item_name, rcvr_ty, cal, span, expected.only_has_type(self),
@@ -405,6 +447,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
probe.is_ok()
});
+
+ self.note_internal_mutation_in_method(
+ &mut err,
+ rcvr_expr,
+ expected.to_option(&self),
+ rcvr_ty,
+ );
}
let mut custom_span_label = false;
@@ -612,19 +661,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Find all the requirements that come from a local `impl` block.
let mut skip_list: FxHashSet<_> = Default::default();
let mut spanned_predicates = FxHashMap::default();
- for (p, parent_p, impl_def_id, cause) in unsatisfied_predicates
- .iter()
- .filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c)))
- .filter_map(|(p, parent, c)| match c.code() {
- ObligationCauseCode::ImplDerivedObligation(data)
- if matches!(p.kind().skip_binder(), ty::PredicateKind::Clause(_)) =>
- {
- Some((p, parent, data.impl_or_alias_def_id, data))
+ for (p, parent_p, cause) in unsatisfied_predicates {
+ // Extract the predicate span and parent def id of the cause,
+ // if we have one.
+ let (item_def_id, cause_span) = match cause.as_ref().map(|cause| cause.code()) {
+ Some(ObligationCauseCode::ImplDerivedObligation(data)) => {
+ (data.impl_or_alias_def_id, data.span)
}
- _ => None,
- })
- {
- match self.tcx.hir().get_if_local(impl_def_id) {
+ Some(
+ ObligationCauseCode::ExprBindingObligation(def_id, span, _, _)
+ | ObligationCauseCode::BindingObligation(def_id, span),
+ ) => (*def_id, *span),
+ _ => continue,
+ };
+
+ // Don't point out the span of `WellFormed` predicates.
+ if !matches!(p.kind().skip_binder(), ty::PredicateKind::Clause(_)) {
+ continue;
+ };
+
+ match self.tcx.hir().get_if_local(item_def_id) {
// Unmet obligation comes from a `derive` macro, point at it once to
// avoid multiple span labels pointing at the same place.
Some(Node::Item(hir::Item {
@@ -669,7 +725,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
});
for param in generics.params {
- if param.span == cause.span && sized_pred {
+ if param.span == cause_span && sized_pred {
let (sp, sugg) = match param.colon_span {
Some(sp) => (sp.shrink_to_hi(), " ?Sized +"),
None => (param.span.shrink_to_hi(), ": ?Sized"),
@@ -692,9 +748,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(FxHashSet::default(), FxHashSet::default(), Vec::new())
});
entry.2.push(p);
- if cause.span != *item_span {
- entry.0.insert(cause.span);
- entry.1.insert((cause.span, "unsatisfied trait bound introduced here"));
+ if cause_span != *item_span {
+ entry.0.insert(cause_span);
+ entry.1.insert((cause_span, "unsatisfied trait bound introduced here"));
} else {
if let Some(trait_ref) = of_trait {
entry.0.insert(trait_ref.path.span);
@@ -726,9 +782,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let entry = entry.or_insert_with(|| {
(FxHashSet::default(), FxHashSet::default(), Vec::new())
});
- entry.0.insert(cause.span);
+ entry.0.insert(cause_span);
entry.1.insert((ident.span, ""));
- entry.1.insert((cause.span, "unsatisfied trait bound introduced here"));
+ entry.1.insert((cause_span, "unsatisfied trait bound introduced here"));
entry.2.push(p);
}
Some(node) => unreachable!("encountered `{node:?}`"),
@@ -1164,7 +1220,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.inputs()
.skip_binder()
.get(0)
- .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr())
+ .filter(|ty| ty.is_ref() && !rcvr_ty.is_ref())
.copied()
.unwrap_or(rcvr_ty),
};
@@ -1247,7 +1303,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let target_ty = self
.autoderef(sugg_span, rcvr_ty)
.find(|(rcvr_ty, _)| {
- DeepRejectCtxt { treat_obligation_params: TreatParams::AsInfer }
+ DeepRejectCtxt { treat_obligation_params: TreatParams::AsCandidateKey }
.types_may_unify(*rcvr_ty, impl_ty)
})
.map_or(impl_ty, |(ty, _)| ty)
@@ -1506,7 +1562,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.into_iter()
.any(|info| self.associated_value(info.def_id, item_name).is_some());
let found_assoc = |ty: Ty<'tcx>| {
- simplify_type(tcx, ty, TreatParams::AsInfer)
+ simplify_type(tcx, ty, TreatParams::AsCandidateKey)
.and_then(|simp| {
tcx.incoherent_impls(simp)
.iter()
@@ -1766,7 +1822,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.variants()
.iter()
.flat_map(|variant| {
- let [field] = &variant.fields[..] else { return None; };
+ let [field] = &variant.fields.raw[..] else { return None; };
let field_ty = field.ty(tcx, substs);
// Skip `_`, since that'll just lead to ambiguity.
@@ -2517,7 +2573,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if !candidates.is_empty() {
// Sort from most relevant to least relevant.
- candidates.sort_by(|a, b| a.cmp(b).reverse());
+ candidates.sort_by_key(|&info| cmp::Reverse(info));
candidates.dedup();
let param_type = match rcvr_ty.kind() {
@@ -2636,7 +2692,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// cases where a positive bound implies a negative impl.
(candidates, Vec::new())
} else if let Some(simp_rcvr_ty) =
- simplify_type(self.tcx, rcvr_ty, TreatParams::AsPlaceholder)
+ simplify_type(self.tcx, rcvr_ty, TreatParams::ForLookup)
{
let mut potential_candidates = Vec::new();
let mut explicitly_negative = Vec::new();
@@ -2651,7 +2707,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.any(|imp_did| {
let imp = self.tcx.impl_trait_ref(imp_did).unwrap().subst_identity();
let imp_simp =
- simplify_type(self.tcx, imp.self_ty(), TreatParams::AsPlaceholder);
+ simplify_type(self.tcx, imp.self_ty(), TreatParams::ForLookup);
imp_simp.map_or(false, |s| s == simp_rcvr_ty)
})
{
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index 80279ed96..a52c94cb0 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -12,16 +12,14 @@ use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
};
use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{
- self, DefIdTree, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
-};
+use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
-use rustc_trait_selection::traits::{self, FulfillmentError};
+use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt};
use rustc_type_ir::sty::TyKind::*;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -103,9 +101,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match BinOpCategory::from(op) {
BinOpCategory::Shortcircuit => {
// && and || are a simple case.
- self.check_expr_coercable_to_type(lhs_expr, tcx.types.bool, None);
+ self.check_expr_coercible_to_type(lhs_expr, tcx.types.bool, None);
let lhs_diverges = self.diverges.get();
- self.check_expr_coercable_to_type(rhs_expr, tcx.types.bool, None);
+ self.check_expr_coercible_to_type(rhs_expr, tcx.types.bool, None);
// Depending on the LHS' value, the RHS can never execute.
self.diverges.set(lhs_diverges);
@@ -148,10 +146,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
rhs_ty,
op,
);
- self.demand_suptype(expr.span, builtin_return_ty, return_ty);
+ self.demand_eqtype(expr.span, builtin_return_ty, return_ty);
+ builtin_return_ty
+ } else {
+ return_ty
}
-
- return_ty
}
}
}
@@ -254,7 +253,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
// see `NB` above
- let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var, Some(lhs_expr));
+ let rhs_ty = self.check_expr_coercible_to_type(rhs_expr, rhs_ty_var, Some(lhs_expr));
let rhs_ty = self.resolve_vars_with_obligations(rhs_ty);
let return_ty = match result {
@@ -433,7 +432,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if self.type_is_copy_modulo_regions(
self.param_env,
*lhs_deref_ty,
- lhs_expr.span,
) {
suggest_deref_binop(*lhs_deref_ty);
}
@@ -775,7 +773,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(None, Some(trait_did)) => {
let (obligation, _) =
self.obligation_for_method(cause, trait_did, lhs_ty, Some(input_types));
- Err(rustc_trait_selection::traits::fully_solve_obligation(self, obligation))
+ // FIXME: This should potentially just add the obligation to the `FnCtxt`
+ let ocx = ObligationCtxt::new(&self.infcx);
+ ocx.register_obligation(obligation);
+ Err(ocx.select_all_or_error())
}
}
}
@@ -962,21 +963,3 @@ fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOp) -> bool
}
}
}
-
-struct TypeParamEraser<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, Span);
-
-impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TypeParamEraser<'_, 'tcx> {
- fn interner(&self) -> TyCtxt<'tcx> {
- self.0.tcx
- }
-
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
- match ty.kind() {
- ty::Param(_) => self.0.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::MiscVariable,
- span: self.1,
- }),
- _ => ty.super_fold_with(self),
- }
- }
-}
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index c36c75e44..af0bd26de 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -19,6 +19,7 @@ use rustc_span::hygiene::DesugaringKind;
use rustc_span::source_map::{Span, Spanned};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{BytePos, DUMMY_SP};
+use rustc_target::abi::FieldIdx;
use rustc_trait_selection::traits::{ObligationCause, Pattern};
use ty::VariantDef;
@@ -36,6 +37,10 @@ pointers. If you encounter this error you should try to avoid dereferencing the
You can read more about trait objects in the Trait Objects section of the Reference: \
https://doc.rust-lang.org/reference/types.html#trait-objects";
+fn is_number(text: &str) -> bool {
+ text.chars().all(|c: char| c.is_digit(10))
+}
+
/// Information about the expected type at the top level of type checking a pattern.
///
/// **NOTE:** This is only for use by diagnostics. Do NOT use for type checking logic!
@@ -238,15 +243,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Note that there are two tests to check that this remains true
// (`regions-reassign-{match,let}-bound-pointer.rs`).
//
- // 2. Things go horribly wrong if we use subtype. The reason for
- // THIS is a fairly subtle case involving bound regions. See the
- // `givens` field in `region_constraints`, as well as the test
+ // 2. An outdated issue related to the old HIR borrowck. See the test
// `regions-relate-bound-regions-on-closures-to-inference-variables.rs`,
- // for details. Short version is that we must sometimes detect
- // relationships between specific region variables and regions
- // bound in a closure signature, and that detection gets thrown
- // off when we substitute fresh region variables here to enable
- // subtyping.
}
/// Compute the new expected type and default binding mode from the old ones
@@ -1098,11 +1096,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
bug!("unexpected pattern type {:?}", pat_ty);
};
for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
- let field_ty = self.field_ty(subpat.span, &variant.fields[i], substs);
+ let field = &variant.fields[FieldIdx::from_usize(i)];
+ let field_ty = self.field_ty(subpat.span, field, substs);
self.check_pat(subpat, field_ty, def_bm, ti);
self.tcx.check_stability(
- variant.fields[i].did,
+ variant.fields[FieldIdx::from_usize(i)].did,
Some(pat.hir_id),
subpat.span,
None,
@@ -1110,7 +1109,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
} else {
// Pattern has wrong number of fields.
- let e = self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected, had_err);
+ let e =
+ self.e0023(pat.span, res, qpath, subpats, &variant.fields.raw, expected, had_err);
on_error(e);
return tcx.ty_error(e);
}
@@ -1340,8 +1340,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Index the struct fields' types.
let field_map = variant
.fields
- .iter()
- .enumerate()
+ .iter_enumerated()
.map(|(i, field)| (field.ident(self.tcx).normalize_to_macros_2_0(), (i, field)))
.collect::<FxHashMap<_, _>>();
@@ -1678,7 +1677,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fields: &'tcx [hir::PatField<'tcx>],
variant: &ty::VariantDef,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
- if let (Some(CtorKind::Fn), PatKind::Struct(qpath, ..)) = (variant.ctor_kind(), &pat.kind) {
+ if let (Some(CtorKind::Fn), PatKind::Struct(qpath, pattern_fields, ..)) =
+ (variant.ctor_kind(), &pat.kind)
+ {
+ let is_tuple_struct_match = !pattern_fields.is_empty()
+ && pattern_fields.iter().map(|field| field.ident.name.as_str()).all(is_number);
+ if is_tuple_struct_match {
+ return None;
+ }
+
let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
s.print_qpath(qpath, false)
});
@@ -1900,7 +1907,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
prefix,
unmentioned_fields
.iter()
- .map(|(_, name)| name.to_string())
+ .map(|(_, name)| {
+ let field_name = name.to_string();
+ if is_number(&field_name) {
+ format!("{}: _", field_name)
+ } else {
+ field_name
+ }
+ })
.collect::<Vec<_>>()
.join(", "),
if have_inaccessible_fields { ", .." } else { "" },
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 4a432328c..41a6ad80b 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -49,8 +49,7 @@ use rustc_span::{BytePos, Pos, Span, Symbol};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_index::vec::Idx;
-use rustc_target::abi::VariantIdx;
+use rustc_target::abi::FIRST_VARIANT;
use std::iter;
@@ -424,7 +423,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// closures. We want to make sure any adjustment that might make us move the place into
// the closure gets handled.
let (place, capture_kind) =
- restrict_precision_for_drop_types(self, place, capture_kind, usage_span);
+ restrict_precision_for_drop_types(self, place, capture_kind);
capture_info.capture_kind = capture_kind;
(place, capture_info)
@@ -712,10 +711,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- unreachable!(
- "we captured two identical projections: capture1 = {:?}, capture2 = {:?}",
- capture1, capture2
+ self.tcx.sess.delay_span_bug(
+ closure_span,
+ &format!(
+ "two identical projections: ({:?}, {:?})",
+ capture1.place.projections, capture2.place.projections
+ ),
);
+ std::cmp::Ordering::Equal
});
}
@@ -1402,7 +1405,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ProjectionKind::Field(..)
))
);
- def.variants().get(VariantIdx::new(0)).unwrap().fields.iter().enumerate().any(
+ def.variants().get(FIRST_VARIANT).unwrap().fields.iter_enumerated().any(
|(i, field)| {
let paths_using_field = captured_by_move_projs
.iter()
@@ -1410,7 +1413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let ProjectionKind::Field(field_idx, _) =
projs.first().unwrap().kind
{
- if (field_idx as usize) == i { Some(&projs[1..]) } else { None }
+ if field_idx == i { Some(&projs[1..]) } else { None }
} else {
unreachable!();
}
@@ -1443,7 +1446,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.filter_map(|projs| {
if let ProjectionKind::Field(field_idx, _) = projs.first().unwrap().kind
{
- if (field_idx as usize) == i { Some(&projs[1..]) } else { None }
+ if field_idx.index() == i { Some(&projs[1..]) } else { None }
} else {
unreachable!();
}
@@ -1498,7 +1501,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
fn should_log_capture_analysis(&self, closure_def_id: LocalDefId) -> bool {
- self.tcx.has_attr(closure_def_id.to_def_id(), sym::rustc_capture_analysis)
+ self.tcx.has_attr(closure_def_id, sym::rustc_capture_analysis)
}
fn log_capture_analysis_first_pass(
@@ -1822,9 +1825,8 @@ fn restrict_precision_for_drop_types<'a, 'tcx>(
fcx: &'a FnCtxt<'a, 'tcx>,
mut place: Place<'tcx>,
mut curr_mode: ty::UpvarCapture,
- span: Span,
) -> (Place<'tcx>, ty::UpvarCapture) {
- let is_copy_type = fcx.infcx.type_is_copy_modulo_regions(fcx.param_env, place.ty(), span);
+ let is_copy_type = fcx.infcx.type_is_copy_modulo_regions(fcx.param_env, place.ty());
if let (false, UpvarCapture::ByValue) = (is_copy_type, curr_mode) {
for i in 0..place.projections.len() {
@@ -1891,14 +1893,13 @@ fn restrict_capture_precision(
for (i, proj) in place.projections.iter().enumerate() {
match proj.kind {
- ProjectionKind::Index => {
- // Arrays are completely captured, so we drop Index projections
+ ProjectionKind::Index | ProjectionKind::Subslice => {
+ // Arrays are completely captured, so we drop Index and Subslice projections
truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, i);
return (place, curr_mode);
}
ProjectionKind::Deref => {}
ProjectionKind::Field(..) => {} // ignore
- ProjectionKind::Subslice => {} // We never capture this
}
}
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 00348f3af..e876fa275 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -44,8 +44,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// This attribute causes us to dump some writeback information
// in the form of errors, which is used for unit tests.
- let rustc_dump_user_substs =
- self.tcx.has_attr(item_def_id.to_def_id(), sym::rustc_dump_user_substs);
+ let rustc_dump_user_substs = self.tcx.has_attr(item_def_id, sym::rustc_dump_user_substs);
let mut wbcx = WritebackCx::new(self, body, rustc_dump_user_substs);
for param in body.params {
@@ -748,7 +747,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
.infcx
.err_ctxt()
.emit_inference_failure_err(
- Some(self.body.id()),
+ self.tcx.hir().body_owner_def_id(self.body.id()),
self.span.to_span(self.tcx),
p.into(),
E0282,