summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_typeck/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /compiler/rustc_hir_typeck/src
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz
rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_hir_typeck/src')
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs14
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs23
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs27
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs267
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs105
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs249
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs20
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs105
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs43
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs86
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs29
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs74
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_propagate.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/mod.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/inherited.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/intrinsicck.rs16
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs56
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs27
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs12
-rw-r--r--compiler/rustc_hir_typeck/src/method/prelude2021.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs17
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs296
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs62
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs36
-rw-r--r--compiler/rustc_hir_typeck/src/place_op.rs50
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs48
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs113
35 files changed, 1122 insertions, 710 deletions
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 6c2ce6272..7d2f7e876 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -271,7 +271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&cause,
&mut |err| {
if let Some((span, msg)) = &ret_reason {
- err.span_label(*span, msg);
+ err.span_label(*span, msg.clone());
} else if let ExprKind::Block(block, _) = &then_expr.kind
&& let Some(expr) = &block.expr
{
@@ -530,7 +530,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for ty in [first_ty, second_ty] {
for (pred, _) in self
.tcx
- .bound_explicit_item_bounds(rpit_def_id)
+ .explicit_item_bounds(rpit_def_id)
.subst_iter_copied(self.tcx, substs)
{
let pred = pred.kind().rebind(match pred.kind().skip_binder() {
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 5235710a2..655ab94eb 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -397,7 +397,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.sess
.struct_span_err(
callee_expr.span,
- &format!("evaluate({:?}) = {:?}", predicate, result),
+ format!("evaluate({:?}) = {:?}", predicate, result),
)
.span_label(predicate_span, "predicate")
.emit();
@@ -630,7 +630,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some((removal_span, kind, path)) = &unit_variant {
err.span_suggestion_verbose(
*removal_span,
- &format!(
+ format!(
"`{path}` is a unit {kind}, and does not take parentheses to be constructed",
),
"",
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 1481c038c..98c683f02 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -146,7 +146,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let reported = self
.tcx
.sess
- .delay_span_bug(span, &format!("`{:?}` should be sized but is not?", t));
+ .delay_span_bug(span, format!("`{:?}` should be sized but is not?", t));
return Err(reported);
}
})
@@ -270,7 +270,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
fcx,
);
if self.cast_ty.is_integral() {
- err.help(&format!(
+ err.help(format!(
"cast through {} first",
match e {
CastError::NeedViaPtr => "a raw pointer",
@@ -292,7 +292,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
self.cast_ty,
fcx,
)
- .help(&format!(
+ .help(format!(
"cast through {} first",
match e {
CastError::NeedViaInt => "an integer",
@@ -465,7 +465,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
.sess
.source_map()
.span_to_snippet(self.expr_span)
- .map_or(false, |snip| snip.starts_with('('));
+ .is_ok_and(|snip| snip.starts_with('('));
// Very crude check to see whether the expression must be wrapped
// in parentheses for the suggestion to work (issue #89497).
@@ -651,13 +651,13 @@ impl<'a, 'tcx> CastCheck<'tcx> {
);
}
Err(_) => {
- let msg = &format!("did you mean `&{}{}`?", mtstr, tstr);
+ let msg = format!("did you mean `&{}{}`?", mtstr, tstr);
err.span_help(self.cast_span, msg);
}
}
} else {
let msg =
- &format!("consider using an implicit coercion to `&{mtstr}{tstr}` instead");
+ format!("consider using an implicit coercion to `&{mtstr}{tstr}` instead");
err.span_help(self.span, msg);
}
}
@@ -674,7 +674,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
Err(_) => {
err.span_help(
self.cast_span,
- &format!("you might have meant `Box<{tstr}>`"),
+ format!("you might have meant `Box<{tstr}>`"),
);
}
}
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index bf8259ff7..bfabd44bb 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -32,6 +32,7 @@ pub(super) fn check_fn<'a, 'tcx>(
fn_def_id: LocalDefId,
body: &'tcx hir::Body<'tcx>,
can_be_generator: Option<hir::Movability>,
+ params_can_be_unsized: bool,
) -> Option<GeneratorTypes<'tcx>> {
let fn_id = fcx.tcx.hir().local_def_id_to_hir_id(fn_def_id);
@@ -94,7 +95,7 @@ pub(super) fn check_fn<'a, 'tcx>(
// The check for a non-trivial pattern is a hack to avoid duplicate warnings
// for simple cases like `fn foo(x: Trait)`,
// where we would error once on the parameter as a whole, and once on the binding `x`.
- if param.pat.simple_ident().is_none() && !tcx.features().unsized_fn_params {
+ if param.pat.simple_ident().is_none() && !params_can_be_unsized {
fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
}
@@ -103,24 +104,8 @@ pub(super) fn check_fn<'a, 'tcx>(
fcx.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
- if let ty::Dynamic(_, _, ty::Dyn) = declared_ret_ty.kind() {
- // FIXME: We need to verify that the return type is `Sized` after the return expression has
- // been evaluated so that we have types available for all the nodes being returned, but that
- // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this
- // causes unsized errors caused by the `declared_ret_ty` to point at the return expression,
- // while keeping the current ordering we will ignore the tail expression's type because we
- // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr`
- // because we will trigger "unreachable expression" lints unconditionally.
- // Because of all of this, we perform a crude check to know whether the simplest `!Sized`
- // case that a newcomer might make, returning a bare trait, and in that case we populate
- // the tail expression's type so that the suggestion will be correct, but ignore all other
- // possible cases.
- fcx.check_expr(&body.value);
- fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
- } else {
- fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
- fcx.check_return_expr(&body.value, false);
- }
+ fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
+ fcx.check_return_expr(&body.value, false);
// We insert the deferred_generator_interiors entry after visiting the body.
// This ensures that all nested generators appear before the entry of this generator.
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 8c2495e1d..9659a0ec1 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -89,6 +89,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr_def_id,
body,
closure.movability,
+ // Closure "rust-call" ABI doesn't support unsized params
+ false,
);
let parent_substs = InternalSubsts::identity_for_item(
@@ -172,7 +174,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self
.deduce_closure_signature_from_predicates(
expected_ty,
- self.tcx.bound_explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs),
+ self.tcx.explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs),
),
ty::Dynamic(ref object_type, ..) => {
let sig = object_type.projection_bounds().find_map(|pb| {
@@ -713,13 +715,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self
.tcx
- .bound_explicit_item_bounds(def_id)
+ .explicit_item_bounds(def_id)
.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.is_impl_trait_in_trait(proj.def_id) => self
.tcx
- .bound_explicit_item_bounds(proj.def_id)
+ .explicit_item_bounds(proj.def_id)
.subst_iter_copied(self.tcx, proj.substs)
.find_map(|(p, s)| get_future_output(p, s))?,
_ => span_bug!(
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 8fa3bcd68..08c4082e8 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -601,7 +601,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
self.tcx,
cause,
self.fcx.param_env,
- self.tcx.mk_trait_ref(coerce_unsized_did, [coerce_source, coerce_target])
+ ty::TraitRef::new(self.tcx, coerce_unsized_did, [coerce_source, coerce_target])
)];
let mut has_unsized_tuple_coercion = false;
@@ -707,9 +707,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
&self.tcx.sess.parse_sess,
sym::trait_upcasting,
self.cause.span,
- &format!("cannot cast `{sub}` to `{sup}`, trait upcasting coercion is experimental"),
+ format!("cannot cast `{sub}` to `{sup}`, trait upcasting coercion is experimental"),
);
- err.note(&format!("required when coercing `{source}` into `{target}`"));
+ err.note(format!("required when coercing `{source}` into `{target}`"));
err.emit();
}
@@ -764,8 +764,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
self.tcx,
self.cause.clone(),
self.param_env,
- ty::Binder::dummy(
- self.tcx.at(self.cause.span).mk_trait_ref(hir::LangItem::PointerLike, [a]),
+ ty::TraitRef::from_lang_item(
+ self.tcx,
+ hir::LangItem::PointerLike,
+ self.cause.span,
+ [a],
),
));
@@ -976,7 +979,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Attempt to coerce an expression to a type, and return the
/// adjusted type of the expression, if successful.
/// Adjustments are only recorded if the coercion succeeded.
- /// The expressions *must not* have any pre-existing adjustments.
+ /// The expressions *must not* have any preexisting adjustments.
pub fn try_coerce(
&self,
expr: &hir::Expr<'_>,
@@ -1340,7 +1343,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
}
/// As an optimization, you can create a `CoerceMany` with a
- /// pre-existing slice of expressions. In this case, you are
+ /// preexisting slice of expressions. In this case, you are
/// expected to pass each element in the slice to `coerce(...)` in
/// order. This is used with arrays in particular to avoid
/// needlessly cloning the slice.
@@ -1657,7 +1660,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
"the function expects a value to always be returned, but loops might run zero times",
);
if MAXITER < ret_exprs.len() {
- err.note(&format!(
+ err.note(format!(
"if the loop doesn't execute, {} other values would never get returned",
ret_exprs.len() - MAXITER
));
@@ -1767,7 +1770,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
{
err.span_note(
sp,
- &format!(
+ format!(
"return type inferred to be `{}` here",
expected
),
@@ -1811,7 +1814,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
.span_to_snippet(return_sp)
.unwrap_or_else(|_| "dyn Trait".to_string());
let mut snippet_iter = snippet.split_whitespace();
- let has_impl = snippet_iter.next().map_or(false, |s| s == "impl");
+ let has_impl = snippet_iter.next().is_some_and(|s| s == "impl");
// Only suggest `Box<dyn Trait>` if `Trait` in `impl Trait` is object safe.
let mut is_object_safe = false;
if let hir::FnRetTy::Return(ty) = fn_output
@@ -1831,7 +1834,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
bound
.trait_ref()
.and_then(|t| t.trait_def_id())
- .map_or(false, |def_id| {
+ .is_some_and(|def_id| {
fcx.tcx.check_is_object_safe(def_id)
})
})
@@ -1864,7 +1867,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
Applicability::MaybeIncorrect,
);
} else {
- err.help(&format!(
+ err.help(format!(
"if the trait `{}` were object safe, you could return a boxed trait object",
&snippet[5..]
));
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 13442c316..b50630e63 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -17,7 +17,6 @@ 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, DUMMY_SP};
-use rustc_target::abi::FieldIdx;
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::ObligationCause;
@@ -52,7 +51,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|| self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty)
|| self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty)
|| self.suggest_no_capture_closure(err, expected, expr_ty)
- || self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty)
+ || self.suggest_boxing_when_appropriate(err, expr.span, expr.hir_id, expected, expr_ty)
|| self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected)
|| self.suggest_copied_or_cloned(err, expr, expr_ty, expected)
|| self.suggest_clone_for_ref(err, expr, expr_ty, expected)
@@ -87,9 +86,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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, 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);
+ self.suggest_method_call_on_range_literal(err, expr, expr_ty, expected);
+ self.suggest_return_binding_for_missing_tail_expr(err, expr, expr_ty, expected);
+ self.note_wrong_return_ty_due_to_generic_arg(err, expr, expr_ty);
}
/// Requires that the two types unify, and prints an error message if
@@ -544,13 +543,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// We are pointing at the binding's type or initializer value, but it's pattern
// is in a different line, so we point at both.
err.span_label(secondary_span, "expected due to the type of this binding");
- err.span_label(primary_span, &format!("expected due to this{post_message}"));
+ err.span_label(primary_span, format!("expected due to this{post_message}"));
} else if post_message == "" {
// We are pointing at either the assignment lhs or the binding def pattern.
err.span_label(primary_span, "expected due to the type of this binding");
} else {
// We are pointing at the binding's type or initializer value.
- err.span_label(primary_span, &format!("expected due to this{post_message}"));
+ err.span_label(primary_span, format!("expected due to this{post_message}"));
}
if !lhs.is_syntactic_place_expr() {
@@ -567,7 +566,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) if rhs.hir_id == expr.hir_id
&& self.typeck_results.borrow().expr_ty_adjusted_opt(lhs) == Some(expected) =>
{
- err.span_label(lhs.span, &format!("expected because this is `{expected}`"));
+ err.span_label(lhs.span, format!("expected because this is `{expected}`"));
}
_ => {}
}
@@ -705,19 +704,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
});
err.span_note(
path_span,
- &format!(
+ format!(
"the `{}` call is resolved to the method in `{container}`, shadowing {tail}",
path.ident,
),
);
if suggestions.len() > other_methods_in_scope.len() {
- err.note(&format!(
+ err.note(format!(
"additionally, there are {} other available methods that aren't in scope",
suggestions.len() - other_methods_in_scope.len()
));
}
err.multipart_suggestions(
- &format!(
+ format!(
"you might have meant to call {}; you can use the fully-qualified path to call {} \
explicitly",
if suggestions.len() == 1 {
@@ -875,7 +874,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
variant.fields.len() == 1
})
.filter_map(|variant| {
- let sole_field = &variant.fields[FieldIdx::from_u32(0)];
+ let sole_field = &variant.single_field();
let field_is_local = sole_field.did.is_local();
let field_is_accessible =
@@ -942,7 +941,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
[(variant, ctor_kind, field_name, note)] => {
// Just a single matching variant.
err.multipart_suggestion_verbose(
- &format!(
+ format!(
"try wrapping the expression in `{variant}`{note}",
note = note.as_deref().unwrap_or("")
),
@@ -954,7 +953,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => {
// More than one matching variant.
err.multipart_suggestions(
- &format!(
+ format!(
"try wrapping the expression in a variant of `{}`",
self.tcx.def_path_str(expected_adt.did())
),
@@ -1088,7 +1087,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// ```ignore (illustrative)
/// opt.map(|param| { takes_ref(param) });
/// ```
- fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Span, &'static str, String)> {
+ fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Vec<(Span, String)>, &'static str)> {
let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.kind else {
return None;
};
@@ -1134,12 +1133,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
_ => false,
};
- match (is_as_ref_able, self.sess().source_map().span_to_snippet(method_path.ident.span)) {
- (true, Ok(src)) => {
- let suggestion = format!("as_ref().{}", src);
- Some((method_path.ident.span, "consider using `as_ref` instead", suggestion))
- }
- _ => None,
+ if is_as_ref_able {
+ Some((
+ vec![(method_path.ident.span.shrink_to_lo(), "as_ref().".to_string())],
+ "consider using `as_ref` instead",
+ ))
+ } else {
+ None
}
}
@@ -1218,14 +1218,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// In addition of this check, it also checks between references mutability state. If the
/// expected is mutable but the provided isn't, maybe we could just say "Hey, try with
/// `&mut`!".
- pub fn check_ref(
+ pub fn suggest_deref_or_ref(
&self,
expr: &hir::Expr<'tcx>,
checked_ty: Ty<'tcx>,
expected: Ty<'tcx>,
) -> Option<(
- Span,
- String,
+ Vec<(Span, String)>,
String,
Applicability,
bool, /* verbose */
@@ -1255,30 +1254,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& let Ok(src) = sm.span_to_snippet(sp)
&& replace_prefix(&src, "b\"", "\"").is_some()
{
- let pos = sp.lo() + BytePos(1);
- return Some((
- sp.with_hi(pos),
- "consider removing the leading `b`".to_string(),
- String::new(),
- Applicability::MachineApplicable,
- true,
- false,
- ));
- }
- }
+ let pos = sp.lo() + BytePos(1);
+ return Some((
+ vec![(sp.with_hi(pos), String::new())],
+ "consider removing the leading `b`".to_string(),
+ Applicability::MachineApplicable,
+ true,
+ false,
+ ));
+ }
+ }
(&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => {
if let hir::ExprKind::Lit(_) = expr.kind
&& let Ok(src) = sm.span_to_snippet(sp)
&& replace_prefix(&src, "\"", "b\"").is_some()
{
- return Some((
- sp.shrink_to_lo(),
- "consider adding a leading `b`".to_string(),
- "b".to_string(),
- Applicability::MachineApplicable,
- true,
- false,
- ));
+ return Some((
+ vec![(sp.shrink_to_lo(), "b".to_string())],
+ "consider adding a leading `b`".to_string(),
+ Applicability::MachineApplicable,
+ true,
+ false,
+ ));
}
}
_ => {}
@@ -1321,66 +1318,73 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner) = expr.kind
- && let Some(1) = self.deref_steps(expected, checked_ty) {
+ && let Some(1) = self.deref_steps(expected, checked_ty)
+ {
// We have `*&T`, check if what was expected was `&T`.
// If so, we may want to suggest removing a `*`.
sugg_sp = sugg_sp.with_hi(inner.span.lo());
return Some((
- sugg_sp,
+ vec![(sugg_sp, String::new())],
"consider removing deref here".to_string(),
- "".to_string(),
Applicability::MachineApplicable,
true,
false,
));
}
- if let Ok(src) = sm.span_to_snippet(sugg_sp) {
- let needs_parens = match expr.kind {
- // parenthesize if needed (Issue #46756)
- hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
- // parenthesize borrows of range literals (Issue #54505)
- _ if is_range_literal(expr) => true,
- _ => false,
- };
-
- if let Some(sugg) = self.can_use_as_ref(expr) {
- return Some((
- sugg.0,
- sugg.1.to_string(),
- sugg.2,
- Applicability::MachineApplicable,
- false,
- false,
- ));
- }
-
- let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
- Some(ident) => format!("{ident}: "),
- None => String::new(),
- };
-
- if let Some(hir::Node::Expr(hir::Expr {
- kind: hir::ExprKind::Assign(..),
- ..
- })) = self.tcx.hir().find_parent(expr.hir_id)
- {
- if mutability.is_mut() {
- // Suppressing this diagnostic, we'll properly print it in `check_expr_assign`
- return None;
- }
- }
+ let needs_parens = match expr.kind {
+ // parenthesize if needed (Issue #46756)
+ hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
+ // parenthesize borrows of range literals (Issue #54505)
+ _ if is_range_literal(expr) => true,
+ _ => false,
+ };
- let sugg_expr = if needs_parens { format!("({src})") } else { src };
+ if let Some((sugg, msg)) = self.can_use_as_ref(expr) {
return Some((
- sp,
- format!("consider {}borrowing here", mutability.mutably_str()),
- format!("{prefix}{}{sugg_expr}", mutability.ref_prefix_str()),
+ sugg,
+ msg.to_string(),
Applicability::MachineApplicable,
- false,
+ true,
false,
));
}
+
+ let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
+ Some(ident) => format!("{ident}: "),
+ None => String::new(),
+ };
+
+ if let Some(hir::Node::Expr(hir::Expr {
+ kind: hir::ExprKind::Assign(..),
+ ..
+ })) = self.tcx.hir().find_parent(expr.hir_id)
+ {
+ if mutability.is_mut() {
+ // Suppressing this diagnostic, we'll properly print it in `check_expr_assign`
+ return None;
+ }
+ }
+
+ let sugg = mutability.ref_prefix_str();
+ let (sugg, verbose) = if needs_parens {
+ (
+ vec![
+ (sp.shrink_to_lo(), format!("{prefix}{sugg}(")),
+ (sp.shrink_to_hi(), ")".to_string()),
+ ],
+ false,
+ )
+ } else {
+ (vec![(sp.shrink_to_lo(), format!("{prefix}{sugg}"))], true)
+ };
+ return Some((
+ sugg,
+ format!("consider {}borrowing here", mutability.mutably_str()),
+ Applicability::MachineApplicable,
+ verbose,
+ false,
+ ));
}
}
(
@@ -1402,23 +1406,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& sm.is_span_accessible(call_span)
{
return Some((
- sp.with_hi(call_span.lo()),
+ vec![(sp.with_hi(call_span.lo()), String::new())],
"consider removing the borrow".to_string(),
- String::new(),
Applicability::MachineApplicable,
true,
- true
+ true,
));
}
return None;
}
- if sp.contains(expr.span)
- && sm.is_span_accessible(expr.span)
- {
+ if sp.contains(expr.span) && sm.is_span_accessible(expr.span) {
return Some((
- sp.with_hi(expr.span.lo()),
+ vec![(sp.with_hi(expr.span.lo()), String::new())],
"consider removing the borrow".to_string(),
- String::new(),
Applicability::MachineApplicable,
true,
true,
@@ -1442,23 +1442,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let suggestion = replace_prefix(&src, old_prefix, &new_prefix).map(|_| {
// skip `&` or `&mut ` if both mutabilities are mutable
- let lo = sp.lo() + BytePos(min(old_prefix.len(), mutbl_b.ref_prefix_str().len()) as _);
+ let lo = sp.lo()
+ + BytePos(min(old_prefix.len(), mutbl_b.ref_prefix_str().len()) as _);
// skip `&` or `&mut `
let hi = sp.lo() + BytePos(old_prefix.len() as _);
let sp = sp.with_lo(lo).with_hi(hi);
(
sp,
- format!("{}{derefs}", if mutbl_a != mutbl_b { mutbl_b.prefix_str() } else { "" }),
- if mutbl_b <= mutbl_a { Applicability::MachineApplicable } else { Applicability::MaybeIncorrect }
+ format!(
+ "{}{derefs}",
+ if mutbl_a != mutbl_b { mutbl_b.prefix_str() } else { "" }
+ ),
+ if mutbl_b <= mutbl_a {
+ Applicability::MachineApplicable
+ } else {
+ Applicability::MaybeIncorrect
+ },
)
});
if let Some((span, src, applicability)) = suggestion {
return Some((
- span,
+ vec![(span, src)],
"consider dereferencing".to_string(),
- src,
applicability,
true,
false,
@@ -1487,9 +1494,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If we've reached our target type with just removing `&`, then just print now.
if steps == 0 && !remove.trim().is_empty() {
return Some((
- prefix_span,
+ vec![(prefix_span, String::new())],
format!("consider removing the `{}`", remove.trim()),
- String::new(),
// Do not remove `&&` to get to bool, because it might be something like
// { a } && b, which we have a separate fixup suggestion that is more
// likely correct...
@@ -1509,6 +1515,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// 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)
+ // We can always deref a binop that takes its arguments by ref.
+ || matches!(
+ self.tcx.hir().get_parent(expr.hir_id),
+ hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(op, ..), .. })
+ if !op.node.is_by_value()
+ )
{
let deref_kind = if checked_ty.is_box() {
"unboxing the value"
@@ -1549,9 +1561,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
return Some((
- span,
+ vec![(span, suggestion)],
message,
- suggestion,
Applicability::MachineApplicable,
true,
false,
@@ -1564,7 +1575,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
None
}
- pub fn check_for_cast(
+ pub fn suggest_cast(
&self,
err: &mut Diagnostic,
expr: &hir::Expr<'_>,
@@ -1721,7 +1732,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
];
(msg, suggestion)
} else {
- let msg = format!("{msg} and panic if the converted value doesn't fit");
+ let msg =
+ format!("{} and panic if the converted value doesn't fit", msg.clone());
let mut suggestion = sugg.clone();
suggestion.push((
expr.span.shrink_to_hi(),
@@ -1729,19 +1741,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
));
(msg, suggestion)
};
- err.multipart_suggestion_verbose(
- &msg,
- suggestion,
- Applicability::MachineApplicable,
- );
+ err.multipart_suggestion_verbose(msg, suggestion, Applicability::MachineApplicable);
};
let suggest_to_change_suffix_or_into =
|err: &mut Diagnostic,
found_to_exp_is_fallible: bool,
exp_to_found_is_fallible: bool| {
- let exp_is_lhs =
- expected_ty_expr.map(|e| self.tcx.hir().is_lhs(e.hir_id)).unwrap_or(false);
+ let exp_is_lhs = expected_ty_expr.is_some_and(|e| self.tcx.hir().is_lhs(e.hir_id));
if exp_is_lhs {
return;
@@ -1750,13 +1757,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let always_fallible = found_to_exp_is_fallible
&& (exp_to_found_is_fallible || expected_ty_expr.is_none());
let msg = if literal_is_ty_suffixed(expr) {
- &lit_msg
+ lit_msg.clone()
} else if always_fallible && (is_negative_int(expr) && is_uint(expected_ty)) {
// We now know that converting either the lhs or rhs is fallible. Before we
// suggest a fallible conversion, check if the value can never fit in the
// expected type.
let msg = format!("`{src}` cannot fit into type `{expected_ty}`");
- err.note(&msg);
+ err.note(msg);
return;
} else if in_const_context {
// Do not recommend `into` or `try_into` in const contexts.
@@ -1764,7 +1771,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else if found_to_exp_is_fallible {
return suggest_fallible_into_or_lhs_from(err, exp_to_found_is_fallible);
} else {
- &msg
+ msg.clone()
};
let suggestion = if literal_is_ty_suffixed(expr) {
suffix_suggestion.clone()
@@ -1826,14 +1833,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
suggest_to_change_suffix_or_into(err, false, true);
} else if literal_is_ty_suffixed(expr) {
err.multipart_suggestion_verbose(
- &lit_msg,
+ lit_msg,
suffix_suggestion,
Applicability::MachineApplicable,
);
} else if can_cast {
// Missing try_into implementation for `f64` to `f32`
err.multipart_suggestion_verbose(
- &format!("{cast_msg}, producing the closest possible value"),
+ format!("{cast_msg}, producing the closest possible value"),
cast_suggestion,
Applicability::MaybeIncorrect, // lossy conversion
);
@@ -1843,14 +1850,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(&ty::Uint(_) | &ty::Int(_), &ty::Float(_)) => {
if literal_is_ty_suffixed(expr) {
err.multipart_suggestion_verbose(
- &lit_msg,
+ lit_msg,
suffix_suggestion,
Applicability::MachineApplicable,
);
} else if can_cast {
// Missing try_into implementation for `{float}` to `{integer}`
err.multipart_suggestion_verbose(
- &format!("{msg}, rounding the float towards zero"),
+ format!("{msg}, rounding the float towards zero"),
cast_suggestion,
Applicability::MaybeIncorrect, // lossy conversion
);
@@ -1861,7 +1868,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// if `found` is `None` (meaning found is `usize`), don't suggest `.into()`
if exp.bit_width() > found.bit_width().unwrap_or(256) {
err.multipart_suggestion_verbose(
- &format!(
+ format!(
"{msg}, producing the floating point representation of the integer",
),
into_suggestion,
@@ -1869,14 +1876,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
} else if literal_is_ty_suffixed(expr) {
err.multipart_suggestion_verbose(
- &lit_msg,
+ lit_msg,
suffix_suggestion,
Applicability::MachineApplicable,
);
} else {
// Missing try_into implementation for `{integer}` to `{float}`
err.multipart_suggestion_verbose(
- &format!(
+ format!(
"{cast_msg}, producing the floating point representation of the integer, \
rounded if necessary",
),
@@ -1890,23 +1897,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// if `found` is `None` (meaning found is `isize`), don't suggest `.into()`
if exp.bit_width() > found.bit_width().unwrap_or(256) {
err.multipart_suggestion_verbose(
- &format!(
+ format!(
"{}, producing the floating point representation of the integer",
- &msg,
+ msg.clone(),
),
into_suggestion,
Applicability::MachineApplicable,
);
} else if literal_is_ty_suffixed(expr) {
err.multipart_suggestion_verbose(
- &lit_msg,
+ lit_msg,
suffix_suggestion,
Applicability::MachineApplicable,
);
} else {
// Missing try_into implementation for `{integer}` to `{float}`
err.multipart_suggestion_verbose(
- &format!(
+ format!(
"{}, producing the floating point representation of the integer, \
rounded if necessary",
&msg,
@@ -1923,7 +1930,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&ty::Char,
) => {
err.multipart_suggestion_verbose(
- &format!("{cast_msg}, since a `char` always occupies 4 bytes"),
+ format!("{cast_msg}, since a `char` always occupies 4 bytes"),
cast_suggestion,
Applicability::MachineApplicable,
);
@@ -1934,7 +1941,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
/// Identify when the user has written `foo..bar()` instead of `foo.bar()`.
- pub fn check_for_range_as_method_call(
+ pub fn suggest_method_call_on_range_literal(
&self,
err: &mut Diagnostic,
expr: &hir::Expr<'tcx>,
@@ -2003,7 +2010,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Identify when the type error is because `()` is found in a binding that was assigned a
/// block without a tail expression.
- fn check_for_binding_assigned_block_without_tail_expression(
+ fn suggest_return_binding_for_missing_tail_expr(
&self,
err: &mut Diagnostic,
expr: &hir::Expr<'_>,
@@ -2045,7 +2052,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- fn check_wrong_return_type_due_to_generic_arg(
+ fn note_wrong_return_ty_due_to_generic_arg(
&self,
err: &mut Diagnostic,
expr: &hir::Expr<'_>,
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 3eee2278d..4222205c8 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -1,4 +1,6 @@
//! Errors emitted by `rustc_hir_typeck`.
+use std::borrow::Cow;
+
use crate::fluent_generated as fluent;
use rustc_errors::{AddToDiagnostic, Applicability, Diagnostic, MultiSpan, SubdiagnosticMessage};
use rustc_macros::{Diagnostic, Subdiagnostic};
@@ -47,8 +49,8 @@ pub struct StructExprNonExhaustive {
}
#[derive(Diagnostic)]
-#[diag(hir_typeck_method_call_on_unknown_type, code = "E0699")]
-pub struct MethodCallOnUnknownType {
+#[diag(hir_typeck_method_call_on_unknown_raw_pointee, code = "E0699")]
+pub struct MethodCallOnUnknownRawPointee {
#[primary_span]
pub span: Span,
}
@@ -108,7 +110,7 @@ pub enum ExpectedReturnTypeLabel<'tcx> {
#[derive(Diagnostic)]
#[diag(hir_typeck_missing_parentheses_in_range, code = "E0689")]
-pub struct MissingParentheseInRange {
+pub struct MissingParenthesesInRange {
#[primary_span]
#[label(hir_typeck_missing_parentheses_in_range)]
pub span: Span,
@@ -228,3 +230,100 @@ impl HelpUseLatestEdition {
}
}
}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_const_select_must_be_const)]
+#[help]
+pub struct ConstSelectMustBeConst {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_const_select_must_be_fn)]
+#[note]
+#[help]
+pub struct ConstSelectMustBeFn<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_union_pat_multiple_fields)]
+pub struct UnionPatMultipleFields {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_union_pat_dotdot)]
+pub struct UnionPatDotDot {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_arg_mismatch_indeterminate)]
+pub struct ArgMismatchIndeterminate {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Subdiagnostic)]
+pub enum SuggestBoxing {
+ #[note(hir_typeck_suggest_boxing_note)]
+ #[multipart_suggestion(
+ hir_typeck_suggest_boxing_when_appropriate,
+ applicability = "machine-applicable"
+ )]
+ Unit {
+ #[suggestion_part(code = "Box::new(())")]
+ start: Span,
+ #[suggestion_part(code = "")]
+ end: Span,
+ },
+ #[note(hir_typeck_suggest_boxing_note)]
+ AsyncBody,
+ #[note(hir_typeck_suggest_boxing_note)]
+ #[multipart_suggestion(
+ hir_typeck_suggest_boxing_when_appropriate,
+ applicability = "machine-applicable"
+ )]
+ Other {
+ #[suggestion_part(code = "Box::new(")]
+ start: Span,
+ #[suggestion_part(code = ")")]
+ end: Span,
+ },
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_no_associated_item, code = "E0599")]
+pub struct NoAssociatedItem {
+ #[primary_span]
+ pub span: Span,
+ pub item_kind: &'static str,
+ pub item_name: Ident,
+ pub ty_prefix: Cow<'static, str>,
+ pub ty_str: String,
+ pub trait_missing_method: bool,
+}
+
+#[derive(Subdiagnostic)]
+#[note(hir_typeck_candidate_trait_note)]
+pub struct CandidateTraitNote {
+ #[primary_span]
+ pub span: Span,
+ pub trait_name: String,
+ pub item_name: Ident,
+ pub action_or_ty: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_ctor_is_private, code = "E0603")]
+pub struct CtorIsPrivate {
+ #[primary_span]
+ pub span: Span,
+ pub def: String,
+}
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 6ffa0134f..19ff77d83 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -38,6 +38,7 @@ 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::query::NoSolution;
use rustc_infer::traits::ObligationCause;
use rustc_middle::middle::stability;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
@@ -53,6 +54,8 @@ 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::error_reporting::TypeErrCtxtExt;
+use rustc_trait_selection::traits::ObligationCtxt;
use rustc_trait_selection::traits::{self, ObligationCauseCode};
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -306,6 +309,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.deferred_asm_checks.borrow_mut().push((asm, expr.hir_id));
self.check_expr_asm(asm)
}
+ ExprKind::OffsetOf(container, ref fields) => {
+ self.check_offset_of(container, fields, expr)
+ }
ExprKind::Break(destination, ref expr_opt) => {
self.check_expr_break(destination, expr_opt.as_deref(), expr)
}
@@ -491,7 +497,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.borrow()
.adjustments()
.get(base.hir_id)
- .map_or(false, |x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_))))
+ .is_some_and(|x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_))))
});
if !is_named {
self.tcx.sess.emit_err(AddressOfTemporaryTaken { span: oprnd.span });
@@ -715,7 +721,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// ICE this expression in particular (see #43162).
if let ExprKind::Path(QPath::Resolved(_, path)) = e.kind {
if path.segments.len() == 1 && path.segments[0].ident.name == sym::rust {
- fatally_break_rust(self.tcx.sess);
+ fatally_break_rust(self.tcx);
}
}
}
@@ -1239,6 +1245,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
error,
Some((rcvr, args)),
expected,
+ false,
) {
err.emit();
}
@@ -1420,6 +1427,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.check_repeat_element_needs_copy_bound(element, count, element_ty);
+ self.register_wf_obligation(
+ tcx.mk_array_with_const_len(t, count).into(),
+ expr.span,
+ traits::WellFormed(None),
+ );
+
tcx.mk_array_with_const_len(t, count)
}
@@ -1735,10 +1748,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {
let base_ty = self.typeck_results.borrow().expr_ty(*base_expr);
- let same_adt = match (adt_ty.kind(), base_ty.kind()) {
- (ty::Adt(adt, _), ty::Adt(base_adt, _)) if adt == base_adt => true,
- _ => false,
- };
+ let same_adt = matches!((adt_ty.kind(), base_ty.kind()),
+ (ty::Adt(adt, _), ty::Adt(base_adt, _)) if adt == base_adt);
if self.tcx.sess.is_nightly_build() && same_adt {
feature_err(
&self.tcx.sess.parse_sess,
@@ -1940,12 +1951,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
private_fields: Vec<&ty::FieldDef>,
used_fields: &'tcx [hir::ExprField<'tcx>],
) {
- let mut err = self.tcx.sess.struct_span_err(
- span,
- &format!(
- "cannot construct `{adt_ty}` with struct literal syntax due to private fields",
- ),
- );
+ let mut err =
+ self.tcx.sess.struct_span_err(
+ span,
+ format!(
+ "cannot construct `{adt_ty}` with struct literal syntax due to private fields",
+ ),
+ );
let (used_private_fields, remaining_private_fields): (
Vec<(Symbol, Span, bool)>,
Vec<(Symbol, Span, bool)>,
@@ -2041,7 +2053,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_label(field.ident.span, "field does not exist");
err.span_suggestion_verbose(
expr_span,
- &format!(
+ format!(
"`{adt}::{variant}` is a tuple {kind_name}, use the appropriate syntax",
adt = ty,
variant = variant.name,
@@ -2059,7 +2071,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_label(field.ident.span, "field does not exist");
err.span_suggestion_verbose(
expr_span,
- &format!(
+ format!(
"`{adt}` is a tuple {kind_name}, use the appropriate syntax",
adt = ty,
kind_name = kind_name,
@@ -2101,7 +2113,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let available_field_names =
self.available_field_names(variant, expr_span);
if !available_field_names.is_empty() {
- err.note(&format!(
+ err.note(format!(
"available fields are: {}",
self.name_series_display(available_field_names)
));
@@ -2380,7 +2392,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
if add_label {
- err.span_label(field_ident.span, &format!("field not found in `{ty}`"));
+ err.span_label(field_ident.span, format!("field not found in `{ty}`"));
}
}
@@ -2449,22 +2461,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
base_did: DefId,
return_ty: Option<Ty<'tcx>>,
) -> ErrorGuaranteed {
- let struct_path = self.tcx().def_path_str(base_did);
- let kind_name = self.tcx().def_descr(base_did);
- let mut err = struct_span_err!(
- self.tcx().sess,
- field.span,
- E0616,
- "field `{field}` of {kind_name} `{struct_path}` is private",
- );
- err.span_label(field.span, "private field");
+ let mut err = self.private_field_err(field, base_did);
+
// Also check if an accessible method exists, which is often what is meant.
if self.method_exists(field, expr_t, expr.hir_id, false, return_ty)
&& !self.expr_in_place(expr.hir_id)
{
self.suggest_method_call(
&mut err,
- &format!("a method `{field}` also exists, call it with parentheses"),
+ format!("a method `{field}` also exists, call it with parentheses"),
field,
expr_t,
expr,
@@ -2568,7 +2573,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let param_span = self.tcx.hir().span(param_hir_id);
let param_name = self.tcx.hir().ty_param_name(param_def_id.expect_local());
- err.span_label(param_span, &format!("type parameter '{param_name}' declared here"));
+ err.span_label(param_span, format!("type parameter '{param_name}' declared here"));
}
fn suggest_fields_on_recordish(
@@ -2592,7 +2597,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let struct_variant_def = def.non_enum_variant();
let field_names = self.available_field_names(struct_variant_def, access_span);
if !field_names.is_empty() {
- err.note(&format!(
+ err.note(format!(
"available fields are: {}",
self.name_series_display(field_names),
));
@@ -2633,7 +2638,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span) {
let msg = format!("`{base}` is a raw pointer; try dereferencing it");
let suggestion = format!("(*{base}).{field}");
- err.span_suggestion(expr.span, &msg, suggestion, Applicability::MaybeIncorrect);
+ err.span_suggestion(expr.span, msg, suggestion, Applicability::MaybeIncorrect);
}
}
@@ -2697,6 +2702,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err
}
+ fn private_field_err(
+ &self,
+ field: Ident,
+ base_did: DefId,
+ ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+ let struct_path = self.tcx().def_path_str(base_did);
+ let kind_name = self.tcx().def_descr(base_did);
+ let mut err = struct_span_err!(
+ self.tcx().sess,
+ field.span,
+ E0616,
+ "field `{field}` of {kind_name} `{struct_path}` is private",
+ );
+ err.span_label(field.span, "private field");
+
+ err
+ }
+
pub(crate) fn get_field_candidates_considering_privacy(
&self,
span: Span,
@@ -2802,6 +2825,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
element_ty
}
None => {
+ // Attempt to *shallowly* search for an impl which matches,
+ // but has nested obligations which are unsatisfied.
+ for (base_t, _) in self.autoderef(base.span, base_t).silence_errors() {
+ if let Some((_, index_ty, element_ty)) =
+ self.find_and_report_unsatisfied_index_impl(base, base_t)
+ {
+ self.demand_coerce(idx, idx_t, index_ty, None, AllowTwoPhase::No);
+ return element_ty;
+ }
+ }
+
let mut err = type_error_struct!(
self.tcx.sess,
expr.span,
@@ -2845,6 +2879,89 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
+ /// Try to match an implementation of `Index` against a self type, and report
+ /// the unsatisfied predicates that result from confirming this impl.
+ ///
+ /// Given an index expression, sometimes the `Self` type shallowly but does not
+ /// deeply satisfy an impl predicate. Instead of simply saying that the type
+ /// does not support being indexed, we want to point out exactly what nested
+ /// predicates cause this to be, so that the user can add them to fix their code.
+ fn find_and_report_unsatisfied_index_impl(
+ &self,
+ base_expr: &hir::Expr<'_>,
+ base_ty: Ty<'tcx>,
+ ) -> Option<(ErrorGuaranteed, Ty<'tcx>, Ty<'tcx>)> {
+ let index_trait_def_id = self.tcx.lang_items().index_trait()?;
+ let index_trait_output_def_id = self.tcx.get_diagnostic_item(sym::IndexOutput)?;
+
+ let mut relevant_impls = vec![];
+ self.tcx.for_each_relevant_impl(index_trait_def_id, base_ty, |impl_def_id| {
+ relevant_impls.push(impl_def_id);
+ });
+ let [impl_def_id] = relevant_impls[..] else {
+ // Only report unsatisfied impl predicates if there's one impl
+ return None;
+ };
+
+ self.commit_if_ok(|_| {
+ let ocx = ObligationCtxt::new_in_snapshot(self);
+ let impl_substs = self.fresh_substs_for_item(base_expr.span, impl_def_id);
+ let impl_trait_ref =
+ self.tcx.impl_trait_ref(impl_def_id).unwrap().subst(self.tcx, impl_substs);
+ let cause = self.misc(base_expr.span);
+
+ // Match the impl self type against the base ty. If this fails,
+ // we just skip this impl, since it's not particularly useful.
+ let impl_trait_ref = ocx.normalize(&cause, self.param_env, impl_trait_ref);
+ ocx.eq(&cause, self.param_env, impl_trait_ref.self_ty(), base_ty)?;
+
+ // Register the impl's predicates. One of these predicates
+ // must be unsatisfied, or else we wouldn't have gotten here
+ // in the first place.
+ ocx.register_obligations(traits::predicates_for_generics(
+ |idx, span| {
+ cause.clone().derived_cause(
+ ty::Binder::dummy(ty::TraitPredicate {
+ trait_ref: impl_trait_ref,
+ polarity: ty::ImplPolarity::Positive,
+ constness: ty::BoundConstness::NotConst,
+ }),
+ |derived| {
+ traits::ImplDerivedObligation(Box::new(
+ traits::ImplDerivedObligationCause {
+ derived,
+ impl_or_alias_def_id: impl_def_id,
+ impl_def_predicate_index: Some(idx),
+ span,
+ },
+ ))
+ },
+ )
+ },
+ self.param_env,
+ self.tcx.predicates_of(impl_def_id).instantiate(self.tcx, impl_substs),
+ ));
+
+ // Normalize the output type, which we can use later on as the
+ // return type of the index expression...
+ let element_ty = ocx.normalize(
+ &cause,
+ self.param_env,
+ self.tcx.mk_projection(index_trait_output_def_id, impl_trait_ref.substs),
+ );
+
+ let errors = ocx.select_where_possible();
+ // There should be at least one error reported. If not, we
+ // will still delay a span bug in `report_fulfillment_errors`.
+ Ok::<_, NoSolution>((
+ self.err_ctxt().report_fulfillment_errors(&errors),
+ impl_trait_ref.substs.type_at(1),
+ element_ty,
+ ))
+ })
+ .ok()
+ }
+
fn point_at_index_if_possible(
&self,
errors: &mut Vec<traits::FulfillmentError<'tcx>>,
@@ -2954,4 +3071,78 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.mk_unit()
}
}
+
+ fn check_offset_of(
+ &self,
+ container: &'tcx hir::Ty<'tcx>,
+ fields: &[Ident],
+ expr: &'tcx hir::Expr<'tcx>,
+ ) -> Ty<'tcx> {
+ let container = self.to_ty(container).normalized;
+
+ let mut field_indices = Vec::with_capacity(fields.len());
+ let mut current_container = container;
+
+ for &field in fields {
+ let container = self.structurally_resolved_type(expr.span, current_container);
+
+ match container.kind() {
+ ty::Adt(container_def, substs) if !container_def.is_enum() => {
+ let block = self.tcx.hir().local_def_id_to_hir_id(self.body_id);
+ let (ident, def_scope) =
+ self.tcx.adjust_ident_and_get_scope(field, container_def.did(), block);
+
+ let fields = &container_def.non_enum_variant().fields;
+ if let Some((index, field)) = fields
+ .iter_enumerated()
+ .find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == ident)
+ {
+ let field_ty = self.field_ty(expr.span, field, substs);
+
+ // FIXME: DSTs with static alignment should be allowed
+ self.require_type_is_sized(field_ty, expr.span, traits::MiscObligation);
+
+ if field.vis.is_accessible_from(def_scope, self.tcx) {
+ self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
+ } else {
+ self.private_field_err(ident, container_def.did()).emit();
+ }
+
+ // Save the index of all fields regardless of their visibility in case
+ // of error recovery.
+ field_indices.push(index);
+ current_container = field_ty;
+
+ continue;
+ }
+ }
+ ty::Tuple(tys) => {
+ let fstr = field.as_str();
+
+ if let Ok(index) = fstr.parse::<usize>() {
+ if fstr == index.to_string() {
+ if let Some(&field_ty) = tys.get(index) {
+ field_indices.push(index.into());
+ current_container = field_ty;
+
+ continue;
+ }
+ }
+ }
+ }
+ _ => (),
+ };
+
+ self.no_such_field_err(field, container, expr.hir_id).emit();
+
+ break;
+ }
+
+ self.typeck_results
+ .borrow_mut()
+ .offset_of_data_mut()
+ .insert(expr.hir_id, (container, field_indices));
+
+ self.tcx.types.usize
+ }
}
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index ee1c6fbfd..e14e8ac2c 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -300,6 +300,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
hir::ExprKind::Continue(..)
| hir::ExprKind::Lit(..)
| hir::ExprKind::ConstBlock(..)
+ | hir::ExprKind::OffsetOf(..)
| hir::ExprKind::Err(_) => {}
hir::ExprKind::Loop(blk, ..) => {
@@ -437,12 +438,19 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
// to borrow discr.
needs_to_be_read = true;
}
- PatKind::Or(_)
- | PatKind::Box(_)
- | PatKind::Slice(..)
- | PatKind::Ref(..)
- | PatKind::Wild => {
- // If the PatKind is Or, Box, Slice or Ref, the decision is made later
+ PatKind::Slice(lhs, wild, rhs) => {
+ // We don't need to test the length if the pattern is `[..]`
+ if matches!((lhs, wild, rhs), (&[], Some(_), &[]))
+ // Arrays have a statically known size, so
+ // there is no need to read their length
+ || discr_place.place.base_ty.is_array()
+ {
+ } else {
+ needs_to_be_read = true;
+ }
+ }
+ PatKind::Or(_) | PatKind::Box(_) | PatKind::Ref(..) | PatKind::Wild => {
+ // If the PatKind is Or, Box, or Ref, the decision is made later
// as these patterns contains subpatterns
// If the PatKind is Wild, the decision is made based on the other patterns being
// examined
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index f736f7a96..557950338 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -1,10 +1,11 @@
use crate::callee::{self, DeferredCallResolution};
+use crate::errors::CtorIsPrivate;
use crate::method::{self, MethodCallee, SelfSource};
use crate::rvalue_scopes;
use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, RawTy};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
+use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan, StashKey};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
@@ -35,7 +36,9 @@ 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};
+use rustc_trait_selection::traits::{
+ self, NormalizeExt, ObligationCauseCode, ObligationCtxt, StructurallyNormalizeExt,
+};
use std::collections::hash_map::Entry;
use std::slice;
@@ -63,9 +66,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
lint::builtin::UNREACHABLE_CODE,
id,
span,
- &msg,
+ msg.clone(),
|lint| {
- lint.span_label(span, &msg).span_label(
+ lint.span_label(span, msg).span_label(
orig_span,
custom_note
.unwrap_or("any code following this expression is unreachable"),
@@ -275,7 +278,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => {
self.tcx.sess.delay_span_bug(
expr.span,
- &format!(
+ format!(
"while adjusting {:?}, can't compose {:?} and {:?}",
expr,
entry.get(),
@@ -420,9 +423,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ast_c: &hir::AnonConst,
param_def_id: DefId,
) -> ty::Const<'tcx> {
- let const_def =
- ty::WithOptConstParam { did: ast_c.def_id, const_param_did: Some(param_def_id) };
- let c = ty::Const::from_opt_const_arg_anon_const(self.tcx, const_def);
+ let did = ast_c.def_id;
+ self.tcx.feed_anon_const_type(did, self.tcx.type_of(param_def_id));
+ let c = ty::Const::from_anon_const(self.tcx, did);
self.register_wf_obligation(
c.into(),
self.tcx.hir().span(ast_c.hir_id),
@@ -827,7 +830,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
QPath::TypeRelative(ref qself, ref segment) => {
// Don't use `self.to_ty`, since this will register a WF obligation.
- // If we're trying to call a non-existent method on a trait
+ // If we're trying to call a nonexistent method on a trait
// (e.g. `MyTrait::missing_method`), then resolution will
// give us a `QPath::TypeRelative` with a trait object as
// `qself`. In that case, we want to avoid registering a WF obligation
@@ -853,23 +856,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let item_name = item_segment.ident;
let result = self
.resolve_fully_qualified_call(span, item_name, ty.normalized, qself.span, hir_id)
+ .and_then(|r| {
+ // lint bare trait if the method is found in the trait
+ if span.edition().rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) {
+ diag.emit();
+ }
+ Ok(r)
+ })
.or_else(|error| {
+ let guar = self
+ .tcx
+ .sess
+ .delay_span_bug(span, "method resolution should've emitted an error");
let result = match error {
method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)),
- _ => Err(ErrorGuaranteed::unchecked_claim_error_was_emitted()),
+ _ => Err(guar),
};
+ let trait_missing_method =
+ matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait();
// If we have a path like `MyTrait::missing_method`, then don't register
// a WF obligation for `dyn MyTrait` when method lookup fails. Otherwise,
// register a WF obligation so that we can detect any additional
// errors in the self type.
- if !(matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait()) {
+ if !trait_missing_method {
self.register_wf_obligation(
ty.raw.into(),
qself.span,
traits::WellFormed(None),
);
}
+
+ // emit or cancel the diagnostic for bare traits
+ if span.edition().rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) {
+ if trait_missing_method {
+ // cancel the diag for bare traits when meeting `MyTrait::missing_method`
+ diag.cancel();
+ } else {
+ diag.emit();
+ }
+ }
+
if item_name.name != kw::Empty {
if let Some(mut e) = self.report_method_error(
span,
@@ -879,10 +906,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
error,
None,
Expectation::NoExpectation,
+ trait_missing_method && span.edition().rust_2021(), // emits missing method for trait only after edition 2021
) {
e.emit();
}
}
+
result
});
@@ -989,8 +1018,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.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);
+ .zip(expected)
+ .is_some_and(|(ty, expected_ty)| expected_ty.peel_refs() == ty.peel_refs());
let prev_call_mutates_and_returns_unit = || {
self.typeck_results
@@ -998,14 +1027,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.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)| {
+ .is_some_and(|(output, inputs)| {
output.is_unit()
&& inputs
.get(0)
.and_then(|self_ty| self_ty.ref_mutability())
- .map_or(false, rustc_ast::Mutability::is_mut)
+ .is_some_and(rustc_ast::Mutability::is_mut)
})
- .unwrap_or(false)
};
if !(rcvr_has_the_expected_type || prev_call_mutates_and_returns_unit()) {
@@ -1034,15 +1062,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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));
+ 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,
modifies_rcvr_note.clone() + ", it is not meant to be used in method chains.",
);
} else {
- err.span_note(sp, &modifies_rcvr_note);
+ err.span_note(sp, modifies_rcvr_note);
}
}
@@ -1172,16 +1200,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- let has_self = path_segs
- .last()
- .map(|PathSeg(def_id, _)| tcx.generics_of(*def_id).has_self)
- .unwrap_or(false);
+ let has_self =
+ path_segs.last().is_some_and(|PathSeg(def_id, _)| tcx.generics_of(*def_id).has_self);
let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res {
let ty = self.handle_raw_ty(span, tcx.at(span).type_of(impl_def_id).subst_identity());
match ty.normalized.ty_adt_def() {
Some(adt_def) if adt_def.has_ctor() => {
let (ctor_kind, ctor_def_id) = adt_def.non_enum_variant().ctor.unwrap();
+ // Check the visibility of the ctor.
+ let vis = tcx.visibility(ctor_def_id);
+ if !vis.is_accessible_from(tcx.parent_module(hir_id).to_def_id(), tcx) {
+ tcx.sess
+ .emit_err(CtorIsPrivate { span, def: tcx.def_path_str(adt_def.did()) });
+ }
let new_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id);
let user_substs = Self::user_substs_for_adt(ty);
user_self_ty = user_substs.user_self_ty;
@@ -1374,7 +1406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Err(_) => {
self.tcx.sess.delay_span_bug(
span,
- &format!(
+ format!(
"instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?",
self_ty,
impl_ty,
@@ -1434,10 +1466,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
/// Resolves `typ` by a single level if `typ` is a type variable.
+ ///
+ /// When the new solver is enabled, this will also attempt to normalize
+ /// the type if it's a projection (note that it will not deeply normalize
+ /// projections within the type, just the outermost layer of the type).
+ ///
/// If no resolution is possible, then an error is reported.
/// Numeric inference variables may be left unresolved.
pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
- let ty = self.resolve_vars_with_obligations(ty);
+ let mut ty = self.resolve_vars_with_obligations(ty);
+
+ if self.tcx.trait_solver_next()
+ && let ty::Alias(ty::Projection, _) = ty.kind()
+ {
+ match self
+ .at(&self.misc(sp), self.param_env)
+ .structurally_normalize(ty, &mut **self.fulfillment_cx.borrow_mut())
+ {
+ Ok(normalized_ty) => {
+ ty = normalized_ty;
+ },
+ Err(errors) => {
+ let guar = self.err_ctxt().report_fulfillment_errors(&errors);
+ return self.tcx.ty_error(guar);
+ }
+ }
+ }
+
if !ty.is_ty_var() {
ty
} else {
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 f879ccbb3..3efdab534 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
@@ -164,24 +164,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
for param in
[param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
+ .into_iter()
+ .flatten()
{
- if let Some(param) = param {
- let refined_expr = self.point_at_field_if_possible(
- def_id,
- param,
- variant_def_id,
- fields,
- );
-
- match refined_expr {
- None => {}
- Some((refined_expr, _)) => {
- error.obligation.cause.span = refined_expr
- .span
- .find_ancestor_in_same_ctxt(error.obligation.cause.span)
- .unwrap_or(refined_expr.span);
- return true;
- }
+ let refined_expr =
+ self.point_at_field_if_possible(def_id, param, variant_def_id, fields);
+
+ match refined_expr {
+ None => {}
+ Some((refined_expr, _)) => {
+ error.obligation.cause.span = refined_expr
+ .span
+ .find_ancestor_in_same_ctxt(error.obligation.cause.span)
+ .unwrap_or(refined_expr.span);
+ return true;
}
}
}
@@ -282,9 +278,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: Span,
) -> bool {
if let traits::FulfillmentErrorCode::CodeSelectionError(
- traits::SelectionError::OutputTypeParameterMismatch(_, expected, _),
+ traits::SelectionError::OutputTypeParameterMismatch(box traits::SelectionOutputTypeParameterMismatch{
+ expected_trait_ref, ..
+ }),
) = error.code
- && let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected.skip_binder().self_ty().kind()
+ && let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected_trait_ref.skip_binder().self_ty().kind()
&& span.overlaps(self.tcx.def_span(*def_id))
{
true
@@ -334,7 +332,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// expression mentioned.
///
/// `blame_specific_arg_if_possible` will find the most-specific expression anywhere inside
- /// the provided function call expression, and mark it as responsible for the fullfillment
+ /// the provided function call expression, and mark it as responsible for the fulfillment
/// error.
fn blame_specific_arg_if_possible(
&self,
@@ -485,7 +483,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// For the purposes of this function, we hope that it is a `struct` type, and that our current `expr` is a literal of
// that struct type.
let impl_trait_self_ref = if self.tcx.is_trait_alias(obligation.impl_or_alias_def_id) {
- self.tcx.mk_trait_ref(
+ ty::TraitRef::new(
+ self.tcx,
obligation.impl_or_alias_def_id,
ty::InternalSubsts::identity_for_item(self.tcx, obligation.impl_or_alias_def_id),
)
@@ -846,7 +845,7 @@ fn find_param_in_ty<'tcx>(
return true;
}
if let ty::GenericArgKind::Type(ty) = arg.unpack()
- && let ty::Alias(ty::Projection, ..) = ty.kind()
+ && let ty::Alias(ty::Projection | ty::Inherent, ..) = ty.kind()
{
// This logic may seem a bit strange, but typically when
// we have a projection type in a function signature, the
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
index 6f26afcaf..d45e3d395 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
@@ -1,6 +1,6 @@
use std::cmp;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::ty::error::TypeError;
rustc_index::newtype_index! {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index ea1b52daa..eba5c829e 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -2,8 +2,8 @@ use crate::coercion::CoerceMany;
use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx};
use crate::gather_locals::Declaration;
use crate::method::MethodCallee;
-use crate::Expectation::*;
use crate::TupleArgumentsFlag::*;
+use crate::{errors, Expectation::*};
use crate::{
struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, Needs, RawTy,
TupleArgumentsFlag,
@@ -21,7 +21,7 @@ use rustc_hir_analysis::astconv::AstConv;
use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt;
use rustc_hir_analysis::check::potentially_plural_count;
use rustc_hir_analysis::structured_errors::StructuredDiagnostic;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::TypeTrace;
@@ -283,19 +283,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if idx == 1 && !self.tcx.is_const_fn_raw(*def_id) {
self.tcx
.sess
- .struct_span_err(provided_arg.span, "this argument must be a `const fn`")
- .help("consult the documentation on `const_eval_select` for more information")
- .emit();
+ .emit_err(errors::ConstSelectMustBeConst { span: provided_arg.span });
}
} else {
- self.tcx
- .sess
- .struct_span_err(provided_arg.span, "this argument must be a function item")
- .note(format!("expected a function item, found {checked_ty}"))
- .help(
- "consult the documentation on `const_eval_select` for more information",
- )
- .emit();
+ self.tcx.sess.emit_err(errors::ConstSelectMustBeFn {
+ span: provided_arg.span,
+ ty: checked_ty,
+ });
}
}
@@ -368,7 +362,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
continue;
}
- let is_closure = matches!(arg.kind, ExprKind::Closure { .. });
+ // For this check, we do *not* want to treat async generator closures (async blocks)
+ // as proper closures. Doing so would regress type inference when feeding
+ // the return value of an argument-position async block to an argument-position
+ // closure wrapped in a block.
+ // See <https://github.com/rust-lang/rust/issues/112225>.
+ let is_closure = if let ExprKind::Closure(closure) = arg.kind {
+ !tcx.generator_is_async(closure.def_id.to_def_id())
+ } else {
+ false
+ };
if is_closure != check_closures {
continue;
}
@@ -691,7 +694,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
err = tcx.sess.struct_span_err_with_code(
full_call_span,
- &format!(
+ format!(
"{call_name} takes {}{} but {} {} supplied",
if c_variadic { "at least " } else { "" },
potentially_plural_count(
@@ -744,17 +747,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if cfg!(debug_assertions) {
span_bug!(error_span, "expected errors from argument matrix");
} else {
- tcx.sess
- .struct_span_err(
- error_span,
- "argument type mismatch was detected, \
- but rustc had trouble determining where",
- )
- .note(
- "we would appreciate a bug report: \
- https://github.com/rust-lang/rust/issues/new",
- )
- .emit();
+ tcx.sess.emit_err(errors::ArgMismatchIndeterminate { span: error_span });
}
return;
}
@@ -844,7 +837,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
tcx.sess.struct_span_err_with_code(
full_call_span,
- &format!(
+ format!(
"this {} takes {}{} but {} {} supplied",
call_name,
if c_variadic { "at least " } else { "" },
@@ -892,7 +885,7 @@ 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));
+ .is_some_and(|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(_));
@@ -1219,7 +1212,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
SuggestionText::Remove(plural) => {
err.multipart_suggestion(
- &format!("remove the extra argument{}", if plural { "s" } else { "" }),
+ format!("remove the extra argument{}", if plural { "s" } else { "" }),
suggestions,
Applicability::HasPlaceholders,
);
@@ -1269,7 +1262,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
suggestion += ")";
err.span_suggestion_verbose(
suggestion_span,
- &suggestion_text,
+ suggestion_text,
suggestion,
Applicability::HasPlaceholders,
);
@@ -1316,6 +1309,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
opt_ty.unwrap_or_else(|| self.next_float_var())
}
ast::LitKind::Bool(_) => tcx.types.bool,
+ ast::LitKind::CStr(_, _) => tcx.mk_imm_ref(
+ tcx.lifetimes.re_static,
+ tcx.type_of(tcx.require_lang_item(hir::LangItem::CStr, Some(lit.span)))
+ .skip_binder(),
+ ),
ast::LitKind::Err => tcx.ty_error_misc(),
}
}
@@ -1530,7 +1528,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// case we can ignore the tail expression (e.g., `'a: {
// break 'a 22; }` would not force the type of the block
// to be `()`).
- let tail_expr = blk.expr.as_ref();
let coerce_to_ty = expected.coercion_target_type(self, blk.span);
let coerce = if blk.targeted_by_break {
CoerceMany::new(coerce_to_ty)
@@ -1548,13 +1545,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// check the tail expression **without** holding the
// `enclosing_breakables` lock below.
- let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected));
+ let tail_expr_ty =
+ blk.expr.map(|expr| (expr, self.check_expr_with_expectation(expr, expected)));
let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
let ctxt = enclosing_breakables.find_breakable(blk.hir_id);
let coerce = ctxt.coerce.as_mut().unwrap();
- if let Some(tail_expr_ty) = tail_expr_ty {
- let tail_expr = tail_expr.unwrap();
+ if let Some((tail_expr, tail_expr_ty)) = tail_expr_ty {
let span = self.get_expr_coercion_span(tail_expr);
let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id));
let ty_for_diagnostic = coerce.merged_ty();
@@ -1607,6 +1604,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self.misc(sp),
&mut |err| {
if let Some(expected_ty) = expected.only_has_type(self) {
+ if blk.stmts.is_empty() && blk.expr.is_none() {
+ self.suggest_boxing_when_appropriate(
+ err,
+ blk.span,
+ blk.hir_id,
+ expected_ty,
+ self.tcx.mk_unit(),
+ );
+ }
if !self.consider_removing_semicolon(blk, expected_ty, err) {
self.err_ctxt().consider_returning_binding(
blk,
@@ -1619,7 +1625,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// silence this redundant error, as we already emit E0070.
// Our block must be a `assign desugar local; assignment`
- if let Some(hir::Node::Block(hir::Block {
+ if let hir::Block {
stmts:
[
hir::Stmt {
@@ -1641,7 +1647,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
},
],
..
- })) = self.tcx.hir().find(blk.hir_id)
+ } = blk
{
self.comes_from_while_condition(blk.hir_id, |_| {
err.downgrade_to_delayed_bug();
@@ -1911,7 +1917,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => {
// Look for a user-provided impl of a `Fn` trait, and point to it.
let new_def_id = self.probe(|_| {
- let trait_ref = self.tcx.mk_trait_ref(
+ let trait_ref = ty::TraitRef::new(self.tcx,
call_kind.to_def_id(self.tcx),
[
callee_ty,
@@ -1963,7 +1969,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
spans.push_span_label(param.span, "");
}
- err.span_note(spans, &format!("{} defined here", self.tcx.def_descr(def_id)));
+ err.span_note(spans, format!("{} defined here", self.tcx.def_descr(def_id)));
} else if let Some(hir::Node::Expr(e)) = self.tcx.hir().get_if_local(def_id)
&& let hir::ExprKind::Closure(hir::Closure { body, .. }) = &e.kind
{
@@ -1974,11 +1980,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
("closure", self.tcx.def_span(def_id))
};
- err.span_note(span, &format!("{} defined here", kind));
+ err.span_note(span, format!("{} defined here", kind));
} else {
err.span_note(
self.tcx.def_span(def_id),
- &format!("{} defined here", self.tcx.def_descr(def_id)),
+ format!("{} defined here", self.tcx.def_descr(def_id)),
);
}
}
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index c6fd0b610..67f45f9aa 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -17,7 +17,6 @@ use rustc_infer::infer;
use rustc_infer::infer::error_reporting::TypeErrCtxt;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
-use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
use rustc_session::Session;
use rustc_span::symbol::Ident;
@@ -169,7 +168,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ocx.normalize(&ObligationCause::dummy(), self.param_env, fn_sig);
if ocx.select_all_or_error().is_empty() {
let normalized_fn_sig = self.resolve_vars_if_possible(normalized_fn_sig);
- if !normalized_fn_sig.needs_infer() {
+ if !normalized_fn_sig.has_infer() {
return normalized_fn_sig;
}
}
@@ -250,16 +249,12 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
}
fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
- if let Some(param) = param {
- if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() {
- return ty;
- }
- unreachable!()
- } else {
- self.next_ty_var(TypeVariableOrigin {
+ match param {
+ Some(param) => self.var_for_def(span, param).as_type().unwrap(),
+ None => self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeInference,
span,
- })
+ }),
}
}
@@ -269,16 +264,12 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
param: Option<&ty::GenericParamDef>,
span: Span,
) -> Const<'tcx> {
- if let Some(param) = param {
- if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() {
- return ct;
- }
- unreachable!()
- } else {
- self.next_const_var(
+ match param {
+ Some(param) => self.var_for_def(span, param).as_const().unwrap(),
+ None => self.next_const_var(
ty,
ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span },
- )
+ ),
}
}
@@ -309,7 +300,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
match ty.kind() {
ty::Adt(adt_def, _) => Some(*adt_def),
// FIXME(#104767): Should we handle bound regions here?
- ty::Alias(ty::Projection, _) if !ty.has_escaping_bound_vars() => {
+ ty::Alias(ty::Projection | ty::Inherent, _) if !ty.has_escaping_bound_vars() => {
self.normalize(span, ty).ty_adt_def()
}
_ => None,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 5fda4e191..c4add4dbd 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -1,6 +1,6 @@
use super::FnCtxt;
-use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
+use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel, SuggestBoxing};
use crate::fluent_generated as fluent;
use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
@@ -9,7 +9,8 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{
- Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
+ AsyncGeneratorKind, Expr, ExprKind, GeneratorKind, GenericBound, HirId, Node, Path, QPath,
+ Stmt, StmtKind, TyKind, WherePredicate,
};
use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::traits::{self, StatementAsExpression};
@@ -274,13 +275,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
) -> bool {
let expr = expr.peel_blocks();
- if let Some((sp, msg, suggestion, applicability, verbose, annotation)) =
- self.check_ref(expr, found, expected)
+ if let Some((suggestion, msg, applicability, verbose, annotation)) =
+ self.suggest_deref_or_ref(expr, found, expected)
{
if verbose {
- err.span_suggestion_verbose(sp, &msg, suggestion, applicability);
+ err.multipart_suggestion_verbose(msg, suggestion, applicability);
} else {
- err.span_suggestion(sp, &msg, suggestion, applicability);
+ err.multipart_suggestion(msg, suggestion, applicability);
}
if annotation {
let suggest_annotation = match expr.peel_drop_temps().kind {
@@ -342,7 +343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_label(sp, format!("{descr} `{name}` defined here"));
}
return true;
- } else if self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
+ } else if self.suggest_cast(err, expr, found, expected, expected_ty_expr) {
return true;
} else {
let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
@@ -438,33 +439,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(in super::super) fn suggest_boxing_when_appropriate(
&self,
err: &mut Diagnostic,
- expr: &hir::Expr<'_>,
+ span: Span,
+ hir_id: HirId,
expected: Ty<'tcx>,
found: Ty<'tcx>,
) -> bool {
- if self.tcx.hir().is_inside_const_context(expr.hir_id) {
- // Do not suggest `Box::new` in const context.
- return false;
- }
- if !expected.is_box() || found.is_box() {
+ // Do not suggest `Box::new` in const context.
+ if self.tcx.hir().is_inside_const_context(hir_id) || !expected.is_box() || found.is_box() {
return false;
}
- let boxed_found = self.tcx.mk_box(found);
- if self.can_coerce(boxed_found, expected) {
- err.multipart_suggestion(
- "store this in the heap by calling `Box::new`",
- vec![
- (expr.span.shrink_to_lo(), "Box::new(".to_string()),
- (expr.span.shrink_to_hi(), ")".to_string()),
- ],
- Applicability::MachineApplicable,
- );
- err.note(
- "for more on the distinction between the stack and the heap, read \
- https://doc.rust-lang.org/book/ch15-01-box.html, \
- https://doc.rust-lang.org/rust-by-example/std/box.html, and \
- https://doc.rust-lang.org/std/boxed/index.html",
- );
+ if self.can_coerce(self.tcx.mk_box(found), expected) {
+ let suggest_boxing = match found.kind() {
+ ty::Tuple(tuple) if tuple.is_empty() => {
+ SuggestBoxing::Unit { start: span.shrink_to_lo(), end: span }
+ }
+ ty::Generator(def_id, ..)
+ if matches!(
+ self.tcx.generator_kind(def_id),
+ Some(GeneratorKind::Async(AsyncGeneratorKind::Closure))
+ ) =>
+ {
+ SuggestBoxing::AsyncBody
+ }
+ _ => SuggestBoxing::Other { start: span.shrink_to_lo(), end: span.shrink_to_hi() },
+ };
+ err.subdiagnostic(suggest_boxing);
+
true
} else {
false
@@ -794,7 +794,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
};
- // get all where BoundPredicates here, because they are used in to cases below
+ // get all where BoundPredicates here, because they are used in two cases below
let where_predicates = predicates
.iter()
.filter_map(|p| match p {
@@ -1096,10 +1096,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx,
self.misc(expr.span),
self.param_env,
- ty::Binder::dummy(self.tcx.mk_trait_ref(
+ ty::TraitRef::new(self.tcx,
into_def_id,
[expr_ty, expected_ty]
- )),
+ ),
))
{
let sugg = if expr.precedence().order() >= PREC_POSTFIX {
@@ -1252,7 +1252,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
node: rustc_ast::LitKind::Int(lit, rustc_ast::LitIntType::Unsuffixed),
span,
}) => {
- let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) else { return false; };
+ let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(*span) else { return false; };
if !(snippet.starts_with("0x") || snippet.starts_with("0X")) {
return false;
}
@@ -1311,7 +1311,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// We have satisfied all requirements to provide a suggestion. Emit it.
err.span_suggestion(
- span,
+ *span,
format!("if you meant to create a null pointer, use `{null_path_str}()`"),
null_path_str + "()",
Applicability::MachineApplicable,
@@ -1384,7 +1384,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
let item_ty = self.tcx.type_of(item.def_id).subst_identity();
// FIXME(compiler-errors): This check is *so* rudimentary
- if item_ty.needs_subst() {
+ if item_ty.has_param() {
return false;
}
if self.can_coerce(item_ty, expected_ty) {
@@ -1438,7 +1438,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& !results.expr_adjustments(callee_expr).iter().any(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(..)))
// Check that we're in fact trying to clone into the expected type
&& self.can_coerce(*pointee_ty, expected_ty)
- && let trait_ref = ty::Binder::dummy(self.tcx.mk_trait_ref(clone_trait_did, [expected_ty]))
+ && let trait_ref = ty::TraitRef::new(self.tcx, clone_trait_did, [expected_ty])
// And the expected type doesn't implement `Clone`
&& !self.predicate_must_hold_considering_regions(&traits::Obligation::new(
self.tcx,
@@ -1449,7 +1449,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
diag.span_note(
callee_expr.span,
- &format!(
+ format!(
"`{expected_ty}` does not implement `Clone`, so `{found_ty}` was cloned instead"
),
);
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 3e9a9ce1b..e4a62ec05 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
@@ -8,7 +8,7 @@ use hir::{
};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_infer::infer::InferCtxt;
use rustc_middle::{
hir::map::Map,
@@ -215,6 +215,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
| ExprKind::Continue(..)
| ExprKind::Ret(..)
| ExprKind::InlineAsm(..)
+ | ExprKind::OffsetOf(..)
| ExprKind::Struct(..)
| ExprKind::Repeat(..)
| ExprKind::Yield(..)
@@ -485,6 +486,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
| ExprKind::Field(..)
| ExprKind::Index(..)
| ExprKind::InlineAsm(..)
+ | ExprKind::OffsetOf(..)
| ExprKind::Let(..)
| ExprKind::Lit(..)
| ExprKind::Path(..)
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_propagate.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_propagate.rs
index 139d17d2e..633b47889 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_propagate.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_propagate.rs
@@ -1,5 +1,5 @@
use super::{DropRangesBuilder, PostOrderId};
-use rustc_index::{bit_set::BitSet, vec::IndexVec};
+use rustc_index::{bit_set::BitSet, IndexVec};
use std::collections::BTreeMap;
impl DropRangesBuilder {
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs
index f7b493bc2..ecafbd668 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs
@@ -20,7 +20,7 @@ use hir::{Body, HirId, HirIdMap, Node};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_index::bit_set::BitSet;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::hir::map::Map;
use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId};
use rustc_middle::ty;
@@ -193,7 +193,7 @@ impl DropRanges {
.get(&TrackedValue::Temporary(hir_id))
.or(self.tracked_value_map.get(&TrackedValue::Variable(hir_id)))
.cloned()
- .map_or(false, |tracked_value_id| {
+ .is_some_and(|tracked_value_id| {
self.expect_node(location.into()).drop_state.contains(tracked_value_id)
})
}
@@ -268,8 +268,7 @@ impl DropRangesBuilder {
fn node_mut(&mut self, id: PostOrderId) -> &mut NodeInfo {
let size = self.num_values();
- self.nodes.ensure_contains_elem(id, || NodeInfo::new(size));
- &mut self.nodes[id]
+ self.nodes.ensure_contains_elem(id, || NodeInfo::new(size))
}
fn add_control_edge(&mut self, from: PostOrderId, to: PostOrderId) {
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
index fa3887362..8ab0bd535 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
@@ -202,10 +202,10 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
// If the type being assigned needs dropped, then the mutation counts as a borrow
// since it is essentially doing `Drop::drop(&mut x); x = new_value;`.
let ty = self.tcx.erase_regions(assignee_place.place.base_ty);
- if ty.needs_infer() {
+ if ty.has_infer() {
self.tcx.sess.delay_span_bug(
self.tcx.hir().span(assignee_place.hir_id),
- &format!("inference variables in {ty}"),
+ format!("inference variables in {ty}"),
);
} else if ty.needs_drop(self.tcx, self.param_env) {
self.places
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
index f39710804..019fb86f5 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
@@ -112,7 +112,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
self.fcx
.tcx
.sess
- .delay_span_bug(span, &format!("Encountered var {:?}", unresolved_term));
+ .delay_span_bug(span, format!("Encountered var {:?}", unresolved_term));
} else {
let note = format!(
"the type is part of the {} because of this {}",
@@ -460,11 +460,11 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
// Avoid ICEs in needs_drop.
let ty = self.fcx.resolve_vars_if_possible(ty);
let ty = self.fcx.tcx.erase_regions(ty);
- if ty.needs_infer() {
+ if ty.has_infer() {
self.fcx
.tcx
.sess
- .delay_span_bug(expr.span, &format!("inference variables in {ty}"));
+ .delay_span_bug(expr.span, format!("inference variables in {ty}"));
true
} else {
ty.needs_drop(self.fcx.tcx, self.fcx.param_env)
@@ -571,7 +571,7 @@ fn check_must_not_suspend_ty<'tcx>(
// FIXME: support adding the attribute to TAITs
ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
let mut has_emitted = false;
- for &(predicate, _) in fcx.tcx.explicit_item_bounds(def) {
+ for &(predicate, _) in fcx.tcx.explicit_item_bounds(def).skip_binder() {
// We only look at the `DefId`, so it is safe to skip the binder here.
if let ty::PredicateKind::Clause(ty::Clause::Trait(ref poly_trait_predicate)) =
predicate.kind().skip_binder()
@@ -650,7 +650,7 @@ fn check_must_not_suspend_ty<'tcx>(
},
)
}
- // If drop tracking is enabled, we want to look through references, since the referrent
+ // If drop tracking is enabled, we want to look through references, since the referent
// may not be considered live across the await point.
ty::Ref(_region, ty, _mutability) if fcx.sess().opts.unstable_opts.drop_tracking => {
let descr_pre = &format!("{}reference{} to ", data.descr_pre, plural_suffix);
diff --git a/compiler/rustc_hir_typeck/src/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs
index 4110b176b..294c3bb78 100644
--- a/compiler/rustc_hir_typeck/src/inherited.rs
+++ b/compiler/rustc_hir_typeck/src/inherited.rs
@@ -4,7 +4,8 @@ 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::{DefiningAnchor, InferCtxt, InferOk, TyCtxtInferExt};
+use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
+use rustc_middle::traits::DefiningAnchor;
use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::def_id::LocalDefIdMap;
@@ -130,7 +131,7 @@ impl<'tcx> Inherited<'tcx> {
// (*) binder skipped
if let ty::PredicateKind::Clause(ty::Clause::Trait(tpred)) = obligation.predicate.kind().skip_binder()
&& let Some(ty) = self.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| self.root_var(t))
- && self.tcx.lang_items().sized_trait().map_or(false, |st| st != tpred.trait_ref.def_id)
+ && self.tcx.lang_items().sized_trait().is_some_and(|st| st != tpred.trait_ref.def_id)
{
let new_self_ty = self.tcx.types.unit;
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
index 106f5bcd7..3c5eafd94 100644
--- a/compiler/rustc_hir_typeck/src/intrinsicck.rs
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -1,10 +1,10 @@
use hir::HirId;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
-use rustc_target::abi::{FieldIdx, Pointer, VariantIdx};
+use rustc_target::abi::{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[FieldIdx::from_u32(0)].ty(tcx, substs);
+ return def.variant(data_idx).single_field().ty(tcx, substs);
}
}
@@ -72,8 +72,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let from = unpack_option_like(tcx, from);
if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer(dl.instruction_address_space).size(&tcx) {
struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type")
- .note(&format!("source type: {from}"))
- .note(&format!("target type: {to}"))
+ .note(format!("source type: {from}"))
+ .note(format!("target type: {to}"))
.help("cast with `as` to a pointer instead")
.emit();
return;
@@ -109,10 +109,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
or dependently-sized types"
);
if from == to {
- err.note(&format!("`{from}` does not have a fixed size"));
+ err.note(format!("`{from}` does not have a fixed size"));
} else {
- err.note(&format!("source type: `{}` ({})", from, skeleton_string(from, sk_from)))
- .note(&format!("target type: `{}` ({})", to, skeleton_string(to, sk_to)));
+ err.note(format!("source type: `{}` ({})", from, skeleton_string(from, sk_from)))
+ .note(format!("target type: `{}` ({})", to, skeleton_string(to, sk_to)));
let mut should_delay_as_bug = false;
if let Err(LayoutError::Unknown(bad_from)) = sk_from && bad_from.references_error() {
should_delay_as_bug = true;
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 45890abad..b97b55d8f 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -2,6 +2,7 @@
#![feature(let_chains)]
#![feature(try_blocks)]
#![feature(never_type)]
+#![feature(box_patterns)]
#![feature(min_specialization)]
#![feature(control_flow_enum)]
#![feature(drain_filter)]
@@ -59,6 +60,7 @@ use rustc_errors::{
struct_span_err, DiagnosticId, DiagnosticMessage, ErrorGuaranteed, MultiSpan,
SubdiagnosticMessage,
};
+use rustc_fluent_macro::fluent_messages;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::Visitor;
@@ -66,12 +68,10 @@ use rustc_hir::{HirIdMap, Node};
use rustc_hir_analysis::astconv::AstConv;
use rustc_hir_analysis::check::check_abi;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_macros::fluent_messages;
+use rustc_middle::query::Providers;
use rustc_middle::traits;
-use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::config;
-use rustc_session::Session;
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::{sym, Span};
@@ -152,25 +152,9 @@ fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet<LocalDef
&*tcx.typeck(def_id).used_trait_imports
}
-fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
- tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
-}
-
-fn typeck_const_arg<'tcx>(
- tcx: TyCtxt<'tcx>,
- (did, param_did): (LocalDefId, DefId),
-) -> &ty::TypeckResults<'tcx> {
- let fallback = move || tcx.type_of(param_did).subst_identity();
- typeck_with_fallback(tcx, did, fallback)
-}
-
fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
- if let Some(param_did) = tcx.opt_const_param_of(def_id) {
- tcx.typeck_const_arg((def_id, param_did))
- } else {
- let fallback = move || tcx.type_of(def_id.to_def_id()).subst_identity();
- typeck_with_fallback(tcx, def_id, fallback)
- }
+ let fallback = move || tcx.type_of(def_id.to_def_id()).subst_identity();
+ typeck_with_fallback(tcx, def_id, fallback)
}
/// Used only to get `TypeckResults` for type inference during error recovery.
@@ -228,7 +212,7 @@ fn typeck_with_fallback<'tcx>(
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);
+ check_fn(&mut fcx, fn_sig, decl, def_id, body, None, tcx.features().unsized_fn_params);
} else {
let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer, span, .. }) = body_ty {
Some(fcx.next_ty_var(TypeVariableOrigin {
@@ -237,12 +221,6 @@ fn typeck_with_fallback<'tcx>(
}))
} 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 =>
{
@@ -459,8 +437,8 @@ enum TupleArgumentsFlag {
TupleArguments,
}
-fn fatally_break_rust(sess: &Session) {
- let handler = sess.diagnostic();
+fn fatally_break_rust(tcx: TyCtxt<'_>) {
+ let handler = tcx.sess.diagnostic();
handler.span_bug_no_panic(
MultiSpan::new(),
"It looks like you're trying to break rust; would you like some ICE?",
@@ -470,29 +448,21 @@ fn fatally_break_rust(sess: &Session) {
"we would appreciate a joke overview: \
https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
);
- handler.note_without_error(&format!(
+ handler.note_without_error(format!(
"rustc {} running on {}",
- option_env!("CFG_VERSION").unwrap_or("unknown_version"),
+ tcx.sess.cfg_version,
config::host_triple(),
));
}
-fn has_expected_num_generic_args(
- tcx: TyCtxt<'_>,
- trait_did: Option<DefId>,
- expected: usize,
-) -> bool {
- trait_did.map_or(true, |trait_did| {
- let generics = tcx.generics_of(trait_did);
- generics.count() == expected + if generics.has_self { 1 } else { 0 }
- })
+fn has_expected_num_generic_args(tcx: TyCtxt<'_>, trait_did: DefId, expected: usize) -> bool {
+ let generics = tcx.generics_of(trait_did);
+ generics.count() == expected + if generics.has_self { 1 } else { 0 }
}
pub fn provide(providers: &mut Providers) {
method::provide(providers);
*providers = Providers {
- typeck_item_bodies,
- typeck_const_arg,
typeck,
diagnostic_only_typeck,
has_typeck_results,
diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index 6c861b593..78171e0b2 100644
--- a/compiler/rustc_hir_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -381,6 +381,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
| hir::ExprKind::Struct(..)
| hir::ExprKind::Repeat(..)
| hir::ExprKind::InlineAsm(..)
+ | hir::ExprKind::OffsetOf(..)
| hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr.span, expr_ty)),
}
}
@@ -410,7 +411,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
}
Res::Local(var_id) => {
- if self.upvars.map_or(false, |upvars| upvars.contains_key(&var_id)) {
+ if self.upvars.is_some_and(|upvars| upvars.contains_key(&var_id)) {
self.cat_upvar(hir_id, var_id)
} else {
Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Local(var_id), Vec::new()))
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 9155a3d8d..98529b666 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -158,7 +158,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
let Some((ty, n)) = autoderef.nth(pick.autoderefs) else {
return self.tcx.ty_error_with_message(
rustc_span::DUMMY_SP,
- &format!("failed autoderef {}", pick.autoderefs),
+ format!("failed autoderef {}", pick.autoderefs),
);
};
assert_eq!(n, pick.autoderefs);
@@ -471,7 +471,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
self_ty, method_self_ty, self.span, pick
);
let cause = self.cause(
- self.span,
+ self.self_expr.span,
ObligationCauseCode::UnifyReceiver(Box::new(UnifyReceiverContext {
assoc_item: pick.item,
param_env: self.param_env,
@@ -482,13 +482,22 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
}
- Err(_) => {
- span_bug!(
- self.span,
- "{} was a subtype of {} but now is not?",
- self_ty,
- method_self_ty
- );
+ Err(terr) => {
+ // FIXME(arbitrary_self_types): We probably should limit the
+ // situations where this can occur by adding additional restrictions
+ // to the feature, like the self type can't reference method substs.
+ if self.tcx.features().arbitrary_self_types {
+ self.err_ctxt()
+ .report_mismatched_types(&cause, method_self_ty, self_ty, terr)
+ .emit();
+ } else {
+ span_bug!(
+ self.span,
+ "{} was a subtype of {} but now is not?",
+ self_ty,
+ method_self_ty
+ );
+ }
}
}
}
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index 0456dd56c..6f4d674ba 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -13,11 +13,12 @@ pub use self::MethodError::*;
use crate::errors::OpMethodGenericParams;
use crate::FnCtxt;
use rustc_data_structures::sync::Lrc;
-use rustc_errors::{Applicability, Diagnostic};
+use rustc_errors::{Applicability, Diagnostic, SubdiagnosticMessage};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Namespace};
use rustc_hir::def_id::DefId;
use rustc_infer::infer::{self, InferOk};
+use rustc_middle::query::Providers;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
use rustc_middle::ty::{self, GenericParamDefKind, Ty, TypeVisitableExt};
@@ -28,7 +29,7 @@ use rustc_trait_selection::traits::{self, NormalizeExt};
use self::probe::{IsSuggestion, ProbeScope};
-pub fn provide(providers: &mut ty::query::Providers) {
+pub fn provide(providers: &mut Providers) {
probe::provide(providers);
}
@@ -129,7 +130,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(crate) fn suggest_method_call(
&self,
err: &mut Diagnostic,
- msg: &str,
+ msg: impl Into<SubdiagnosticMessage> + std::fmt::Debug,
method_name: Ident,
self_ty: Ty<'tcx>,
call_expr: &hir::Expr<'tcx>,
@@ -300,8 +301,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
trait_def_id: DefId,
self_ty: Ty<'tcx>,
opt_input_types: Option<&[Ty<'tcx>]>,
- ) -> (traits::Obligation<'tcx, ty::Predicate<'tcx>>, &'tcx ty::List<ty::subst::GenericArg<'tcx>>)
- {
+ ) -> (traits::PredicateObligation<'tcx>, &'tcx ty::List<ty::subst::GenericArg<'tcx>>) {
// Construct a trait-reference `self_ty : Trait<input_tys>`
let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| {
match param.kind {
@@ -317,7 +317,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.var_for_def(cause.span, param)
});
- let trait_ref = self.tcx.mk_trait_ref(trait_def_id, substs);
+ let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, substs);
// Construct an obligation
let poly_trait_ref = ty::Binder::dummy(trait_ref);
diff --git a/compiler/rustc_hir_typeck/src/method/prelude2021.rs b/compiler/rustc_hir_typeck/src/method/prelude2021.rs
index 3d6c2119b..ec4e7f7f8 100644
--- a/compiler/rustc_hir_typeck/src/method/prelude2021.rs
+++ b/compiler/rustc_hir_typeck/src/method/prelude2021.rs
@@ -118,7 +118,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
lint.span_help(
sp,
- &format!("disambiguate the method call with `({})`", self_adjusted,),
+ format!("disambiguate the method call with `({})`", self_adjusted,),
);
}
@@ -180,7 +180,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
lint.span_help(
sp,
- &format!(
+ format!(
"disambiguate the associated function with `{}::{}(...)`",
trait_name, segment.ident,
),
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 4fd778910..9f3d35a77 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -3,7 +3,7 @@ use super::CandidateSource;
use super::MethodError;
use super::NoMatchData;
-use crate::errors::MethodCallOnUnknownType;
+use crate::errors::MethodCallOnUnknownRawPointee;
use crate::FnCtxt;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
@@ -16,6 +16,7 @@ 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::query::Providers;
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
use rustc_middle::ty::AssocItem;
use rustc_middle::ty::GenericParamDefKind;
@@ -437,7 +438,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// so we do a future-compat lint here for the 2015 edition
// (see https://github.com/rust-lang/rust/issues/46906)
if self.tcx.sess.rust_2018() {
- self.tcx.sess.emit_err(MethodCallOnUnknownType { span });
+ self.tcx.sess.emit_err(MethodCallOnUnknownRawPointee { span });
} else {
self.tcx.struct_span_lint_hir(
lint::builtin::TYVAR_BEHIND_RAW_POINTER,
@@ -495,7 +496,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
-pub fn provide(providers: &mut ty::query::Providers) {
+pub fn provide(providers: &mut Providers) {
providers.method_autoderef_steps = method_autoderef_steps;
}
@@ -954,7 +955,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
) {
debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id);
let trait_substs = self.fresh_item_substs(trait_def_id);
- let trait_ref = self.tcx.mk_trait_ref(trait_def_id, trait_substs);
+ let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, trait_substs);
if self.tcx.is_trait_alias(trait_def_id) {
// For trait aliases, recursively assume all explicitly named traits are relevant
@@ -1193,7 +1194,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
pick.autoderefs += 1;
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
mutbl,
- unsize: pick.autoref_or_ptr_adjustment.map_or(false, |a| a.get_unsize()),
+ unsize: pick.autoref_or_ptr_adjustment.is_some_and(|a| a.get_unsize()),
})
}
@@ -1396,7 +1397,7 @@ impl<'tcx> Pick<'tcx> {
// However `self.span` only
// highlights the method name, so we can't use it. Also consider reusing
// the code from `report_method_error()`.
- lint.help(&format!(
+ lint.help(format!(
"call with fully qualified syntax `{}(...)` to keep using the current \
method",
tcx.def_path_str(self.item.def_id),
@@ -1420,7 +1421,7 @@ impl<'tcx> Pick<'tcx> {
}
if tcx.sess.is_nightly_build() {
for (candidate, feature) in &self.unstable_candidates {
- lint.help(&format!(
+ lint.help(format!(
"add `#![feature({})]` to the crate attributes to enable `{}`",
feature,
tcx.def_path_str(candidate.item.def_id),
@@ -2032,7 +2033,7 @@ impl<'tcx> Candidate<'tcx> {
// means they are safe to put into the
// `WhereClausePick`.
assert!(
- !trait_ref.skip_binder().substs.needs_infer()
+ !trait_ref.skip_binder().substs.has_infer()
&& !trait_ref.skip_binder().substs.has_placeholders()
);
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 900a6fa0d..e04cc44b5 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -2,6 +2,8 @@
//! found or is otherwise invalid.
use crate::errors;
+use crate::errors::CandidateTraitNote;
+use crate::errors::NoAssociatedItem;
use crate::Expectation;
use crate::FnCtxt;
use rustc_ast::ast::Mutability;
@@ -27,8 +29,8 @@ 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::IsSuggestable;
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;
use rustc_span::{edit_distance, source_map, ExpnKind, FileName, MacroKind, Span};
@@ -38,6 +40,7 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _
use rustc_trait_selection::traits::{
FulfillmentError, Obligation, ObligationCause, ObligationCauseCode,
};
+use std::borrow::Cow;
use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope};
use super::{CandidateSource, MethodError, NoMatchData};
@@ -72,7 +75,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.autoderef(span, ty).any(|(ty, _)| {
info!("check deref {:?} impl FnOnce", ty);
self.probe(|_| {
- let trait_ref = tcx.mk_trait_ref(
+ let trait_ref = ty::TraitRef::new(
+ tcx,
fn_once,
[
ty,
@@ -111,6 +115,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
error: MethodError<'tcx>,
args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
expected: Expectation<'tcx>,
+ trait_missing_method: bool,
) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
// Avoid suggestions when we don't know what's going on.
if rcvr_ty.references_error() {
@@ -135,6 +140,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
sugg_span,
&mut no_match_data,
expected,
+ trait_missing_method,
);
}
@@ -169,13 +175,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
kind,
item_name
);
- err.span_label(item_name.span, &format!("private {}", kind));
+ err.span_label(item_name.span, format!("private {}", kind));
let sp = self
.tcx
.hir()
.span_if_local(def_id)
.unwrap_or_else(|| self.tcx.def_span(def_id));
- err.span_label(sp, &format!("private {} defined here", kind));
+ err.span_label(sp, format!("private {} defined here", kind));
self.suggest_valid_traits(&mut err, out_of_scope_traits);
err.emit();
}
@@ -188,7 +194,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
format!("the `{item_name}` method cannot be invoked on a trait object")
};
- let mut err = self.sess().struct_span_err(span, &msg);
+ let mut err = self.sess().struct_span_err(span, msg);
if !needs_mut {
err.span_label(bound_span, "this has a `Sized` requirement");
}
@@ -228,12 +234,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
err.span_suggestion_verbose(
mut_ty.ty.span.shrink_to_lo(),
- &msg,
+ msg,
"mut ",
Applicability::MachineApplicable,
);
} else {
- err.help(&msg);
+ err.help(msg);
}
}
}
@@ -277,12 +283,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
sugg_span: Span,
no_match_data: &mut NoMatchData<'tcx>,
expected: Expectation<'tcx>,
+ trait_missing_method: bool,
) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
let mode = no_match_data.mode;
let tcx = self.tcx;
let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
- let (ty_str, ty_file) = tcx.short_ty_string(rcvr_ty);
- let short_ty_str = with_forced_trimmed_paths!(rcvr_ty.to_string());
+ let ((mut ty_str, ty_file), short_ty_str) = if trait_missing_method
+ && let ty::Dynamic(predicates, _, _) = rcvr_ty.kind() {
+ ((predicates.to_string(), None), with_forced_trimmed_paths!(predicates.to_string()))
+ } else {
+ (tcx.short_ty_string(rcvr_ty), with_forced_trimmed_paths!(rcvr_ty.to_string()))
+ };
let is_method = mode == Mode::MethodCall;
let unsatisfied_predicates = &no_match_data.unsatisfied_predicates;
let similar_candidate = no_match_data.similar_candidate;
@@ -345,7 +356,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- let is_write = sugg_span.ctxt().outer_expn_data().macro_def_id.map_or(false, |def_id| {
+ let is_write = sugg_span.ctxt().outer_expn_data().macro_def_id.is_some_and(|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");
@@ -354,34 +365,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
self.suggest_missing_writer(rcvr_ty, args)
} else {
- struct_span_err!(
- tcx.sess,
+ tcx.sess.create_err(NoAssociatedItem {
span,
- E0599,
- "no {} named `{}` found for {} `{}` in the current scope",
item_kind,
item_name,
- rcvr_ty.prefix_string(self.tcx),
- ty_str_reported,
- )
+ ty_prefix: if trait_missing_method {
+ // FIXME(mu001999) E0599 maybe not suitable here because it is for types
+ Cow::from("trait")
+ } else {
+ rcvr_ty.prefix_string(self.tcx)
+ },
+ ty_str: ty_str_reported,
+ trait_missing_method,
+ })
};
if tcx.sess.source_map().is_multiline(sugg_span) {
err.span_label(sugg_span.with_hi(span.lo()), "");
}
- let ty_str = if short_ty_str.len() < ty_str.len() && ty_str.len() > 10 {
- short_ty_str
- } else {
- ty_str
- };
+
+ if short_ty_str.len() < ty_str.len() && ty_str.len() > 10 {
+ ty_str = short_ty_str;
+ }
+
if let Some(file) = ty_file {
- err.note(&format!("the full type name has been written to '{}'", file.display(),));
+ err.note(format!("the full type name has been written to '{}'", file.display(),));
}
if rcvr_ty.references_error() {
err.downgrade_to_delayed_bug();
}
if tcx.ty_is_opaque_future(rcvr_ty) && item_name.name == sym::poll {
- err.help(&format!(
+ err.help(format!(
"method `poll` found on `Pin<&mut {ty_str}>`, \
see documentation for `std::pin::Pin`"
));
@@ -510,7 +524,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
if let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) {
let iterator_trait = self.tcx.def_path_str(iterator_trait);
- err.note(&format!(
+ err.note(format!(
"`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement"
));
}
@@ -810,7 +824,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for (sp, label) in span_labels {
span.push_span_label(sp, label);
}
- err.span_note(span, &msg);
+ err.span_note(span, msg);
unsatisfied_bounds = true;
}
@@ -867,7 +881,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
obligations.sort();
err.span_suggestion_verbose(
span,
- &format!(
+ format!(
"consider restricting the type parameter{s} to satisfy the \
trait bound{s}",
s = pluralize!(obligations.len())
@@ -912,13 +926,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
but its trait bounds were not satisfied"
)
});
- err.set_primary_message(&primary_message);
+ err.set_primary_message(primary_message);
if let Some(label) = label {
custom_span_label = true;
err.span_label(span, label);
}
if !bound_list.is_empty() {
- err.note(&format!(
+ err.note(format!(
"the following trait bounds were not satisfied:\n{bound_list}"
));
}
@@ -1002,7 +1016,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
"".to_string()
};
- err.note(&format!(
+ err.note(format!(
"the {item_kind} was found for\n{}{}",
type_candidates, additional_types
));
@@ -1044,12 +1058,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
- self.check_for_inner_self(&mut err, source, rcvr_ty, item_name);
+ self.suggest_unwrapping_inner_self(&mut err, source, rcvr_ty, item_name);
bound_spans.sort();
bound_spans.dedup();
for (span, msg) in bound_spans.into_iter() {
- err.span_label(span, &msg);
+ err.span_label(span, msg);
}
if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params {
@@ -1066,6 +1080,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&static_candidates,
unsatisfied_bounds,
expected.only_has_type(self),
+ trait_missing_method,
);
}
@@ -1119,7 +1134,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
err.span_suggestion(
span,
- &format!(
+ format!(
"there is {} {} with a similar name",
self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id),
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
@@ -1131,7 +1146,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- self.check_for_deref_method(&mut err, source, rcvr_ty, item_name, expected);
+ self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected);
return Some(err);
}
@@ -1203,9 +1218,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
if let Some(note_span) = note_span {
// We have a span pointing to the method. Show note with snippet.
- err.span_note(note_span, &note_str);
+ err.span_note(note_span, note_str);
} else {
- err.note(&note_str);
+ err.note(note_str);
}
if let Some(sugg_span) = sugg_span
&& let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
@@ -1243,7 +1258,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let Some(item) = self.associated_value(trait_did, item_name) else { continue };
let item_span = self.tcx.def_span(item.def_id);
let idx = if sources.len() > 1 {
- let msg = &format!(
+ let msg = format!(
"candidate #{} is defined in the trait `{}`",
idx + 1,
self.tcx.def_path_str(trait_did)
@@ -1251,7 +1266,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_note(item_span, msg);
Some(idx + 1)
} else {
- let msg = &format!(
+ let msg = format!(
"the candidate is defined in the trait `{}`",
self.tcx.def_path_str(trait_did)
);
@@ -1278,7 +1293,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
if sources.len() > limit {
- err.note(&format!("and {} others", sources.len() - limit));
+ err.note(format!("and {} others", sources.len() - limit));
}
}
@@ -1402,7 +1417,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
applicability,
);
} else {
- err.help(&format!("try with `{}::{}`", ty_str, item_name,));
+ err.help(format!("try with `{}::{}`", ty_str, item_name,));
}
}
@@ -1436,7 +1451,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if self.is_fn_ty(field_ty, span) {
let expr_span = expr.span.to(item_name.span);
err.multipart_suggestion(
- &format!(
+ format!(
"to call the function stored in `{}`, \
surround the field access with parentheses",
item_name,
@@ -1507,7 +1522,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let span_included = match parent_expr.kind {
hir::ExprKind::Struct(_, eps, _) => {
- eps.len() > 0 && eps.last().map_or(false, |ep| ep.span.contains(span))
+ eps.len() > 0 && eps.last().is_some_and(|ep| ep.span.contains(span))
}
// `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
hir::ExprKind::Call(ref func, ..) => func.span.contains(span),
@@ -1530,7 +1545,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
if pick.is_ok() {
let range_span = parent_expr.span.with_hi(expr.span.hi());
- tcx.sess.emit_err(errors::MissingParentheseInRange {
+ tcx.sess.emit_err(errors::MissingParenthesesInRange {
span,
ty_str: ty_str.to_string(),
method_name: item_name.as_str().to_string(),
@@ -1612,7 +1627,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let snippet = snippet.strip_suffix('.').unwrap_or(&snippet);
err.span_suggestion(
lit.span,
- &format!(
+ format!(
"you must specify a concrete type for this numeric value, \
like `{}`",
concrete_type
@@ -1648,7 +1663,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// account for `let x: _ = 42;`
// ^^^
type_span,
- &msg,
+ msg,
format!(": {concrete_type}"),
Applicability::MaybeIncorrect,
);
@@ -1766,7 +1781,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ProbeScope::TraitsInScope,
return_type,
)
- .map_or(false, |pick| {
+ .is_ok_and(|pick| {
!never_mention_traits
.iter()
.flatten()
@@ -1804,7 +1819,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- fn check_for_inner_self(
+ fn suggest_unwrapping_inner_self(
&self,
err: &mut Diagnostic,
source: SelfSource<'tcx>,
@@ -1861,7 +1876,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let self_ty = field.ty(tcx, substs);
err.span_note(
tcx.def_span(pick.item.def_id),
- &format!("the method `{item_name}` exists on the type `{self_ty}`"),
+ format!("the method `{item_name}` exists on the type `{self_ty}`"),
);
let (article, kind, variant, question) =
if tcx.is_diagnostic_item(sym::Result, kind.did()) {
@@ -1975,7 +1990,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_note(
tcx.def_span(pick.item.def_id),
- &format!("the method `{item_name}` exists on the type `{ty}`"),
+ format!("the method `{item_name}` exists on the type `{ty}`"),
);
}
}
@@ -2046,7 +2061,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pluralize!(preds.len()),
)
};
- err.span_note(spans, &msg);
+ err.span_note(spans, msg);
}
let preds: Vec<_> = errors
@@ -2068,7 +2083,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut derives = Vec::<(String, Span, Symbol)>::new();
let mut traits = Vec::new();
for (pred, _, _) in unsatisfied_predicates {
- let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = pred.kind().skip_binder() else { continue };
+ let Some(ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred))) =
+ pred.kind().no_bound_vars()
+ else {
+ continue
+ };
let adt = match trait_pred.self_ty().ty_adt_def() {
Some(adt) if adt.did().is_local() => adt,
_ => continue,
@@ -2089,18 +2108,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if can_derive {
let self_name = trait_pred.self_ty().to_string();
let self_span = self.tcx.def_span(adt.did());
- if let Some(poly_trait_ref) = pred.to_opt_poly_trait_pred() {
- for super_trait in supertraits(self.tcx, poly_trait_ref.to_poly_trait_ref())
+ for super_trait in
+ supertraits(self.tcx, ty::Binder::dummy(trait_pred.trait_ref))
+ {
+ if let Some(parent_diagnostic_name) =
+ self.tcx.get_diagnostic_name(super_trait.def_id())
{
- if let Some(parent_diagnostic_name) =
- self.tcx.get_diagnostic_name(super_trait.def_id())
- {
- derives.push((
- self_name.clone(),
- self_span,
- parent_diagnostic_name,
- ));
- }
+ derives.push((self_name.clone(), self_span, parent_diagnostic_name));
}
}
derives.push((self_name, self_span, diagnostic_name));
@@ -2147,21 +2161,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
err.span_note(
span,
- &format!("the trait{} {} must be implemented", pluralize!(len), names),
+ format!("the trait{} {} must be implemented", pluralize!(len), names),
);
}
for (self_name, self_span, traits) in &derives_grouped {
err.span_suggestion_verbose(
self_span.shrink_to_lo(),
- &format!("consider annotating `{}` with `#[derive({})]`", self_name, traits),
+ format!("consider annotating `{}` with `#[derive({})]`", self_name, traits),
format!("#[derive({})]\n", traits),
Applicability::MaybeIncorrect,
);
}
}
- fn check_for_deref_method(
+ fn note_derefed_ty_has_method(
&self,
err: &mut Diagnostic,
self_source: SelfSource<'tcx>,
@@ -2197,7 +2211,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| ty::Float(_)
| ty::Adt(_, _)
| ty::Str
- | ty::Alias(ty::Projection, _)
+ | ty::Alias(ty::Projection | ty::Inherent, _)
| ty::Param(_) => format!("{deref_ty}"),
// we need to test something like <&[_]>::len or <(&[u32])>::len
// and Vec::function();
@@ -2300,7 +2314,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_suggestions(
span,
- &msg,
+ msg,
path_strings.chain(glob_path_strings),
Applicability::MaybeIncorrect,
);
@@ -2332,7 +2346,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.suggest_use_candidates(err, msg, candidates);
if let Some(did) = edition_fix {
- err.note(&format!(
+ err.note(format!(
"'{}' is included in the prelude starting in Edition 2021",
with_crate_prefix!(self.tcx.def_path_str(did))
));
@@ -2361,6 +2375,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
static_candidates: &[CandidateSource],
unsatisfied_bounds: bool,
return_type: Option<Ty<'tcx>>,
+ trait_missing_method: bool,
) {
let mut alt_rcvr_sugg = false;
if let (SelfSource::MethodCall(rcvr), false) = (source, unsatisfied_bounds) {
@@ -2400,7 +2415,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if pick.autoderefs == 0 && !skip {
err.span_label(
pick.item.ident(self.tcx).span,
- &format!("the method is available for `{}` here", rcvr_ty),
+ format!("the method is available for `{}` here", rcvr_ty),
);
}
break;
@@ -2439,14 +2454,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// implement the `AsRef` trait.
let skip = skippable.contains(&did)
|| (("Pin::new" == *pre) && (sym::as_ref == item_name.name))
- || inputs_len.map_or(false, |inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() != inputs_len);
+ || inputs_len.is_some_and(|inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() != inputs_len);
// Make sure the method is defined for the *actual* receiver: we don't
// want to treat `Box<Self>` as a receiver if it only works because of
// an autoderef to `&self`
if pick.autoderefs == 0 && !skip {
err.span_label(
pick.item.ident(self.tcx).span,
- &format!("the method is available for `{}` here", new_rcvr_t),
+ format!("the method is available for `{}` here", new_rcvr_t),
);
err.multipart_suggestion(
"consider wrapping the receiver expression with the \
@@ -2584,11 +2599,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
},
_ => None,
};
- err.help(if param_type.is_some() {
- "items from traits can only be used if the type parameter is bounded by the trait"
- } else {
- "items from traits can only be used if the trait is implemented and in scope"
- });
+ if !trait_missing_method {
+ err.help(if param_type.is_some() {
+ "items from traits can only be used if the type parameter is bounded by the trait"
+ } else {
+ "items from traits can only be used if the trait is implemented and in scope"
+ });
+ }
+
let candidates_len = candidates.len();
let message = |action| {
format!(
@@ -2619,47 +2637,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Nothing,
}
let ast_generics = hir.get_generics(id.owner.def_id).unwrap();
- let (sp, mut introducer) = if let Some(span) =
- ast_generics.bounds_span_for_suggestions(def_id)
- {
- (span, Introducer::Plus)
- } else if let Some(colon_span) = param.colon_span {
- (colon_span.shrink_to_hi(), Introducer::Nothing)
- } else {
- (param.span.shrink_to_hi(), Introducer::Colon)
- };
- if matches!(
- param.kind,
- hir::GenericParamKind::Type { synthetic: true, .. },
- ) {
- introducer = Introducer::Plus
- }
let trait_def_ids: FxHashSet<DefId> = ast_generics
.bounds_for_param(def_id)
.flat_map(|bp| bp.bounds.iter())
.filter_map(|bound| bound.trait_ref()?.trait_def_id())
.collect();
- if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
- err.span_suggestions(
- sp,
- &message(format!(
- "restrict type parameter `{}` with",
- param.name.ident(),
- )),
+ if candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
+ return;
+ }
+ let msg = message(format!(
+ "restrict type parameter `{}` with",
+ param.name.ident(),
+ ));
+ let bounds_span = ast_generics.bounds_span_for_suggestions(def_id);
+ if rcvr_ty.is_ref() && param.is_impl_trait() && bounds_span.is_some() {
+ err.multipart_suggestions(
+ msg,
candidates.iter().map(|t| {
- format!(
- "{} {}",
- match introducer {
- Introducer::Plus => " +",
- Introducer::Colon => ":",
- Introducer::Nothing => "",
- },
- self.tcx.def_path_str(t.def_id),
- )
+ vec![
+ (param.span.shrink_to_lo(), "(".to_string()),
+ (
+ bounds_span.unwrap(),
+ format!(" + {})", self.tcx.def_path_str(t.def_id)),
+ ),
+ ]
}),
Applicability::MaybeIncorrect,
);
+ return;
}
+
+ let (sp, introducer) = if let Some(span) = bounds_span {
+ (span, Introducer::Plus)
+ } else if let Some(colon_span) = param.colon_span {
+ (colon_span.shrink_to_hi(), Introducer::Nothing)
+ } else if param.is_impl_trait() {
+ (param.span.shrink_to_hi(), Introducer::Plus)
+ } else {
+ (param.span.shrink_to_hi(), Introducer::Colon)
+ };
+
+ err.span_suggestions(
+ sp,
+ msg,
+ candidates.iter().map(|t| {
+ format!(
+ "{} {}",
+ match introducer {
+ Introducer::Plus => " +",
+ Introducer::Colon => ":",
+ Introducer::Nothing => "",
+ },
+ self.tcx.def_path_str(t.def_id)
+ )
+ }),
+ Applicability::MaybeIncorrect,
+ );
return;
}
Node::Item(hir::Item {
@@ -2674,7 +2707,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
err.span_suggestions(
sp,
- &message(format!("add {} supertrait for", article)),
+ message(format!("add {} supertrait for", article)),
candidates.iter().map(|t| {
format!("{} {}", sep, self.tcx.def_path_str(t.def_id),)
}),
@@ -2708,7 +2741,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let imp = self.tcx.impl_trait_ref(imp_did).unwrap().subst_identity();
let imp_simp =
simplify_type(self.tcx, imp.self_ty(), TreatParams::ForLookup);
- imp_simp.map_or(false, |s| s == simp_rcvr_ty)
+ imp_simp.is_some_and(|s| s == simp_rcvr_ty)
})
{
explicitly_negative.push(candidate);
@@ -2722,27 +2755,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(candidates, Vec::new())
};
- let action = if let Some(param) = param_type {
- format!("restrict type parameter `{}` with", param)
- } else {
- // FIXME: it might only need to be imported into scope, not implemented.
- "implement".to_string()
- };
match &potential_candidates[..] {
[] => {}
[trait_info] if trait_info.def_id.is_local() => {
- err.span_note(
- self.tcx.def_span(trait_info.def_id),
- &format!(
- "`{}` defines an item `{}`, perhaps you need to {} it",
- self.tcx.def_path_str(trait_info.def_id),
- item_name,
- action
- ),
- );
+ err.subdiagnostic(CandidateTraitNote {
+ span: self.tcx.def_span(trait_info.def_id),
+ trait_name: self.tcx.def_path_str(trait_info.def_id),
+ item_name,
+ action_or_ty: if trait_missing_method {
+ "NONE".to_string()
+ } else {
+ param_type.map_or_else(
+ || "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented.
+ ToString::to_string,
+ )
+ },
+ });
}
trait_infos => {
- let mut msg = message(action);
+ let mut msg = message(param_type.map_or_else(
+ || "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented.
+ |param| format!("restrict type parameter `{}` with", param),
+ ));
for (i, trait_info) in trait_infos.iter().enumerate() {
msg.push_str(&format!(
"\ncandidate #{}: `{}`",
@@ -2750,7 +2784,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.def_path_str(trait_info.def_id),
));
}
- err.note(&msg);
+ err.note(msg);
}
}
match &explicitly_negative[..] {
@@ -2761,7 +2795,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.def_path_str(trait_info.def_id),
item_name
);
- err.note(&msg);
+ err.note(msg);
}
trait_infos => {
let mut msg = format!(
@@ -2771,7 +2805,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for trait_info in trait_infos {
msg.push_str(&format!("\n{}", self.tcx.def_path_str(trait_info.def_id)));
}
- err.note(&msg);
+ err.note(msg);
}
}
}
@@ -2823,7 +2857,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn_args.len() == args.len() + 1 {
err.span_suggestion_verbose(
method_name.span.shrink_to_hi(),
- &format!("try calling `{}` instead", new_name.name.as_str()),
+ format!("try calling `{}` instead", new_name.name.as_str()),
"_else",
Applicability::MaybeIncorrect,
);
@@ -2845,7 +2879,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match ty.kind() {
ty::Adt(def, _) => def.did().is_local(),
ty::Foreign(did) => did.is_local(),
- ty::Dynamic(tr, ..) => tr.principal().map_or(false, |d| d.def_id().is_local()),
+ ty::Dynamic(tr, ..) => tr.principal().is_some_and(|d| d.def_id().is_local()),
ty::Param(_) => true,
// Everything else (primitive types, etc.) is effectively
@@ -2943,7 +2977,7 @@ fn print_disambiguation_help<'tcx>(
};
err.span_suggestion_verbose(
span,
- &format!(
+ format!(
"disambiguate the {} for {}",
def_kind_descr,
if let Some(candidate) = candidate {
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index a52c94cb0..b8bf2b691 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -390,7 +390,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
.is_ok()
{
- let msg = &format!(
+ let msg = format!(
"`{}{}` can be used on `{}` if you dereference the left-hand side",
op.node.as_str(),
match is_assign {
@@ -408,7 +408,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
};
- let is_compatible = |lhs_ty, rhs_ty| {
+ let is_compatible_after_call = |lhs_ty, rhs_ty| {
self.lookup_op_method(
lhs_ty,
Some((rhs_expr, rhs_ty)),
@@ -416,6 +416,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected,
)
.is_ok()
+ // Suggest calling even if, after calling, the types don't
+ // implement the operator, since it'll lead to better
+ // diagnostics later.
+ || self.can_eq(self.param_env, lhs_ty, rhs_ty)
};
// We should suggest `a + b` => `*a + b` if `a` is copy, and suggest
@@ -436,16 +440,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
suggest_deref_binop(*lhs_deref_ty);
}
} else if self.suggest_fn_call(&mut err, lhs_expr, lhs_ty, |lhs_ty| {
- is_compatible(lhs_ty, rhs_ty)
+ is_compatible_after_call(lhs_ty, rhs_ty)
}) || self.suggest_fn_call(&mut err, rhs_expr, rhs_ty, |rhs_ty| {
- is_compatible(lhs_ty, rhs_ty)
+ is_compatible_after_call(lhs_ty, rhs_ty)
}) || self.suggest_two_fn_call(
&mut err,
rhs_expr,
rhs_ty,
lhs_expr,
lhs_ty,
- |lhs_ty, rhs_ty| is_compatible(lhs_ty, rhs_ty),
+ |lhs_ty, rhs_ty| is_compatible_after_call(lhs_ty, rhs_ty),
) {
// Cool
}
@@ -511,7 +515,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
// When we know that a missing bound is responsible, we don't show
// this note as it is redundant.
- err.note(&format!(
+ err.note(format!(
"the trait `{missing_trait}` is not implemented for `{lhs_ty}`"
));
}
@@ -545,9 +549,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let to_owned_msg = "create an owned `String` from a string reference";
let string_type = self.tcx.lang_items().string();
- let is_std_string = |ty: Ty<'tcx>| {
- ty.ty_adt_def().map_or(false, |ty_def| Some(ty_def.did()) == string_type)
- };
+ let is_std_string =
+ |ty: Ty<'tcx>| ty.ty_adt_def().is_some_and(|ty_def| Some(ty_def.did()) == string_type);
match (lhs_ty.kind(), rhs_ty.kind()) {
(&Ref(_, l_ty, _), &Ref(_, r_ty, _)) // &str or &String + &str, &String or &&str
@@ -686,7 +689,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
err.span_suggestion(
ex.span,
- &format!(
+ format!(
"you may have meant the maximum value of `{actual}`",
),
format!("{actual}::MAX"),
@@ -719,7 +722,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Op::Binary(op, _) => op.span,
Op::Unary(_, span) => span,
};
- let (opname, trait_did) = lang_item_for_op(self.tcx, op, span);
+ let (opname, Some(trait_did)) = lang_item_for_op(self.tcx, op, span) else {
+ // Bail if the operator trait is not defined.
+ return Err(vec![]);
+ };
debug!(
"lookup_op_method(lhs_ty={:?}, op={:?}, opname={:?}, trait_did={:?})",
@@ -753,24 +759,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span,
traits::BinOp {
rhs_span: opt_rhs_expr.map(|expr| expr.span),
- is_lit: opt_rhs_expr
- .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
+ is_lit: opt_rhs_expr.is_some_and(|expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
output_ty: expected.only_has_type(self),
},
);
- let method = trait_did.and_then(|trait_did| {
- self.lookup_method_in_trait(cause.clone(), opname, trait_did, lhs_ty, Some(input_types))
- });
-
- match (method, trait_did) {
- (Some(ok), _) => {
+ let method = self.lookup_method_in_trait(
+ cause.clone(),
+ opname,
+ trait_did,
+ lhs_ty,
+ Some(input_types),
+ );
+ match method {
+ Some(ok) => {
let method = self.register_infer_ok_obligations(ok);
self.select_obligations_where_possible(|_| {});
Ok(method)
}
- (None, None) => Err(vec![]),
- (None, Some(trait_did)) => {
+ None => {
+ // This path may do some inference, so make sure we've really
+ // doomed compilation so as to not accidentally stabilize new
+ // inference or something here...
+ self.tcx.sess.delay_span_bug(span, "this path really should be doomed...");
+ // Guide inference for the RHS expression if it's provided --
+ // this will allow us to better error reporting, at the expense
+ // of making some error messages a bit more specific.
+ if let Some((rhs_expr, rhs_ty)) = opt_rhs
+ && rhs_ty.is_ty_var()
+ {
+ self.check_expr_coercible_to_type(rhs_expr, rhs_ty, None);
+ }
+
let (obligation, _) =
self.obligation_for_method(cause, trait_did, lhs_ty, Some(input_types));
// FIXME: This should potentially just add the obligation to the `FnCtxt`
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index af0bd26de..5af955d31 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -1,4 +1,4 @@
-use crate::{FnCtxt, RawTy};
+use crate::{errors, FnCtxt, RawTy};
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{
@@ -517,7 +517,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn endpoint_has_type(&self, err: &mut Diagnostic, span: Span, ty: Ty<'_>) {
if !ty.references_error() {
- err.span_label(span, &format!("this is of type `{}`", ty));
+ err.span_label(span, format!("this is of type `{}`", ty));
}
}
@@ -544,7 +544,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!("this is of type `{}` but it should be `char` or numeric", ty)
};
let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| {
- err.span_label(first_span, &msg(first_ty));
+ err.span_label(first_span, msg(first_ty));
if let Some((_, ty, sp)) = second {
let ty = self.resolve_vars_if_possible(ty);
self.endpoint_has_type(&mut err, sp, ty);
@@ -552,8 +552,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
match (lhs, rhs) {
(Some((true, lhs_ty, lhs_sp)), Some((true, rhs_ty, rhs_sp))) => {
- err.span_label(lhs_sp, &msg(lhs_ty));
- err.span_label(rhs_sp, &msg(rhs_ty));
+ err.span_label(lhs_sp, msg(lhs_ty));
+ err.span_label(rhs_sp, msg(rhs_ty));
}
(Some((true, lhs_ty, lhs_sp)), rhs) => one_side_err(lhs_sp, lhs_ty, rhs),
(lhs, Some((true, rhs_ty, rhs_sp))) => one_side_err(rhs_sp, rhs_ty, lhs),
@@ -651,7 +651,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
});
let pre = if in_match { "in the same arm, " } else { "" };
- err.note(&format!("{}a binding must have the same type in all alternatives", pre));
+ err.note(format!("{}a binding must have the same type in all alternatives", pre));
self.suggest_adding_missing_ref_or_removing_ref(
&mut err,
span,
@@ -958,11 +958,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) {
let pat_span = pat.span;
if let Some(span) = self.tcx.hir().res_span(pat_res) {
- e.span_label(span, &format!("{} defined here", res.descr()));
+ e.span_label(span, format!("{} defined here", res.descr()));
if let [hir::PathSegment { ident, .. }] = &*segments {
e.span_label(
pat_span,
- &format!(
+ format!(
"`{}` is interpreted as {} {}, not a new binding",
ident,
res.article(),
@@ -1158,7 +1158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
err.span_label(
last_subpat_span,
- &format!("expected {} field{}, found {}", fields.len(), fields_ending, subpats.len()),
+ format!("expected {} field{}, found {}", fields.len(), fields_ending, subpats.len()),
);
if self.tcx.sess.source_map().is_multiline(qpath.span().between(last_subpat_span)) {
err.span_label(qpath.span(), "");
@@ -1171,7 +1171,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
err.span_label(
last_field_def_span,
- &format!("{} has {} field{}", res.descr(), fields.len(), fields_ending),
+ format!("{} has {} field{}", res.descr(), fields.len(), fields_ending),
);
// Identify the case `Some(x, y)` where the expected type is e.g. `Option<(T, U)>`.
@@ -1410,12 +1410,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Report an error if an incorrect number of fields was specified.
if adt.is_union() {
if fields.len() != 1 {
- tcx.sess
- .struct_span_err(pat.span, "union patterns should have exactly one field")
- .emit();
+ tcx.sess.emit_err(errors::UnionPatMultipleFields { span: pat.span });
}
if has_rest_pat {
- tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit();
+ tcx.sess.emit_err(errors::UnionPatDotDot { span: pat.span });
}
} else if !unmentioned_fields.is_empty() {
let accessible_unmentioned_fields: Vec<_> = unmentioned_fields
@@ -1643,7 +1641,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let unmentioned_field = unmentioned_fields[0].1.name;
err.span_suggestion_short(
pat_field.ident.span,
- &format!(
+ format!(
"`{}` has a field named `{}`",
tcx.def_path_str(variant.def_id),
unmentioned_field
@@ -1659,7 +1657,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if tcx.sess.teach(&err.get_code().unwrap()) {
err.note(
"This error indicates that a struct pattern attempted to \
- extract a non-existent field from a struct. Struct fields \
+ extract a nonexistent field from a struct. Struct fields \
are identified by the name used before the colon : so struct \
patterns should resemble the declaration of the struct type \
being matched.\n\n\
@@ -1833,7 +1831,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
lint.help(
"ensure that all fields are mentioned explicitly by adding the suggested fields",
);
- lint.note(&format!(
+ lint.note(format!(
"the pattern is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found",
ty,
));
@@ -1897,7 +1895,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
err.span_suggestion(
sp,
- &format!(
+ format!(
"include the missing field{} in the pattern{}",
pluralize!(len),
if have_inaccessible_fields { " and ignore the inaccessible fields" } else { "" }
@@ -1924,7 +1922,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
err.span_suggestion(
sp,
- &format!(
+ format!(
"if you don't care about {these} missing field{s}, you can explicitly ignore {them}",
these = pluralize!("this", len),
s = pluralize!(len),
diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs
index 2cca45de5..e2b1dc007 100644
--- a/compiler/rustc_hir_typeck/src/place_op.rs
+++ b/compiler/rustc_hir_typeck/src/place_op.rs
@@ -73,16 +73,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ty = self.resolve_vars_if_possible(ty);
let mut err = self.tcx.sess.struct_span_err(
span,
- &format!("negative integers cannot be used to index on a `{ty}`"),
+ format!("negative integers cannot be used to index on a `{ty}`"),
);
- err.span_label(span, &format!("cannot use a negative integer for indexing on `{ty}`"));
+ err.span_label(span, format!("cannot use a negative integer for indexing on `{ty}`"));
if let (hir::ExprKind::Path(..), Ok(snippet)) =
(&base_expr.kind, self.tcx.sess.source_map().span_to_snippet(base_expr.span))
{
// `foo[-1]` to `foo[foo.len() - 1]`
err.span_suggestion_verbose(
span.shrink_to_lo(),
- &format!(
+ format!(
"to access an element starting from the end of the `{ty}`, compute the index",
),
format!("{snippet}.len() "),
@@ -200,9 +200,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
debug!("try_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op);
- let (imm_tr, imm_op) = match op {
+ let (Some(imm_tr), imm_op) = (match op {
PlaceOp::Deref => (self.tcx.lang_items().deref_trait(), sym::deref),
PlaceOp::Index => (self.tcx.lang_items().index_trait(), sym::index),
+ }) else {
+ // Bail if `Deref` or `Index` isn't defined.
+ return None;
};
// If the lang item was declared incorrectly, stop here so that we don't
@@ -219,15 +222,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return None;
}
- imm_tr.and_then(|trait_did| {
- self.lookup_method_in_trait(
- self.misc(span),
- Ident::with_dummy_span(imm_op),
- trait_did,
- base_ty,
- Some(arg_tys),
- )
- })
+ self.lookup_method_in_trait(
+ self.misc(span),
+ Ident::with_dummy_span(imm_op),
+ imm_tr,
+ base_ty,
+ Some(arg_tys),
+ )
}
fn try_mutable_overloaded_place_op(
@@ -239,9 +240,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
debug!("try_mutable_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op);
- let (mut_tr, mut_op) = match op {
+ let (Some(mut_tr), mut_op) = (match op {
PlaceOp::Deref => (self.tcx.lang_items().deref_mut_trait(), sym::deref_mut),
PlaceOp::Index => (self.tcx.lang_items().index_mut_trait(), sym::index_mut),
+ }) else {
+ // Bail if `DerefMut` or `IndexMut` isn't defined.
+ return None;
};
// If the lang item was declared incorrectly, stop here so that we don't
@@ -258,15 +262,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return None;
}
- mut_tr.and_then(|trait_did| {
- self.lookup_method_in_trait(
- self.misc(span),
- Ident::with_dummy_span(mut_op),
- trait_did,
- base_ty,
- Some(arg_tys),
- )
- })
+ self.lookup_method_in_trait(
+ self.misc(span),
+ Ident::with_dummy_span(mut_op),
+ mut_tr,
+ base_ty,
+ Some(arg_tys),
+ )
}
/// Convert auto-derefs, indices, etc of an expression from `Deref` and `Index`
@@ -327,7 +329,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If this is a union field, also throw an error for `DerefMut` of `ManuallyDrop` (see RFC 2514).
// This helps avoid accidental drops.
if inside_union
- && source.ty_adt_def().map_or(false, |adt| adt.is_manually_drop())
+ && source.ty_adt_def().is_some_and(|adt| adt.is_manually_drop())
{
let mut err = self.tcx.sess.struct_span_err(
expr.span,
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 41a6ad80b..9458099f5 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -223,7 +223,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(closure_def_id);
if should_do_rust_2021_incompatible_closure_captures_analysis(self.tcx, closure_hir_id) {
- self.perform_2229_migration_anaysis(closure_def_id, body_id, capture_clause, span);
+ self.perform_2229_migration_analysis(closure_def_id, body_id, capture_clause, span);
}
let after_feature_tys = self.final_upvar_tys(closure_def_id);
@@ -713,7 +713,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.sess.delay_span_bug(
closure_span,
- &format!(
+ format!(
"two identical projections: ({:?}, {:?})",
capture1.place.projections, capture2.place.projections
),
@@ -731,7 +731,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Perform the migration analysis for RFC 2229, and emit lint
/// `disjoint_capture_drop_reorder` if needed.
- fn perform_2229_migration_anaysis(
+ fn perform_2229_migration_analysis(
&self,
closure_def_id: LocalDefId,
body_id: hir::BodyId,
@@ -863,7 +863,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let indent = line2.split_once(|c: char| !c.is_whitespace()).unwrap_or_default().0;
lint.span_suggestion(
closure_body_span.with_lo(closure_body_span.lo() + BytePos::from_usize(line1.len())).shrink_to_lo(),
- &diagnostic_msg,
+ diagnostic_msg,
format!("\n{indent}{migration_string};"),
Applicability::MachineApplicable,
);
@@ -874,7 +874,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// directly after the `{`.
lint.span_suggestion(
closure_body_span.with_lo(closure_body_span.lo() + BytePos(1)).shrink_to_lo(),
- &diagnostic_msg,
+ diagnostic_msg,
format!(" {migration_string};"),
Applicability::MachineApplicable,
);
@@ -882,7 +882,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// This is a closure without braces around the body.
// We add braces to add the `let` before the body.
lint.multipart_suggestion(
- &diagnostic_msg,
+ diagnostic_msg,
vec![
(closure_body_span.shrink_to_lo(), format!("{{ {migration_string}; ")),
(closure_body_span.shrink_to_hi(), " }".to_string()),
@@ -893,7 +893,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
lint.span_suggestion(
closure_span,
- &diagnostic_msg,
+ diagnostic_msg,
migration_string,
Applicability::HasPlaceholders
);
@@ -972,15 +972,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut obligations_should_hold = Vec::new();
// Checks if a root variable implements any of the auto traits
for check_trait in auto_traits_def_id.iter() {
- obligations_should_hold.push(
- check_trait
- .map(|check_trait| {
- self.infcx
- .type_implements_trait(check_trait, [ty], self.param_env)
- .must_apply_modulo_regions()
- })
- .unwrap_or(false),
- );
+ obligations_should_hold.push(check_trait.is_some_and(|check_trait| {
+ self.infcx
+ .type_implements_trait(check_trait, [ty], self.param_env)
+ .must_apply_modulo_regions()
+ }));
}
let mut problematic_captures = FxHashMap::default();
@@ -996,15 +992,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Checks if a capture implements any of the auto traits
let mut obligations_holds_for_capture = Vec::new();
for check_trait in auto_traits_def_id.iter() {
- obligations_holds_for_capture.push(
- check_trait
- .map(|check_trait| {
- self.infcx
- .type_implements_trait(check_trait, [ty], self.param_env)
- .must_apply_modulo_regions()
- })
- .unwrap_or(false),
- );
+ obligations_holds_for_capture.push(check_trait.is_some_and(|check_trait| {
+ self.infcx
+ .type_implements_trait(check_trait, [ty], self.param_env)
+ .must_apply_modulo_regions()
+ }));
}
let mut capture_problems = FxHashSet::default();
@@ -1519,7 +1511,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let span =
capture_info.path_expr_id.map_or(closure_span, |e| self.tcx.hir().span(e));
- diag.span_note(span, &output_str);
+ diag.span_note(span, output_str);
}
diag.emit();
}
@@ -1560,13 +1552,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
multi_span.push_span_label(path_span, path_label);
multi_span.push_span_label(capture_kind_span, capture_kind_label);
- diag.span_note(multi_span, &output_str);
+ diag.span_note(multi_span, output_str);
} else {
let span = capture_info
.path_expr_id
.map_or(closure_span, |e| self.tcx.hir().span(e));
- diag.span_note(span, &output_str);
+ diag.span_note(span, output_str);
};
}
}
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index e876fa275..0f21fc1e6 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -5,11 +5,10 @@
use crate::FnCtxt;
use hir::def_id::LocalDefId;
use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::ErrorGuaranteed;
+use rustc_errors::{ErrorGuaranteed, StashKey};
use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor};
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
-use rustc_infer::infer::InferCtxt;
use rustc_middle::hir::place::Place as HirPlace;
use rustc_middle::mir::FakeReadCause;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
@@ -70,6 +69,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
wbcx.visit_user_provided_tys();
wbcx.visit_user_provided_sigs();
wbcx.visit_generator_interior_types();
+ wbcx.visit_offset_of_container_types();
wbcx.typeck_results.rvalue_scopes =
mem::take(&mut self.typeck_results.borrow_mut().rvalue_scopes);
@@ -82,10 +82,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
wbcx.typeck_results.treat_byte_string_as_slice =
mem::take(&mut self.typeck_results.borrow_mut().treat_byte_string_as_slice);
- if let Some(e) = self.tainted_by_errors() {
- wbcx.typeck_results.tainted_by_errors = Some(e);
- }
-
debug!("writeback: typeck results for {:?} are {:#?}", item_def_id, wbcx.typeck_results);
self.tcx.arena.alloc(wbcx.typeck_results)
@@ -118,12 +114,21 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
) -> WritebackCx<'cx, 'tcx> {
let owner = body.id().hir_id.owner;
- WritebackCx {
+ let mut wbcx = WritebackCx {
fcx,
typeck_results: ty::TypeckResults::new(owner),
body,
rustc_dump_user_substs,
+ };
+
+ // HACK: We specifically don't want the (opaque) error from tainting our
+ // inference context. That'll prevent us from doing opaque type inference
+ // later on in borrowck, which affects diagnostic spans pretty negatively.
+ if let Some(e) = fcx.tainted_by_errors() {
+ wbcx.typeck_results.tainted_by_errors = Some(e);
}
+
+ wbcx
}
fn tcx(&self) -> TyCtxt<'tcx> {
@@ -132,7 +137,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
fn write_ty_to_typeck_results(&mut self, hir_id: hir::HirId, ty: Ty<'tcx>) {
debug!("write_ty_to_typeck_results({:?}, {:?})", hir_id, ty);
- assert!(!ty.needs_infer() && !ty.has_placeholders() && !ty.has_free_regions());
+ assert!(!ty.has_infer() && !ty.has_placeholders() && !ty.has_free_regions());
self.typeck_results.node_types_mut().insert(hir_id, ty);
}
@@ -226,7 +231,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
// When encountering `return [0][0]` outside of a `fn` body we can encounter a base
// that isn't in the type table. We assume more relevant errors have already been
// emitted, so we delay an ICE if none have. (#64638)
- self.tcx().sess.delay_span_bug(e.span, &format!("bad base: `{:?}`", base));
+ self.tcx().sess.delay_span_bug(e.span, format!("bad base: `{:?}`", base));
}
if let Some(ty::Ref(_, base_ty, _)) = base_ty {
let index_ty = typeck_results.expr_ty_adjusted_opt(index).unwrap_or_else(|| {
@@ -236,7 +241,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
// error has been emitted. (#64638)
self.fcx.tcx.ty_error_with_message(
e.span,
- &format!("bad index {:?} for base: `{:?}`", index, base),
+ format!("bad index {:?} for base: `{:?}`", index, base),
)
});
let index_ty = self.fcx.resolve_vars_if_possible(index_ty);
@@ -295,7 +300,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
self.visit_field_id(field.hir_id);
}
}
- hir::ExprKind::Field(..) => {
+ hir::ExprKind::Field(..) | hir::ExprKind::OffsetOf(..) => {
self.visit_field_id(e.hir_id);
}
hir::ExprKind::ConstBlock(anon_const) => {
@@ -490,7 +495,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
let err = self
.tcx()
.sess
- .struct_span_err(span, &format!("user substs: {:?}", user_substs));
+ .struct_span_err(span, format!("user substs: {:?}", user_substs));
err.buffer(&mut errors_buffer);
}
}
@@ -507,7 +512,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
fcx_typeck_results.user_provided_types().items().map(|(local_id, c_ty)| {
let hir_id = hir::HirId { owner: common_hir_owner, local_id };
- if cfg!(debug_assertions) && c_ty.needs_infer() {
+ if cfg!(debug_assertions) && c_ty.has_infer() {
span_bug!(
hir_id.to_span(self.fcx.tcx),
"writeback: `{:?}` has inference variables",
@@ -526,7 +531,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
self.typeck_results.user_provided_sigs.extend(
fcx_typeck_results.user_provided_sigs.items().map(|(&def_id, c_sig)| {
- if cfg!(debug_assertions) && c_sig.needs_infer() {
+ if cfg!(debug_assertions) && c_sig.has_infer() {
span_bug!(
self.fcx.tcx.def_span(def_id),
"writeback: `{:?}` has inference variables",
@@ -578,13 +583,26 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
continue;
}
- let hidden_type = hidden_type.remap_generic_params_to_declaration_params(
- opaque_type_key,
- self.fcx.infcx.tcx,
- true,
- );
-
- self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type);
+ let hidden_type =
+ self.tcx().erase_regions(hidden_type.remap_generic_params_to_declaration_params(
+ opaque_type_key,
+ self.tcx(),
+ true,
+ ));
+
+ if let Some(last_opaque_ty) = self
+ .typeck_results
+ .concrete_opaque_types
+ .insert(opaque_type_key.def_id, hidden_type)
+ && last_opaque_ty.ty != hidden_type.ty
+ {
+ hidden_type
+ .report_mismatch(&last_opaque_ty, opaque_type_key.def_id, self.tcx())
+ .stash(
+ self.tcx().def_span(opaque_type_key.def_id),
+ StashKey::OpaqueHiddenTypeMismatch,
+ );
+ }
}
}
@@ -617,7 +635,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
if let Some(substs) = self.fcx.typeck_results.borrow().node_substs_opt(hir_id) {
let substs = self.resolve(substs, &span);
debug!("write_substs_to_tcx({:?}, {:?})", hir_id, substs);
- assert!(!substs.needs_infer() && !substs.has_placeholders());
+ assert!(!substs.has_infer() && !substs.has_placeholders());
self.typeck_results.node_substs_mut().insert(hir_id, substs);
}
}
@@ -682,13 +700,27 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
}
}
+ fn visit_offset_of_container_types(&mut self) {
+ let fcx_typeck_results = self.fcx.typeck_results.borrow();
+ assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
+ let common_hir_owner = fcx_typeck_results.hir_owner;
+
+ for (local_id, &(container, ref indices)) in
+ fcx_typeck_results.offset_of_data().items_in_stable_order()
+ {
+ let hir_id = hir::HirId { owner: common_hir_owner, local_id };
+ let container = self.resolve(container, &hir_id);
+ self.typeck_results.offset_of_data_mut().insert(hir_id, (container, indices.clone()));
+ }
+ }
+
fn resolve<T>(&mut self, x: T, span: &dyn Locatable) -> T
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
let mut resolver = Resolver::new(self.fcx, span, self.body);
let x = x.fold_with(&mut resolver);
- if cfg!(debug_assertions) && x.needs_infer() {
+ if cfg!(debug_assertions) && x.has_infer() {
span_bug!(span.to_span(self.fcx.tcx), "writeback: `{:?}` has inference variables", x);
}
@@ -722,8 +754,7 @@ impl Locatable for hir::HirId {
/// The Resolver. This is the type folding engine that detects
/// unresolved types and so forth.
struct Resolver<'cx, 'tcx> {
- tcx: TyCtxt<'tcx>,
- infcx: &'cx InferCtxt<'tcx>,
+ fcx: &'cx FnCtxt<'cx, 'tcx>,
span: &'cx dyn Locatable,
body: &'tcx hir::Body<'tcx>,
@@ -737,18 +768,18 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
span: &'cx dyn Locatable,
body: &'tcx hir::Body<'tcx>,
) -> Resolver<'cx, 'tcx> {
- Resolver { tcx: fcx.tcx, infcx: fcx, span, body, replaced_with_error: None }
+ Resolver { fcx, span, body, replaced_with_error: None }
}
fn report_error(&self, p: impl Into<ty::GenericArg<'tcx>>) -> ErrorGuaranteed {
- match self.tcx.sess.has_errors() {
+ match self.fcx.tcx.sess.has_errors() {
Some(e) => e,
None => self
- .infcx
+ .fcx
.err_ctxt()
.emit_inference_failure_err(
- self.tcx.hir().body_owner_def_id(self.body.id()),
- self.span.to_span(self.tcx),
+ self.fcx.tcx.hir().body_owner_def_id(self.body.id()),
+ self.span.to_span(self.fcx.tcx),
p.into(),
E0282,
false,
@@ -780,40 +811,46 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EraseEarlyRegions<'tcx> {
impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> {
fn interner(&self) -> TyCtxt<'tcx> {
- self.tcx
+ self.fcx.tcx
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- match self.infcx.fully_resolve(t) {
+ match self.fcx.fully_resolve(t) {
+ Ok(t) if self.fcx.tcx.trait_solver_next() => {
+ // We must normalize erasing regions here, since later lints
+ // expect that types that show up in the typeck are fully
+ // normalized.
+ self.fcx.tcx.try_normalize_erasing_regions(self.fcx.param_env, t).unwrap_or(t)
+ }
Ok(t) => {
// Do not anonymize late-bound regions
// (e.g. keep `for<'a>` named `for<'a>`).
// This allows NLL to generate error messages that
// refer to the higher-ranked lifetime names written by the user.
- EraseEarlyRegions { tcx: self.tcx }.fold_ty(t)
+ EraseEarlyRegions { tcx: self.fcx.tcx }.fold_ty(t)
}
Err(_) => {
debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t);
let e = self.report_error(t);
self.replaced_with_error = Some(e);
- self.interner().ty_error(e)
+ self.fcx.tcx.ty_error(e)
}
}
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
debug_assert!(!r.is_late_bound(), "Should not be resolving bound region.");
- self.tcx.lifetimes.re_erased
+ self.fcx.tcx.lifetimes.re_erased
}
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
- match self.infcx.fully_resolve(ct) {
- Ok(ct) => self.tcx.erase_regions(ct),
+ match self.fcx.fully_resolve(ct) {
+ Ok(ct) => self.fcx.tcx.erase_regions(ct),
Err(_) => {
debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct);
let e = self.report_error(ct);
self.replaced_with_error = Some(e);
- self.interner().const_error_with_guaranteed(ct.ty(), e)
+ self.fcx.tcx.const_error(ct.ty(), e)
}
}
}