summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_typeck
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
commit4547b622d8d29df964fa2914213088b148c498fc (patch)
tree9fc6b25f3c3add6b745be9a2400a6e96140046e9 /compiler/rustc_hir_typeck
parentReleasing progress-linux version 1.66.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-4547b622d8d29df964fa2914213088b148c498fc.tar.xz
rustc-4547b622d8d29df964fa2914213088b148c498fc.zip
Merging upstream version 1.67.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_hir_typeck')
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs160
-rw-r--r--compiler/rustc_hir_typeck/src/autoderef.rs19
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs70
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs52
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs139
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs250
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs174
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs129
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs80
-rw-r--r--compiler/rustc_hir_typeck/src/expectation.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs148
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs43
-rw-r--r--compiler/rustc_hir_typeck/src/fallback.rs28
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs249
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs86
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs66
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs149
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs63
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/mod.rs129
-rw-r--r--compiler/rustc_hir_typeck/src/inherited.rs82
-rw-r--r--compiler/rustc_hir_typeck/src/intrinsicck.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs100
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs26
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs169
-rw-r--r--compiler/rustc_hir_typeck/src/method/prelude2021.rs28
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs210
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs555
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs37
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs106
-rw-r--r--compiler/rustc_hir_typeck/src/place_op.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs24
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs52
34 files changed, 1743 insertions, 1706 deletions
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 2b15d4dcd..e25a9e903 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -1,10 +1,10 @@
use crate::coercion::{AsCoercionSite, CoerceMany};
use crate::{Diverges, Expectation, FnCtxt, Needs};
-use rustc_errors::{Applicability, MultiSpan};
+use rustc_errors::{Applicability, Diagnostic, MultiSpan};
use rustc_hir::{self as hir, ExprKind};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::traits::Obligation;
-use rustc_middle::ty::{self, ToPredicate, Ty};
+use rustc_middle::ty::{self, Ty};
use rustc_span::Span;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{
@@ -137,55 +137,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Some(&arm.body),
arm_ty,
Some(&mut |err| {
- let Some(ret) = self
- .tcx
- .hir()
- .find_by_def_id(self.body_id.owner.def_id)
- .and_then(|owner| owner.fn_decl())
- .map(|decl| decl.output.span())
- else { return; };
- let Expectation::IsLast(stmt) = orig_expected else {
- return
- };
- let can_coerce_to_return_ty = match self.ret_coercion.as_ref() {
- Some(ret_coercion) if self.in_tail_expr => {
- let ret_ty = ret_coercion.borrow().expected_ty();
- let ret_ty = self.inh.infcx.shallow_resolve(ret_ty);
- self.can_coerce(arm_ty, ret_ty)
- && prior_arm.map_or(true, |(_, t, _)| self.can_coerce(t, ret_ty))
- // The match arms need to unify for the case of `impl Trait`.
- && !matches!(ret_ty.kind(), ty::Opaque(..))
- }
- _ => false,
- };
- if !can_coerce_to_return_ty {
- return;
- }
-
- let semi_span = expr.span.shrink_to_hi().with_hi(stmt.hi());
- let mut ret_span: MultiSpan = semi_span.into();
- ret_span.push_span_label(
- expr.span,
- "this could be implicitly returned but it is a statement, not a \
- tail expression",
- );
- ret_span
- .push_span_label(ret, "the `match` arms can conform to this return type");
- ret_span.push_span_label(
- semi_span,
- "the `match` is a statement because of this semicolon, consider \
- removing it",
- );
- err.span_note(
- ret_span,
- "you might have meant to return the `match` expression",
- );
- err.tool_only_span_suggestion(
- semi_span,
- "remove this semicolon",
- "",
- Applicability::MaybeIncorrect,
- );
+ self.suggest_removing_semicolon_for_coerce(
+ err,
+ expr,
+ orig_expected,
+ arm_ty,
+ prior_arm,
+ )
}),
false,
);
@@ -219,6 +177,71 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
coercion.complete(self)
}
+ fn suggest_removing_semicolon_for_coerce(
+ &self,
+ diag: &mut Diagnostic,
+ expr: &hir::Expr<'tcx>,
+ expectation: Expectation<'tcx>,
+ arm_ty: Ty<'tcx>,
+ prior_arm: Option<(Option<hir::HirId>, Ty<'tcx>, Span)>,
+ ) {
+ let hir = self.tcx.hir();
+
+ // First, check that we're actually in the tail of a function.
+ let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Block(block, _), .. }) =
+ hir.get(self.body_id) else { return; };
+ let Some(hir::Stmt { kind: hir::StmtKind::Semi(last_expr), .. })
+ = block.innermost_block().stmts.last() else { return; };
+ if last_expr.hir_id != expr.hir_id {
+ return;
+ }
+
+ // Next, make sure that we have no type expectation.
+ let Some(ret) = hir
+ .find_by_def_id(self.body_id.owner.def_id)
+ .and_then(|owner| owner.fn_decl())
+ .map(|decl| decl.output.span()) else { return; };
+ let Expectation::IsLast(stmt) = expectation else {
+ return;
+ };
+
+ let can_coerce_to_return_ty = match self.ret_coercion.as_ref() {
+ Some(ret_coercion) => {
+ let ret_ty = ret_coercion.borrow().expected_ty();
+ let ret_ty = self.inh.infcx.shallow_resolve(ret_ty);
+ self.can_coerce(arm_ty, ret_ty)
+ && prior_arm.map_or(true, |(_, ty, _)| self.can_coerce(ty, ret_ty))
+ // The match arms need to unify for the case of `impl Trait`.
+ && !matches!(ret_ty.kind(), ty::Opaque(..))
+ }
+ _ => false,
+ };
+ if !can_coerce_to_return_ty {
+ return;
+ }
+
+ let semi_span = expr.span.shrink_to_hi().with_hi(stmt.hi());
+ let mut ret_span: MultiSpan = semi_span.into();
+ ret_span.push_span_label(
+ expr.span,
+ "this could be implicitly returned but it is a statement, not a \
+ tail expression",
+ );
+ ret_span.push_span_label(ret, "the `match` arms can conform to this return type");
+ ret_span.push_span_label(
+ semi_span,
+ "the `match` is a statement because of this semicolon, consider \
+ removing it",
+ );
+ diag.span_note(ret_span, "you might have meant to return the `match` expression");
+ diag.tool_only_span_suggestion(
+ semi_span,
+ "remove this semicolon",
+ "",
+ Applicability::MaybeIncorrect,
+ );
+ }
+
/// When the previously checked expression (the scrutinee) diverges,
/// warn the user about the match arms being unreachable.
fn warn_arms_when_scrutinee_diverges(&self, arms: &'tcx [hir::Arm<'tcx>]) {
@@ -491,11 +514,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
..
} = self.type_var_origin(expected)? else { return None; };
- let sig = *self
- .typeck_results
- .borrow()
- .liberated_fn_sigs()
- .get(hir::HirId::make_owner(self.body_id.owner.def_id))?;
+ let sig = self.body_fn_sig()?;
let substs = sig.output().walk().find_map(|arg| {
if let ty::GenericArgKind::Type(ty) = arg.unpack()
@@ -519,23 +538,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.bound_explicit_item_bounds(rpit_def_id)
.subst_iter_copied(self.tcx, substs)
{
- let pred = match pred.kind().skip_binder() {
- ty::PredicateKind::Trait(mut trait_pred) => {
+ let pred = pred.kind().rebind(match pred.kind().skip_binder() {
+ ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => {
assert_eq!(trait_pred.trait_ref.self_ty(), opaque_ty);
- trait_pred.trait_ref.substs =
- self.tcx.mk_substs_trait(ty, &trait_pred.trait_ref.substs[1..]);
- pred.kind().rebind(trait_pred).to_predicate(self.tcx)
+ ty::PredicateKind::Clause(ty::Clause::Trait(
+ trait_pred.with_self_type(self.tcx, ty),
+ ))
}
- ty::PredicateKind::Projection(mut proj_pred) => {
+ ty::PredicateKind::Clause(ty::Clause::Projection(mut proj_pred)) => {
assert_eq!(proj_pred.projection_ty.self_ty(), opaque_ty);
- proj_pred.projection_ty.substs = self
- .tcx
- .mk_substs_trait(ty, &proj_pred.projection_ty.substs[1..]);
- pred.kind().rebind(proj_pred).to_predicate(self.tcx)
+ proj_pred.projection_ty.substs = self.tcx.mk_substs_trait(
+ ty,
+ proj_pred.projection_ty.substs.iter().skip(1),
+ );
+ ty::PredicateKind::Clause(ty::Clause::Projection(proj_pred))
}
_ => continue,
- };
+ });
if !self.predicate_must_hold_modulo_regions(&Obligation::new(
+ self.tcx,
ObligationCause::misc(span, self.body_id),
self.param_env,
pred,
@@ -553,8 +574,5 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
fn arms_contain_ref_bindings<'tcx>(arms: &'tcx [hir::Arm<'tcx>]) -> Option<hir::Mutability> {
- arms.iter().filter_map(|a| a.pat.contains_explicit_ref_binding()).max_by_key(|m| match *m {
- hir::Mutability::Mut => 1,
- hir::Mutability::Not => 0,
- })
+ arms.iter().filter_map(|a| a.pat.contains_explicit_ref_binding()).max()
}
diff --git a/compiler/rustc_hir_typeck/src/autoderef.rs b/compiler/rustc_hir_typeck/src/autoderef.rs
index 59c366ad7..41b52a4c4 100644
--- a/compiler/rustc_hir_typeck/src/autoderef.rs
+++ b/compiler/rustc_hir_typeck/src/autoderef.rs
@@ -12,18 +12,7 @@ use std::iter;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> {
- Autoderef::new(self, self.param_env, self.body_id, span, base_ty, span)
- }
-
- /// Like `autoderef`, but provides a custom `Span` to use for calls to
- /// an overloaded `Deref` operator
- pub fn autoderef_overloaded_span(
- &'a self,
- span: Span,
- base_ty: Ty<'tcx>,
- overloaded_span: Span,
- ) -> Autoderef<'a, 'tcx> {
- Autoderef::new(self, self.param_env, self.body_id, span, base_ty, overloaded_span)
+ Autoderef::new(self, self.param_env, self.body_id, span, base_ty)
}
pub fn try_overloaded_deref(
@@ -55,11 +44,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|InferOk { value: method, obligations: o }| {
obligations.extend(o);
if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() {
- Some(OverloadedDeref {
- region,
- mutbl,
- span: autoderef.overloaded_span(),
- })
+ Some(OverloadedDeref { region, mutbl, span: autoderef.span() })
} else {
None
}
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 1b33f2f02..b09ddf80e 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -6,7 +6,7 @@ use crate::type_error_struct;
use rustc_ast::util::parser::PREC_POSTFIX;
use rustc_errors::{struct_span_err, Applicability, Diagnostic, StashKey};
use rustc_hir as hir;
-use rustc_hir::def::{self, Namespace, Res};
+use rustc_hir::def::{self, CtorKind, Namespace, Res};
use rustc_hir::def_id::DefId;
use rustc_infer::{
infer,
@@ -30,7 +30,7 @@ use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::error_reporting::DefIdOrName;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
-use std::iter;
+use std::{iter, slice};
/// Checks that it is legal to call methods of the trait corresponding
/// to `trait_id` (this only cares about the trait, not the specific
@@ -129,6 +129,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
output
}
+ #[instrument(level = "debug", skip(self, call_expr, callee_expr, arg_exprs, autoderef), ret)]
fn try_overloaded_call_step(
&self,
call_expr: &'tcx hir::Expr<'tcx>,
@@ -138,10 +139,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> Option<CallStep<'tcx>> {
let adjusted_ty =
self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
- debug!(
- "try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?})",
- call_expr, adjusted_ty
- );
// If the callee is a bare function or a closure, then we're all set.
match *adjusted_ty.kind() {
@@ -182,12 +179,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Hack: we know that there are traits implementing Fn for &F
// where F:Fn and so forth. In the particular case of types
- // like `x: &mut FnMut()`, if there is a call `x()`, we would
- // normally translate to `FnMut::call_mut(&mut x, ())`, but
- // that winds up requiring `mut x: &mut FnMut()`. A little
- // over the top. The simplest fix by far is to just ignore
- // this case and deref again, so we wind up with
- // `FnMut::call_mut(&mut *x, ())`.
+ // like `f: &mut FnMut()`, if there is a call `f()`, we would
+ // normally translate to `FnMut::call_mut(&mut f, ())`, but
+ // that winds up potentially requiring the user to mark their
+ // variable as `mut` which feels unnecessary and unexpected.
+ //
+ // fn foo(f: &mut impl FnMut()) { f() }
+ // ^ without this hack `f` would have to be declared as mutable
+ //
+ // The simplest fix by far is to just ignore this case and deref again,
+ // so we wind up with `FnMut::call_mut(&mut *f, ())`.
ty::Ref(..) if autoderef.step_count() == 0 => {
return None;
}
@@ -230,22 +231,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
] {
let Some(trait_def_id) = opt_trait_def_id else { continue };
- let opt_input_types = opt_arg_exprs.map(|arg_exprs| {
- [self.tcx.mk_tup(arg_exprs.iter().map(|e| {
+ let opt_input_type = opt_arg_exprs.map(|arg_exprs| {
+ self.tcx.mk_tup(arg_exprs.iter().map(|e| {
self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeInference,
span: e.span,
})
- }))]
+ }))
});
- let opt_input_types = opt_input_types.as_ref().map(AsRef::as_ref);
if let Some(ok) = self.lookup_method_in_trait(
call_expr.span,
method_name,
trait_def_id,
adjusted_ty,
- opt_input_types,
+ opt_input_type.as_ref().map(slice::from_ref),
) {
let method = self.register_infer_ok_obligations(ok);
let mut autoref = None;
@@ -261,15 +261,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return None;
};
- let mutbl = match mutbl {
- hir::Mutability::Not => AutoBorrowMutability::Not,
- hir::Mutability::Mut => AutoBorrowMutability::Mut {
- // For initial two-phase borrow
- // deployment, conservatively omit
- // overloaded function call ops.
- allow_two_phase_borrow: AllowTwoPhase::No,
- },
- };
+ // For initial two-phase borrow
+ // deployment, conservatively omit
+ // overloaded function call ops.
+ let mutbl = AutoBorrowMutability::new(*mutbl, AllowTwoPhase::No);
+
autoref = Some(Adjustment {
kind: Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)),
target: method.sig.inputs()[0],
@@ -383,6 +379,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
predicates.predicates.iter().zip(&predicates.spans)
{
let obligation = Obligation::new(
+ self.tcx,
ObligationCause::dummy_with_span(callee_expr.span),
self.param_env,
*predicate,
@@ -451,7 +448,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// previously appeared within a `Binder<>` and hence would not
// have been normalized before.
let fn_sig = self.replace_bound_vars_with_fresh_vars(call_expr.span, infer::FnCall, fn_sig);
- let fn_sig = self.normalize_associated_types_in(call_expr.span, fn_sig);
+ let fn_sig = self.normalize(call_expr.span, fn_sig);
// Call the generic checker.
let expected_arg_tys = self.expected_inputs_for_expected_output(
@@ -471,6 +468,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
def_id,
);
+ if fn_sig.abi == abi::Abi::RustCall {
+ let sp = arg_exprs.last().map_or(call_expr.span, |expr| expr.span);
+ if let Some(ty) = fn_sig.inputs().last().copied() {
+ self.register_bound(
+ ty,
+ self.tcx.require_lang_item(hir::LangItem::Tuple, Some(sp)),
+ traits::ObligationCause::new(sp, self.body_id, traits::RustCall),
+ );
+ } else {
+ self.tcx.sess.span_err(
+ sp,
+ "functions with the \"rust-call\" ABI must take a single non-self tuple argument",
+ );
+ }
+ }
+
fn_sig.output()
}
@@ -491,7 +504,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// method lookup.
let Ok(pick) = self
.probe_for_name(
- call_expr.span,
Mode::MethodCall,
segment.ident,
IsSuggestion(true),
@@ -582,7 +594,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) {
let mut unit_variant = None;
if let hir::ExprKind::Path(qpath) = &callee_expr.kind
- && let Res::Def(def::DefKind::Ctor(kind, def::CtorKind::Const), _)
+ && let Res::Def(def::DefKind::Ctor(kind, CtorKind::Const), _)
= self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id)
// Only suggest removing parens if there are no arguments
&& arg_exprs.is_empty()
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index d1dab0540..890a068a7 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -33,6 +33,7 @@ use super::FnCtxt;
use crate::type_error_struct;
use rustc_errors::{struct_span_err, Applicability, DelayDm, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
+use rustc_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::mir::Mutability;
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::cast::{CastKind, CastTy};
@@ -45,7 +46,6 @@ use rustc_span::def_id::{DefId, LOCAL_CRATE};
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
-use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
/// Reifies a cast check to be checked once we have full type information for
/// a function context.
@@ -67,7 +67,7 @@ pub struct CastCheck<'tcx> {
/// The kind of pointer and associated metadata (thin, length or vtable) - we
/// only allow casts between fat pointers if their metadata have the same
/// kind.
-#[derive(Copy, Clone, PartialEq, Eq)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, TypeVisitable, TypeFoldable)]
enum PointerKind<'tcx> {
/// No metadata attached, ie pointer to sized type or foreign type
Thin,
@@ -76,11 +76,11 @@ enum PointerKind<'tcx> {
/// Slice
Length,
/// The unsize info of this projection
- OfProjection(&'tcx ty::ProjectionTy<'tcx>),
+ OfProjection(ty::ProjectionTy<'tcx>),
/// The unsize info of this opaque ty
OfOpaque(DefId, SubstsRef<'tcx>),
/// The unsize info of this parameter
- OfParam(&'tcx ty::ParamTy),
+ OfParam(ty::ParamTy),
}
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -94,10 +94,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
debug!("pointer_kind({:?}, {:?})", t, span);
let t = self.resolve_vars_if_possible(t);
-
- if let Some(reported) = t.error_reported() {
- return Err(reported);
- }
+ t.error_reported()?;
if self.type_is_sized_modulo_regions(self.param_env, t, span) {
return Ok(Some(PointerKind::Thin));
@@ -121,9 +118,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Pointers to foreign types are thin, despite being unsized
ty::Foreign(..) => Some(PointerKind::Thin),
// We should really try to normalize here.
- ty::Projection(ref pi) => Some(PointerKind::OfProjection(pi)),
+ ty::Projection(pi) => Some(PointerKind::OfProjection(pi)),
ty::Opaque(def_id, substs) => Some(PointerKind::OfOpaque(def_id, substs)),
- ty::Param(ref p) => Some(PointerKind::OfParam(p)),
+ ty::Param(p) => Some(PointerKind::OfParam(p)),
// Insufficient type information.
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) => None,
@@ -222,8 +219,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
// inference is more completely known.
match cast_ty.kind() {
ty::Dynamic(_, _, ty::Dyn) | ty::Slice(..) => {
- let reported = check.report_cast_to_unsized_type(fcx);
- Err(reported)
+ Err(check.report_cast_to_unsized_type(fcx))
}
_ => Ok(check),
}
@@ -501,10 +497,9 @@ impl<'a, 'tcx> CastCheck<'tcx> {
let ty = fcx.tcx.erase_regions(ty);
let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
let expr_ty = fcx.tcx.erase_regions(expr_ty);
- let ty_params = fcx.tcx.mk_substs_trait(expr_ty, &[]);
if fcx
.infcx
- .type_implements_trait(from_trait, ty, ty_params, fcx.param_env)
+ .type_implements_trait(from_trait, [ty, expr_ty], fcx.param_env)
.must_apply_modulo_regions()
{
label = false;
@@ -614,10 +609,11 @@ impl<'a, 'tcx> CastCheck<'tcx> {
}
fn report_cast_to_unsized_type(&self, fcx: &FnCtxt<'a, 'tcx>) -> ErrorGuaranteed {
- if let Some(reported) =
- self.cast_ty.error_reported().or_else(|| self.expr_ty.error_reported())
- {
- return reported;
+ if let Err(err) = self.cast_ty.error_reported() {
+ return err;
+ }
+ if let Err(err) = self.expr_ty.error_reported() {
+ return err;
}
let tstr = fcx.ty_to_string(self.cast_ty);
@@ -730,9 +726,6 @@ impl<'a, 'tcx> CastCheck<'tcx> {
debug!(" -> CoercionCast");
fcx.typeck_results.borrow_mut().set_coercion_cast(self.expr.hir_id.local_id);
}
- Err(ty::error::TypeError::ObjectUnsafeCoercion(did)) => {
- self.report_object_unsafe_cast(&fcx, did);
- }
Err(_) => {
match self.do_check(fcx) {
Ok(k) => {
@@ -744,14 +737,6 @@ impl<'a, 'tcx> CastCheck<'tcx> {
};
}
}
-
- fn report_object_unsafe_cast(&self, fcx: &FnCtxt<'a, 'tcx>, did: DefId) {
- let violations = fcx.tcx.object_safety_violations(did);
- let mut err = report_object_safety_error(fcx.tcx, self.cast_span, did, violations);
- err.note(&format!("required by cast to type '{}'", fcx.ty_to_string(self.cast_ty)));
- err.emit();
- }
-
/// Checks a cast, and report an error if one exists. In some cases, this
/// can return Ok and create type errors in the fcx rather than returning
/// directly. coercion-cast is handled in check instead of here.
@@ -767,10 +752,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
match *self.expr_ty.kind() {
ty::FnDef(..) => {
// Attempt a coercion to a fn pointer type.
- let f = fcx.normalize_associated_types_in(
- self.expr_span,
- self.expr_ty.fn_sig(fcx.tcx),
- );
+ let f = fcx.normalize(self.expr_span, self.expr_ty.fn_sig(fcx.tcx));
let res = fcx.try_coerce(
self.expr,
self.expr_ty,
@@ -912,7 +894,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
}
// vtable kinds must match
- if cast_kind == expr_kind {
+ if fcx.tcx.erase_regions(cast_kind) == fcx.tcx.erase_regions(expr_kind) {
Ok(CastKind::PtrPtrCast)
} else {
Err(CastError::DifferingKinds)
@@ -954,7 +936,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
m_cast: ty::TypeAndMut<'tcx>,
) -> Result<CastKind, CastError> {
// array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const
- if m_expr.mutbl == hir::Mutability::Mut || m_cast.mutbl == hir::Mutability::Not {
+ if m_expr.mutbl >= m_cast.mutbl {
if let ty::Array(ety, _) = m_expr.ty.kind() {
// Due to the limitations of LLVM global constants,
// region pointers end up pointing at copies of
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index 7f76364e1..32f86b804 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -1,18 +1,16 @@
use crate::coercion::CoerceMany;
use crate::gather_locals::GatherLocalsVisitor;
-use crate::{FnCtxt, Inherited};
-use crate::{GeneratorTypes, UnsafetyState};
+use crate::FnCtxt;
+use crate::GeneratorTypes;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
-use rustc_hir::{ImplicitSelfKind, ItemKind, Node};
use rustc_hir_analysis::check::fn_maybe_err;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::RegionVariableOrigin;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::def_id::LocalDefId;
-use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits;
use std::cell::RefCell;
@@ -22,22 +20,16 @@ use std::cell::RefCell;
///
/// * ...
/// * inherited: other fields inherited from the enclosing fn (if any)
-#[instrument(skip(inherited, body), level = "debug")]
+#[instrument(skip(fcx, body), level = "debug")]
pub(super) fn check_fn<'a, 'tcx>(
- inherited: &'a Inherited<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
+ fcx: &mut FnCtxt<'a, 'tcx>,
fn_sig: ty::FnSig<'tcx>,
decl: &'tcx hir::FnDecl<'tcx>,
- fn_id: hir::HirId,
+ fn_def_id: LocalDefId,
body: &'tcx hir::Body<'tcx>,
can_be_generator: Option<hir::Movability>,
- return_type_pre_known: bool,
-) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
- // Create the function context. This is either derived from scratch or,
- // in the case of closures, based on the outer context.
- let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
- fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id));
- fcx.return_type_pre_known = return_type_pre_known;
+) -> Option<GeneratorTypes<'tcx>> {
+ let fn_id = fcx.tcx.hir().local_def_id_to_hir_id(fn_def_id);
let tcx = fcx.tcx;
let hir = tcx.hir();
@@ -49,11 +41,8 @@ pub(super) fn check_fn<'a, 'tcx>(
declared_ret_ty,
body.value.hir_id,
decl.output.span(),
- param_env,
+ fcx.param_env,
));
- // If we replaced declared_ret_ty with infer vars, then we must be inferring
- // an opaque type, so set a flag so we can improve diagnostics.
- fcx.return_type_has_opaque = ret_ty != declared_ret_ty;
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
@@ -61,45 +50,15 @@ pub(super) fn check_fn<'a, 'tcx>(
fn_maybe_err(tcx, span, fn_sig.abi);
- if fn_sig.abi == Abi::RustCall {
- let expected_args = if let ImplicitSelfKind::None = decl.implicit_self { 1 } else { 2 };
-
- let err = || {
- let item = match tcx.hir().get(fn_id) {
- Node::Item(hir::Item { kind: ItemKind::Fn(header, ..), .. }) => Some(header),
- Node::ImplItem(hir::ImplItem {
- kind: hir::ImplItemKind::Fn(header, ..), ..
- }) => Some(header),
- Node::TraitItem(hir::TraitItem {
- kind: hir::TraitItemKind::Fn(header, ..),
- ..
- }) => Some(header),
- // Closures are RustCall, but they tuple their arguments, so shouldn't be checked
- Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => None,
- node => bug!("Item being checked wasn't a function/closure: {:?}", node),
- };
-
- if let Some(header) = item {
- tcx.sess.span_err(header.span, "functions with the \"rust-call\" ABI must take a single non-self argument that is a tuple");
- }
- };
-
- if fn_sig.inputs().len() != expected_args {
- err()
+ if let Some(kind) = body.generator_kind && can_be_generator.is_some() {
+ let yield_ty = if kind == hir::GeneratorKind::Gen {
+ let yield_ty = fcx
+ .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
+ fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
+ yield_ty
} else {
- // FIXME(CraftSpider) Add a check on parameter expansion, so we don't just make the ICE happen later on
- // This will probably require wide-scale changes to support a TupleKind obligation
- // We can't resolve this without knowing the type of the param
- if !matches!(fn_sig.inputs()[expected_args - 1].kind(), ty::Tuple(_) | ty::Param(_)) {
- err()
- }
- }
- }
-
- if body.generator_kind.is_some() && can_be_generator.is_some() {
- let yield_ty = fcx
- .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
- fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
+ tcx.mk_unit()
+ };
// Resume type defaults to `()` if the generator has no argument.
let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit());
@@ -140,10 +99,9 @@ pub(super) fn check_fn<'a, 'tcx>(
fcx.write_ty(param.hir_id, param_ty);
}
- inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
+ fcx.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
- fcx.in_tail_expr = true;
- if let ty::Dynamic(..) = declared_ret_ty.kind() {
+ 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
@@ -161,7 +119,6 @@ pub(super) fn check_fn<'a, 'tcx>(
fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
fcx.check_return_expr(&body.value, false);
}
- fcx.in_tail_expr = 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.
@@ -211,14 +168,7 @@ pub(super) fn check_fn<'a, 'tcx>(
check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
}
- // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
- if let Some(alloc_error_handler_did) = tcx.lang_items().oom()
- && alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id()
- {
- check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty);
- }
-
- (fcx, gen_ty)
+ gen_ty
}
fn check_panic_info_fn(
@@ -246,7 +196,7 @@ fn check_panic_info_fn(
let arg_is_panic_info = match *inputs[0].kind() {
ty::Ref(region, ty, mutbl) => match *ty.kind() {
ty::Adt(ref adt, _) => {
- adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static()
+ adt.did() == panic_info_did && mutbl.is_not() && !region.is_static()
}
_ => false,
},
@@ -273,52 +223,3 @@ fn check_panic_info_fn(
tcx.sess.span_err(span, "should have no const parameters");
}
}
-
-fn check_alloc_error_fn(
- tcx: TyCtxt<'_>,
- fn_id: LocalDefId,
- fn_sig: ty::FnSig<'_>,
- decl: &hir::FnDecl<'_>,
- declared_ret_ty: Ty<'_>,
-) {
- let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else {
- tcx.sess.err("language item required, but not found: `alloc_layout`");
- return;
- };
-
- if *declared_ret_ty.kind() != ty::Never {
- tcx.sess.span_err(decl.output.span(), "return type should be `!`");
- }
-
- let inputs = fn_sig.inputs();
- if inputs.len() != 1 {
- tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
- return;
- }
-
- let arg_is_alloc_layout = match inputs[0].kind() {
- ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
- _ => false,
- };
-
- if !arg_is_alloc_layout {
- tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
- }
-
- let DefKind::Fn = tcx.def_kind(fn_id) else {
- let span = tcx.def_span(fn_id);
- tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function");
- return;
- };
-
- let generic_counts = tcx.generics_of(fn_id).own_counts();
- if generic_counts.types != 0 {
- let span = tcx.def_span(fn_id);
- tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters");
- }
- if generic_counts.consts != 0 {
- let span = tcx.def_span(fn_id);
- tcx.sess
- .span_err(span, "`#[alloc_error_handler]` function should have no const parameters");
- }
-}
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index a5a45f75e..429cb60ba 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -4,24 +4,26 @@ use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
use hir::def::DefKind;
use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::LocalDefId;
use rustc_hir::lang_items::LangItem;
use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_infer::infer::{InferOk, InferResult};
+use rustc_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{self, Ty};
use rustc_span::source_map::Span;
use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::traits;
use rustc_trait_selection::traits::error_reporting::ArgKind;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use std::cmp;
use std::iter;
/// What signature do we *expect* the closure to have from context?
-#[derive(Debug)]
+#[derive(Debug, Clone, TypeFoldable, TypeVisitable)]
struct ExpectedSig<'tcx> {
/// Span that gave us this expectation, if we know that.
cause_span: Option<Span>,
@@ -33,24 +35,20 @@ struct ClosureSignatures<'tcx> {
bound_sig: ty::PolyFnSig<'tcx>,
/// The signature within the function body.
/// This mostly differs in the sense that lifetimes are now early bound and any
- /// opaque types from the signature expectation are overriden in case there are
+ /// opaque types from the signature expectation are overridden in case there are
/// explicit hidden types written by the user in the closure signature.
liberated_sig: ty::FnSig<'tcx>,
}
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
- #[instrument(skip(self, expr, _capture, decl, body_id), level = "debug")]
+ #[instrument(skip(self, closure), level = "debug")]
pub fn check_expr_closure(
&self,
- expr: &hir::Expr<'_>,
- _capture: hir::CaptureBy,
- decl: &'tcx hir::FnDecl<'tcx>,
- body_id: hir::BodyId,
- gen: Option<hir::Movability>,
+ closure: &hir::Closure<'tcx>,
+ expr_span: Span,
expected: Expectation<'tcx>,
) -> Ty<'tcx> {
- trace!("decl = {:#?}", decl);
- trace!("expr = {:#?}", expr);
+ trace!("decl = {:#?}", closure.fn_decl);
// It's always helpful for inference if we know the kind of
// closure sooner rather than later, so first examine the expected
@@ -59,42 +57,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Some(ty) => self.deduce_expectations_from_expected_type(ty),
None => (None, None),
};
- let body = self.tcx.hir().body(body_id);
- self.check_closure(expr, expected_kind, decl, body, gen, expected_sig)
+ let body = self.tcx.hir().body(closure.body);
+ self.check_closure(closure, expr_span, expected_kind, body, expected_sig)
}
- #[instrument(skip(self, expr, body, decl), level = "debug", ret)]
+ #[instrument(skip(self, closure, body), level = "debug", ret)]
fn check_closure(
&self,
- expr: &hir::Expr<'_>,
+ closure: &hir::Closure<'tcx>,
+ expr_span: Span,
opt_kind: Option<ty::ClosureKind>,
- decl: &'tcx hir::FnDecl<'tcx>,
body: &'tcx hir::Body<'tcx>,
- gen: Option<hir::Movability>,
expected_sig: Option<ExpectedSig<'tcx>>,
) -> Ty<'tcx> {
- trace!("decl = {:#?}", decl);
- let expr_def_id = self.tcx.hir().local_def_id(expr.hir_id);
+ trace!("decl = {:#?}", closure.fn_decl);
+ let expr_def_id = closure.def_id;
debug!(?expr_def_id);
let ClosureSignatures { bound_sig, liberated_sig } =
- self.sig_of_closure(expr.hir_id, expr_def_id.to_def_id(), decl, body, expected_sig);
+ self.sig_of_closure(expr_def_id, closure.fn_decl, body, expected_sig);
debug!(?bound_sig, ?liberated_sig);
- let return_type_pre_known = !liberated_sig.output().is_ty_infer();
-
+ let mut fcx = FnCtxt::new(self, self.param_env.without_const(), body.value.hir_id);
let generator_types = check_fn(
- self,
- self.param_env.without_const(),
+ &mut fcx,
liberated_sig,
- decl,
- expr.hir_id,
+ closure.fn_decl,
+ expr_def_id,
body,
- gen,
- return_type_pre_known,
- )
- .1;
+ closure.movability,
+ );
let parent_substs = InternalSubsts::identity_for_item(
self.tcx,
@@ -103,7 +96,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let tupled_upvars_ty = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::ClosureSynthetic,
- span: self.tcx.hir().span(expr.hir_id),
+ span: self.tcx.def_span(expr_def_id),
});
if let Some(GeneratorTypes { resume_ty, yield_ty, interior, movability }) = generator_types
@@ -149,7 +142,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
None => self.next_ty_var(TypeVariableOrigin {
// FIXME(eddyb) distinguish closure kind inference variables from the rest.
kind: TypeVariableOriginKind::ClosureSynthetic,
- span: expr.span,
+ span: expr_span,
}),
};
@@ -174,34 +167,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected_ty: Ty<'tcx>,
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
match *expected_ty.kind() {
- ty::Opaque(def_id, substs) => {
- let bounds = self.tcx.bound_explicit_item_bounds(def_id);
- let sig =
- bounds.subst_iter_copied(self.tcx, substs).find_map(|(pred, span)| match pred
- .kind()
- .skip_binder()
- {
- ty::PredicateKind::Projection(proj_predicate) => self
- .deduce_sig_from_projection(
- Some(span),
- pred.kind().rebind(proj_predicate),
- ),
- _ => None,
- });
-
- let kind = bounds
- .0
- .iter()
- .filter_map(|(pred, _)| match pred.kind().skip_binder() {
- ty::PredicateKind::Trait(tp) => {
- self.tcx.fn_trait_kind_from_lang_item(tp.def_id())
- }
- _ => None,
- })
- .fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));
- trace!(?sig, ?kind);
- (sig, kind)
- }
+ ty::Opaque(def_id, substs) => self.deduce_signature_from_predicates(
+ self.tcx.bound_explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs),
+ ),
ty::Dynamic(ref object_type, ..) => {
let sig = object_type.projection_bounds().find_map(|pb| {
let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self);
@@ -209,10 +177,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
});
let kind = object_type
.principal_def_id()
- .and_then(|did| self.tcx.fn_trait_kind_from_lang_item(did));
+ .and_then(|did| self.tcx.fn_trait_kind_from_def_id(did));
(sig, kind)
}
- ty::Infer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid),
+ ty::Infer(ty::TyVar(vid)) => self.deduce_signature_from_predicates(
+ self.obligations_for_self_ty(vid).map(|obl| (obl.predicate, obl.cause.span)),
+ ),
ty::FnPtr(sig) => {
let expected_sig = ExpectedSig { cause_span: None, sig };
(Some(expected_sig), Some(ty::ClosureKind::Fn))
@@ -221,37 +191,57 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- fn deduce_expectations_from_obligations(
+ fn deduce_signature_from_predicates(
&self,
- expected_vid: ty::TyVid,
+ predicates: impl DoubleEndedIterator<Item = (ty::Predicate<'tcx>, Span)>,
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
- let expected_sig =
- self.obligations_for_self_ty(expected_vid).find_map(|(_, obligation)| {
- debug!(?obligation.predicate);
-
- let bound_predicate = obligation.predicate.kind();
- if let ty::PredicateKind::Projection(proj_predicate) =
- obligation.predicate.kind().skip_binder()
- {
- // Given a Projection predicate, we can potentially infer
- // the complete signature.
+ let mut expected_sig = None;
+ let mut expected_kind = None;
+
+ for obligation in traits::elaborate_predicates_with_span(
+ self.tcx,
+ // Reverse the obligations here, since `elaborate_*` uses a stack,
+ // and we want to keep inference generally in the same order of
+ // the registered obligations.
+ predicates.rev(),
+ ) {
+ debug!(?obligation.predicate);
+ let bound_predicate = obligation.predicate.kind();
+
+ // Given a Projection predicate, we can potentially infer
+ // the complete signature.
+ if expected_sig.is_none()
+ && let ty::PredicateKind::Clause(ty::Clause::Projection(proj_predicate)) = bound_predicate.skip_binder()
+ {
+ expected_sig = self.normalize(
+ obligation.cause.span,
self.deduce_sig_from_projection(
- Some(obligation.cause.span),
+ Some(obligation.cause.span),
bound_predicate.rebind(proj_predicate),
- )
- } else {
- None
- }
- });
+ ),
+ );
+ }
- // Even if we can't infer the full signature, we may be able to
- // infer the kind. This can occur when we elaborate a predicate
- // like `F : Fn<A>`. Note that due to subtyping we could encounter
- // many viable options, so pick the most restrictive.
- let expected_kind = self
- .obligations_for_self_ty(expected_vid)
- .filter_map(|(tr, _)| self.tcx.fn_trait_kind_from_lang_item(tr.def_id()))
- .fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));
+ // Even if we can't infer the full signature, we may be able to
+ // infer the kind. This can occur when we elaborate a predicate
+ // like `F : Fn<A>`. Note that due to subtyping we could encounter
+ // many viable options, so pick the most restrictive.
+ let trait_def_id = match bound_predicate.skip_binder() {
+ ty::PredicateKind::Clause(ty::Clause::Projection(data)) => {
+ Some(data.projection_ty.trait_def_id(self.tcx))
+ }
+ ty::PredicateKind::Clause(ty::Clause::Trait(data)) => Some(data.def_id()),
+ _ => None,
+ };
+ if let Some(closure_kind) =
+ trait_def_id.and_then(|def_id| self.tcx.fn_trait_kind_from_def_id(def_id))
+ {
+ expected_kind = Some(
+ expected_kind
+ .map_or_else(|| closure_kind, |current| cmp::min(current, closure_kind)),
+ );
+ }
+ }
(expected_sig, expected_kind)
}
@@ -272,7 +262,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let trait_def_id = projection.trait_def_id(tcx);
- let is_fn = tcx.fn_trait_kind_from_lang_item(trait_def_id).is_some();
+ let is_fn = tcx.is_fn_trait(trait_def_id);
let gen_trait = tcx.require_lang_item(LangItem::Generator, cause_span);
let is_gen = gen_trait == trait_def_id;
if !is_fn && !is_gen {
@@ -323,30 +313,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn sig_of_closure(
&self,
- hir_id: hir::HirId,
- expr_def_id: DefId,
+ expr_def_id: LocalDefId,
decl: &hir::FnDecl<'_>,
body: &hir::Body<'_>,
expected_sig: Option<ExpectedSig<'tcx>>,
) -> ClosureSignatures<'tcx> {
if let Some(e) = expected_sig {
- self.sig_of_closure_with_expectation(hir_id, expr_def_id, decl, body, e)
+ self.sig_of_closure_with_expectation(expr_def_id, decl, body, e)
} else {
- self.sig_of_closure_no_expectation(hir_id, expr_def_id, decl, body)
+ self.sig_of_closure_no_expectation(expr_def_id, decl, body)
}
}
/// If there is no expected signature, then we will convert the
/// types that the user gave into a signature.
- #[instrument(skip(self, hir_id, expr_def_id, decl, body), level = "debug")]
+ #[instrument(skip(self, expr_def_id, decl, body), level = "debug")]
fn sig_of_closure_no_expectation(
&self,
- hir_id: hir::HirId,
- expr_def_id: DefId,
+ expr_def_id: LocalDefId,
decl: &hir::FnDecl<'_>,
body: &hir::Body<'_>,
) -> ClosureSignatures<'tcx> {
- let bound_sig = self.supplied_sig_of_closure(hir_id, expr_def_id, decl, body);
+ let bound_sig = self.supplied_sig_of_closure(expr_def_id, decl, body);
self.closure_sigs(expr_def_id, body, bound_sig)
}
@@ -392,17 +380,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
///
/// # Arguments
///
- /// - `expr_def_id`: the `DefId` of the closure expression
+ /// - `expr_def_id`: the `LocalDefId` of the closure expression
/// - `decl`: the HIR declaration of the closure
/// - `body`: the body of the closure
/// - `expected_sig`: the expected signature (if any). Note that
/// this is missing a binder: that is, there may be late-bound
/// regions with depth 1, which are bound then by the closure.
- #[instrument(skip(self, hir_id, expr_def_id, decl, body), level = "debug")]
+ #[instrument(skip(self, expr_def_id, decl, body), level = "debug")]
fn sig_of_closure_with_expectation(
&self,
- hir_id: hir::HirId,
- expr_def_id: DefId,
+ expr_def_id: LocalDefId,
decl: &hir::FnDecl<'_>,
body: &hir::Body<'_>,
expected_sig: ExpectedSig<'tcx>,
@@ -411,7 +398,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// expectation if things don't see to match up with what we
// expect.
if expected_sig.sig.c_variadic() != decl.c_variadic {
- return self.sig_of_closure_no_expectation(hir_id, expr_def_id, decl, body);
+ return self.sig_of_closure_no_expectation(expr_def_id, decl, body);
} else if expected_sig.sig.skip_binder().inputs_and_output.len() != decl.inputs.len() + 1 {
return self.sig_of_closure_with_mismatched_number_of_arguments(
expr_def_id,
@@ -447,27 +434,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Along the way, it also writes out entries for types that the user
// wrote into our typeck results, which are then later used by the privacy
// check.
- match self.merge_supplied_sig_with_expectation(
- hir_id,
- expr_def_id,
- decl,
- body,
- closure_sigs,
- ) {
+ match self.merge_supplied_sig_with_expectation(expr_def_id, decl, body, closure_sigs) {
Ok(infer_ok) => self.register_infer_ok_obligations(infer_ok),
- Err(_) => self.sig_of_closure_no_expectation(hir_id, expr_def_id, decl, body),
+ Err(_) => self.sig_of_closure_no_expectation(expr_def_id, decl, body),
}
}
fn sig_of_closure_with_mismatched_number_of_arguments(
&self,
- expr_def_id: DefId,
+ expr_def_id: LocalDefId,
decl: &hir::FnDecl<'_>,
body: &hir::Body<'_>,
expected_sig: ExpectedSig<'tcx>,
) -> ClosureSignatures<'tcx> {
let hir = self.tcx.hir();
- let expr_map_node = hir.get_if_local(expr_def_id).unwrap();
+ let expr_map_node = hir.get_by_def_id(expr_def_id);
let expected_args: Vec<_> = expected_sig
.sig
.skip_binder()
@@ -475,18 +456,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.iter()
.map(|ty| ArgKind::from_expected_ty(*ty, None))
.collect();
- let (closure_span, found_args) = match self.get_fn_like_arguments(expr_map_node) {
- Some((sp, args)) => (Some(sp), args),
- None => (None, Vec::new()),
- };
+ let (closure_span, closure_arg_span, found_args) =
+ match self.get_fn_like_arguments(expr_map_node) {
+ Some((sp, arg_sp, args)) => (Some(sp), arg_sp, args),
+ None => (None, None, Vec::new()),
+ };
let expected_span =
- expected_sig.cause_span.unwrap_or_else(|| hir.span_if_local(expr_def_id).unwrap());
+ expected_sig.cause_span.unwrap_or_else(|| self.tcx.def_span(expr_def_id));
self.report_arg_count_mismatch(
expected_span,
closure_span,
expected_args,
found_args,
true,
+ closure_arg_span,
)
.emit();
@@ -498,11 +481,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Enforce the user's types against the expectation. See
/// `sig_of_closure_with_expectation` for details on the overall
/// strategy.
- #[instrument(level = "debug", skip(self, hir_id, expr_def_id, decl, body, expected_sigs))]
+ #[instrument(level = "debug", skip(self, expr_def_id, decl, body, expected_sigs))]
fn merge_supplied_sig_with_expectation(
&self,
- hir_id: hir::HirId,
- expr_def_id: DefId,
+ expr_def_id: LocalDefId,
decl: &hir::FnDecl<'_>,
body: &hir::Body<'_>,
mut expected_sigs: ClosureSignatures<'tcx>,
@@ -511,7 +493,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
//
// (See comment on `sig_of_closure_with_expectation` for the
// meaning of these letters.)
- let supplied_sig = self.supplied_sig_of_closure(hir_id, expr_def_id, decl, body);
+ let supplied_sig = self.supplied_sig_of_closure(expr_def_id, decl, body);
debug!(?supplied_sig);
@@ -591,8 +573,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
#[instrument(skip(self, decl, body), level = "debug", ret)]
fn supplied_sig_of_closure(
&self,
- hir_id: hir::HirId,
- expr_def_id: DefId,
+ expr_def_id: LocalDefId,
decl: &hir::FnDecl<'_>,
body: &hir::Body<'_>,
) -> ty::PolyFnSig<'tcx> {
@@ -601,6 +582,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
trace!("decl = {:#?}", decl);
debug!(?body.generator_kind);
+ let hir_id = self.tcx.hir().local_def_id_to_hir_id(expr_def_id);
let bound_vars = self.tcx.late_bound_vars(hir_id);
// First, convert the types that the user supplied (if any).
@@ -642,7 +624,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
// Astconv can't normalize inputs or outputs with escaping bound vars,
// so normalize them here, after we've wrapped them in a binder.
- let result = self.normalize_associated_types_in(self.tcx.hir().span(hir_id), result);
+ let result = self.normalize(self.tcx.hir().span(hir_id), result);
let c_result = self.inh.infcx.canonicalize_response(result);
self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result);
@@ -659,7 +641,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
#[instrument(skip(self), level = "debug", ret)]
fn deduce_future_output_from_obligations(
&self,
- expr_def_id: DefId,
+ expr_def_id: LocalDefId,
body_id: hir::HirId,
) -> Option<Ty<'tcx>> {
let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| {
@@ -677,7 +659,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// where R is the return type we are expecting. This type `T`
// will be our output.
let bound_predicate = predicate.kind();
- if let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder() {
+ if let ty::PredicateKind::Clause(ty::Clause::Projection(proj_predicate)) =
+ bound_predicate.skip_binder()
+ {
self.deduce_future_output_from_projection(
span,
bound_predicate.rebind(proj_predicate),
@@ -689,7 +673,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let output_ty = match *ret_ty.kind() {
ty::Infer(ty::TyVar(ret_vid)) => {
- self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| {
+ self.obligations_for_self_ty(ret_vid).find_map(|obligation| {
get_future_output(obligation.predicate, obligation.cause.span)
})?
}
@@ -808,17 +792,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn closure_sigs(
&self,
- expr_def_id: DefId,
+ expr_def_id: LocalDefId,
body: &hir::Body<'_>,
bound_sig: ty::PolyFnSig<'tcx>,
) -> ClosureSignatures<'tcx> {
- let liberated_sig = self.tcx().liberate_late_bound_regions(expr_def_id, bound_sig);
- let liberated_sig = self.inh.normalize_associated_types_in(
- body.value.span,
- body.value.hir_id,
- self.param_env,
- liberated_sig,
- );
+ let liberated_sig =
+ self.tcx().liberate_late_bound_regions(expr_def_id.to_def_id(), bound_sig);
+ let liberated_sig = self.normalize(body.value.span, liberated_sig);
ClosureSignatures { bound_sig, liberated_sig }
}
}
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 86597a703..f0b349f0c 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -46,7 +46,7 @@ use rustc_hir::Expr;
use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{Coercion, InferOk, InferResult};
-use rustc_infer::traits::{Obligation, TraitEngine, TraitEngineExt};
+use rustc_infer::traits::Obligation;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
@@ -55,14 +55,16 @@ use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::relate::RelateResult;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::visit::TypeVisitable;
-use rustc_middle::ty::{self, ToPredicate, Ty, TypeAndMut};
+use rustc_middle::ty::{self, Ty, TypeAndMut};
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
use rustc_span::{self, BytePos, DesugaringKind, Span};
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
-use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
+use rustc_trait_selection::traits::{
+ self, NormalizeExt, ObligationCause, ObligationCauseCode, ObligationCtxt,
+};
use smallvec::{smallvec, SmallVec};
use std::ops::Deref;
@@ -108,11 +110,7 @@ fn coerce_mutbls<'tcx>(
from_mutbl: hir::Mutability,
to_mutbl: hir::Mutability,
) -> RelateResult<'tcx, ()> {
- match (from_mutbl, to_mutbl) {
- (hir::Mutability::Mut, hir::Mutability::Mut | hir::Mutability::Not)
- | (hir::Mutability::Not, hir::Mutability::Not) => Ok(()),
- (hir::Mutability::Not, hir::Mutability::Mut) => Err(TypeError::Mutability),
- }
+ if from_mutbl >= to_mutbl { Ok(()) } else { Err(TypeError::Mutability) }
}
/// Do not require any adjustments, i.e. coerce `x -> x`.
@@ -199,10 +197,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
debug!("coerce: unsize successful");
return unsize;
}
- Err(TypeError::ObjectUnsafeCoercion(did)) => {
- debug!("coerce: unsize not object safe");
- return Err(TypeError::ObjectUnsafeCoercion(did));
- }
Err(error) => {
debug!(?error, "coerce: unsize failed");
}
@@ -277,13 +271,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
for &source_ty in &[a, b] {
if source_ty != target_ty {
obligations.push(Obligation::new(
+ self.tcx(),
self.cause.clone(),
self.param_env,
ty::Binder::dummy(ty::PredicateKind::Coerce(ty::CoercePredicate {
a: source_ty,
b: target_ty,
- }))
- .to_predicate(self.tcx()),
+ })),
));
}
}
@@ -456,7 +450,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
return Err(err);
};
- if ty == a && mt_a.mutbl == hir::Mutability::Not && autoderef.step_count() == 1 {
+ if ty == a && mt_a.mutbl.is_not() && autoderef.step_count() == 1 {
// As a special case, if we would produce `&'a *x`, that's
// a total no-op. We end up with the type `&'a T` just as
// we started with. In that case, just skip it
@@ -468,7 +462,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// `self.x` both have `&mut `type would be a move of
// `self.x`, but we auto-coerce it to `foo(&mut *self.x)`,
// which is a borrow.
- assert_eq!(mutbl_b, hir::Mutability::Not); // can only coerce &T -> &U
+ assert!(mutbl_b.is_not()); // can only coerce &T -> &U
return success(vec![], ty, obligations);
}
@@ -482,12 +476,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
let ty::Ref(r_borrow, _, _) = ty.kind() else {
span_bug!(span, "expected a ref type, got {:?}", ty);
};
- let mutbl = match mutbl_b {
- hir::Mutability::Not => AutoBorrowMutability::Not,
- hir::Mutability::Mut => {
- AutoBorrowMutability::Mut { allow_two_phase_borrow: self.allow_two_phase }
- }
- };
+ let mutbl = AutoBorrowMutability::new(mutbl_b, self.allow_two_phase);
adjustments.push(Adjustment {
kind: Adjust::Borrow(AutoBorrow::Ref(*r_borrow, mutbl)),
target: ty,
@@ -507,27 +496,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
target = self.shallow_resolve(target);
debug!(?source, ?target);
- // These 'if' statements require some explanation.
- // The `CoerceUnsized` trait is special - it is only
- // possible to write `impl CoerceUnsized<B> for A` where
- // A and B have 'matching' fields. This rules out the following
- // two types of blanket impls:
- //
- // `impl<T> CoerceUnsized<T> for SomeType`
- // `impl<T> CoerceUnsized<SomeType> for T`
- //
- // Both of these trigger a special `CoerceUnsized`-related error (E0376)
- //
- // We can take advantage of this fact to avoid performing unnecessary work.
- // If either `source` or `target` is a type variable, then any applicable impl
- // would need to be generic over the self-type (`impl<T> CoerceUnsized<SomeType> for T`)
- // or generic over the `CoerceUnsized` type parameter (`impl<T> CoerceUnsized<T> for
- // SomeType`).
- //
- // However, these are exactly the kinds of impls which are forbidden by
- // the compiler! Therefore, we can be sure that coercion will always fail
- // when either the source or target type is a type variable. This allows us
- // to skip performing any trait selection, and immediately bail out.
+ // We don't apply any coercions incase either the source or target
+ // aren't sufficiently well known but tend to instead just equate
+ // them both.
if source.is_ty_var() {
debug!("coerce_unsized: source is a TyVar, bailing out");
return Err(TypeError::Mismatch);
@@ -556,15 +527,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
let coercion = Coercion(self.cause.span);
let r_borrow = self.next_region_var(coercion);
- let mutbl = match mutbl_b {
- hir::Mutability::Not => AutoBorrowMutability::Not,
- hir::Mutability::Mut => AutoBorrowMutability::Mut {
- // We don't allow two-phase borrows here, at least for initial
- // implementation. If it happens that this coercion is a function argument,
- // the reborrow in coerce_borrowed_ptr will pick it up.
- allow_two_phase_borrow: AllowTwoPhase::No,
- },
- };
+
+ // We don't allow two-phase borrows here, at least for initial
+ // implementation. If it happens that this coercion is a function argument,
+ // the reborrow in coerce_borrowed_ptr will pick it up.
+ let mutbl = AutoBorrowMutability::new(mutbl_b, AllowTwoPhase::No);
+
Some((
Adjustment { kind: Adjust::Deref(None), target: ty_a },
Adjustment {
@@ -588,7 +556,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
}
_ => None,
};
- let coerce_source = reborrow.as_ref().map_or(source, |&(_, ref r)| r.target);
+ let coerce_source = reborrow.as_ref().map_or(source, |(_, r)| r.target);
// Setup either a subtyping or a LUB relationship between
// the `CoerceUnsized` target type and the expected type.
@@ -629,8 +597,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
cause,
coerce_unsized_did,
0,
- coerce_source,
- &[coerce_target.into()]
+ [coerce_source, coerce_target]
)];
let mut has_unsized_tuple_coercion = false;
@@ -645,7 +612,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
debug!("coerce_unsized resolve step: {:?}", obligation);
let bound_predicate = obligation.predicate.kind();
let trait_pred = match bound_predicate.skip_binder() {
- ty::PredicateKind::Trait(trait_pred) if traits.contains(&trait_pred.def_id()) => {
+ ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred))
+ if traits.contains(&trait_pred.def_id()) =>
+ {
if unsize_did == trait_pred.def_id() {
let self_ty = trait_pred.self_ty();
let unsize_ty = trait_pred.trait_ref.substs[1].expect_ty();
@@ -668,7 +637,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
continue;
}
};
- match selcx.select(&obligation.with(trait_pred)) {
+ match selcx.select(&obligation.with(selcx.tcx(), trait_pred)) {
// Uncertain or unimplemented.
Ok(None) => {
if trait_pred.def_id() == unsize_did {
@@ -705,12 +674,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// Object safety violations or miscellaneous.
Err(err) => {
- self.err_ctxt().report_selection_error(
- obligation.clone(),
- &obligation,
- &err,
- false,
- );
+ self.err_ctxt().report_selection_error(obligation.clone(), &obligation, &err);
// Treat this like an obligation and follow through
// with the unsizing - the lack of a coercion should
// be silent, as it causes a type mismatch later.
@@ -752,7 +716,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
&self,
a: Ty<'tcx>,
b: Ty<'tcx>,
- predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
+ predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
b_region: ty::Region<'tcx>,
) -> CoerceResult<'tcx> {
if !self.tcx.features().dyn_star {
@@ -761,25 +725,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
if let ty::Dynamic(a_data, _, _) = a.kind()
&& let ty::Dynamic(b_data, _, _) = b.kind()
+ && a_data.principal_def_id() == b_data.principal_def_id()
{
- if a_data.principal_def_id() == b_data.principal_def_id() {
- return self.unify_and(a, b, |_| vec![]);
- } else if !self.tcx().features().trait_upcasting {
- let mut err = feature_err(
- &self.tcx.sess.parse_sess,
- sym::trait_upcasting,
- self.cause.span,
- &format!(
- "cannot cast `{a}` to `{b}`, trait upcasting coercion is experimental"
- ),
- );
- err.emit();
- }
+ return self.unify_and(a, b, |_| vec![]);
}
// Check the obligations of the cast -- for example, when casting
// `usize` to `dyn* Clone + 'static`:
- let obligations = predicates
+ let mut obligations: Vec<_> = predicates
.iter()
.map(|predicate| {
// For each existential predicate (e.g., `?Self: Clone`) substitute
@@ -787,18 +740,31 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// and then require that the resulting predicate (e.g., `usize: Clone`)
// holds (it does).
let predicate = predicate.with_self_ty(self.tcx, a);
- Obligation::new(self.cause.clone(), self.param_env, predicate)
+ Obligation::new(self.tcx, self.cause.clone(), self.param_env, predicate)
})
- // Enforce the region bound (e.g., `usize: 'static`, in our example).
- .chain([Obligation::new(
- self.cause.clone(),
- self.param_env,
- self.tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::TypeOutlives(
- ty::OutlivesPredicate(a, b_region),
- ))),
- )])
+ .chain([
+ // Enforce the region bound (e.g., `usize: 'static`, in our example).
+ Obligation::new(
+ self.tcx,
+ self.cause.clone(),
+ self.param_env,
+ ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::TypeOutlives(
+ ty::OutlivesPredicate(a, b_region),
+ ))),
+ ),
+ ])
.collect();
+ // Enforce that the type is `usize`/pointer-sized.
+ obligations.push(Obligation::new(
+ self.tcx,
+ self.cause.clone(),
+ self.param_env,
+ ty::Binder::dummy(
+ self.tcx.at(self.cause.span).mk_trait_ref(hir::LangItem::PointerSized, [a]),
+ ),
+ ));
+
Ok(InferOk {
value: (vec![Adjustment { kind: Adjust::DynStar, target: b }], b),
obligations,
@@ -868,7 +834,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
let b = self.shallow_resolve(b);
let InferOk { value: b, mut obligations } =
- self.normalize_associated_types_in_as_infer_ok(self.cause.span, b);
+ self.at(&self.cause, self.param_env).normalize(b);
debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b);
match b.kind() {
@@ -890,7 +856,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
}
let InferOk { value: a_sig, obligations: o1 } =
- self.normalize_associated_types_in_as_infer_ok(self.cause.span, a_sig);
+ self.at(&self.cause, self.param_env).normalize(a_sig);
obligations.extend(o1);
let a_fn_pointer = self.tcx.mk_fn_ptr(a_sig);
@@ -1043,9 +1009,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let Ok(ok) = coerce.coerce(source, target) else {
return false;
};
- let mut fcx = traits::FulfillmentContext::new_in_snapshot();
- fcx.register_predicate_obligations(self, ok.obligations);
- fcx.select_where_possible(&self).is_empty()
+ let ocx = ObligationCtxt::new_in_snapshot(self);
+ ocx.register_obligations(ok.obligations);
+ ocx.select_where_possible().is_empty()
})
}
@@ -1072,8 +1038,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.infcx
.type_implements_trait(
self.tcx.lang_items().deref_mut_trait()?,
- expr_ty,
- ty::List::empty(),
+ [expr_ty],
self.param_env,
)
.may_apply()
@@ -1116,15 +1081,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Special-case that coercion alone cannot handle:
// Function items or non-capturing closures of differing IDs or InternalSubsts.
let (a_sig, b_sig) = {
- #[allow(rustc::usage_of_ty_tykind)]
- let is_capturing_closure = |ty: &ty::TyKind<'tcx>| {
- if let &ty::Closure(closure_def_id, _substs) = ty {
+ let is_capturing_closure = |ty: Ty<'tcx>| {
+ if let &ty::Closure(closure_def_id, _substs) = ty.kind() {
self.tcx.upvars_mentioned(closure_def_id.expect_local()).is_some()
} else {
false
}
};
- if is_capturing_closure(prev_ty.kind()) || is_capturing_closure(new_ty.kind()) {
+ if is_capturing_closure(prev_ty) || is_capturing_closure(new_ty) {
(None, None)
} else {
match (prev_ty.kind(), new_ty.kind()) {
@@ -1179,8 +1143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return Err(TypeError::IntrinsicCast);
}
// The signature must match.
- let a_sig = self.normalize_associated_types_in(new.span, a_sig);
- let b_sig = self.normalize_associated_types_in(new.span, b_sig);
+ let (a_sig, b_sig) = self.normalize(new.span, (a_sig, b_sig));
let sig = self
.at(cause, self.param_env)
.trace(prev_ty, new_ty)
@@ -1547,7 +1510,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
// Mark that we've failed to coerce the types here to suppress
// any superfluous errors we might encounter while trying to
// emit or provide suggestions on how to fix the initial error.
- fcx.set_tainted_by_errors();
+ fcx.set_tainted_by_errors(
+ fcx.tcx.sess.delay_span_bug(cause.span, "coercion error but no error emitted"),
+ );
let (expected, found) = if label_expression_as_expected {
// In the case where this is a "forced unit", like
// `break`, we want to call the `()` "expected"
@@ -1644,9 +1609,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
if visitor.ret_exprs.len() > 0 && let Some(expr) = expression {
self.note_unreachable_loop_return(&mut err, &expr, &visitor.ret_exprs);
}
- err.emit_unless(unsized_return);
+ let reported = err.emit_unless(unsized_return);
- self.final_ty = Some(fcx.tcx.ty_error());
+ self.final_ty = Some(fcx.tcx.ty_error_with_guaranteed(reported));
}
}
}
@@ -1782,7 +1747,8 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
// may occur at the first return expression we see in the closure
// (if it conflicts with the declared return type). Skip adding a
// note in this case, since it would be incorrect.
- && !fcx.return_type_pre_known
+ && let Some(fn_sig) = fcx.body_fn_sig()
+ && fn_sig.output().is_ty_var()
{
err.span_note(
sp,
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 16febfc46..24184bdbf 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -2,6 +2,7 @@ use crate::FnCtxt;
use rustc_ast::util::parser::PREC_POSTFIX;
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
+use rustc_hir::def::CtorKind;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{is_range_literal, Node};
use rustc_infer::infer::InferOk;
@@ -18,6 +19,7 @@ use rustc_trait_selection::traits::ObligationCause;
use super::method::probe;
+use std::cmp::min;
use std::iter;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -30,6 +32,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
error: Option<TypeError<'tcx>>,
) {
+ if expr_ty == expected {
+ return;
+ }
+
self.annotate_expected_due_to_let_ty(err, expr, error);
// Use `||` to give these suggestions a precedence
@@ -42,15 +48,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|| self.suggest_boxing_when_appropriate(err, expr, 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_into(err, expr, expr_ty, expected);
+ || self.suggest_into(err, expr, expr_ty, expected)
+ || self.suggest_option_to_bool(err, expr, expr_ty, expected)
+ || self.suggest_floating_point_literal(err, expr, expected);
self.note_type_is_not_clone(err, expected, expr_ty, expr);
self.note_need_for_fn_pointer(err, expected, expr_ty);
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
}
- // Requires that the two types unify, and prints an error message if
- // they don't.
+ /// Requires that the two types unify, and prints an error message if
+ /// they don't.
pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
if let Some(mut e) = self.demand_suptype_diag(sp, expected, actual) {
e.emit();
@@ -148,7 +156,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Err(e) => e,
};
- self.set_tainted_by_errors();
+ self.set_tainted_by_errors(self.tcx.sess.delay_span_bug(
+ expr.span,
+ "`TypeError` when attempting coercion but no error emitted",
+ ));
let expr = expr.peel_drop_temps();
let cause = self.misc(expr.span);
let expr_ty = self.resolve_vars_with_obligations(checked_ty);
@@ -395,27 +406,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some(path) = variant_path.strip_prefix("std::prelude::")
&& let Some((_, path)) = path.split_once("::")
{
- return Some((path.to_string(), variant.ctor_kind, sole_field.name, note_about_variant_field_privacy));
+ return Some((path.to_string(), variant.ctor_kind(), sole_field.name, note_about_variant_field_privacy));
}
- Some((variant_path, variant.ctor_kind, sole_field.name, note_about_variant_field_privacy))
+ Some((variant_path, variant.ctor_kind(), sole_field.name, note_about_variant_field_privacy))
} else {
None
}
})
.collect();
- let suggestions_for = |variant: &_, ctor, field_name| {
+ let suggestions_for = |variant: &_, ctor_kind, field_name| {
let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
Some(ident) => format!("{ident}: "),
None => String::new(),
};
- let (open, close) = match ctor {
- hir::def::CtorKind::Fn => ("(".to_owned(), ")"),
- hir::def::CtorKind::Fictive => (format!(" {{ {field_name}: "), " }"),
+ let (open, close) = match ctor_kind {
+ Some(CtorKind::Fn) => ("(".to_owned(), ")"),
+ None => (format!(" {{ {field_name}: "), " }"),
// unit variants don't have fields
- hir::def::CtorKind::Const => unreachable!(),
+ Some(CtorKind::Const) => unreachable!(),
};
// Suggest constructor as deep into the block tree as possible.
@@ -845,31 +856,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
..
})) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id))
{
- if mutability == hir::Mutability::Mut {
+ if mutability.is_mut() {
// Suppressing this diagnostic, we'll properly print it in `check_expr_assign`
return None;
}
}
let sugg_expr = if needs_parens { format!("({src})") } else { src };
- return Some(match mutability {
- hir::Mutability::Mut => (
- sp,
- "consider mutably borrowing here".to_string(),
- format!("{prefix}&mut {sugg_expr}"),
- Applicability::MachineApplicable,
- false,
- false,
- ),
- hir::Mutability::Not => (
- sp,
- "consider borrowing here".to_string(),
- format!("{prefix}&{sugg_expr}"),
- Applicability::MachineApplicable,
- false,
- false,
- ),
- });
+ return Some((
+ sp,
+ format!("consider {}borrowing here", mutability.mutably_str()),
+ format!("{prefix}{}{sugg_expr}", mutability.ref_prefix_str()),
+ Applicability::MachineApplicable,
+ false,
+ false,
+ ));
}
}
}
@@ -927,51 +928,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& let Ok(src) = sm.span_to_snippet(sp)
{
let derefs = "*".repeat(steps);
- if let Some((span, src, applicability)) = match mutbl_b {
- hir::Mutability::Mut => {
- let new_prefix = "&mut ".to_owned() + &derefs;
- match mutbl_a {
- hir::Mutability::Mut => {
- replace_prefix(&src, "&mut ", &new_prefix).map(|_| {
- let pos = sp.lo() + BytePos(5);
- let sp = sp.with_lo(pos).with_hi(pos);
- (sp, derefs, Applicability::MachineApplicable)
- })
- }
- hir::Mutability::Not => {
- replace_prefix(&src, "&", &new_prefix).map(|_| {
- let pos = sp.lo() + BytePos(1);
- let sp = sp.with_lo(pos).with_hi(pos);
- (
- sp,
- format!("mut {derefs}"),
- Applicability::Unspecified,
- )
- })
- }
- }
- }
- hir::Mutability::Not => {
- let new_prefix = "&".to_owned() + &derefs;
- match mutbl_a {
- hir::Mutability::Mut => {
- replace_prefix(&src, "&mut ", &new_prefix).map(|_| {
- let lo = sp.lo() + BytePos(1);
- let hi = sp.lo() + BytePos(5);
- let sp = sp.with_lo(lo).with_hi(hi);
- (sp, derefs, Applicability::MachineApplicable)
- })
- }
- hir::Mutability::Not => {
- replace_prefix(&src, "&", &new_prefix).map(|_| {
- let pos = sp.lo() + BytePos(1);
- let sp = sp.with_lo(pos).with_hi(pos);
- (sp, derefs, Applicability::MachineApplicable)
- })
- }
- }
- }
- } {
+ let old_prefix = mutbl_a.ref_prefix_str();
+ let new_prefix = mutbl_b.ref_prefix_str().to_owned() + &derefs;
+
+ 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 _);
+ // 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 }
+ )
+ });
+
+ if let Some((span, src, applicability)) = suggestion {
return Some((
span,
"consider dereferencing".to_string(),
@@ -995,10 +969,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If the expression has `&`, removing it would fix the error
prefix_span = prefix_span.with_hi(inner.span.lo());
expr = inner;
- remove += match mutbl {
- hir::Mutability::Not => "&",
- hir::Mutability::Mut => "&mut ",
- };
+ remove.push_str(mutbl.ref_prefix_str());
steps -= 1;
} else {
break;
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 175037f9b..507272fde 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -1,10 +1,11 @@
-//! Errors emitted by `rustc_hir_analysis`.
+//! Errors emitted by `rustc_hir_typeck`.
+use rustc_errors::{AddToDiagnostic, Applicability, Diagnostic, MultiSpan, SubdiagnosticMessage};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_middle::ty::Ty;
use rustc_span::{symbol::Ident, Span};
#[derive(Diagnostic)]
-#[diag(hir_analysis_field_multiply_specified_in_initializer, code = "E0062")]
+#[diag(hir_typeck_field_multiply_specified_in_initializer, code = "E0062")]
pub struct FieldMultiplySpecifiedInInitializer {
#[primary_span]
#[label]
@@ -15,7 +16,7 @@ pub struct FieldMultiplySpecifiedInInitializer {
}
#[derive(Diagnostic)]
-#[diag(hir_analysis_return_stmt_outside_of_fn_body, code = "E0572")]
+#[diag(hir_typeck_return_stmt_outside_of_fn_body, code = "E0572")]
pub struct ReturnStmtOutsideOfFnBody {
#[primary_span]
pub span: Span,
@@ -26,14 +27,14 @@ pub struct ReturnStmtOutsideOfFnBody {
}
#[derive(Diagnostic)]
-#[diag(hir_analysis_yield_expr_outside_of_generator, code = "E0627")]
+#[diag(hir_typeck_yield_expr_outside_of_generator, code = "E0627")]
pub struct YieldExprOutsideOfGenerator {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
-#[diag(hir_analysis_struct_expr_non_exhaustive, code = "E0639")]
+#[diag(hir_typeck_struct_expr_non_exhaustive, code = "E0639")]
pub struct StructExprNonExhaustive {
#[primary_span]
pub span: Span,
@@ -41,21 +42,21 @@ pub struct StructExprNonExhaustive {
}
#[derive(Diagnostic)]
-#[diag(hir_analysis_method_call_on_unknown_type, code = "E0699")]
+#[diag(hir_typeck_method_call_on_unknown_type, code = "E0699")]
pub struct MethodCallOnUnknownType {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
-#[diag(hir_analysis_functional_record_update_on_non_struct, code = "E0436")]
+#[diag(hir_typeck_functional_record_update_on_non_struct, code = "E0436")]
pub struct FunctionalRecordUpdateOnNonStruct {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
-#[diag(hir_analysis_address_of_temporary_taken, code = "E0745")]
+#[diag(hir_typeck_address_of_temporary_taken, code = "E0745")]
pub struct AddressOfTemporaryTaken {
#[primary_span]
#[label]
@@ -65,7 +66,7 @@ pub struct AddressOfTemporaryTaken {
#[derive(Subdiagnostic)]
pub enum AddReturnTypeSuggestion {
#[suggestion(
- hir_analysis_add_return_type_add,
+ hir_typeck_add_return_type_add,
code = "-> {found} ",
applicability = "machine-applicable"
)]
@@ -75,7 +76,7 @@ pub enum AddReturnTypeSuggestion {
found: String,
},
#[suggestion(
- hir_analysis_add_return_type_missing_here,
+ hir_typeck_add_return_type_missing_here,
code = "-> _ ",
applicability = "has-placeholders"
)]
@@ -87,12 +88,12 @@ pub enum AddReturnTypeSuggestion {
#[derive(Subdiagnostic)]
pub enum ExpectedReturnTypeLabel<'tcx> {
- #[label(hir_analysis_expected_default_return_type)]
+ #[label(hir_typeck_expected_default_return_type)]
Unit {
#[primary_span]
span: Span,
},
- #[label(hir_analysis_expected_return_type)]
+ #[label(hir_typeck_expected_return_type)]
Other {
#[primary_span]
span: Span,
@@ -101,10 +102,10 @@ pub enum ExpectedReturnTypeLabel<'tcx> {
}
#[derive(Diagnostic)]
-#[diag(hir_analysis_missing_parentheses_in_range, code = "E0689")]
+#[diag(hir_typeck_missing_parentheses_in_range, code = "E0689")]
pub struct MissingParentheseInRange {
#[primary_span]
- #[label(hir_analysis_missing_parentheses_in_range)]
+ #[label(hir_typeck_missing_parentheses_in_range)]
pub span: Span,
pub ty_str: String,
pub method_name: String,
@@ -113,8 +114,9 @@ pub struct MissingParentheseInRange {
}
#[derive(Subdiagnostic)]
-#[multipart_suggestion_verbose(
- hir_analysis_add_missing_parentheses_in_range,
+#[multipart_suggestion(
+ hir_typeck_add_missing_parentheses_in_range,
+ style = "verbose",
applicability = "maybe-incorrect"
)]
pub struct AddMissingParenthesesInRange {
@@ -124,3 +126,49 @@ pub struct AddMissingParenthesesInRange {
#[suggestion_part(code = ")")]
pub right: Span,
}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_op_trait_generic_params)]
+pub struct OpMethodGenericParams {
+ #[primary_span]
+ pub span: Span,
+ pub method_name: String,
+}
+
+pub struct TypeMismatchFruTypo {
+ /// Span of the LHS of the range
+ pub expr_span: Span,
+ /// Span of the `..RHS` part of the range
+ pub fru_span: Span,
+ /// Rendered expression of the RHS of the range
+ pub expr: Option<String>,
+}
+
+impl AddToDiagnostic for TypeMismatchFruTypo {
+ fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+ where
+ F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+ {
+ diag.set_arg("expr", self.expr.as_deref().unwrap_or("NONE"));
+
+ // Only explain that `a ..b` is a range if it's split up
+ if self.expr_span.between(self.fru_span).is_empty() {
+ diag.span_note(
+ self.expr_span.to(self.fru_span),
+ rustc_errors::fluent::hir_typeck_fru_note,
+ );
+ } else {
+ let mut multispan: MultiSpan = vec![self.expr_span, self.fru_span].into();
+ multispan.push_span_label(self.expr_span, rustc_errors::fluent::hir_typeck_fru_expr);
+ multispan.push_span_label(self.fru_span, rustc_errors::fluent::hir_typeck_fru_expr2);
+ diag.span_note(multispan, rustc_errors::fluent::hir_typeck_fru_note);
+ }
+
+ diag.span_suggestion(
+ self.expr_span.shrink_to_hi(),
+ rustc_errors::fluent::hir_typeck_fru_suggestion,
+ ", ",
+ Applicability::MaybeIncorrect,
+ );
+ }
+}
diff --git a/compiler/rustc_hir_typeck/src/expectation.rs b/compiler/rustc_hir_typeck/src/expectation.rs
index e9e810344..4f086cf59 100644
--- a/compiler/rustc_hir_typeck/src/expectation.rs
+++ b/compiler/rustc_hir_typeck/src/expectation.rs
@@ -79,9 +79,9 @@ impl<'a, 'tcx> Expectation<'tcx> {
}
}
- // Resolves `expected` by a single level if it is a variable. If
- // there is no expected type or resolution is not possible (e.g.,
- // no constraints yet present), just returns `self`.
+ /// Resolves `expected` by a single level if it is a variable. If
+ /// there is no expected type or resolution is not possible (e.g.,
+ /// no constraints yet present), just returns `self`.
fn resolve(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
match self {
NoExpectation => NoExpectation,
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 9fde62a81..ed87b94a0 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -5,6 +5,7 @@
use crate::cast;
use crate::coercion::CoerceMany;
use crate::coercion::DynamicCoerceMany;
+use crate::errors::TypeMismatchFruTypo;
use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
use crate::errors::{
FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct,
@@ -30,7 +31,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
-use rustc_hir::{Closure, ExprKind, HirId, QPath};
+use rustc_hir::{ExprKind, HirId, QPath};
use rustc_hir_analysis::astconv::AstConv as _;
use rustc_hir_analysis::check::ty_kind_suggestion;
use rustc_infer::infer;
@@ -80,14 +81,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// coercions from ! to `expected`.
if ty.is_never() {
if let Some(adjustments) = self.typeck_results.borrow().adjustments().get(expr.hir_id) {
- self.tcx().sess.delay_span_bug(
+ let reported = self.tcx().sess.delay_span_bug(
expr.span,
"expression with never type wound up being adjusted",
);
return if let [Adjustment { kind: Adjust::NeverToAny, target }] = &adjustments[..] {
target.to_owned()
} else {
- self.tcx().ty_error()
+ self.tcx().ty_error_with_guaranteed(reported)
};
}
@@ -103,8 +104,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
if let Some(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) {
- let expr = expr.peel_drop_temps();
- self.suggest_deref_ref_or_into(&mut err, expr, expected_ty, ty, None);
+ // FIXME(compiler-errors): We probably should fold some of the
+ // `suggest_` functions from `emit_coerce_suggestions` into here,
+ // since some of those aren't necessarily just coerce suggestions.
+ let _ = self.suggest_deref_ref_or_into(
+ &mut err,
+ expr.peel_drop_temps(),
+ expected_ty,
+ ty,
+ None,
+ ) || self.suggest_option_to_bool(&mut err, expr, ty, expected_ty);
extend_err(&mut err);
err.emit();
}
@@ -220,7 +229,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Hide the outer diverging and has_errors flags.
let old_diverges = self.diverges.replace(Diverges::Maybe);
- let old_has_errors = self.has_errors.replace(false);
let ty = ensure_sufficient_stack(|| match &expr.kind {
hir::ExprKind::Path(
@@ -259,7 +267,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Combine the diverging and has_error flags.
self.diverges.set(self.diverges.get() | old_diverges);
- self.has_errors.set(self.has_errors.get() | old_has_errors);
debug!("type of {} is...", self.tcx.hir().node_to_string(expr.hir_id));
debug!("... {:?}, expected is {:?}", ty, expected);
@@ -318,9 +325,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ExprKind::Match(discrim, arms, match_src) => {
self.check_match(expr, &discrim, arms, expected, match_src)
}
- ExprKind::Closure(&Closure { capture_clause, fn_decl, body, movability, .. }) => {
- self.check_expr_closure(expr, capture_clause, &fn_decl, body, movability, expected)
- }
+ ExprKind::Closure(closure) => self.check_expr_closure(closure, expr.span, expected),
ExprKind::Block(body, _) => self.check_block_with_expected(&body, expected),
ExprKind::Call(callee, args) => self.check_call(expr, &callee, args, expected),
ExprKind::MethodCall(segment, receiver, args, _) => {
@@ -398,8 +403,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
}
- err.emit();
- oprnd_t = tcx.ty_error();
+ oprnd_t = tcx.ty_error_with_guaranteed(err.emit());
}
}
hir::UnOp::Not => {
@@ -524,12 +528,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.resolve_ty_and_res_fully_qualified_call(qpath, expr.hir_id, expr.span);
let ty = match res {
Res::Err => {
- self.set_tainted_by_errors();
- tcx.ty_error()
+ self.suggest_assoc_method_call(segs);
+ let e =
+ self.tcx.sess.delay_span_bug(qpath.span(), "`Res::Err` but no error emitted");
+ self.set_tainted_by_errors(e);
+ tcx.ty_error_with_guaranteed(e)
}
- Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _) => {
- report_unexpected_variant_res(tcx, res, qpath, expr.span);
- tcx.ty_error()
+ Res::Def(DefKind::Variant, _) => {
+ let e = report_unexpected_variant_res(tcx, res, qpath, expr.span, "E0533", "value");
+ tcx.ty_error_with_guaranteed(e)
}
_ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0,
};
@@ -840,10 +847,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return_expr_ty,
);
- if self.return_type_has_opaque {
+ if let Some(fn_sig) = self.body_fn_sig()
+ && fn_sig.output().has_opaque_types()
+ {
// Point any obligations that were registered due to opaque type
// inference at the return expression.
- self.select_obligations_where_possible(false, |errors| {
+ self.select_obligations_where_possible(|errors| {
self.point_at_return_for_opaque_ty_error(errors, span, return_expr_ty);
});
}
@@ -906,8 +915,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
// Check if an expression `original_expr_id` comes from the condition of a while loop,
- // as opposed from the body of a while loop, which we can naively check by iterating
- // parents until we find a loop...
+ /// as opposed from the body of a while loop, which we can naively check by iterating
+ /// parents until we find a loop...
pub(super) fn comes_from_while_condition(
&self,
original_expr_id: HirId,
@@ -1097,12 +1106,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If the assignment expression itself is ill-formed, don't
// bother emitting another error
- if lhs_ty.references_error() || rhs_ty.references_error() {
- err.delay_as_bug()
- } else {
- err.emit();
- }
- return self.tcx.ty_error();
+ let reported = err.emit_unless(lhs_ty.references_error() || rhs_ty.references_error());
+ return self.tcx.ty_error_with_guaranteed(reported);
}
let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace);
@@ -1114,9 +1119,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let lhs_deref_ty_is_sized = self
.infcx
.type_implements_trait(
- self.tcx.lang_items().sized_trait().unwrap(),
- lhs_deref_ty,
- ty::List::empty(),
+ self.tcx.require_lang_item(LangItem::Sized, None),
+ [lhs_deref_ty],
self.param_env,
)
.may_apply();
@@ -1613,10 +1617,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.demand_coerce_diag(&field.expr, ty, field_type, None, AllowTwoPhase::No);
if let Some(mut diag) = diag {
- if idx == ast_fields.len() - 1 && remaining_fields.is_empty() {
- self.suggest_fru_from_range(field, variant, substs, &mut diag);
+ if idx == ast_fields.len() - 1 {
+ if remaining_fields.is_empty() {
+ self.suggest_fru_from_range(field, variant, substs, &mut diag);
+ diag.emit();
+ } else {
+ diag.stash(field.span, StashKey::MaybeFruTypo);
+ }
+ } else {
+ diag.emit();
}
- diag.emit();
}
}
@@ -1637,6 +1647,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// the fields with the base_expr. This could cause us to hit errors later
// when certain fields are assumed to exist that in fact do not.
if error_happened {
+ if let Some(base_expr) = base_expr {
+ self.check_expr(base_expr);
+ }
return;
}
@@ -1655,7 +1668,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.fields
.iter()
.map(|f| {
- let fru_ty = self.normalize_associated_types_in(
+ let fru_ty = self.normalize(
expr_span,
self.field_ty(base_expr.span, f, fresh_substs),
);
@@ -1739,9 +1752,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::Adt(adt, substs) if adt.is_struct() => variant
.fields
.iter()
- .map(|f| {
- self.normalize_associated_types_in(expr_span, f.ty(self.tcx, substs))
- })
+ .map(|f| self.normalize(expr_span, f.ty(self.tcx, substs)))
.collect(),
_ => {
self.tcx
@@ -1874,19 +1885,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.map(|adt| adt.did())
!= range_def_id
{
- let instead = self
+ // Suppress any range expr type mismatches
+ if let Some(mut diag) = self
+ .tcx
+ .sess
+ .diagnostic()
+ .steal_diagnostic(last_expr_field.span, StashKey::MaybeFruTypo)
+ {
+ diag.delay_as_bug();
+ }
+
+ // Use a (somewhat arbitrary) filtering heuristic to avoid printing
+ // expressions that are either too long, or have control character
+ //such as newlines in them.
+ let expr = self
.tcx
.sess
.source_map()
.span_to_snippet(range_end.expr.span)
- .map(|s| format!(" from `{s}`"))
- .unwrap_or_default();
- err.span_suggestion(
- range_start.span.shrink_to_hi(),
- &format!("to set the remaining fields{instead}, separate the last named field with a comma"),
- ",",
- Applicability::MaybeIncorrect,
- );
+ .ok()
+ .filter(|s| s.len() < 25 && !s.contains(|c: char| c.is_control()));
+
+ let fru_span = self
+ .tcx
+ .sess
+ .source_map()
+ .span_extend_while(range_start.span, |c| c.is_whitespace())
+ .unwrap_or(range_start.span).shrink_to_hi().to(range_end.span);
+
+ err.subdiagnostic(TypeMismatchFruTypo {
+ expr_span: range_start.span,
+ fru_span,
+ expr,
+ });
}
}
@@ -1961,7 +1992,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr_span: Span,
) {
if variant.is_recovered() {
- self.set_tainted_by_errors();
+ self.set_tainted_by_errors(
+ self.tcx
+ .sess
+ .delay_span_bug(expr_span, "parser recovered but no error was emitted"),
+ );
return;
}
let mut err = self.err_ctxt().type_error_struct_with_diag(
@@ -1991,8 +2026,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
let variant_ident_span = self.tcx.def_ident_span(variant.def_id).unwrap();
- match variant.ctor_kind {
- CtorKind::Fn => match ty.kind() {
+ match variant.ctor_kind() {
+ Some(CtorKind::Fn) => match ty.kind() {
ty::Adt(adt, ..) if adt.is_enum() => {
err.span_label(
variant_ident_span,
@@ -2300,12 +2335,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
base: &'tcx hir::Expr<'tcx>,
ty: Ty<'tcx>,
) {
- let output_ty = match self.get_impl_future_output_ty(ty) {
- Some(output_ty) => self.resolve_vars_if_possible(output_ty),
- _ => return,
- };
+ let Some(output_ty) = self.get_impl_future_output_ty(ty) else { return; };
let mut add_label = true;
- if let ty::Adt(def, _) = output_ty.skip_binder().kind() {
+ if let ty::Adt(def, _) = output_ty.kind() {
// no field access on enum type
if !def.is_enum() {
if def
@@ -2738,7 +2770,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Some((index_ty, element_ty)) => {
// two-phase not needed because index_ty is never mutable
self.demand_coerce(idx, idx_t, index_ty, None, AllowTwoPhase::No);
- self.select_obligations_where_possible(false, |errors| {
+ self.select_obligations_where_possible(|errors| {
self.point_at_index_if_possible(errors, idx.span)
});
element_ty
@@ -2777,8 +2809,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
}
- err.emit();
- self.tcx.ty_error()
+ let reported = err.emit();
+ self.tcx.ty_error_with_guaranteed(reported)
}
}
}
@@ -2791,7 +2823,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) {
for error in errors {
match error.obligation.predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(predicate)
+ ty::PredicateKind::Clause(ty::Clause::Trait(predicate))
if self.tcx.is_diagnostic_item(sym::SliceIndex, predicate.trait_ref.def_id) => {
}
_ => continue,
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index fce2a5888..03b174c77 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -252,11 +252,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
hir::ExprKind::Match(ref discr, arms, _) => {
let discr_place = return_if_err!(self.mc.cat_expr(discr));
- self.maybe_read_scrutinee(
+ return_if_err!(self.maybe_read_scrutinee(
discr,
discr_place.clone(),
arms.iter().map(|arm| arm.pat),
- );
+ ));
// treatment of the discriminant is handled while walking the arms.
for arm in arms {
@@ -352,8 +352,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
self.consume_expr(base);
}
- hir::ExprKind::Closure { .. } => {
- self.walk_captures(expr);
+ hir::ExprKind::Closure(closure) => {
+ self.walk_captures(closure);
}
hir::ExprKind::Box(ref base) => {
@@ -390,7 +390,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
discr: &Expr<'_>,
discr_place: PlaceWithHirId<'tcx>,
pats: impl Iterator<Item = &'t hir::Pat<'t>>,
- ) {
+ ) -> Result<(), ()> {
// Matching should not always be considered a use of the place, hence
// discr does not necessarily need to be borrowed.
// We only want to borrow discr if the pattern contain something other
@@ -398,7 +398,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
let ExprUseVisitor { ref mc, body_owner: _, delegate: _ } = *self;
let mut needs_to_be_read = false;
for pat in pats {
- return_if_err!(mc.cat_pattern(discr_place.clone(), pat, |place, pat| {
+ mc.cat_pattern(discr_place.clone(), pat, |place, pat| {
match &pat.kind {
PatKind::Binding(.., opt_sub_pat) => {
// If the opt_sub_pat is None, than the binding does not count as
@@ -453,7 +453,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
// examined
}
}
- }));
+ })?
}
if needs_to_be_read {
@@ -474,6 +474,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
// that the discriminant has been initialized.
self.walk_expr(discr);
}
+ Ok(())
}
fn walk_local<F>(
@@ -490,7 +491,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
f(self);
if let Some(els) = els {
// borrowing because we need to test the discriminant
- self.maybe_read_scrutinee(expr, expr_place.clone(), from_ref(pat).iter());
+ return_if_err!(self.maybe_read_scrutinee(
+ expr,
+ expr_place.clone(),
+ from_ref(pat).iter()
+ ));
self.walk_block(els)
}
self.walk_irrefutable_pat(&expr_place, &pat);
@@ -518,6 +523,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
// Consume the expressions supplying values for each field.
for field in fields {
self.consume_expr(field.expr);
+
+ // The struct path probably didn't resolve
+ if self.mc.typeck_results.opt_field_index(field.hir_id).is_none() {
+ self.tcx().sess.delay_span_bug(field.span, "couldn't resolve index for field");
+ }
}
let with_expr = match *opt_with {
@@ -535,9 +545,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
ty::Adt(adt, substs) if adt.is_struct() => {
// Consume those fields of the with expression that are needed.
for (f_index, with_field) in adt.non_enum_variant().fields.iter().enumerate() {
- let is_mentioned = fields.iter().any(|f| {
- self.tcx().field_index(f.hir_id, self.mc.typeck_results) == f_index
- });
+ let is_mentioned = fields
+ .iter()
+ .any(|f| self.mc.typeck_results.opt_field_index(f.hir_id) == Some(f_index));
if !is_mentioned {
let field_place = self.mc.cat_projection(
&*with_expr,
@@ -745,7 +755,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
///
/// - When reporting the Place back to the Delegate, ensure that the UpvarId uses the enclosing
/// closure as the DefId.
- fn walk_captures(&mut self, closure_expr: &hir::Expr<'_>) {
+ fn walk_captures(&mut self, closure_expr: &hir::Closure<'_>) {
fn upvar_is_local_variable<'tcx>(
upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
upvar_id: hir::HirId,
@@ -757,7 +767,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
debug!("walk_captures({:?})", closure_expr);
let tcx = self.tcx();
- let closure_def_id = tcx.hir().local_def_id(closure_expr.hir_id);
+ let closure_def_id = closure_expr.def_id;
let upvars = tcx.upvars_mentioned(self.body_owner);
// For purposes of this function, generator and closures are equivalent.
@@ -829,10 +839,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
// be a local variable
PlaceBase::Local(*var_hir_id)
};
+ let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_def_id);
let place_with_id = PlaceWithHirId::new(
- capture_info.path_expr_id.unwrap_or(
- capture_info.capture_kind_expr_id.unwrap_or(closure_expr.hir_id),
- ),
+ capture_info
+ .path_expr_id
+ .unwrap_or(capture_info.capture_kind_expr_id.unwrap_or(closure_hir_id)),
place.base_ty,
place_base,
place.projections.clone(),
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index 747ecb036..ac6b0924a 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -7,16 +7,16 @@ use rustc_data_structures::{
use rustc_middle::ty::{self, Ty};
impl<'tcx> FnCtxt<'_, 'tcx> {
- /// Performs type inference fallback, returning true if any fallback
- /// occurs.
- pub(super) fn type_inference_fallback(&self) -> bool {
+ /// Performs type inference fallback, setting `FnCtxt::fallback_has_occurred`
+ /// if fallback has occurred.
+ pub(super) fn type_inference_fallback(&self) {
debug!(
"type-inference-fallback start obligations: {:#?}",
self.fulfillment_cx.borrow_mut().pending_obligations()
);
// All type checking constraints were added, try to fallback unsolved variables.
- self.select_obligations_where_possible(false, |_| {});
+ self.select_obligations_where_possible(|_| {});
debug!(
"type-inference-fallback post selection obligations: {:#?}",
@@ -26,18 +26,17 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
// Check if we have any unsolved variables. If not, no need for fallback.
let unsolved_variables = self.unsolved_variables();
if unsolved_variables.is_empty() {
- return false;
+ return;
}
let diverging_fallback = self.calculate_diverging_fallback(&unsolved_variables);
- let mut fallback_has_occurred = false;
// We do fallback in two passes, to try to generate
// better error messages.
// The first time, we do *not* replace opaque types.
for ty in unsolved_variables {
debug!("unsolved_variable = {:?}", ty);
- fallback_has_occurred |= self.fallback_if_possible(ty, &diverging_fallback);
+ self.fallback_if_possible(ty, &diverging_fallback);
}
// We now see if we can make progress. This might cause us to
@@ -63,9 +62,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
// If we had tried to fallback the opaque inference variable to `MyType`,
// we will generate a confusing type-check error that does not explicitly
// refer to opaque types.
- self.select_obligations_where_possible(fallback_has_occurred, |_| {});
-
- fallback_has_occurred
+ self.select_obligations_where_possible(|_| {});
}
// Tries to apply a fallback to `ty` if it is an unsolved variable.
@@ -81,12 +78,13 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
// Fallback becomes very dubious if we have encountered
// type-checking errors. In that case, fallback to Error.
//
- // The return value indicates whether fallback has occurred.
+ // Sets `FnCtxt::fallback_has_occurred` if fallback is performed
+ // during this call.
fn fallback_if_possible(
&self,
ty: Ty<'tcx>,
diverging_fallback: &FxHashMap<Ty<'tcx>, Ty<'tcx>>,
- ) -> bool {
+ ) {
// Careful: we do NOT shallow-resolve `ty`. We know that `ty`
// is an unsolved variable, and we determine its fallback
// based solely on how it was created, not what other type
@@ -106,12 +104,12 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
// type, `?T` is not considered unsolved, but `?I` is. The
// same is true for float variables.)
let fallback = match ty.kind() {
- _ if self.is_tainted_by_errors() => self.tcx.ty_error(),
+ _ if let Some(e) = self.tainted_by_errors() => self.tcx.ty_error_with_guaranteed(e),
ty::Infer(ty::IntVar(_)) => self.tcx.types.i32,
ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64,
_ => match diverging_fallback.get(&ty) {
Some(&fallback_ty) => fallback_ty,
- None => return false,
+ None => return,
},
};
debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback);
@@ -122,7 +120,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
.map(|origin| origin.span)
.unwrap_or(rustc_span::DUMMY_SP);
self.demand_eqtype(span, ty, fallback);
- true
+ self.fallback_has_occurred.set(true);
}
/// The "diverging fallback" system is rather complicated. This is
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 6a1cffe3e..952d27262 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -16,13 +16,13 @@ use rustc_hir_analysis::astconv::{
};
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
-use rustc_infer::infer::{InferOk, InferResult};
+use rustc_infer::infer::InferResult;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
+use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{
- self, AdtKind, CanonicalUserType, DefIdTree, EarlyBinder, GenericParamDefKind, ToPolyTraitRef,
- ToPredicate, Ty, UserType,
+ self, AdtKind, CanonicalUserType, DefIdTree, EarlyBinder, GenericParamDefKind, Ty, UserType,
};
use rustc_middle::ty::{GenericArgKind, InternalSubsts, SubstsRef, UserSelfTy, UserSubsts};
use rustc_session::lint;
@@ -30,11 +30,8 @@ use rustc_span::def_id::LocalDefId;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{Span, DUMMY_SP};
-use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
-use rustc_trait_selection::traits::{
- self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt,
-};
+use rustc_trait_selection::traits::{self, NormalizeExt, ObligationCauseCode, ObligationCtxt};
use std::collections::hash_map::Entry;
use std::slice;
@@ -106,7 +103,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// possible. This can help substantially when there are
// indirect dependencies that don't seem worth tracking
// precisely.
- self.select_obligations_where_possible(false, mutate_fulfillment_errors);
+ self.select_obligations_where_possible(mutate_fulfillment_errors);
self.resolve_vars_if_possible(ty)
}
@@ -142,9 +139,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
debug!("write_ty({:?}, {:?}) in fcx {}", id, self.resolve_vars_if_possible(ty), self.tag());
self.typeck_results.borrow_mut().node_types_mut().insert(id, ty);
- if ty.references_error() {
- self.has_errors.set(true);
- self.set_tainted_by_errors();
+ if let Err(e) = ty.error_reported() {
+ self.set_tainted_by_errors(e);
}
}
@@ -346,7 +342,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
debug!("instantiate_type_scheme(value={:?}, substs={:?})", value, substs);
let value = EarlyBinder(value).subst(self.tcx, substs);
- let result = self.normalize_associated_types_in(span, value);
+ let result = self.normalize(span, value);
debug!("instantiate_type_scheme = {:?}", result);
result
}
@@ -362,7 +358,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let bounds = self.tcx.predicates_of(def_id);
let spans: Vec<Span> = bounds.predicates.iter().map(|(_, span)| *span).collect();
let result = bounds.instantiate(self.tcx, substs);
- let result = self.normalize_associated_types_in(span, result);
+ let result = self.normalize(span, result);
debug!(
"instantiate_bounds(bounds={:?}, substs={:?}) = {:?}, {:?}",
bounds, substs, result, spans,
@@ -370,50 +366,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(result, spans)
}
- pub(in super::super) fn normalize_associated_types_in<T>(&self, span: Span, value: T) -> T
- where
- T: TypeFoldable<'tcx>,
- {
- self.inh.normalize_associated_types_in(span, self.body_id, self.param_env, value)
- }
-
- pub(in super::super) fn normalize_associated_types_in_as_infer_ok<T>(
- &self,
- span: Span,
- value: T,
- ) -> InferOk<'tcx, T>
+ pub(in super::super) fn normalize<T>(&self, span: Span, value: T) -> T
where
T: TypeFoldable<'tcx>,
{
- self.inh.partially_normalize_associated_types_in(
- ObligationCause::misc(span, self.body_id),
- self.param_env,
- value,
- )
- }
-
- pub(in super::super) fn normalize_op_associated_types_in_as_infer_ok<T>(
- &self,
- span: Span,
- value: T,
- opt_input_expr: Option<&hir::Expr<'_>>,
- ) -> InferOk<'tcx, T>
- where
- T: TypeFoldable<'tcx>,
- {
- self.inh.partially_normalize_associated_types_in(
- ObligationCause::new(
- span,
- self.body_id,
- traits::BinOp {
- rhs_span: opt_input_expr.map(|expr| expr.span),
- is_lit: opt_input_expr
- .map_or(false, |expr| matches!(expr.kind, ExprKind::Lit(_))),
- output_ty: None,
- },
- ),
- self.param_env,
- value,
+ self.register_infer_ok_obligations(
+ self.at(&self.misc(span), self.param_env).normalize(value),
)
}
@@ -490,11 +448,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match length {
&hir::ArrayLen::Infer(_, span) => self.ct_infer(self.tcx.types.usize, None, span),
hir::ArrayLen::Body(anon_const) => {
- let const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
- let span = self.tcx.hir().span(anon_const.hir_id);
- let c = ty::Const::from_anon_const(self.tcx, const_def_id);
+ let span = self.tcx.def_span(anon_const.def_id);
+ let c = ty::Const::from_anon_const(self.tcx, anon_const.def_id);
self.register_wf_obligation(c.into(), span, ObligationCauseCode::WellFormed(None));
- self.normalize_associated_types_in(span, c)
+ self.normalize(span, c)
}
}
}
@@ -504,10 +461,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ast_c: &hir::AnonConst,
param_def_id: DefId,
) -> ty::Const<'tcx> {
- let const_def = ty::WithOptConstParam {
- did: self.tcx.hir().local_def_id(ast_c.hir_id),
- const_param_did: Some(param_def_id),
- };
+ 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);
self.register_wf_obligation(
c.into(),
@@ -534,7 +489,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
match self.typeck_results.borrow().node_types().get(id) {
Some(&t) => t,
- None if self.is_tainted_by_errors() => self.tcx.ty_error(),
+ None if let Some(e) = self.tainted_by_errors() => self.tcx.ty_error_with_guaranteed(e),
None => {
bug!(
"no type for node {}: {} in fcx {}",
@@ -549,7 +504,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn node_ty_opt(&self, id: hir::HirId) -> Option<Ty<'tcx>> {
match self.typeck_results.borrow().node_types().get(id) {
Some(&t) => Some(t),
- None if self.is_tainted_by_errors() => Some(self.tcx.ty_error()),
+ None if let Some(e) = self.tainted_by_errors() => Some(self.tcx.ty_error_with_guaranteed(e)),
None => None,
}
}
@@ -564,9 +519,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// WF obligations never themselves fail, so no real need to give a detailed cause:
let cause = traits::ObligationCause::new(span, self.body_id, code);
self.register_predicate(traits::Obligation::new(
+ self.tcx,
cause,
self.param_env,
- ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(self.tcx),
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)),
));
}
@@ -588,7 +544,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
field: &'tcx ty::FieldDef,
substs: SubstsRef<'tcx>,
) -> Ty<'tcx> {
- self.normalize_associated_types_in(span, field.ty(self.tcx, substs))
+ self.normalize(span, field.ty(self.tcx, substs))
}
pub(in super::super) fn resolve_rvalue_scopes(&self, def_id: DefId) {
@@ -601,7 +557,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(in super::super) fn resolve_generator_interiors(&self, def_id: DefId) {
let mut generators = self.deferred_generator_interiors.borrow_mut();
for (body_id, interior, kind) in generators.drain(..) {
- self.select_obligations_where_possible(false, |_| {});
+ self.select_obligations_where_possible(|_| {});
crate::generator_interior::resolve_interior(self, def_id, body_id, interior, kind);
}
}
@@ -612,25 +568,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if !errors.is_empty() {
self.adjust_fulfillment_errors_for_expr_obligation(&mut errors);
- self.err_ctxt().report_fulfillment_errors(&errors, self.inh.body_id, false);
+ self.err_ctxt().report_fulfillment_errors(&errors, self.inh.body_id);
}
}
/// Select as many obligations as we can at present.
pub(in super::super) fn select_obligations_where_possible(
&self,
- fallback_has_occurred: bool,
mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
) {
let mut result = self.fulfillment_cx.borrow_mut().select_where_possible(self);
if !result.is_empty() {
mutate_fulfillment_errors(&mut result);
self.adjust_fulfillment_errors_for_expr_obligation(&mut result);
- self.err_ctxt().report_fulfillment_errors(
- &result,
- self.inh.body_id,
- fallback_has_occurred,
- );
+ self.err_ctxt().report_fulfillment_errors(&result, self.inh.body_id);
}
}
@@ -650,12 +601,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
#[instrument(skip(self), level = "debug")]
- fn self_type_matches_expected_vid(
- &self,
- trait_ref: ty::PolyTraitRef<'tcx>,
- expected_vid: ty::TyVid,
- ) -> bool {
- let self_ty = self.shallow_resolve(trait_ref.skip_binder().self_ty());
+ fn self_type_matches_expected_vid(&self, self_ty: Ty<'tcx>, expected_vid: ty::TyVid) -> bool {
+ let self_ty = self.shallow_resolve(self_ty);
debug!(?self_ty);
match *self_ty.kind() {
@@ -674,54 +621,64 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(in super::super) fn obligations_for_self_ty<'b>(
&'b self,
self_ty: ty::TyVid,
- ) -> impl Iterator<Item = (ty::PolyTraitRef<'tcx>, traits::PredicateObligation<'tcx>)>
- + Captures<'tcx>
- + 'b {
+ ) -> impl DoubleEndedIterator<Item = traits::PredicateObligation<'tcx>> + Captures<'tcx> + 'b
+ {
// FIXME: consider using `sub_root_var` here so we
// can see through subtyping.
let ty_var_root = self.root_var(self_ty);
trace!("pending_obligations = {:#?}", self.fulfillment_cx.borrow().pending_obligations());
- self.fulfillment_cx
- .borrow()
- .pending_obligations()
- .into_iter()
- .filter_map(move |obligation| {
- let bound_predicate = obligation.predicate.kind();
- match bound_predicate.skip_binder() {
- ty::PredicateKind::Projection(data) => Some((
- bound_predicate.rebind(data).required_poly_trait_ref(self.tcx),
- obligation,
- )),
- ty::PredicateKind::Trait(data) => {
- Some((bound_predicate.rebind(data).to_poly_trait_ref(), obligation))
- }
- ty::PredicateKind::Subtype(..) => None,
- ty::PredicateKind::Coerce(..) => None,
- ty::PredicateKind::RegionOutlives(..) => None,
- ty::PredicateKind::TypeOutlives(..) => None,
- ty::PredicateKind::WellFormed(..) => None,
- ty::PredicateKind::ObjectSafe(..) => None,
- ty::PredicateKind::ConstEvaluatable(..) => None,
- ty::PredicateKind::ConstEquate(..) => None,
- // N.B., this predicate is created by breaking down a
- // `ClosureType: FnFoo()` predicate, where
- // `ClosureType` represents some `Closure`. It can't
- // possibly be referring to the current closure,
- // because we haven't produced the `Closure` for
- // this closure yet; this is exactly why the other
- // code is looking for a self type of an unresolved
- // inference variable.
- ty::PredicateKind::ClosureKind(..) => None,
- ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
+ self.fulfillment_cx.borrow().pending_obligations().into_iter().filter_map(
+ move |obligation| match &obligation.predicate.kind().skip_binder() {
+ ty::PredicateKind::Clause(ty::Clause::Projection(data))
+ if self.self_type_matches_expected_vid(
+ data.projection_ty.self_ty(),
+ ty_var_root,
+ ) =>
+ {
+ Some(obligation)
}
- })
- .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root))
+ ty::PredicateKind::Clause(ty::Clause::Trait(data))
+ if self.self_type_matches_expected_vid(data.self_ty(), ty_var_root) =>
+ {
+ Some(obligation)
+ }
+
+ ty::PredicateKind::Clause(ty::Clause::Trait(..))
+ | ty::PredicateKind::Clause(ty::Clause::Projection(..))
+ | ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::Coerce(..)
+ | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))
+ | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
+ | ty::PredicateKind::WellFormed(..)
+ | ty::PredicateKind::ObjectSafe(..)
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::ConstEquate(..)
+ // N.B., this predicate is created by breaking down a
+ // `ClosureType: FnFoo()` predicate, where
+ // `ClosureType` represents some `Closure`. It can't
+ // possibly be referring to the current closure,
+ // because we haven't produced the `Closure` for
+ // this closure yet; this is exactly why the other
+ // code is looking for a self type of an unresolved
+ // inference variable.
+ | ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::Ambiguous
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
+ },
+ )
}
pub(in super::super) fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool {
- self.obligations_for_self_ty(self_ty)
- .any(|(tr, _)| Some(tr.def_id()) == self.tcx.lang_items().sized_trait())
+ let sized_did = self.tcx.lang_items().sized_trait();
+ self.obligations_for_self_ty(self_ty).any(|obligation| {
+ match obligation.predicate.kind().skip_binder() {
+ ty::PredicateKind::Clause(ty::Clause::Trait(data)) => {
+ Some(data.def_id()) == sized_did
+ }
+ _ => false,
+ }
+ })
}
pub(in super::super) fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> {
@@ -769,34 +726,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let expect_args = self
.fudge_inference_if_ok(|| {
+ let ocx = ObligationCtxt::new_in_snapshot(self);
+
// Attempt to apply a subtyping relationship between the formal
// return type (likely containing type variables if the function
// is polymorphic) and the expected return type.
// No argument expectations are produced if unification fails.
let origin = self.misc(call_span);
- let ures = self.at(&origin, self.param_env).sup(ret_ty, formal_ret);
-
- // FIXME(#27336) can't use ? here, Try::from_error doesn't default
- // to identity so the resulting type is not constrained.
- match ures {
- Ok(ok) => {
- // Process any obligations locally as much as
- // we can. We don't care if some things turn
- // out unconstrained or ambiguous, as we're
- // just trying to get hints here.
- let errors = self.save_and_restore_in_snapshot_flag(|_| {
- let mut fulfill = <dyn TraitEngine<'_>>::new(self.tcx);
- for obligation in ok.obligations {
- fulfill.register_predicate_obligation(self, obligation);
- }
- fulfill.select_where_possible(self)
- });
-
- if !errors.is_empty() {
- return Err(());
- }
- }
- Err(_) => return Err(()),
+ ocx.sup(&origin, self.param_env, ret_ty, formal_ret)?;
+ if !ocx.select_where_possible().is_empty() {
+ return Err(TypeError::Mismatch);
}
// Record all the argument types, with the substitutions
@@ -1132,7 +1071,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Res::Local(hid) = res {
let ty = self.local_ty(span, hid).decl_ty;
- let ty = self.normalize_associated_types_in(span, ty);
+ let ty = self.normalize(span, ty);
self.write_ty(hir_id, ty);
return (ty, res);
}
@@ -1173,9 +1112,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
explicit_late_bound = ExplicitLateBound::Yes;
}
- if let Err(GenericArgCountMismatch { reported: Some(_), .. }) = arg_count.correct {
+ if let Err(GenericArgCountMismatch { reported: Some(e), .. }) = arg_count.correct {
infer_args_for_err.insert(index);
- self.set_tainted_by_errors(); // See issue #53251.
+ self.set_tainted_by_errors(e); // See issue #53251.
}
}
@@ -1189,11 +1128,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match *ty.kind() {
ty::Adt(adt_def, substs) if adt_def.has_ctor() => {
let variant = adt_def.non_enum_variant();
- let ctor_def_id = variant.ctor_def_id.unwrap();
- (
- Res::Def(DefKind::Ctor(CtorOf::Struct, variant.ctor_kind), ctor_def_id),
- Some(substs),
- )
+ let (ctor_kind, ctor_def_id) = variant.ctor.unwrap();
+ (Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id), Some(substs))
}
_ => {
let mut err = tcx.sess.struct_span_err(
@@ -1215,9 +1151,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
}
- err.emit();
-
- return (tcx.ty_error(), res);
+ let reported = err.emit();
+ return (tcx.ty_error_with_guaranteed(reported), res);
}
}
} else {
@@ -1466,12 +1401,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if !ty.is_ty_var() {
ty
} else {
- if !self.is_tainted_by_errors() {
+ let e = self.tainted_by_errors().unwrap_or_else(|| {
self.err_ctxt()
.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282, true)
- .emit();
- }
- let err = self.tcx.ty_error();
+ .emit()
+ });
+ let err = self.tcx.ty_error_with_guaranteed(e);
self.demand_suptype(sp, err, ty);
err
}
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 8e0fcb56c..60fec05d3 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -73,7 +73,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ty = self.typeck_results.borrow().expr_ty_adjusted(expr);
let ty = self.resolve_vars_if_possible(ty);
if ty.has_non_region_infer() {
- assert!(self.is_tainted_by_errors());
self.tcx.ty_error()
} else {
self.tcx.erase_regions(ty)
@@ -136,6 +135,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
tuple_arguments,
Some(method.def_id),
);
+
method.sig.output()
}
@@ -214,7 +214,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"cannot use call notation; the first type parameter \
for the function trait is neither a tuple nor unit"
)
- .emit();
+ .delay_as_bug();
(self.err_args(provided_args.len()), None)
}
}
@@ -344,7 +344,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// an "opportunistic" trait resolution of any trait bounds on
// the call. This helps coercions.
if check_closures {
- self.select_obligations_where_possible(false, |_| {})
+ self.select_obligations_where_possible(|_| {})
}
// Check each argument, to satisfy the input it was provided for
@@ -511,8 +511,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
tys.into_iter().any(|ty| ty.references_error() || ty.is_ty_var())
}
- self.set_tainted_by_errors();
let tcx = self.tcx;
+ // FIXME: taint after emitting errors and pass through an `ErrorGuaranteed`
+ self.set_tainted_by_errors(
+ tcx.sess.delay_span_bug(call_span, "no errors reported for args"),
+ );
// Get the argument span in the context of the call span so that
// suggestions and labels are (more) correct when an arg is a
@@ -596,6 +599,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
};
+ let mk_trace = |span, (formal_ty, expected_ty), provided_ty| {
+ let mismatched_ty = if expected_ty == provided_ty {
+ // If expected == provided, then we must have failed to sup
+ // the formal type. Avoid printing out "expected Ty, found Ty"
+ // in that case.
+ formal_ty
+ } else {
+ expected_ty
+ };
+ TypeTrace::types(&self.misc(span), true, mismatched_ty, provided_ty)
+ };
+
// The algorithm here is inspired by levenshtein distance and longest common subsequence.
// We'll try to detect 4 different types of mistakes:
// - An extra parameter has been provided that doesn't satisfy *any* of the other inputs
@@ -660,10 +675,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// A tuple wrap suggestion actually occurs within,
// so don't do anything special here.
err = self.err_ctxt().report_and_explain_type_error(
- TypeTrace::types(
- &self.misc(*lo),
- true,
- formal_and_expected_inputs[mismatch_idx.into()].1,
+ mk_trace(
+ *lo,
+ formal_and_expected_inputs[mismatch_idx.into()],
provided_arg_tys[mismatch_idx.into()].0,
),
terr,
@@ -747,9 +761,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
errors.drain_filter(|error| {
let Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(e))) = error else { return false };
let (provided_ty, provided_span) = provided_arg_tys[*provided_idx];
- let (expected_ty, _) = formal_and_expected_inputs[*expected_idx];
- let cause = &self.misc(provided_span);
- let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
+ let trace = mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty);
if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308(_)) {
self.err_ctxt().report_and_explain_type_error(trace, *e).emit();
return true;
@@ -773,8 +785,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx];
let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx];
- let cause = &self.misc(provided_arg_span);
- let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
+ let trace = mk_trace(provided_arg_span, (formal_ty, expected_ty), provided_ty);
let mut err = self.err_ctxt().report_and_explain_type_error(trace, *err);
self.emit_coerce_suggestions(
&mut err,
@@ -846,8 +857,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx];
let (provided_ty, provided_span) = provided_arg_tys[provided_idx];
if let Compatibility::Incompatible(error) = compatibility {
- let cause = &self.misc(provided_span);
- let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
+ let trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty);
if let Some(e) = error {
self.err_ctxt().note_type_err(
&mut err,
@@ -1200,7 +1210,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id);
let variant = match def {
Res::Err => {
- self.set_tainted_by_errors();
+ self.set_tainted_by_errors(
+ self.tcx.sess.delay_span_bug(path_span, "`Res::Err` but no error emitted"),
+ );
return None;
}
Res::Def(DefKind::Variant, _) => match ty.kind() {
@@ -1334,7 +1346,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Hide the outer diverging and `has_errors` flags.
let old_diverges = self.diverges.replace(Diverges::Maybe);
- let old_has_errors = self.has_errors.replace(false);
match stmt.kind {
hir::StmtKind::Local(l) => {
@@ -1364,7 +1375,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Combine the diverging and `has_error` flags.
self.diverges.set(self.diverges.get() | old_diverges);
- self.has_errors.set(self.has_errors.get() | old_has_errors);
}
pub fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) {
@@ -1383,8 +1393,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
blk: &'tcx hir::Block<'tcx>,
expected: Expectation<'tcx>,
) -> Ty<'tcx> {
- let prev = self.ps.replace(self.ps.get().recurse(blk));
-
// In some cases, blocks have just one exit, but other blocks
// can be targeted by multiple breaks. This can happen both
// with labeled blocks as well as when we desugar
@@ -1544,15 +1552,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.diverges.set(prev_diverges);
}
- let mut ty = ctxt.coerce.unwrap().complete(self);
-
- if self.has_errors.get() || ty.references_error() {
- ty = self.tcx.ty_error()
- }
+ let ty = ctxt.coerce.unwrap().complete(self);
self.write_ty(blk.hir_id, ty);
- self.ps.set(prev);
ty
}
@@ -1728,22 +1731,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let hir = self.tcx.hir();
let hir::Node::Expr(expr) = hir.get(hir_id) else { return false; };
- // Skip over mentioning async lang item
- if Some(def_id) == self.tcx.lang_items().from_generator_fn()
- && error.obligation.cause.span.desugaring_kind()
- == Some(rustc_span::DesugaringKind::Async)
- {
- return false;
- }
-
let Some(unsubstituted_pred) =
self.tcx.predicates_of(def_id).instantiate_identity(self.tcx).predicates.into_iter().nth(idx)
else { return false; };
let generics = self.tcx.generics_of(def_id);
let predicate_substs = match unsubstituted_pred.kind().skip_binder() {
- ty::PredicateKind::Trait(pred) => pred.trait_ref.substs,
- ty::PredicateKind::Projection(pred) => pred.projection_ty.substs,
+ ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs,
+ ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => pred.projection_ty.substs,
_ => ty::List::empty(),
};
@@ -1920,7 +1915,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
receiver: Option<&'tcx hir::Expr<'tcx>>,
args: &'tcx [hir::Expr<'tcx>],
) -> bool {
- let sig = self.tcx.fn_sig(def_id).skip_binder();
+ let ty = self.tcx.type_of(def_id);
+ if !ty.is_fn() {
+ return false;
+ }
+ let sig = ty.fn_sig(self.tcx).skip_binder();
let args_referencing_param: Vec<_> = sig
.inputs()
.iter()
@@ -2091,7 +2090,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& let maybe_trait_item_def_id = assoc_item.trait_item_def_id.unwrap_or(def_id)
&& let maybe_trait_def_id = self.tcx.parent(maybe_trait_item_def_id)
// Just an easy way to check "trait_def_id == Fn/FnMut/FnOnce"
- && let Some(call_kind) = ty::ClosureKind::from_def_id(self.tcx, maybe_trait_def_id)
+ && let Some(call_kind) = self.tcx.fn_trait_kind_from_def_id(maybe_trait_def_id)
&& let Some(callee_ty) = callee_ty
{
let callee_ty = callee_ty.peel_refs();
@@ -2115,9 +2114,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for (predicate, span) in
std::iter::zip(instantiated.predicates, instantiated.spans)
{
- if let ty::PredicateKind::Trait(pred) = predicate.kind().skip_binder()
+ if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = predicate.kind().skip_binder()
&& pred.self_ty().peel_refs() == callee_ty
- && ty::ClosureKind::from_def_id(self.tcx, pred.def_id()).is_some()
+ && self.tcx.is_fn_trait(pred.def_id())
{
err.span_note(span, "callable defined here");
return;
@@ -2148,13 +2147,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
),
);
let obligation = traits::Obligation::new(
+ self.tcx,
traits::ObligationCause::dummy(),
self.param_env,
- ty::Binder::dummy(ty::TraitPredicate {
- trait_ref,
- constness: ty::BoundConstness::NotConst,
- polarity: ty::ImplPolarity::Positive,
- }),
+ ty::Binder::dummy(trait_ref),
);
match SelectionContext::new(&self).select(&obligation) {
Ok(Some(traits::ImplSource::UserDefined(impl_source))) => {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 0c600daf4..30b59da78 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -4,10 +4,11 @@ mod checks;
mod suggestions;
pub use _impl::*;
+use rustc_errors::ErrorGuaranteed;
pub use suggestions::*;
use crate::coercion::DynamicCoerceMany;
-use crate::{Diverges, EnclosingBreakables, Inherited, UnsafetyState};
+use crate::{Diverges, EnclosingBreakables, Inherited};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir_analysis::astconv::AstConv;
@@ -21,7 +22,7 @@ use rustc_middle::ty::{self, Const, Ty, TyCtxt};
use rustc_session::Session;
use rustc_span::symbol::Ident;
use rustc_span::{self, Span};
-use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
+use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt};
use std::cell::{Cell, RefCell};
use std::ops::Deref;
@@ -68,17 +69,11 @@ pub struct FnCtxt<'a, 'tcx> {
/// any).
pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
- /// Used exclusively to reduce cost of advanced evaluation used for
- /// more helpful diagnostics.
- pub(super) in_tail_expr: bool,
-
/// First span of a return site that we find. Used in error messages.
pub(super) ret_coercion_span: Cell<Option<Span>>,
pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>,
- pub(super) ps: Cell<UnsafetyState>,
-
/// Whether the last checked node generates a divergence (e.g.,
/// `return` will set this to `Always`). In general, when entering
/// an expression or other node in the tree, the initial value
@@ -112,21 +107,11 @@ pub struct FnCtxt<'a, 'tcx> {
/// the diverges flag is set to something other than `Maybe`.
pub(super) diverges: Cell<Diverges>,
- /// Whether any child nodes have any type errors.
- pub(super) has_errors: Cell<bool>,
-
pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
pub(super) inh: &'a Inherited<'tcx>,
- /// True if the function or closure's return type is known before
- /// entering the function/closure, i.e. if the return type is
- /// either given explicitly or inferred from, say, an `Fn*` trait
- /// bound. Used for diagnostic purposes only.
- pub(super) return_type_pre_known: bool,
-
- /// True if the return type has an Opaque type
- pub(super) return_type_has_opaque: bool,
+ pub(super) fallback_has_occurred: Cell<bool>,
}
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -140,19 +125,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
param_env,
err_count_on_creation: inh.tcx.sess.err_count(),
ret_coercion: None,
- in_tail_expr: false,
ret_coercion_span: Cell::new(None),
resume_yield_tys: None,
- ps: Cell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),
diverges: Cell::new(Diverges::Maybe),
- has_errors: Cell::new(false),
enclosing_breakables: RefCell::new(EnclosingBreakables {
stack: Vec::new(),
by_id: Default::default(),
}),
inh,
- return_type_pre_known: true,
- return_type_has_opaque: false,
+ fallback_has_occurred: Cell::new(false),
}
}
@@ -174,7 +155,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
///
/// [`InferCtxt::err_ctxt`]: infer::InferCtxt::err_ctxt
pub fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> {
- TypeErrCtxt { infcx: &self.infcx, typeck_results: Some(self.typeck_results.borrow()) }
+ TypeErrCtxt {
+ infcx: &self.infcx,
+ typeck_results: Some(self.typeck_results.borrow()),
+ fallback_has_occurred: self.fallback_has_occurred.get(),
+ normalize_fn_sig: Box::new(|fn_sig| {
+ if fn_sig.has_escaping_bound_vars() {
+ return fn_sig;
+ }
+ self.probe(|_| {
+ let ocx = ObligationCtxt::new_in_snapshot(self);
+ let normalized_fn_sig =
+ 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() {
+ return normalized_fn_sig;
+ }
+ }
+ fn_sig
+ })
+ }),
+ }
}
pub fn errors_reported_since_creation(&self) -> bool {
@@ -194,8 +196,8 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
self.tcx
}
- fn item_def_id(&self) -> Option<DefId> {
- None
+ fn item_def_id(&self) -> DefId {
+ self.body_id.owner.to_def_id()
}
fn get_type_parameter_bounds(
@@ -213,7 +215,9 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
predicates: tcx.arena.alloc_from_iter(
self.param_env.caller_bounds().iter().filter_map(|predicate| {
match predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(data) if data.self_ty().is_param(index) => {
+ ty::PredicateKind::Clause(ty::Clause::Trait(data))
+ if data.self_ty().is_param(index) =>
+ {
// HACK(eddyb) should get the original `Span`.
let span = tcx.def_span(def_id);
Some((predicate, span))
@@ -298,12 +302,12 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
if ty.has_escaping_bound_vars() {
ty // FIXME: normalization and escaping regions
} else {
- self.normalize_associated_types_in(span, ty)
+ self.normalize(span, ty)
}
}
- fn set_tainted_by_errors(&self) {
- self.infcx.set_tainted_by_errors()
+ fn set_tainted_by_errors(&self, e: ErrorGuaranteed) {
+ self.infcx.set_tainted_by_errors(e)
}
fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 4db9c56f9..4f92477b5 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -10,24 +10,35 @@ use rustc_hir::{
Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
};
use rustc_hir_analysis::astconv::AstConv;
-use rustc_infer::infer::{self, TyCtxtInferExt};
+use rustc_infer::infer;
use rustc_infer::traits::{self, StatementAsExpression};
use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::{self, Binder, IsSuggestable, ToPredicate, Ty};
+use rustc_middle::ty::{self, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty};
use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::DefIdOrName;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
+use rustc_trait_selection::traits::NormalizeExt;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+ pub(crate) fn body_fn_sig(&self) -> Option<ty::FnSig<'tcx>> {
+ self.typeck_results
+ .borrow()
+ .liberated_fn_sigs()
+ .get(self.tcx.hir().get_parent_node(self.body_id))
+ .copied()
+ }
+
pub(in super::super) fn suggest_semicolon_at_end(&self, span: Span, err: &mut Diagnostic) {
+ // This suggestion is incorrect for
+ // fn foo() -> bool { match () { () => true } || match () { () => true } }
err.span_suggestion_short(
span.shrink_to_hi(),
"consider using a semicolon here",
";",
- Applicability::MachineApplicable,
+ Applicability::MaybeIncorrect,
);
}
@@ -165,7 +176,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
ty::Opaque(def_id, substs) => {
self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
- if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder()
+ if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
&& Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
// args tuple will always be substs[1]
&& let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
@@ -200,7 +211,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::Param(param) => {
let def_id = self.tcx.generics_of(self.body_id.owner).type_param(&param, self.tcx).def_id;
self.tcx.predicates_of(self.body_id.owner).predicates.iter().find_map(|(pred, _)| {
- if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder()
+ if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
&& Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
&& proj.projection_ty.self_ty() == found
// args tuple will always be substs[1]
@@ -237,7 +248,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// implied by wf, but also because that would possibly result in
// erroneous errors later on.
let infer::InferOk { value: output, obligations: _ } =
- self.normalize_associated_types_in_as_infer_ok(expr.span, output);
+ self.at(&self.misc(expr.span), self.param_env).normalize(output);
if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) }
}
@@ -337,8 +348,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
if annotation {
let suggest_annotation = match expr.peel_drop_temps().kind {
- hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, _) => "&",
- hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, _) => "&mut ",
+ hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mutbl, _) => mutbl.ref_prefix_str(),
_ => return true,
};
let mut tuple_indexes = Vec::new();
@@ -366,7 +376,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let annotation_span = ty.span;
err.span_suggestion(
annotation_span.with_hi(annotation_span.lo()),
- format!("alternatively, consider changing the type annotation"),
+ "alternatively, consider changing the type annotation",
suggest_annotation,
Applicability::MaybeIncorrect,
);
@@ -456,7 +466,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ref_cnt += 1;
}
if let ty::Adt(adt, _) = peeled.kind()
- && self.tcx.is_diagnostic_item(sym::String, adt.did())
+ && Some(adt.did()) == self.tcx.lang_items().string()
{
err.span_suggestion_verbose(
expr.span.shrink_to_hi(),
@@ -752,7 +762,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
debug!("suggest_missing_return_type: expected type {:?}", ty);
let bound_vars = self.tcx.late_bound_vars(fn_id);
let ty = Binder::bind_with_vars(ty, bound_vars);
- let ty = self.normalize_associated_types_in(span, ty);
+ let ty = self.normalize(span, ty);
let ty = self.tcx.erase_late_bound_regions(ty);
if self.can_coerce(expected, ty) {
err.subdiagnostic(ExpectedReturnTypeLabel::Other { span, expected });
@@ -913,22 +923,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, ty);
let bound_vars = self.tcx.late_bound_vars(fn_id);
let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars));
- let ty = self.normalize_associated_types_in(expr.span, ty);
let ty = match self.tcx.asyncness(fn_id.owner) {
- hir::IsAsync::Async => {
- let infcx = self.tcx.infer_ctxt().build();
- infcx
- .get_impl_future_output_ty(ty)
- .unwrap_or_else(|| {
- span_bug!(
- fn_decl.output.span(),
- "failed to get output type of async function"
- )
- })
- .skip_binder()
- }
+ hir::IsAsync::Async => self.get_impl_future_output_ty(ty).unwrap_or_else(|| {
+ span_bug!(fn_decl.output.span(), "failed to get output type of async function")
+ }),
hir::IsAsync::NotAsync => ty,
};
+ let ty = self.normalize(expr.span, ty);
if self.can_coerce(found, ty) {
err.multipart_suggestion(
"you might have meant to return this value",
@@ -1082,14 +1083,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some(into_def_id) = self.tcx.get_diagnostic_item(sym::Into)
&& self.predicate_must_hold_modulo_regions(&traits::Obligation::new(
+ self.tcx,
self.misc(expr.span),
self.param_env,
- ty::Binder::dummy(ty::TraitRef {
- def_id: into_def_id,
- substs: self.tcx.mk_substs_trait(expr_ty, &[expected_ty.into()]),
- })
- .to_poly_trait_predicate()
- .to_predicate(self.tcx),
+ ty::Binder::dummy(self.tcx.mk_trait_ref(
+ into_def_id,
+ [expr_ty, expected_ty]
+ )),
))
{
let sugg = if expr.precedence().order() >= PREC_POSTFIX {
@@ -1108,6 +1108,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
false
}
+ /// When expecting a `bool` and finding an `Option`, suggests using `let Some(..)` or `.is_some()`
+ pub(crate) fn suggest_option_to_bool(
+ &self,
+ diag: &mut Diagnostic,
+ expr: &hir::Expr<'_>,
+ expr_ty: Ty<'tcx>,
+ expected_ty: Ty<'tcx>,
+ ) -> bool {
+ if !expected_ty.is_bool() {
+ return false;
+ }
+
+ let ty::Adt(def, _) = expr_ty.peel_refs().kind() else { return false; };
+ if !self.tcx.is_diagnostic_item(sym::Option, def.did()) {
+ return false;
+ }
+
+ let hir = self.tcx.hir();
+ let cond_parent = hir.parent_iter(expr.hir_id).skip_while(|(_, node)| {
+ matches!(node, hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(op, _, _), .. }) if op.node == hir::BinOpKind::And)
+ }).next();
+ // Don't suggest:
+ // `let Some(_) = a.is_some() && b`
+ // ++++++++++
+ // since the user probably just misunderstood how `let else`
+ // and `&&` work together.
+ if let Some((_, hir::Node::Local(local))) = cond_parent
+ && let hir::PatKind::Path(qpath) | hir::PatKind::TupleStruct(qpath, _, _) = &local.pat.kind
+ && let hir::QPath::Resolved(None, path) = qpath
+ && let Some(did) = path.res.opt_def_id()
+ .and_then(|did| self.tcx.opt_parent(did))
+ .and_then(|did| self.tcx.opt_parent(did))
+ && self.tcx.is_diagnostic_item(sym::Option, did)
+ {
+ return false;
+ }
+
+ diag.span_suggestion(
+ expr.span.shrink_to_hi(),
+ "use `Option::is_some` to test if the `Option` has a value",
+ ".is_some()",
+ Applicability::MachineApplicable,
+ );
+
+ true
+ }
+
/// Suggest wrapping the block in square brackets instead of curly braces
/// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`.
pub(crate) fn suggest_block_to_brackets(
@@ -1149,6 +1196,48 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
+ #[instrument(skip(self, err))]
+ pub(crate) fn suggest_floating_point_literal(
+ &self,
+ err: &mut Diagnostic,
+ expr: &hir::Expr<'_>,
+ expected_ty: Ty<'tcx>,
+ ) -> bool {
+ if !expected_ty.is_floating_point() {
+ return false;
+ }
+ match expr.kind {
+ ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), [start, end], _) => {
+ err.span_suggestion_verbose(
+ start.span.shrink_to_hi().with_hi(end.span.lo()),
+ "remove the unnecessary `.` operator for a floating point literal",
+ '.',
+ Applicability::MaybeIncorrect,
+ );
+ true
+ }
+ ExprKind::Struct(QPath::LangItem(LangItem::RangeFrom, ..), [start], _) => {
+ err.span_suggestion_verbose(
+ expr.span.with_lo(start.span.hi()),
+ "remove the unnecessary `.` operator for a floating point literal",
+ '.',
+ Applicability::MaybeIncorrect,
+ );
+ true
+ }
+ ExprKind::Struct(QPath::LangItem(LangItem::RangeTo, ..), [end], _) => {
+ err.span_suggestion_verbose(
+ expr.span.until(end.span),
+ "remove the unnecessary `.` operator and add an integer part for a floating point literal",
+ "0.",
+ Applicability::MaybeIncorrect,
+ );
+ true
+ }
+ _ => false,
+ }
+ }
+
fn is_loop(&self, id: hir::HirId) -> bool {
let node = self.tcx.hir().get(id);
matches!(node, Node::Expr(Expr { kind: ExprKind::Loop(..), .. }))
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 122ad7009..fd8ea1ad7 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
@@ -9,9 +9,10 @@ use hir::{
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_index::vec::IndexVec;
+use rustc_infer::infer::InferCtxt;
use rustc_middle::{
hir::map::Map,
- ty::{TyCtxt, TypeckResults},
+ ty::{ParamEnv, TyCtxt, TypeVisitable, TypeckResults},
};
use std::mem::swap;
@@ -21,20 +22,29 @@ use std::mem::swap;
/// The resulting structure still needs to be iterated to a fixed point, which
/// can be done with propagate_to_fixpoint in cfg_propagate.
pub(super) fn build_control_flow_graph<'tcx>(
- hir: Map<'tcx>,
- tcx: TyCtxt<'tcx>,
+ infcx: &InferCtxt<'tcx>,
typeck_results: &TypeckResults<'tcx>,
+ param_env: ParamEnv<'tcx>,
consumed_borrowed_places: ConsumedAndBorrowedPlaces,
body: &'tcx Body<'tcx>,
num_exprs: usize,
) -> (DropRangesBuilder, FxHashSet<HirId>) {
- let mut drop_range_visitor =
- DropRangeVisitor::new(hir, tcx, typeck_results, consumed_borrowed_places, num_exprs);
+ let mut drop_range_visitor = DropRangeVisitor::new(
+ infcx,
+ typeck_results,
+ param_env,
+ consumed_borrowed_places,
+ num_exprs,
+ );
intravisit::walk_body(&mut drop_range_visitor, body);
drop_range_visitor.drop_ranges.process_deferred_edges();
- if let Some(filename) = &tcx.sess.opts.unstable_opts.dump_drop_tracking_cfg {
- super::cfg_visualize::write_graph_to_file(&drop_range_visitor.drop_ranges, filename, tcx);
+ if let Some(filename) = &infcx.tcx.sess.opts.unstable_opts.dump_drop_tracking_cfg {
+ super::cfg_visualize::write_graph_to_file(
+ &drop_range_visitor.drop_ranges,
+ filename,
+ infcx.tcx,
+ );
}
(drop_range_visitor.drop_ranges, drop_range_visitor.places.borrowed_temporaries)
@@ -82,40 +92,44 @@ pub(super) fn build_control_flow_graph<'tcx>(
/// ```
struct DropRangeVisitor<'a, 'tcx> {
- hir: Map<'tcx>,
+ typeck_results: &'a TypeckResults<'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
+ param_env: ParamEnv<'tcx>,
places: ConsumedAndBorrowedPlaces,
drop_ranges: DropRangesBuilder,
expr_index: PostOrderId,
- tcx: TyCtxt<'tcx>,
- typeck_results: &'a TypeckResults<'tcx>,
label_stack: Vec<(Option<rustc_ast::Label>, PostOrderId)>,
}
impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
fn new(
- hir: Map<'tcx>,
- tcx: TyCtxt<'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
typeck_results: &'a TypeckResults<'tcx>,
+ param_env: ParamEnv<'tcx>,
places: ConsumedAndBorrowedPlaces,
num_exprs: usize,
) -> Self {
debug!("consumed_places: {:?}", places.consumed);
let drop_ranges = DropRangesBuilder::new(
places.consumed.iter().flat_map(|(_, places)| places.iter().cloned()),
- hir,
+ infcx.tcx.hir(),
num_exprs,
);
Self {
- hir,
+ infcx,
+ typeck_results,
+ param_env,
places,
drop_ranges,
expr_index: PostOrderId::from_u32(0),
- typeck_results,
- tcx,
label_stack: vec![],
}
}
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.infcx.tcx
+ }
+
fn record_drop(&mut self, value: TrackedValue) {
if self.places.borrowed.contains(&value) {
debug!("not marking {:?} as dropped because it is borrowed at some point", value);
@@ -137,7 +151,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
.map_or(vec![], |places| places.iter().cloned().collect());
for place in places {
trace!(?place, "consuming place");
- for_each_consumable(self.hir, place, |value| self.record_drop(value));
+ for_each_consumable(self.tcx().hir(), place, |value| self.record_drop(value));
}
}
@@ -214,10 +228,15 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
/// return.
fn handle_uninhabited_return(&mut self, expr: &Expr<'tcx>) {
let ty = self.typeck_results.expr_ty(expr);
- let ty = self.tcx.erase_regions(ty);
- let m = self.tcx.parent_module(expr.hir_id).to_def_id();
- let param_env = self.tcx.param_env(m.expect_local());
- if self.tcx.is_ty_uninhabited_from(m, ty, param_env) {
+ let ty = self.infcx.resolve_vars_if_possible(ty);
+ if ty.has_non_region_infer() {
+ self.tcx()
+ .sess
+ .delay_span_bug(expr.span, format!("could not resolve infer vars in `{ty}`"));
+ }
+ let ty = self.tcx().erase_regions(ty);
+ let m = self.tcx().parent_module(expr.hir_id).to_def_id();
+ if !ty.is_inhabited_from(self.tcx(), m, self.param_env) {
// This function will not return. We model this fact as an infinite loop.
self.drop_ranges.add_control_edge(self.expr_index + 1, self.expr_index + 1);
}
@@ -238,7 +257,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
destination: hir::Destination,
) -> Result<HirId, LoopIdError> {
destination.target_id.map(|target| {
- let node = self.hir.get(target);
+ let node = self.tcx().hir().get(target);
match node {
hir::Node::Expr(_) => target,
hir::Node::Block(b) => find_last_block_expression(b),
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 4f3bdfbe7..2abcadcc9 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
@@ -43,9 +43,9 @@ pub fn compute_drop_ranges<'a, 'tcx>(
let typeck_results = &fcx.typeck_results.borrow();
let num_exprs = fcx.tcx.region_scope_tree(def_id).body_expr_count(body.id()).unwrap_or(0);
let (mut drop_ranges, borrowed_temporaries) = build_control_flow_graph(
- fcx.tcx.hir(),
- fcx.tcx,
+ &fcx,
typeck_results,
+ fcx.param_env,
consumed_borrowed_places,
body,
num_exprs,
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
index b7dd599cd..3b1518ff7 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
@@ -13,10 +13,13 @@ use rustc_hir::def_id::DefId;
use rustc_hir::hir_id::HirIdSet;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
+use rustc_infer::infer::RegionVariableOrigin;
use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData};
-use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::fold::FnMutDelegate;
+use rustc_middle::ty::{self, BoundVariableKind, RvalueScopes, Ty, TyCtxt, TypeVisitable};
use rustc_span::symbol::sym;
use rustc_span::Span;
+use smallvec::{smallvec, SmallVec};
mod drop_ranges;
@@ -95,8 +98,8 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
expr, scope, ty, self.expr_count, yield_data.span
);
- if let Some((unresolved_type, unresolved_type_span)) =
- self.fcx.unresolved_type_vars(&ty)
+ if let Some((unresolved_term, unresolved_type_span)) =
+ self.fcx.first_unresolved_const_or_ty_var(&ty)
{
// If unresolved type isn't a ty_var then unresolved_type_span is None
let span = self
@@ -105,21 +108,22 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
// If we encounter an int/float variable, then inference fallback didn't
// finish due to some other error. Don't emit spurious additional errors.
- if let ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(_)) =
- unresolved_type.kind()
+ if let Some(unresolved_ty) = unresolved_term.ty()
+ && let ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(_)) = unresolved_ty.kind()
{
self.fcx
.tcx
.sess
- .delay_span_bug(span, &format!("Encountered var {:?}", unresolved_type));
+ .delay_span_bug(span, &format!("Encountered var {:?}", unresolved_term));
} else {
let note = format!(
"the type is part of the {} because of this {}",
- self.kind, yield_data.source
+ self.kind.descr(),
+ yield_data.source
);
self.fcx
- .need_type_info_err_in_generator(self.kind, span, unresolved_type)
+ .need_type_info_err_in_generator(self.kind, span, unresolved_term)
.span_note(yield_data.span, &*note)
.emit();
}
@@ -159,7 +163,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
expr.map(|e| e.span)
);
if let Some((unresolved_type, unresolved_type_span)) =
- self.fcx.unresolved_type_vars(&ty)
+ self.fcx.first_unresolved_const_or_ty_var(&ty)
{
debug!(
"remained unresolved_type = {:?}, unresolved_type_span: {:?}",
@@ -211,31 +215,57 @@ pub fn resolve_interior<'a, 'tcx>(
debug!("types in generator {:?}, span = {:?}", types, body.value.span);
- let mut counter = 0;
+ // We want to deduplicate if the lifetimes are the same modulo some non-informative counter.
+ // So, we need to actually do two passes: first by type to anonymize (preserving information
+ // required for diagnostics), then a second pass over all captured types to reassign disjoint
+ // region indices.
let mut captured_tys = FxHashSet::default();
let type_causes: Vec<_> = types
.into_iter()
.filter_map(|mut cause| {
- // Erase regions and canonicalize late-bound regions to deduplicate as many types as we
- // can.
- let ty = fcx.normalize_associated_types_in(cause.span, cause.ty);
- let erased = fcx.tcx.erase_regions(ty);
- if captured_tys.insert(erased) {
- // Replace all regions inside the generator interior with late bound regions.
- // Note that each region slot in the types gets a new fresh late bound region,
- // which means that none of the regions inside relate to any other, even if
- // typeck had previously found constraints that would cause them to be related.
- let folded = fcx.tcx.fold_regions(erased, |_, current_depth| {
- let br = ty::BoundRegion {
- var: ty::BoundVar::from_u32(counter),
- kind: ty::BrAnon(counter),
- };
- let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, br));
- counter += 1;
- r
- });
-
- cause.ty = folded;
+ // Replace all regions inside the generator interior with late bound regions.
+ // Note that each region slot in the types gets a new fresh late bound region,
+ // which means that none of the regions inside relate to any other, even if
+ // typeck had previously found constraints that would cause them to be related.
+
+ let mut counter = 0;
+ let mut mk_bound_region = |span| {
+ let kind = ty::BrAnon(counter, span);
+ let var = ty::BoundVar::from_u32(counter);
+ counter += 1;
+ ty::BoundRegion { var, kind }
+ };
+ let ty = fcx.normalize(cause.span, cause.ty);
+ let ty = fcx.tcx.fold_regions(ty, |region, current_depth| {
+ let br = match region.kind() {
+ ty::ReVar(vid) => {
+ let origin = fcx.region_var_origin(vid);
+ match origin {
+ RegionVariableOrigin::EarlyBoundRegion(span, _) => {
+ mk_bound_region(Some(span))
+ }
+ _ => mk_bound_region(None),
+ }
+ }
+ // FIXME: these should use `BrNamed`
+ ty::ReEarlyBound(region) => {
+ mk_bound_region(Some(fcx.tcx.def_span(region.def_id)))
+ }
+ ty::ReLateBound(_, ty::BoundRegion { kind, .. })
+ | ty::ReFree(ty::FreeRegion { bound_region: kind, .. }) => match kind {
+ ty::BoundRegionKind::BrAnon(_, span) => mk_bound_region(span),
+ ty::BoundRegionKind::BrNamed(def_id, _) => {
+ mk_bound_region(Some(fcx.tcx.def_span(def_id)))
+ }
+ ty::BoundRegionKind::BrEnv => mk_bound_region(None),
+ },
+ _ => mk_bound_region(None),
+ };
+ let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, br));
+ r
+ });
+ if captured_tys.insert(ty) {
+ cause.ty = ty;
Some(cause)
} else {
None
@@ -243,11 +273,38 @@ pub fn resolve_interior<'a, 'tcx>(
})
.collect();
+ let mut bound_vars: SmallVec<[BoundVariableKind; 4]> = smallvec![];
+ let mut counter = 0;
+ // Optimization: If there is only one captured type, then we don't actually
+ // need to fold and reindex (since the first type doesn't change).
+ let type_causes = if captured_tys.len() > 0 {
+ // Optimization: Use `replace_escaping_bound_vars_uncached` instead of
+ // `fold_regions`, since we only have late bound regions, and it skips
+ // types without bound regions.
+ fcx.tcx.replace_escaping_bound_vars_uncached(
+ type_causes,
+ FnMutDelegate {
+ regions: &mut |br| {
+ let kind = match br.kind {
+ ty::BrAnon(_, span) => ty::BrAnon(counter, span),
+ _ => br.kind,
+ };
+ let var = ty::BoundVar::from_usize(bound_vars.len());
+ bound_vars.push(ty::BoundVariableKind::Region(kind));
+ counter += 1;
+ fcx.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var, kind }))
+ },
+ types: &mut |b| bug!("unexpected bound ty in binder: {b:?}"),
+ consts: &mut |b, ty| bug!("unexpected bound ct in binder: {b:?} {ty}"),
+ },
+ )
+ } else {
+ type_causes
+ };
+
// Extract type components to build the witness type.
let type_list = fcx.tcx.mk_type_list(type_causes.iter().map(|cause| cause.ty));
- let bound_vars = fcx.tcx.mk_bound_variable_kinds(
- (0..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i))),
- );
+ let bound_vars = fcx.tcx.mk_bound_variable_kinds(bound_vars.iter());
let witness =
fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars.clone()));
@@ -486,10 +543,10 @@ fn check_must_not_suspend_ty<'tcx>(
data: SuspendCheckData<'_, 'tcx>,
) -> bool {
if ty.is_unit()
- // FIXME: should this check `is_ty_uninhabited_from`. This query is not available in this stage
+ // FIXME: should this check `Ty::is_inhabited_from`. This query is not available in this stage
// of typeck (before ReVar and RePlaceholder are removed), but may remove noise, like in
// `must_use`
- // || fcx.tcx.is_ty_uninhabited_from(fcx.tcx.parent_module(hir_id).to_def_id(), ty, fcx.param_env)
+ // || !ty.is_inhabited_from(fcx.tcx, fcx.tcx.parent_module(hir_id).to_def_id(), fcx.param_env)
{
return false;
}
@@ -510,7 +567,7 @@ fn check_must_not_suspend_ty<'tcx>(
let mut has_emitted = false;
for &(predicate, _) in fcx.tcx.explicit_item_bounds(def) {
// We only look at the `DefId`, so it is safe to skip the binder here.
- if let ty::PredicateKind::Trait(ref poly_trait_predicate) =
+ if let ty::PredicateKind::Clause(ty::Clause::Trait(ref poly_trait_predicate)) =
predicate.kind().skip_binder()
{
let def_id = poly_trait_predicate.trait_ref.def_id;
diff --git a/compiler/rustc_hir_typeck/src/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs
index 0fb7651b3..b33e7b8d6 100644
--- a/compiler/rustc_hir_typeck/src/inherited.rs
+++ b/compiler/rustc_hir_typeck/src/inherited.rs
@@ -1,21 +1,16 @@
use super::callee::DeferredCallResolution;
use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::sync::Lrc;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::HirIdMap;
use rustc_infer::infer;
use rustc_infer::infer::{DefiningAnchor, InferCtxt, InferOk, TyCtxtInferExt};
-use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::def_id::LocalDefIdMap;
use rustc_span::{self, Span};
-use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::traits::{
- self, ObligationCause, ObligationCtxt, TraitEngine, TraitEngineExt as _,
-};
+use rustc_trait_selection::traits::{self, TraitEngine, TraitEngineExt as _};
use std::cell::RefCell;
use std::ops::Deref;
@@ -38,19 +33,19 @@ pub struct Inherited<'tcx> {
pub(super) fulfillment_cx: RefCell<Box<dyn TraitEngine<'tcx>>>,
- // Some additional `Sized` obligations badly affect type inference.
- // These obligations are added in a later stage of typeck.
- // Removing these may also cause additional complications, see #101066.
+ /// Some additional `Sized` obligations badly affect type inference.
+ /// These obligations are added in a later stage of typeck.
+ /// Removing these may also cause additional complications, see #101066.
pub(super) deferred_sized_obligations:
RefCell<Vec<(Ty<'tcx>, Span, traits::ObligationCauseCode<'tcx>)>>,
- // When we process a call like `c()` where `c` is a closure type,
- // we may not have decided yet whether `c` is a `Fn`, `FnMut`, or
- // `FnOnce` closure. In that case, we defer full resolution of the
- // call until upvar inference can kick in and make the
- // decision. We keep these deferred resolutions grouped by the
- // def-id of the closure, so that once we decide, we can easily go
- // back and process them.
+ /// When we process a call like `c()` where `c` is a closure type,
+ /// we may not have decided yet whether `c` is a `Fn`, `FnMut`, or
+ /// `FnOnce` closure. In that case, we defer full resolution of the
+ /// call until upvar inference can kick in and make the
+ /// decision. We keep these deferred resolutions grouped by the
+ /// def-id of the closure, so that once we decide, we can easily go
+ /// back and process them.
pub(super) deferred_call_resolutions: RefCell<LocalDefIdMap<Vec<DeferredCallResolution<'tcx>>>>,
pub(super) deferred_cast_checks: RefCell<Vec<super::cast::CastCheck<'tcx>>>,
@@ -94,29 +89,7 @@ impl<'tcx> Inherited<'tcx> {
infcx: tcx
.infer_ctxt()
.ignoring_regions()
- .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id))
- .with_normalize_fn_sig_for_diagnostic(Lrc::new(move |infcx, fn_sig| {
- if fn_sig.has_escaping_bound_vars() {
- return fn_sig;
- }
- infcx.probe(|_| {
- let ocx = ObligationCtxt::new_in_snapshot(infcx);
- let normalized_fn_sig = ocx.normalize(
- ObligationCause::dummy(),
- // FIXME(compiler-errors): This is probably not the right param-env...
- infcx.tcx.param_env(def_id),
- fn_sig,
- );
- if ocx.select_all_or_error().is_empty() {
- let normalized_fn_sig =
- infcx.resolve_vars_if_possible(normalized_fn_sig);
- if !normalized_fn_sig.needs_infer() {
- return normalized_fn_sig;
- }
- }
- fn_sig
- })
- })),
+ .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id)),
def_id,
typeck_results: RefCell::new(ty::TypeckResults::new(hir_owner)),
}
@@ -179,35 +152,4 @@ impl<'tcx> Inherited<'tcx> {
self.register_predicates(infer_ok.obligations);
infer_ok.value
}
-
- pub(super) fn normalize_associated_types_in<T>(
- &self,
- span: Span,
- body_id: hir::HirId,
- param_env: ty::ParamEnv<'tcx>,
- value: T,
- ) -> T
- where
- T: TypeFoldable<'tcx>,
- {
- self.normalize_associated_types_in_with_cause(
- ObligationCause::misc(span, body_id),
- param_env,
- value,
- )
- }
-
- pub(super) fn normalize_associated_types_in_with_cause<T>(
- &self,
- cause: ObligationCause<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- value: T,
- ) -> T
- where
- T: TypeFoldable<'tcx>,
- {
- let ok = self.partially_normalize_associated_types_in(cause, param_env, value);
- debug!(?ok);
- self.register_infer_ok_obligations(ok)
- }
}
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
index 9812d96fc..c2dc14024 100644
--- a/compiler/rustc_hir_typeck/src/intrinsicck.rs
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -3,7 +3,7 @@ use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_index::vec::Idx;
use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
use rustc_target::abi::{Pointer, VariantIdx};
use super::FnCtxt;
@@ -46,7 +46,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let from = normalize(from);
let to = normalize(to);
trace!(?from, ?to);
-
+ if from.has_non_region_infer() || to.has_non_region_infer() {
+ tcx.sess.delay_span_bug(span, "argument to transmute has inference variables");
+ return;
+ }
// Transmutes that are only changing lifetimes are always ok.
if from == to {
return;
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 959c54866..5b2352cda 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -53,9 +53,9 @@ use crate::check::check_fn;
use crate::coercion::DynamicCoerceMany;
use crate::gather_locals::GatherLocalsVisitor;
use rustc_data_structures::unord::UnordSet;
-use rustc_errors::{struct_span_err, MultiSpan};
+use rustc_errors::{struct_span_err, DiagnosticId, ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
-use rustc_hir::def::Res;
+use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::Visitor;
use rustc_hir::{HirIdMap, Node};
use rustc_hir_analysis::astconv::AstConv;
@@ -89,38 +89,6 @@ pub struct LocalTy<'tcx> {
revealed_ty: Ty<'tcx>,
}
-#[derive(Copy, Clone)]
-pub struct UnsafetyState {
- pub def: hir::HirId,
- pub unsafety: hir::Unsafety,
- from_fn: bool,
-}
-
-impl UnsafetyState {
- pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
- UnsafetyState { def, unsafety, from_fn: true }
- }
-
- pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
- use hir::BlockCheckMode;
- match self.unsafety {
- // If this unsafe, then if the outer function was already marked as
- // unsafe we shouldn't attribute the unsafe'ness to the block. This
- // way the block can be warned about instead of ignoring this
- // extraneous block (functions are never warned about).
- hir::Unsafety::Unsafe if self.from_fn => self,
-
- unsafety => {
- let (unsafety, def) = match blk.rules {
- BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id),
- BlockCheckMode::DefaultBlock => (unsafety, self.def),
- };
- UnsafetyState { def, unsafety, from_fn: false }
- }
- }
- }
-}
-
/// If this `DefId` is a "primary tables entry", returns
/// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
///
@@ -209,6 +177,7 @@ fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::T
typeck_with_fallback(tcx, def_id, fallback)
}
+#[instrument(level = "debug", skip(tcx, fallback), ret)]
fn typeck_with_fallback<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
@@ -232,9 +201,10 @@ fn typeck_with_fallback<'tcx>(
let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
let param_env = tcx.param_env(def_id);
- let mut fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
+ let mut fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
+
+ if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() {
- let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
<dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
} else {
tcx.fn_sig(def_id)
@@ -244,15 +214,10 @@ fn typeck_with_fallback<'tcx>(
// Compute the function signature from point of view of inside the fn.
let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
- let fn_sig = inh.normalize_associated_types_in(
- body.value.span,
- body_id.hir_id,
- param_env,
- fn_sig,
- );
- check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0
+ let fn_sig = fcx.normalize(body.value.span, fn_sig);
+
+ check_fn(&mut fcx, fn_sig, decl, def_id, body, None);
} else {
- let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
let expected_type = body_ty
.and_then(|ty| match ty.kind {
hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
@@ -303,7 +268,7 @@ fn typeck_with_fallback<'tcx>(
_ => fallback(),
});
- let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type);
+ let expected_type = fcx.normalize(body.value.span, expected_type);
fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
// Gather locals in statics (because of block expressions).
@@ -312,16 +277,14 @@ fn typeck_with_fallback<'tcx>(
fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
fcx.write_ty(id, expected_type);
-
- fcx
};
- let fallback_has_occurred = fcx.type_inference_fallback();
+ fcx.type_inference_fallback();
// Even though coercion casts provide type hints, we check casts after fallback for
// backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
fcx.check_casts();
- fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
+ fcx.select_obligations_where_possible(|_| {});
// Closure and generator analysis may run after fallback
// because they don't constrain other type variables.
@@ -343,7 +306,7 @@ fn typeck_with_fallback<'tcx>(
fcx.select_all_obligations_or_error();
- if !fcx.infcx.is_tainted_by_errors() {
+ if let None = fcx.infcx.tainted_by_errors() {
fcx.check_transmutes();
}
@@ -427,16 +390,33 @@ impl<'tcx> EnclosingBreakables<'tcx> {
}
}
-fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'_>, span: Span) {
- struct_span_err!(
- tcx.sess,
+fn report_unexpected_variant_res(
+ tcx: TyCtxt<'_>,
+ res: Res,
+ qpath: &hir::QPath<'_>,
+ span: Span,
+ err_code: &str,
+ expected: &str,
+) -> ErrorGuaranteed {
+ let res_descr = match res {
+ Res::Def(DefKind::Variant, _) => "struct variant",
+ _ => res.descr(),
+ };
+ let path_str = rustc_hir_pretty::qpath_to_string(qpath);
+ let mut err = tcx.sess.struct_span_err_with_code(
span,
- E0533,
- "expected unit struct, unit variant or constant, found {} `{}`",
- res.descr(),
- rustc_hir_pretty::qpath_to_string(qpath),
- )
- .emit();
+ format!("expected {expected}, found {res_descr} `{path_str}`"),
+ DiagnosticId::Error(err_code.into()),
+ );
+ match res {
+ Res::Def(DefKind::Fn | DefKind::AssocFn, _) if err_code == "E0164" => {
+ let patterns_url = "https://doc.rust-lang.org/book/ch18-00-patterns.html";
+ err.span_label(span, "`fn` calls are not allowed in patterns");
+ err.help(format!("for more information, visit {patterns_url}"))
+ }
+ _ => err.span_label(span, format!("not a {expected}")),
+ }
+ .emit()
}
/// Controls whether the arguments are tupled. This is used for the call
@@ -458,7 +438,7 @@ fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'
/// # fn f(x: (isize, isize)) {}
/// f((1, 2));
/// ```
-#[derive(Clone, Eq, PartialEq)]
+#[derive(Copy, Clone, Eq, PartialEq)]
enum TupleArgumentsFlag {
DontTupleArguments,
TupleArguments,
diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index 362f1c343..0b5dc946c 100644
--- a/compiler/rustc_hir_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -133,7 +133,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
}
fn is_tainted_by_errors(&self) -> bool {
- self.infcx.is_tainted_by_errors()
+ self.infcx.tainted_by_errors().is_some()
}
fn resolve_type_vars_or_error(
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index be4ea9986..03d0e7926 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -106,7 +106,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
// traits, no trait system method can be called before this point because they
// could alter our Self-type, except for normalizing the receiver from the
// signature (which is also done during probing).
- let method_sig_rcvr = self.normalize_associated_types_in(self.span, method_sig.inputs()[0]);
+ let method_sig_rcvr = self.normalize(self.span, method_sig.inputs()[0]);
debug!(
"confirm: self_ty={:?} method_sig_rcvr={:?} method_sig={:?} method_predicates={:?}",
self_ty, method_sig_rcvr, method_sig, method_predicates
@@ -114,7 +114,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
self.unify_receivers(self_ty, method_sig_rcvr, &pick, all_substs);
let (method_sig, method_predicates) =
- self.normalize_associated_types_in(self.span, (method_sig, method_predicates));
+ self.normalize(self.span, (method_sig, method_predicates));
let method_sig = ty::Binder::dummy(method_sig);
// Make sure nobody calls `drop()` explicitly.
@@ -151,8 +151,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
) -> Ty<'tcx> {
// Commit the autoderefs by calling `autoderef` again, but this
// time writing the results into the various typeck results.
- let mut autoderef =
- self.autoderef_overloaded_span(self.span, unadjusted_self_ty, self.call_expr.span);
+ let mut autoderef = self.autoderef(self.call_expr.span, unadjusted_self_ty);
let Some((ty, n)) = autoderef.nth(pick.autoderefs) else {
return self.tcx.ty_error_with_message(
rustc_span::DUMMY_SP,
@@ -171,14 +170,11 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
let base_ty = target;
target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl, ty: target });
- let mutbl = match mutbl {
- hir::Mutability::Not => AutoBorrowMutability::Not,
- hir::Mutability::Mut => AutoBorrowMutability::Mut {
- // Method call receivers are the primary use case
- // for two-phase borrows.
- allow_two_phase_borrow: AllowTwoPhase::Yes,
- },
- };
+
+ // Method call receivers are the primary use case
+ // for two-phase borrows.
+ let mutbl = AutoBorrowMutability::new(mutbl, AllowTwoPhase::Yes);
+
adjustments.push(Adjustment {
kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
target,
@@ -203,7 +199,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
Some(probe::AutorefOrPtrAdjustment::ToConstPtr) => {
target = match target.kind() {
&ty::RawPtr(ty::TypeAndMut { ty, mutbl }) => {
- assert_eq!(mutbl, hir::Mutability::Mut);
+ assert!(mutbl.is_mut());
self.tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty })
}
other => panic!("Cannot adjust receiver type {:?} to const ptr", other),
@@ -532,7 +528,9 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
traits::elaborate_predicates(self.tcx, predicates.predicates.iter().copied())
// We don't care about regions here.
.filter_map(|obligation| match obligation.predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(trait_pred) if trait_pred.def_id() == sized_def_id => {
+ ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred))
+ if trait_pred.def_id() == sized_def_id =>
+ {
let span = iter::zip(&predicates.predicates, &predicates.spans)
.find_map(
|(p, span)| {
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index a1278edef..a2ca5c3b7 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -10,6 +10,7 @@ mod suggest;
pub use self::suggest::SelfSource;
pub use self::MethodError::*;
+use crate::errors::OpMethodGenericParams;
use crate::{Expectation, FnCtxt};
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, Diagnostic};
@@ -19,11 +20,11 @@ use rustc_hir::def_id::DefId;
use rustc_infer::infer::{self, InferOk};
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
-use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TypeVisitable};
+use rustc_middle::ty::{self, GenericParamDefKind, Ty, TypeVisitable};
use rustc_span::symbol::Ident;
use rustc_span::Span;
-use rustc_trait_selection::traits;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
+use rustc_trait_selection::traits::{self, NormalizeExt};
use self::probe::{IsSuggestion, ProbeScope};
@@ -55,8 +56,7 @@ pub enum MethodError<'tcx> {
// not-in-scope traits which may work.
PrivateMatch(DefKind, DefId, Vec<DefId>),
- // Found a `Self: Sized` bound where `Self` is a trait object, also the caller may have
- // forgotten to import a trait.
+ // Found a `Self: Sized` bound where `Self` is a trait object.
IllegalSizedBound(Vec<DefId>, bool, Span),
// Found a match, but the return type is wrong
@@ -93,17 +93,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
call_expr_id: hir::HirId,
allow_private: bool,
) -> bool {
- let mode = probe::Mode::MethodCall;
match self.probe_for_name(
- method_name.span,
- mode,
+ probe::Mode::MethodCall,
method_name,
IsSuggestion(false),
self_ty,
call_expr_id,
ProbeScope::TraitsInScope,
) {
- Ok(..) => true,
+ Ok(pick) => {
+ pick.maybe_emit_unstable_name_collision_hint(
+ self.tcx,
+ method_name.span,
+ call_expr_id,
+ );
+ true
+ }
Err(NoMatch(..)) => false,
Err(Ambiguity(..)) => true,
Err(PrivateMatch(..)) => allow_private,
@@ -125,10 +130,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) {
let params = self
.probe_for_name(
- method_name.span,
probe::Mode::MethodCall,
method_name,
- IsSuggestion(false),
+ IsSuggestion(true),
self_ty,
call_expr.hir_id,
ProbeScope::TraitsInScope,
@@ -175,7 +179,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
args: &'tcx [hir::Expr<'tcx>],
) -> Result<MethodCallee<'tcx>, MethodError<'tcx>> {
let pick =
- self.lookup_probe(span, segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?;
+ self.lookup_probe(segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?;
self.lint_dot_call_from_2018(self_ty, segment, span, call_expr, self_expr, &pick, args);
@@ -200,13 +204,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.mk_ref(*region, ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() });
// We probe again to see if there might be a borrow mutability discrepancy.
match self.lookup_probe(
- span,
segment.ident,
trait_type,
call_expr,
ProbeScope::TraitsInScope,
) {
- Ok(ref new_pick) if *new_pick != pick => {
+ Ok(ref new_pick) if pick.differs_from(new_pick) => {
needs_mut = true;
}
_ => {}
@@ -214,29 +217,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
// We probe again, taking all traits into account (not only those in scope).
- let mut candidates = match self.lookup_probe(
- span,
- segment.ident,
- self_ty,
- call_expr,
- ProbeScope::AllTraits,
- ) {
- // If we find a different result the caller probably forgot to import a trait.
- Ok(ref new_pick) if *new_pick != pick => vec![new_pick.item.container_id(self.tcx)],
- Err(Ambiguity(ref sources)) => sources
- .iter()
- .filter_map(|source| {
- match *source {
- // Note: this cannot come from an inherent impl,
- // because the first probing succeeded.
- CandidateSource::Impl(def) => self.tcx.trait_id_of_impl(def),
- CandidateSource::Trait(_) => None,
- }
- })
- .collect(),
- _ => Vec::new(),
- };
- candidates.retain(|candidate| *candidate != self.tcx.parent(result.callee.def_id));
+ let candidates =
+ match self.lookup_probe(segment.ident, self_ty, call_expr, ProbeScope::AllTraits) {
+ // If we find a different result the caller probably forgot to import a trait.
+ Ok(ref new_pick) if pick.differs_from(new_pick) => {
+ vec![new_pick.item.container_id(self.tcx)]
+ }
+ Err(Ambiguity(ref sources)) => sources
+ .iter()
+ .filter_map(|source| {
+ match *source {
+ // Note: this cannot come from an inherent impl,
+ // because the first probing succeeded.
+ CandidateSource::Impl(def) => self.tcx.trait_id_of_impl(def),
+ CandidateSource::Trait(_) => None,
+ }
+ })
+ .collect(),
+ _ => Vec::new(),
+ };
return Err(IllegalSizedBound(candidates, needs_mut, span));
}
@@ -247,23 +246,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
#[instrument(level = "debug", skip(self, call_expr))]
pub fn lookup_probe(
&self,
- span: Span,
method_name: Ident,
self_ty: Ty<'tcx>,
call_expr: &'tcx hir::Expr<'tcx>,
scope: ProbeScope,
) -> probe::PickResult<'tcx> {
- let mode = probe::Mode::MethodCall;
- let self_ty = self.resolve_vars_if_possible(self_ty);
- self.probe_for_name(
- span,
- mode,
+ let pick = self.probe_for_name(
+ probe::Mode::MethodCall,
method_name,
IsSuggestion(false),
self_ty,
call_expr.hir_id,
scope,
- )
+ )?;
+ pick.maybe_emit_unstable_name_collision_hint(self.tcx, method_name.span, call_expr.hir_id);
+ Ok(pick)
}
pub(super) fn obligation_for_method(
@@ -295,10 +292,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let poly_trait_ref = ty::Binder::dummy(trait_ref);
(
traits::Obligation::misc(
+ self.tcx,
span,
self.body_id,
self.param_env,
- poly_trait_ref.without_const().to_predicate(self.tcx),
+ poly_trait_ref.without_const(),
),
substs,
)
@@ -337,6 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(
traits::Obligation::new(
+ self.tcx,
traits::ObligationCause::new(
span,
self.body_id,
@@ -348,7 +347,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
},
),
self.param_env,
- poly_trait_ref.without_const().to_predicate(self.tcx),
+ poly_trait_ref,
),
substs,
)
@@ -444,7 +443,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let def_id = method_item.def_id;
let generics = tcx.generics_of(def_id);
- assert_eq!(generics.params.len(), 0);
+
+ if generics.params.len() != 0 {
+ tcx.sess.emit_fatal(OpMethodGenericParams {
+ span: tcx.def_span(method_item.def_id),
+ method_name: m_name.to_string(),
+ });
+ }
debug!("lookup_in_trait_adjusted: method_item={:?}", method_item);
let mut obligations = vec![];
@@ -459,11 +464,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let fn_sig = fn_sig.subst(self.tcx, substs);
let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig);
- let InferOk { value, obligations: o } = if is_op {
- self.normalize_op_associated_types_in_as_infer_ok(span, fn_sig, opt_input_expr)
+ let cause = if is_op {
+ ObligationCause::new(
+ span,
+ self.body_id,
+ traits::BinOp {
+ rhs_span: opt_input_expr.map(|expr| expr.span),
+ is_lit: opt_input_expr
+ .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
+ output_ty: None,
+ },
+ )
} else {
- self.normalize_associated_types_in_as_infer_ok(span, fn_sig)
+ traits::ObligationCause::misc(span, self.body_id)
};
+
+ let InferOk { value, obligations: o } = self.at(&cause, self.param_env).normalize(fn_sig);
let fn_sig = {
obligations.extend(o);
value
@@ -479,11 +495,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// any late-bound regions appearing in its bounds.
let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, substs);
- let InferOk { value, obligations: o } = if is_op {
- self.normalize_op_associated_types_in_as_infer_ok(span, bounds, opt_input_expr)
- } else {
- self.normalize_associated_types_in_as_infer_ok(span, bounds)
- };
+ let InferOk { value, obligations: o } = self.at(&cause, self.param_env).normalize(bounds);
let bounds = {
obligations.extend(o);
value
@@ -491,20 +503,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
assert!(!bounds.has_escaping_bound_vars());
- let cause = if is_op {
- ObligationCause::new(
- span,
- self.body_id,
- traits::BinOp {
- rhs_span: opt_input_expr.map(|expr| expr.span),
- is_lit: opt_input_expr
- .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
- output_ty: None,
- },
- )
- } else {
- traits::ObligationCause::misc(span, self.body_id)
- };
let predicates_cause = cause.clone();
obligations.extend(traits::predicates_for_generics(
move |_, _| predicates_cause.clone(),
@@ -519,9 +517,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
method_ty, obligation
);
obligations.push(traits::Obligation::new(
+ tcx,
cause,
self.param_env,
- ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())).to_predicate(tcx),
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())),
));
let callee = MethodCallee { def_id, substs, sig: fn_sig };
@@ -559,6 +558,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let tcx = self.tcx;
// Check if we have an enum variant.
+ let mut struct_variant = None;
if let ty::Adt(adt_def, _) = self_ty.kind() {
if adt_def.is_enum() {
let variant_def = adt_def
@@ -566,29 +566,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.iter()
.find(|vd| tcx.hygienic_eq(method_name, vd.ident(tcx), adt_def.did()));
if let Some(variant_def) = variant_def {
- // Braced variants generate unusable names in value namespace (reserved for
- // possible future use), so variants resolved as associated items may refer to
- // them as well. It's ok to use the variant's id as a ctor id since an
- // error will be reported on any use of such resolution anyway.
- let ctor_def_id = variant_def.ctor_def_id.unwrap_or(variant_def.def_id);
- tcx.check_stability(ctor_def_id, Some(expr_id), span, Some(method_name.span));
- return Ok((
- DefKind::Ctor(CtorOf::Variant, variant_def.ctor_kind),
- ctor_def_id,
- ));
+ if let Some((ctor_kind, ctor_def_id)) = variant_def.ctor {
+ tcx.check_stability(
+ ctor_def_id,
+ Some(expr_id),
+ span,
+ Some(method_name.span),
+ );
+ return Ok((DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id));
+ } else {
+ struct_variant = Some((DefKind::Variant, variant_def.def_id));
+ }
}
}
}
let pick = self.probe_for_name(
- span,
probe::Mode::Path,
method_name,
IsSuggestion(false),
self_ty,
expr_id,
ProbeScope::TraitsInScope,
- )?;
+ );
+ let pick = match (pick, struct_variant) {
+ // Fall back to a resolution that will produce an error later.
+ (Err(_), Some(res)) => return Ok(res),
+ (pick, _) => pick?,
+ };
+
+ pick.maybe_emit_unstable_name_collision_hint(self.tcx, span, expr_id);
self.lint_fully_qualified_call_from_2018(
span,
diff --git a/compiler/rustc_hir_typeck/src/method/prelude2021.rs b/compiler/rustc_hir_typeck/src/method/prelude2021.rs
index 3c98a2aa3..dea14dd93 100644
--- a/compiler/rustc_hir_typeck/src/method/prelude2021.rs
+++ b/compiler/rustc_hir_typeck/src/method/prelude2021.rs
@@ -5,10 +5,9 @@ use crate::{
use hir::def_id::DefId;
use hir::HirId;
use hir::ItemKind;
-use rustc_ast::Mutability;
use rustc_errors::Applicability;
use rustc_hir as hir;
-use rustc_middle::ty::subst::InternalSubsts;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::ty::{Adt, Array, Ref, Ty};
use rustc_session::lint::builtin::RUST_2021_PRELUDE_COLLISIONS;
use rustc_span::symbol::kw::{Empty, Underscore};
@@ -88,14 +87,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let derefs = "*".repeat(pick.autoderefs);
let autoref = match pick.autoref_or_ptr_adjustment {
- Some(probe::AutorefOrPtrAdjustment::Autoref {
- mutbl: Mutability::Mut,
- ..
- }) => "&mut ",
- Some(probe::AutorefOrPtrAdjustment::Autoref {
- mutbl: Mutability::Not,
- ..
- }) => "&",
+ Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, .. }) => {
+ mutbl.ref_prefix_str()
+ }
Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
};
if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span)
@@ -227,14 +221,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If we know it does not, we don't need to warn.
if method_name.name == sym::from_iter {
if let Some(trait_def_id) = self.tcx.get_diagnostic_item(sym::FromIterator) {
+ let any_type = self.infcx.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::MiscVariable,
+ span,
+ });
if !self
.infcx
- .type_implements_trait(
- trait_def_id,
- self_ty,
- InternalSubsts::empty(),
- self.param_env,
- )
+ .type_implements_trait(trait_def_id, [self_ty, any_type], self.param_env)
.may_apply()
{
return;
@@ -387,8 +380,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let derefs = "*".repeat(pick.autoderefs);
let autoref = match pick.autoref_or_ptr_adjustment {
- Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl: Mutability::Mut, .. }) => "&mut ",
- Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl: Mutability::Not, .. }) => "&",
+ Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, .. }) => mutbl.ref_prefix_str(),
Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
};
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 28aa2302f..ae299cc9d 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -9,7 +9,6 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
-use rustc_hir::def::Namespace;
use rustc_infer::infer::canonical::OriginalQueryValues;
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -17,8 +16,10 @@ use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use rustc_middle::middle::stability;
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
+use rustc_middle::ty::AssocItem;
use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitable};
+use rustc_middle::ty::ToPredicate;
+use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFoldable, TypeVisitable};
use rustc_middle::ty::{InternalSubsts, SubstsRef};
use rustc_session::lint;
use rustc_span::def_id::DefId;
@@ -35,6 +36,7 @@ use rustc_trait_selection::traits::query::method_autoderef::{
CandidateStep, MethodAutoderefStepsResult,
};
use rustc_trait_selection::traits::query::CanonicalTyGoal;
+use rustc_trait_selection::traits::NormalizeExt;
use rustc_trait_selection::traits::{self, ObligationCause};
use std::cmp::max;
use std::iter;
@@ -83,8 +85,6 @@ struct ProbeContext<'a, 'tcx> {
unsatisfied_predicates:
Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>,
- is_suggestion: IsSuggestion,
-
scope_expr_id: hir::HirId,
}
@@ -193,7 +193,7 @@ impl AutorefOrPtrAdjustment {
}
}
-#[derive(Debug, PartialEq, Clone)]
+#[derive(Debug, Clone)]
pub struct Pick<'tcx> {
pub item: ty::AssocItem,
pub kind: PickKind<'tcx>,
@@ -209,6 +209,9 @@ pub struct Pick<'tcx> {
/// `*mut T`, convert it to `*const T`.
pub autoref_or_ptr_adjustment: Option<AutorefOrPtrAdjustment>,
pub self_ty: Ty<'tcx>,
+
+ /// Unstable candidates alongside the stable ones.
+ unstable_candidates: Vec<(Candidate<'tcx>, Symbol)>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
@@ -298,7 +301,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
#[instrument(level = "debug", skip(self))]
pub fn probe_for_name(
&self,
- span: Span,
mode: Mode,
item_name: Ident,
is_suggestion: IsSuggestion,
@@ -307,7 +309,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
scope: ProbeScope,
) -> PickResult<'tcx> {
self.probe_op(
- span,
+ item_name.span,
mode,
Some(item_name),
None,
@@ -340,10 +342,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&mut orig_values,
);
- let steps = if mode == Mode::MethodCall {
- self.tcx.method_autoderef_steps(param_env_and_self_ty)
- } else {
- self.probe(|_| {
+ let steps = match mode {
+ Mode::MethodCall => self.tcx.method_autoderef_steps(param_env_and_self_ty),
+ Mode::Path => self.probe(|_| {
// Mode::Path - the deref steps is "trivial". This turns
// our CanonicalQuery into a "trivial" QueryResponse. This
// is a bit inefficient, but I don't think that writing
@@ -372,7 +373,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
opt_bad_ty: None,
reached_recursion_limit: false,
}
- })
+ }),
};
// If our autoderef loop had reached the recursion limit,
@@ -446,7 +447,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return_type,
orig_values,
steps.steps,
- is_suggestion,
scope_expr_id,
);
@@ -475,10 +475,9 @@ fn method_autoderef_steps<'tcx>(
let (ref infcx, goal, inference_vars) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &goal);
let ParamEnvAnd { param_env, value: self_ty } = goal;
- let mut autoderef =
- Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty, DUMMY_SP)
- .include_raw_pointers()
- .silence_errors();
+ let mut autoderef = Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty)
+ .include_raw_pointers()
+ .silence_errors();
let mut reached_raw_pointer = false;
let mut steps: Vec<_> = autoderef
.by_ref()
@@ -542,7 +541,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
return_type: Option<Ty<'tcx>>,
orig_steps_var_values: OriginalQueryValues<'tcx>,
steps: &'tcx [CandidateStep<'tcx>],
- is_suggestion: IsSuggestion,
scope_expr_id: hir::HirId,
) -> ProbeContext<'a, 'tcx> {
ProbeContext {
@@ -560,7 +558,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
allow_similar_names: false,
private_candidate: None,
unsatisfied_predicates: Vec::new(),
- is_suggestion,
scope_expr_id,
}
}
@@ -718,9 +715,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// maybe shouldn't include `Param`s, but rather fresh variables or be canonicalized,
// see issue #89650
let cause = traits::ObligationCause::misc(self.span, self.body_id);
- let selcx = &mut traits::SelectionContext::new(self.fcx);
- let traits::Normalized { value: xform_self_ty, obligations } =
- traits::normalize(selcx, self.param_env, cause, xform_self_ty);
+ let InferOk { value: xform_self_ty, obligations } =
+ self.fcx.at(&cause, self.param_env).normalize(xform_self_ty);
+
debug!(
"assemble_inherent_impl_probe after normalization: xform_self_ty = {:?}/{:?}",
xform_self_ty, xform_ret_ty
@@ -787,7 +784,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| {
let bound_predicate = predicate.kind();
match bound_predicate.skip_binder() {
- ty::PredicateKind::Trait(trait_predicate) => {
+ ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
match *trait_predicate.trait_ref.self_ty().kind() {
ty::Param(p) if p == param_ty => {
Some(bound_predicate.rebind(trait_predicate.trait_ref))
@@ -797,14 +794,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
- | ty::PredicateKind::Projection(..)
- | ty::PredicateKind::RegionOutlives(..)
+ | ty::PredicateKind::Clause(ty::Clause::Projection(..))
+ | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))
| ty::PredicateKind::WellFormed(..)
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
- | ty::PredicateKind::TypeOutlives(..)
+ | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::Ambiguous
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
}
});
@@ -882,7 +880,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}
- pub fn matches_return_type(
+ fn matches_return_type(
&self,
method: &ty::AssocItem,
self_ty: Option<Ty<'tcx>>,
@@ -1019,7 +1017,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let out_of_scope_traits = match self.pick_core() {
Some(Ok(p)) => vec![p.item.container_id(self.tcx)],
- //Some(Ok(p)) => p.iter().map(|p| p.item.container().id()).collect(),
Some(Err(MethodError::Ambiguity(v))) => v
.into_iter()
.map(|source| match source {
@@ -1054,26 +1051,17 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
fn pick_core(&mut self) -> Option<PickResult<'tcx>> {
- let mut unstable_candidates = Vec::new();
- let pick = self.pick_all_method(Some(&mut unstable_candidates));
+ let pick = self.pick_all_method(Some(&mut vec![]));
// In this case unstable picking is done by `pick_method`.
if !self.tcx.sess.opts.unstable_opts.pick_stable_methods_before_any_unstable {
return pick;
}
- match pick {
- // Emit a lint if there are unstable candidates alongside the stable ones.
- //
- // We suppress warning if we're picking the method only because it is a
- // suggestion.
- Some(Ok(ref p)) if !self.is_suggestion.0 && !unstable_candidates.is_empty() => {
- self.emit_unstable_name_collision_hint(p, &unstable_candidates);
- pick
- }
- Some(_) => pick,
- None => self.pick_all_method(None),
+ if pick.is_none() {
+ return self.pick_all_method(None);
}
+ pick
}
fn pick_all_method(
@@ -1218,7 +1206,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
debug!("pick_method_with_unstable(self_ty={})", self.ty_to_string(self_ty));
let mut possibly_unsatisfied_predicates = Vec::new();
- let mut unstable_candidates = Vec::new();
for (kind, candidates) in
&[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)]
@@ -1228,26 +1215,17 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self_ty,
candidates.iter(),
&mut possibly_unsatisfied_predicates,
- Some(&mut unstable_candidates),
+ Some(&mut vec![]),
);
- if let Some(pick) = res {
- if !self.is_suggestion.0 && !unstable_candidates.is_empty() {
- if let Ok(p) = &pick {
- // Emit a lint if there are unstable candidates alongside the stable ones.
- //
- // We suppress warning if we're picking the method only because it is a
- // suggestion.
- self.emit_unstable_name_collision_hint(p, &unstable_candidates);
- }
- }
- return Some(pick);
+ if res.is_some() {
+ return res;
}
}
debug!("searching unstable candidates");
let res = self.consider_candidates(
self_ty,
- unstable_candidates.iter().map(|(c, _)| c),
+ self.inherent_candidates.iter().chain(&self.extension_candidates),
&mut possibly_unsatisfied_predicates,
None,
);
@@ -1302,7 +1280,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
Option<ty::Predicate<'tcx>>,
Option<ObligationCause<'tcx>>,
)>,
- unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
+ mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
) -> Option<PickResult<'tcx>>
where
ProbesIter: Iterator<Item = &'b Candidate<'tcx>> + Clone,
@@ -1326,7 +1304,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}
- if let Some(uc) = unstable_candidates {
+ if let Some(uc) = &mut unstable_candidates {
applicable_candidates.retain(|&(p, _)| {
if let stability::EvalResult::Deny { feature, .. } =
self.tcx.eval_stability(p.item.def_id, None, self.span, None)
@@ -1345,30 +1323,63 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
applicable_candidates.pop().map(|(probe, status)| {
if status == ProbeResult::Match {
- Ok(probe.to_unadjusted_pick(self_ty))
+ Ok(probe
+ .to_unadjusted_pick(self_ty, unstable_candidates.cloned().unwrap_or_default()))
} else {
Err(MethodError::BadReturnType)
}
})
}
+}
+
+impl<'tcx> Pick<'tcx> {
+ /// In case there were unstable name collisions, emit them as a lint.
+ /// Checks whether two picks do not refer to the same trait item for the same `Self` type.
+ /// Only useful for comparisons of picks in order to improve diagnostics.
+ /// Do not use for type checking.
+ pub fn differs_from(&self, other: &Self) -> bool {
+ let Self {
+ item:
+ AssocItem {
+ def_id,
+ name: _,
+ kind: _,
+ container: _,
+ trait_item_def_id: _,
+ fn_has_self_parameter: _,
+ },
+ kind: _,
+ import_ids: _,
+ autoderefs: _,
+ autoref_or_ptr_adjustment: _,
+ self_ty,
+ unstable_candidates: _,
+ } = *self;
+ self_ty != other.self_ty || def_id != other.item.def_id
+ }
- fn emit_unstable_name_collision_hint(
+ /// In case there were unstable name collisions, emit them as a lint.
+ pub fn maybe_emit_unstable_name_collision_hint(
&self,
- stable_pick: &Pick<'_>,
- unstable_candidates: &[(Candidate<'tcx>, Symbol)],
+ tcx: TyCtxt<'tcx>,
+ span: Span,
+ scope_expr_id: hir::HirId,
) {
- let def_kind = stable_pick.item.kind.as_def_kind();
- self.tcx.struct_span_lint_hir(
+ if self.unstable_candidates.is_empty() {
+ return;
+ }
+ let def_kind = self.item.kind.as_def_kind();
+ tcx.struct_span_lint_hir(
lint::builtin::UNSTABLE_NAME_COLLISIONS,
- self.scope_expr_id,
- self.span,
+ scope_expr_id,
+ span,
format!(
"{} {} with this name may be added to the standard library in the future",
def_kind.article(),
- def_kind.descr(stable_pick.item.def_id),
+ def_kind.descr(self.item.def_id),
),
|lint| {
- match (stable_pick.item.kind, stable_pick.item.container) {
+ match (self.item.kind, self.item.container) {
(ty::AssocKind::Fn, _) => {
// FIXME: This should be a `span_suggestion` instead of `help`
// However `self.span` only
@@ -1377,31 +1388,31 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
lint.help(&format!(
"call with fully qualified syntax `{}(...)` to keep using the current \
method",
- self.tcx.def_path_str(stable_pick.item.def_id),
+ tcx.def_path_str(self.item.def_id),
));
}
(ty::AssocKind::Const, ty::AssocItemContainer::TraitContainer) => {
- let def_id = stable_pick.item.container_id(self.tcx);
+ let def_id = self.item.container_id(tcx);
lint.span_suggestion(
- self.span,
+ span,
"use the fully qualified path to the associated const",
format!(
"<{} as {}>::{}",
- stable_pick.self_ty,
- self.tcx.def_path_str(def_id),
- stable_pick.item.name
+ self.self_ty,
+ tcx.def_path_str(def_id),
+ self.item.name
),
Applicability::MachineApplicable,
);
}
_ => {}
}
- if self.tcx.sess.is_nightly_build() {
- for (candidate, feature) in unstable_candidates {
+ if tcx.sess.is_nightly_build() {
+ for (candidate, feature) in &self.unstable_candidates {
lint.help(&format!(
"add `#![feature({})]` to the crate attributes to enable `{}`",
feature,
- self.tcx.def_path_str(candidate.item.def_id),
+ tcx.def_path_str(candidate.item.def_id),
));
}
}
@@ -1410,14 +1421,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
},
);
}
+}
+impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
fn select_trait_candidate(
&self,
trait_ref: ty::TraitRef<'tcx>,
) -> traits::SelectionResult<'tcx, traits::Selection<'tcx>> {
let cause = traits::ObligationCause::misc(self.span, self.body_id);
- let predicate = ty::Binder::dummy(trait_ref).to_poly_trait_predicate();
- let obligation = traits::Obligation::new(cause, self.param_env, predicate);
+ let predicate = ty::Binder::dummy(trait_ref);
+ let obligation = traits::Obligation::new(self.tcx, cause, self.param_env, predicate);
traits::SelectionContext::new(self).select(&obligation)
}
@@ -1476,7 +1489,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let mut xform_ret_ty = probe.xform_ret_ty;
debug!(?xform_ret_ty);
- let selcx = &mut traits::SelectionContext::new(self);
let cause = traits::ObligationCause::misc(self.span, self.body_id);
let mut parent_pred = None;
@@ -1490,10 +1502,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// `xform_ret_ty` hasn't been normalized yet, only `xform_self_ty`,
// see the reasons mentioned in the comments in `assemble_inherent_impl_probe`
// for why this is necessary
- let traits::Normalized {
+ let InferOk {
value: normalized_xform_ret_ty,
obligations: normalization_obligations,
- } = traits::normalize(selcx, self.param_env, cause.clone(), probe.xform_ret_ty);
+ } = self.fcx.at(&cause, self.param_env).normalize(probe.xform_ret_ty);
xform_ret_ty = normalized_xform_ret_ty;
debug!("xform_ret_ty after normalization: {:?}", xform_ret_ty);
@@ -1501,8 +1513,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let impl_def_id = probe.item.container_id(self.tcx);
let impl_bounds = self.tcx.predicates_of(impl_def_id);
let impl_bounds = impl_bounds.instantiate(self.tcx, substs);
- let traits::Normalized { value: impl_bounds, obligations: norm_obligations } =
- traits::normalize(selcx, self.param_env, cause.clone(), impl_bounds);
+
+ let InferOk { value: impl_bounds, obligations: norm_obligations } =
+ self.fcx.at(&cause, self.param_env).normalize(impl_bounds);
// Convert the bounds into obligations.
let impl_obligations = traits::predicates_for_generics(
@@ -1548,7 +1561,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let predicate =
ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx);
parent_pred = Some(predicate);
- let obligation = traits::Obligation::new(cause, self.param_env, predicate);
+ let obligation =
+ traits::Obligation::new(self.tcx, cause, self.param_env, predicate);
if !self.predicate_may_hold(&obligation) {
result = ProbeResult::NoMatch;
if self.probe(|_| {
@@ -1669,6 +1683,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
autoderefs: 0,
autoref_or_ptr_adjustment: None,
self_ty,
+ unstable_candidates: vec![],
})
}
@@ -1688,7 +1703,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self.return_type,
self.orig_steps_var_values.clone(),
steps,
- IsSuggestion(true),
self.scope_expr_id,
);
pcx.allow_similar_names = true;
@@ -1861,6 +1875,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self.tcx.erase_late_bound_regions(value)
}
+ /// Determine if the given associated item type is relevant in the current context.
+ fn is_relevant_kind_for_mode(&self, kind: ty::AssocKind) -> bool {
+ match (self.mode, kind) {
+ (Mode::MethodCall, ty::AssocKind::Fn) => true,
+ (Mode::Path, ty::AssocKind::Const | ty::AssocKind::Fn) => true,
+ _ => false,
+ }
+ }
+
/// Finds the method with the appropriate name (or return type, as the case may be). If
/// `allow_similar_names` is set, find methods with close-matching names.
// The length of the returned iterator is nearly always 0 or 1 and this
@@ -1873,7 +1896,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
.associated_items(def_id)
.in_definition_order()
.filter(|x| {
- if x.kind.namespace() != Namespace::ValueNS {
+ if !self.is_relevant_kind_for_mode(x.kind) {
return false;
}
match lev_distance_with_substrings(name.as_str(), x.name.as_str(), max_dist)
@@ -1887,16 +1910,26 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
} else {
self.fcx
.associated_value(def_id, name)
+ .filter(|x| self.is_relevant_kind_for_mode(x.kind))
.map_or_else(SmallVec::new, |x| SmallVec::from_buf([x]))
}
} else {
- self.tcx.associated_items(def_id).in_definition_order().copied().collect()
+ self.tcx
+ .associated_items(def_id)
+ .in_definition_order()
+ .filter(|x| self.is_relevant_kind_for_mode(x.kind))
+ .copied()
+ .collect()
}
}
}
impl<'tcx> Candidate<'tcx> {
- fn to_unadjusted_pick(&self, self_ty: Ty<'tcx>) -> Pick<'tcx> {
+ fn to_unadjusted_pick(
+ &self,
+ self_ty: Ty<'tcx>,
+ unstable_candidates: Vec<(Candidate<'tcx>, Symbol)>,
+ ) -> Pick<'tcx> {
Pick {
item: self.item,
kind: match self.kind {
@@ -1921,6 +1954,7 @@ impl<'tcx> Candidate<'tcx> {
autoderefs: 0,
autoref_or_ptr_adjustment: None,
self_ty,
+ unstable_candidates,
}
}
}
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 6c21ed902..db93cfab2 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -5,6 +5,7 @@ use crate::errors;
use crate::FnCtxt;
use rustc_ast::ast::Mutability;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::StashKey;
use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
MultiSpan,
@@ -13,27 +14,35 @@ use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
+use rustc_hir::PatKind::Binding;
+use rustc_hir::PathSegment;
use rustc_hir::{ExprKind, Node, QPath};
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::{
+ type_variable::{TypeVariableOrigin, TypeVariableOriginKind},
+ RegionVariableOrigin,
+};
+use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
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;
-use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{self, DefIdTree, GenericArgKind, Ty, TyCtxt, TypeVisitable};
use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Symbol;
use rustc_span::{lev_distance, source_map, ExpnKind, FileName, MacroKind, Span};
+use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedNote;
use rustc_trait_selection::traits::error_reporting::on_unimplemented::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::{
- FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedNote,
+ FulfillmentError, Obligation, ObligationCause, ObligationCauseCode,
};
-use std::cmp::Ordering;
-use std::iter;
-
use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope};
use super::{CandidateSource, MethodError, NoMatchData};
+use rustc_hir::intravisit::Visitor;
+use std::cmp::Ordering;
+use std::iter;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
@@ -62,22 +71,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.autoderef(span, ty).any(|(ty, _)| {
info!("check deref {:?} impl FnOnce", ty);
self.probe(|_| {
- let fn_once_substs = tcx.mk_substs_trait(
- ty,
- &[self
- .next_ty_var(TypeVariableOrigin {
+ let trait_ref = tcx.mk_trait_ref(
+ fn_once,
+ [
+ ty,
+ self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::MiscVariable,
span,
- })
- .into()],
+ }),
+ ],
);
- let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
let poly_trait_ref = ty::Binder::dummy(trait_ref);
let obligation = Obligation::misc(
+ tcx,
span,
self.body_id,
self.param_env,
- poly_trait_ref.without_const().to_predicate(tcx),
+ poly_trait_ref.without_const(),
);
self.predicate_may_hold(&obligation)
})
@@ -107,7 +117,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let report_candidates = |span: Span,
err: &mut Diagnostic,
sources: &mut Vec<CandidateSource>,
- sugg_span: Span| {
+ sugg_span: Option<Span>| {
sources.sort();
sources.dedup();
// Dynamic limit to avoid hiding just one candidate, which is silly.
@@ -168,7 +178,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
err.note(&note_str);
}
- if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
+ if let Some(sugg_span) = sugg_span
+ && let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
let path = self.tcx.def_path_str(trait_ref.def_id);
let ty = match item.kind {
@@ -217,20 +228,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_note(item_span, msg);
None
};
- let path = self.tcx.def_path_str(trait_did);
- print_disambiguation_help(
- item_name,
- args,
- err,
- path,
- rcvr_ty,
- item.kind,
- item.def_id,
- sugg_span,
- idx,
- self.tcx.sess.source_map(),
- item.fn_has_self_parameter,
- );
+ if let Some(sugg_span) = sugg_span {
+ let path = self.tcx.def_path_str(trait_did);
+ print_disambiguation_help(
+ item_name,
+ args,
+ err,
+ path,
+ rcvr_ty,
+ item.kind,
+ item.def_id,
+ sugg_span,
+ idx,
+ self.tcx.sess.source_map(),
+ item.fn_has_self_parameter,
+ );
+ }
}
}
}
@@ -248,7 +261,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match error {
MethodError::NoMatch(NoMatchData {
- static_candidates: mut static_sources,
+ mut static_candidates,
unsatisfied_predicates,
out_of_scope_traits,
lev_candidate,
@@ -256,15 +269,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}) => {
let tcx = self.tcx;
- let actual = self.resolve_vars_if_possible(rcvr_ty);
- let ty_str = self.ty_to_string(actual);
+ let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
+ let ty_str = self.ty_to_string(rcvr_ty);
let is_method = mode == Mode::MethodCall;
let item_kind = if is_method {
"method"
- } else if actual.is_enum() {
+ } else if rcvr_ty.is_enum() {
"variant or associated item"
} else {
- match (item_name.as_str().chars().next(), actual.is_fresh_ty()) {
+ match (item_name.as_str().chars().next(), rcvr_ty.is_fresh_ty()) {
(Some(name), false) if name.is_lowercase() => "function or associated item",
(Some(_), false) => "associated item",
(Some(_), true) | (None, false) => "variant or associated item",
@@ -273,24 +286,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
if self.suggest_wrapping_range_with_parens(
- tcx, actual, source, span, item_name, &ty_str,
+ tcx, rcvr_ty, source, span, item_name, &ty_str,
) || self.suggest_constraining_numerical_ty(
- tcx, actual, source, span, item_kind, item_name, &ty_str,
+ tcx, rcvr_ty, source, span, item_kind, item_name, &ty_str,
) {
return None;
}
-
span = item_name.span;
// Don't show generic arguments when the method can't be found in any implementation (#81576).
let mut ty_str_reported = ty_str.clone();
- if let ty::Adt(_, generics) = actual.kind() {
+ if let ty::Adt(_, generics) = rcvr_ty.kind() {
if generics.len() > 0 {
- let mut autoderef = self.autoderef(span, actual);
+ let mut autoderef = self.autoderef(span, rcvr_ty);
let candidate_found = autoderef.any(|(ty, _)| {
- if let ty::Adt(adt_deref, _) = ty.kind() {
+ if let ty::Adt(adt_def, _) = ty.kind() {
self.tcx
- .inherent_impls(adt_deref.did())
+ .inherent_impls(adt_def.did())
.iter()
.filter_map(|def_id| self.associated_value(*def_id, item_name))
.count()
@@ -315,16 +327,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"no {} named `{}` found for {} `{}` in the current scope",
item_kind,
item_name,
- actual.prefix_string(self.tcx),
+ rcvr_ty.prefix_string(self.tcx),
ty_str_reported,
);
- if actual.references_error() {
+ if rcvr_ty.references_error() {
err.downgrade_to_delayed_bug();
}
if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
self.suggest_await_before_method(
- &mut err, item_name, actual, cal, span,
+ &mut err, item_name, rcvr_ty, cal, span,
);
}
if let Some(span) = tcx.resolutions(()).confused_type_with_std_module.get(&span) {
@@ -335,7 +347,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Applicability::MachineApplicable,
);
}
- if let ty::RawPtr(_) = &actual.kind() {
+ if let ty::RawPtr(_) = &rcvr_ty.kind() {
err.note(
"try using `<*const T>::as_ref()` to get a reference to the \
type behind the pointer: https://doc.rust-lang.org/std/\
@@ -347,22 +359,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
- let ty_span = match actual.kind() {
- ty::Param(param_type) => {
- let generics = self.tcx.generics_of(self.body_id.owner.to_def_id());
- let type_param = generics.type_param(param_type, self.tcx);
- Some(self.tcx.def_span(type_param.def_id))
- }
+ let ty_span = match rcvr_ty.kind() {
+ ty::Param(param_type) => Some(
+ param_type.span_from_generics(self.tcx, self.body_id.owner.to_def_id()),
+ ),
ty::Adt(def, _) if def.did().is_local() => Some(tcx.def_span(def.did())),
_ => None,
};
-
if let Some(span) = ty_span {
err.span_label(
span,
format!(
"{item_kind} `{item_name}` not found for this {}",
- actual.prefix_string(self.tcx)
+ rcvr_ty.prefix_string(self.tcx)
),
);
}
@@ -374,7 +383,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.hir()
.expect_expr(self.tcx.hir().get_parent_node(rcvr_expr.hir_id));
let probe = self.lookup_probe(
- span,
item_name,
output_ty,
call_expr,
@@ -386,7 +394,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut custom_span_label = false;
- if !static_sources.is_empty() {
+ if !static_candidates.is_empty() {
err.note(
"found the following associated functions; to be used as methods, \
functions must have a `self` parameter",
@@ -394,43 +402,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_label(span, "this is an associated function, not a method");
custom_span_label = true;
}
- if static_sources.len() == 1 {
- let ty_str =
- if let Some(CandidateSource::Impl(impl_did)) = static_sources.get(0) {
- // When the "method" is resolved through dereferencing, we really want the
- // original type that has the associated function for accurate suggestions.
- // (#61411)
- let ty = tcx.at(span).type_of(*impl_did);
- match (&ty.peel_refs().kind(), &actual.peel_refs().kind()) {
- (ty::Adt(def, _), ty::Adt(def_actual, _)) if def == def_actual => {
- // Use `actual` as it will have more `substs` filled in.
- self.ty_to_value_string(actual.peel_refs())
- }
- _ => self.ty_to_value_string(ty.peel_refs()),
- }
- } else {
- self.ty_to_value_string(actual.peel_refs())
- };
- if let SelfSource::MethodCall(expr) = source {
- err.span_suggestion(
- expr.span.to(span),
- "use associated function syntax instead",
- format!("{}::{}", ty_str, item_name),
- Applicability::MachineApplicable,
- );
- } else {
- err.help(&format!("try with `{}::{}`", ty_str, item_name,));
- }
+ if static_candidates.len() == 1 {
+ self.suggest_associated_call_syntax(
+ &mut err,
+ &static_candidates,
+ rcvr_ty,
+ source,
+ item_name,
+ args,
+ sugg_span,
+ );
- report_candidates(span, &mut err, &mut static_sources, sugg_span);
- } else if static_sources.len() > 1 {
- report_candidates(span, &mut err, &mut static_sources, sugg_span);
+ report_candidates(span, &mut err, &mut static_candidates, None);
+ } else if static_candidates.len() > 1 {
+ report_candidates(span, &mut err, &mut static_candidates, Some(sugg_span));
}
let mut bound_spans = vec![];
let mut restrict_type_params = false;
let mut unsatisfied_bounds = false;
- if item_name.name == sym::count && self.is_slice_ty(actual, span) {
+ if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) {
let msg = "consider using `len` instead";
if let SelfSource::MethodCall(_expr) = source {
err.span_suggestion_short(
@@ -444,7 +435,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!("`count` is defined on `{iterator_trait}`, which `{actual}` does not implement"));
+ err.note(&format!("`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement"));
}
} else if !unsatisfied_predicates.is_empty() {
let mut type_params = FxHashMap::default();
@@ -454,7 +445,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut unimplemented_traits = FxHashMap::default();
let mut unimplemented_traits_only = true;
for (predicate, _parent_pred, cause) in &unsatisfied_predicates {
- if let (ty::PredicateKind::Trait(p), Some(cause)) =
+ if let (ty::PredicateKind::Clause(ty::Clause::Trait(p)), Some(cause)) =
(predicate.kind().skip_binder(), cause.as_ref())
{
if p.trait_ref.self_ty() != rcvr_ty {
@@ -481,7 +472,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// because of some non-Clone item being iterated over.
for (predicate, _parent_pred, _cause) in &unsatisfied_predicates {
match predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(p)
+ ty::PredicateKind::Clause(ty::Clause::Trait(p))
if unimplemented_traits.contains_key(&p.trait_ref.def_id) => {}
_ => {
unimplemented_traits_only = false;
@@ -493,27 +484,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut collect_type_param_suggestions =
|self_ty: Ty<'tcx>, parent_pred: ty::Predicate<'tcx>, obligation: &str| {
// We don't care about regions here, so it's fine to skip the binder here.
- if let (ty::Param(_), ty::PredicateKind::Trait(p)) =
+ if let (ty::Param(_), ty::PredicateKind::Clause(ty::Clause::Trait(p))) =
(self_ty.kind(), parent_pred.kind().skip_binder())
{
+ let hir = self.tcx.hir();
let node = match p.trait_ref.self_ty().kind() {
ty::Param(_) => {
// Account for `fn` items like in `issue-35677.rs` to
// suggest restricting its type params.
- let did = self.tcx.hir().body_owner_def_id(hir::BodyId {
- hir_id: self.body_id,
- });
- Some(
- self.tcx
- .hir()
- .get(self.tcx.hir().local_def_id_to_hir_id(did)),
- )
+ let parent_body =
+ hir.body_owner(hir::BodyId { hir_id: self.body_id });
+ Some(hir.get(parent_body))
+ }
+ ty::Adt(def, _) => {
+ def.did().as_local().map(|def_id| hir.get_by_def_id(def_id))
}
- ty::Adt(def, _) => def.did().as_local().map(|def_id| {
- self.tcx
- .hir()
- .get(self.tcx.hir().local_def_id_to_hir_id(def_id))
- }),
_ => None,
};
if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
@@ -562,7 +547,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut format_pred = |pred: ty::Predicate<'tcx>| {
let bound_predicate = pred.kind();
match bound_predicate.skip_binder() {
- ty::PredicateKind::Projection(pred) => {
+ ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => {
let pred = bound_predicate.rebind(pred);
// `<Foo as Iterator>::Item = String`.
let projection_ty = pred.skip_binder().projection_ty;
@@ -585,7 +570,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
Some((obligation, projection_ty.self_ty()))
}
- ty::PredicateKind::Trait(poly_trait_ref) => {
+ ty::PredicateKind::Clause(ty::Clause::Trait(poly_trait_ref)) => {
let p = poly_trait_ref.trait_ref;
let self_ty = p.self_ty();
let path = p.print_only_trait_path();
@@ -605,7 +590,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.iter()
.filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c)))
.filter_map(|(p, parent, c)| match c.code() {
- ObligationCauseCode::ImplDerivedObligation(ref data) => {
+ ObligationCauseCode::ImplDerivedObligation(data) => {
Some((&data.derived, p, parent, data.impl_def_id, data))
}
_ => None,
@@ -621,22 +606,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Unmet obligation comes from a `derive` macro, point at it once to
// avoid multiple span labels pointing at the same place.
Some(Node::Item(hir::Item {
- kind: hir::ItemKind::Trait(..),
- ident,
- ..
- })) if matches!(
- ident.span.ctxt().outer_expn_data().kind,
- ExpnKind::Macro(MacroKind::Derive, _)
- ) =>
- {
- let span = ident.span.ctxt().outer_expn_data().call_site;
- let mut spans: MultiSpan = span.into();
- spans.push_span_label(span, derive_msg);
- let entry = spanned_predicates.entry(spans);
- entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
- }
-
- Some(Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
..
})) if matches!(
@@ -659,34 +628,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
}
- // Unmet obligation coming from a `trait`.
- Some(Node::Item(hir::Item {
- kind: hir::ItemKind::Trait(..),
- ident,
- span: item_span,
- ..
- })) if !matches!(
- ident.span.ctxt().outer_expn_data().kind,
- ExpnKind::Macro(MacroKind::Derive, _)
- ) =>
- {
- if let Some(pred) = parent_p {
- // Done to add the "doesn't satisfy" `span_label`.
- let _ = format_pred(*pred);
- }
- skip_list.insert(p);
- let mut spans = if cause.span != *item_span {
- let mut spans: MultiSpan = cause.span.into();
- spans.push_span_label(cause.span, unsatisfied_msg);
- spans
- } else {
- ident.span.into()
- };
- spans.push_span_label(ident.span, "in this trait");
- let entry = spanned_predicates.entry(spans);
- entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
- }
-
// Unmet obligation coming from an `impl`.
Some(Node::Item(hir::Item {
kind:
@@ -695,23 +636,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}),
span: item_span,
..
- })) if !matches!(
- self_ty.span.ctxt().outer_expn_data().kind,
- ExpnKind::Macro(MacroKind::Derive, _)
- ) && !matches!(
- of_trait.as_ref().map(|t| t
- .path
- .span
- .ctxt()
- .outer_expn_data()
- .kind),
- Some(ExpnKind::Macro(MacroKind::Derive, _))
- ) =>
- {
+ })) => {
let sized_pred =
unsatisfied_predicates.iter().any(|(pred, _, _)| {
match pred.kind().skip_binder() {
- ty::PredicateKind::Trait(pred) => {
+ ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => {
Some(pred.def_id())
== self.tcx.lang_items().sized_trait()
&& pred.polarity == ty::ImplPolarity::Positive
@@ -759,7 +688,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let entry = spanned_predicates.entry(spans);
entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
}
- _ => {}
+ Some(_) => unreachable!(),
+ None => (),
}
}
let mut spanned_predicates: Vec<_> = spanned_predicates.into_iter().collect();
@@ -844,7 +774,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.map(|(_, path)| path)
.collect::<Vec<_>>()
.join("\n");
- let actual_prefix = actual.prefix_string(self.tcx);
+ let actual_prefix = rcvr_ty.prefix_string(self.tcx);
info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
let (primary_message, label) =
if unimplemented_traits.len() == 1 && unimplemented_traits_only {
@@ -853,7 +783,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.next()
.map(|(_, (trait_ref, obligation))| {
if trait_ref.self_ty().references_error()
- || actual.references_error()
+ || rcvr_ty.references_error()
{
// Avoid crashing.
return (None, None);
@@ -863,7 +793,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.on_unimplemented_note(trait_ref, &obligation);
(message, label)
})
- .unwrap_or((None, None))
+ .unwrap()
} else {
(None, None)
};
@@ -889,15 +819,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let label_span_not_found = |err: &mut Diagnostic| {
if unsatisfied_predicates.is_empty() {
err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
- let is_string_or_ref_str = match actual.kind() {
+ let is_string_or_ref_str = match rcvr_ty.kind() {
ty::Ref(_, ty, _) => {
ty.is_str()
|| matches!(
ty.kind(),
- ty::Adt(adt, _) if self.tcx.is_diagnostic_item(sym::String, adt.did())
+ ty::Adt(adt, _) if Some(adt.did()) == self.tcx.lang_items().string()
)
}
- ty::Adt(adt, _) => self.tcx.is_diagnostic_item(sym::String, adt.did()),
+ ty::Adt(adt, _) => Some(adt.did()) == self.tcx.lang_items().string(),
_ => false,
};
if is_string_or_ref_str && item_name.name == sym::iter {
@@ -925,7 +855,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// different from the received one
// So we avoid suggestion method with Box<Self>
// for instance
- self.tcx.at(span).type_of(*def_id) != actual
+ self.tcx.at(span).type_of(*def_id) != rcvr_ty
&& self.tcx.at(span).type_of(*def_id) != rcvr_ty
}
(Mode::Path, false, _) => true,
@@ -972,7 +902,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If the method name is the name of a field with a function or closure type,
// give a helping note that it has to be called as `(x.f)(...)`.
if let SelfSource::MethodCall(expr) = source {
- if !self.suggest_field_call(span, rcvr_ty, expr, item_name, &mut err)
+ if !self.suggest_calling_field_as_fn(span, rcvr_ty, expr, item_name, &mut err)
&& lev_candidate.is_none()
&& !custom_span_label
{
@@ -982,13 +912,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
label_span_not_found(&mut err);
}
- // Don't suggest (for example) `expr.field.method()` if `expr.method()`
- // doesn't exist due to unsatisfied predicates.
+ // Don't suggest (for example) `expr.field.clone()` if `expr.clone()`
+ // can't be called due to `typeof(expr): Clone` not holding.
if unsatisfied_predicates.is_empty() {
- self.check_for_field_method(&mut err, source, span, actual, item_name);
+ self.suggest_calling_method_on_field(
+ &mut err, source, span, rcvr_ty, item_name,
+ );
}
- self.check_for_inner_self(&mut err, source, span, actual, item_name);
+ self.check_for_inner_self(&mut err, source, rcvr_ty, item_name);
bound_spans.sort();
bound_spans.dedup();
@@ -996,7 +928,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_label(span, &msg);
}
- if actual.is_numeric() && actual.is_fresh() || restrict_type_params {
+ if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params {
} else {
self.suggest_traits_to_import(
&mut err,
@@ -1007,15 +939,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
source,
out_of_scope_traits,
&unsatisfied_predicates,
- &static_sources,
+ &static_candidates,
unsatisfied_bounds,
);
}
// Don't emit a suggestion if we found an actual method
// that had unsatisfied trait bounds
- if unsatisfied_predicates.is_empty() && actual.is_enum() {
- let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
+ if unsatisfied_predicates.is_empty() && rcvr_ty.is_enum() {
+ let adt_def = rcvr_ty.ty_adt_def().expect("enum is not an ADT");
if let Some(suggestion) = lev_distance::find_best_match_for_name(
&adt_def.variants().iter().map(|s| s.name).collect::<Vec<_>>(),
item_name.name,
@@ -1030,7 +962,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- if item_name.name == sym::as_str && actual.peel_refs().is_str() {
+ if item_name.name == sym::as_str && rcvr_ty.peel_refs().is_str() {
let msg = "remove this method call";
let mut fallback_span = true;
if let SelfSource::MethodCall(expr) = source {
@@ -1089,7 +1021,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
err.span_label(item_name.span, format!("multiple `{}` found", item_name));
- report_candidates(span, &mut err, &mut sources, sugg_span);
+ report_candidates(span, &mut err, &mut sources, Some(sugg_span));
err.emit();
}
@@ -1146,7 +1078,133 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
None
}
- fn suggest_field_call(
+ /// Suggest calling `Ty::method` if `.method()` isn't found because the method
+ /// doesn't take a `self` receiver.
+ fn suggest_associated_call_syntax(
+ &self,
+ err: &mut Diagnostic,
+ static_candidates: &Vec<CandidateSource>,
+ rcvr_ty: Ty<'tcx>,
+ source: SelfSource<'tcx>,
+ item_name: Ident,
+ args: Option<(&hir::Expr<'tcx>, &[hir::Expr<'tcx>])>,
+ sugg_span: Span,
+ ) {
+ let mut has_unsuggestable_args = false;
+ let ty_str = if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0) {
+ // When the "method" is resolved through dereferencing, we really want the
+ // original type that has the associated function for accurate suggestions.
+ // (#61411)
+ let impl_ty = self.tcx.type_of(*impl_did);
+ let target_ty = self
+ .autoderef(sugg_span, rcvr_ty)
+ .find(|(rcvr_ty, _)| {
+ DeepRejectCtxt { treat_obligation_params: TreatParams::AsInfer }
+ .types_may_unify(*rcvr_ty, impl_ty)
+ })
+ .map_or(impl_ty, |(ty, _)| ty)
+ .peel_refs();
+ if let ty::Adt(def, substs) = target_ty.kind() {
+ // If there are any inferred arguments, (`{integer}`), we should replace
+ // them with underscores to allow the compiler to infer them
+ let infer_substs = self.tcx.mk_substs(substs.into_iter().map(|arg| {
+ if !arg.is_suggestable(self.tcx, true) {
+ has_unsuggestable_args = true;
+ match arg.unpack() {
+ GenericArgKind::Lifetime(_) => self
+ .next_region_var(RegionVariableOrigin::MiscVariable(
+ rustc_span::DUMMY_SP,
+ ))
+ .into(),
+ GenericArgKind::Type(_) => self
+ .next_ty_var(TypeVariableOrigin {
+ span: rustc_span::DUMMY_SP,
+ kind: TypeVariableOriginKind::MiscVariable,
+ })
+ .into(),
+ GenericArgKind::Const(arg) => self
+ .next_const_var(
+ arg.ty(),
+ ConstVariableOrigin {
+ span: rustc_span::DUMMY_SP,
+ kind: ConstVariableOriginKind::MiscVariable,
+ },
+ )
+ .into(),
+ }
+ } else {
+ arg
+ }
+ }));
+
+ self.tcx.value_path_str_with_substs(def.did(), infer_substs)
+ } else {
+ self.ty_to_value_string(target_ty)
+ }
+ } else {
+ self.ty_to_value_string(rcvr_ty.peel_refs())
+ };
+ if let SelfSource::MethodCall(_) = source {
+ let first_arg = if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0)
+ && let Some(assoc) = self.associated_value(*impl_did, item_name)
+ && assoc.kind == ty::AssocKind::Fn
+ {
+ let sig = self.tcx.fn_sig(assoc.def_id);
+ sig.inputs().skip_binder().get(0).and_then(|first| if first.peel_refs() == rcvr_ty.peel_refs() {
+ None
+ } else {
+ Some(first.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()))
+ })
+ } else {
+ None
+ };
+ let mut applicability = Applicability::MachineApplicable;
+ let args = if let Some((receiver, args)) = args {
+ // The first arg is the same kind as the receiver
+ let explicit_args = if first_arg.is_some() {
+ std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>()
+ } else {
+ // There is no `Self` kind to infer the arguments from
+ if has_unsuggestable_args {
+ applicability = Applicability::HasPlaceholders;
+ }
+ args.iter().collect()
+ };
+ format!(
+ "({}{})",
+ first_arg.unwrap_or(""),
+ explicit_args
+ .iter()
+ .map(|arg| self
+ .tcx
+ .sess
+ .source_map()
+ .span_to_snippet(arg.span)
+ .unwrap_or_else(|_| {
+ applicability = Applicability::HasPlaceholders;
+ "_".to_owned()
+ }))
+ .collect::<Vec<_>>()
+ .join(", "),
+ )
+ } else {
+ applicability = Applicability::HasPlaceholders;
+ "(...)".to_owned()
+ };
+ err.span_suggestion(
+ sugg_span,
+ "use associated function syntax instead",
+ format!("{}::{}{}", ty_str, item_name, args),
+ applicability,
+ );
+ } else {
+ err.help(&format!("try with `{}::{}`", ty_str, item_name,));
+ }
+ }
+
+ /// Suggest calling a field with a type that implements the `Fn*` traits instead of a method with
+ /// the same name as the field i.e. `(a.my_fn_ptr)(10)` instead of `a.my_fn_ptr(10)`.
+ fn suggest_calling_field_as_fn(
&self,
span: Span,
rcvr_ty: Ty<'tcx>,
@@ -1261,7 +1319,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.bound_type_of(range_def_id).subst(self.tcx, &[actual.into()]);
let pick = self.probe_for_name(
- span,
Mode::MethodCall,
item_name,
IsSuggestion(true),
@@ -1408,7 +1465,66 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
false
}
- fn check_for_field_method(
+ /// For code `rect::area(...)`,
+ /// if `rect` is a local variable and `area` is a valid assoc method for it,
+ /// we try to suggest `rect.area()`
+ pub(crate) fn suggest_assoc_method_call(&self, segs: &[PathSegment<'_>]) {
+ debug!("suggest_assoc_method_call segs: {:?}", segs);
+ let [seg1, seg2] = segs else { return; };
+ let Some(mut diag) =
+ self.tcx.sess.diagnostic().steal_diagnostic(seg1.ident.span, StashKey::CallAssocMethod)
+ else { return };
+
+ let map = self.infcx.tcx.hir();
+ let body = map.body(rustc_hir::BodyId { hir_id: self.body_id });
+ struct LetVisitor<'a> {
+ result: Option<&'a hir::Expr<'a>>,
+ ident_name: Symbol,
+ }
+
+ // FIXME: This really should be taking scoping, etc into account.
+ impl<'v> Visitor<'v> for LetVisitor<'v> {
+ fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
+ if let hir::StmtKind::Local(hir::Local { pat, init, .. }) = &ex.kind
+ && let Binding(_, _, ident, ..) = pat.kind
+ && ident.name == self.ident_name
+ {
+ self.result = *init;
+ } else {
+ hir::intravisit::walk_stmt(self, ex);
+ }
+ }
+ }
+
+ let mut visitor = LetVisitor { result: None, ident_name: seg1.ident.name };
+ visitor.visit_body(&body);
+
+ let parent = self.tcx.hir().get_parent_node(seg1.hir_id);
+ if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent)
+ && let Some(expr) = visitor.result
+ && let Some(self_ty) = self.node_ty_opt(expr.hir_id)
+ {
+ let probe = self.lookup_probe(
+ seg2.ident,
+ self_ty,
+ call_expr,
+ ProbeScope::TraitsInScope,
+ );
+ if probe.is_ok() {
+ let sm = self.infcx.tcx.sess.source_map();
+ diag.span_suggestion_verbose(
+ sm.span_extend_while(seg1.ident.span.shrink_to_hi(), |c| c == ':').unwrap(),
+ "you may have meant to call an instance method",
+ ".".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ diag.emit();
+ }
+
+ /// Suggest calling a method on a field i.e. `a.field.bar()` instead of `a.bar()`
+ fn suggest_calling_method_on_field(
&self,
err: &mut Diagnostic,
source: SelfSource<'tcx>,
@@ -1439,7 +1555,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span,
&|_, field_ty| {
self.lookup_probe(
- span,
item_name,
field_ty,
call_expr,
@@ -1487,7 +1602,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
err: &mut Diagnostic,
source: SelfSource<'tcx>,
- span: Span,
actual: Ty<'tcx>,
item_name: Ident,
) {
@@ -1510,15 +1624,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return None;
}
- self.lookup_probe(
- span,
- item_name,
- field_ty,
- call_expr,
- ProbeScope::TraitsInScope,
- )
- .ok()
- .map(|pick| (variant, field, pick))
+ self.lookup_probe(item_name, field_ty, call_expr, ProbeScope::TraitsInScope)
+ .ok()
+ .map(|pick| (variant, field, pick))
})
.collect();
@@ -1583,12 +1691,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let [first] = ***substs else { return; };
let ty::GenericArgKind::Type(ty) = first.unpack() else { return; };
let Ok(pick) = self.lookup_probe(
- span,
- item_name,
- ty,
- call_expr,
- ProbeScope::TraitsInScope,
- ) else { return; };
+ item_name,
+ ty,
+ call_expr,
+ ProbeScope::TraitsInScope,
+ ) else { return; };
let name = self.ty_to_value_string(actual);
let inner_id = kind.did();
@@ -1668,7 +1775,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) {
let all_local_types_needing_impls =
errors.iter().all(|e| match e.obligation.predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(pred) => match pred.self_ty().kind() {
+ ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => match pred.self_ty().kind() {
ty::Adt(def, _) => def.did().is_local(),
_ => false,
},
@@ -1677,7 +1784,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut preds: Vec<_> = errors
.iter()
.filter_map(|e| match e.obligation.predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(pred) => Some(pred),
+ ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => Some(pred),
_ => None,
})
.collect();
@@ -1748,7 +1855,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut derives = Vec::<(String, Span, Symbol)>::new();
let mut traits = Vec::<Span>::new();
for (pred, _, _) in unsatisfied_predicates {
- let ty::PredicateKind::Trait(trait_pred) = pred.kind().skip_binder() else { continue };
+ let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = pred.kind().skip_binder() else { continue };
let adt = match trait_pred.self_ty().ty_adt_def() {
Some(adt) if adt.did().is_local() => adt,
_ => continue,
@@ -1838,7 +1945,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let SelfSource::QPath(ty) = self_source else { return; };
for (deref_ty, _) in self.autoderef(rustc_span::DUMMY_SP, rcvr_ty).skip(1) {
if let Ok(pick) = self.probe_for_name(
- ty.span,
Mode::Path,
item_name,
IsSuggestion(true),
@@ -1865,6 +1971,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| ty::Str
| ty::Projection(_)
| ty::Param(_) => format!("{deref_ty}"),
+ // we need to test something like <&[_]>::len or <(&[u32])>::len
+ // and Vec::function();
+ // <&[_]>::len or <&[u32]>::len doesn't need an extra "<>" between
+ // but for Adt type like Vec::function()
+ // we would suggest <[_]>::function();
+ _ if self.tcx.sess.source_map().span_wrapped_by_angle_or_parentheses(ty.span) => format!("{deref_ty}"),
_ => format!("<{deref_ty}>"),
};
err.span_suggestion_verbose(
@@ -1887,7 +1999,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Print out the type for use in value namespace.
fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
match ty.kind() {
- ty::Adt(def, substs) => format!("{}", ty::Instance::new(def.did(), substs)),
+ ty::Adt(def, substs) => self.tcx.def_path_str_with_substs(def.did(), substs),
_ => self.ty_to_string(ty),
}
}
@@ -1901,7 +2013,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: Span,
) {
let output_ty = match self.get_impl_future_output_ty(ty) {
- Some(output_ty) => self.resolve_vars_if_possible(output_ty).skip_binder(),
+ Some(output_ty) => self.resolve_vars_if_possible(output_ty),
_ => return,
};
let method_exists = self.method_exists(item_name, output_ty, call.hir_id, true);
@@ -2021,7 +2133,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) {
let mut alt_rcvr_sugg = false;
if let (SelfSource::MethodCall(rcvr), false) = (source, unsatisfied_bounds) {
- debug!(?span, ?item_name, ?rcvr_ty, ?rcvr);
+ debug!(
+ "suggest_traits_to_import: span={:?}, item_name={:?}, rcvr_ty={:?}, rcvr={:?}",
+ span, item_name, rcvr_ty, rcvr
+ );
let skippable = [
self.tcx.lang_items().clone_trait(),
self.tcx.lang_items().deref_trait(),
@@ -2037,7 +2152,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(self.tcx.mk_mut_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&mut "),
(self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&"),
] {
- match self.lookup_probe(span, item_name, *rcvr_ty, rcvr, ProbeScope::AllTraits) {
+ match self.lookup_probe(item_name, *rcvr_ty, rcvr, ProbeScope::AllTraits) {
Ok(pick) => {
// If the method is defined for the receiver we have, it likely wasn't `use`d.
// We point at the method, but we just skip the rest of the check for arbitrary
@@ -2060,7 +2175,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// suggestions are generally misleading (see #94218).
break;
}
- _ => {}
+ Err(_) => (),
}
for (rcvr_ty, pre) in &[
@@ -2071,7 +2186,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
] {
if let Some(new_rcvr_t) = *rcvr_ty
&& let Ok(pick) = self.lookup_probe(
- span,
item_name,
new_rcvr_t,
rcvr,
@@ -2151,8 +2265,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match p.kind().skip_binder() {
// Hide traits if they are present in predicates as they can be fixed without
// having to implement them.
- ty::PredicateKind::Trait(t) => t.def_id() == info.def_id,
- ty::PredicateKind::Projection(p) => {
+ ty::PredicateKind::Clause(ty::Clause::Trait(t)) => {
+ t.def_id() == info.def_id
+ }
+ ty::PredicateKind::Clause(ty::Clause::Projection(p)) => {
p.projection_ty.item_def_id == info.def_id
}
_ => false,
@@ -2452,7 +2568,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: method_name.span,
};
let probe = self.lookup_probe(
- expr.span,
new_name,
self_ty,
self_expr,
@@ -2565,11 +2680,7 @@ fn print_disambiguation_help<'tcx>(
let (span, sugg) = if let (ty::AssocKind::Fn, Some((receiver, args))) = (kind, args) {
let args = format!(
"({}{})",
- if rcvr_ty.is_region_ptr() {
- if rcvr_ty.is_mutable_ptr() { "&mut " } else { "&" }
- } else {
- ""
- },
+ rcvr_ty.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()),
std::iter::once(receiver)
.chain(args.iter())
.map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| {
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index 895739976..b12d84af4 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -19,7 +19,7 @@ use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
-use rustc_trait_selection::traits::{FulfillmentError, TraitEngine, TraitEngineExt};
+use rustc_trait_selection::traits::FulfillmentError;
use rustc_type_ir::sty::TyKind::*;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -263,14 +263,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let by_ref_binop = !op.node.is_by_value();
if is_assign == IsAssign::Yes || by_ref_binop {
if let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].kind() {
- let mutbl = match mutbl {
- hir::Mutability::Not => AutoBorrowMutability::Not,
- hir::Mutability::Mut => AutoBorrowMutability::Mut {
- // Allow two-phase borrows for binops in initial deployment
- // since they desugar to methods
- allow_two_phase_borrow: AllowTwoPhase::Yes,
- },
- };
+ let mutbl = AutoBorrowMutability::new(*mutbl, AllowTwoPhase::Yes);
let autoref = Adjustment {
kind: Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)),
target: method.sig.inputs()[0],
@@ -280,14 +273,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
if by_ref_binop {
if let ty::Ref(region, _, mutbl) = method.sig.inputs()[1].kind() {
- let mutbl = match mutbl {
- hir::Mutability::Not => AutoBorrowMutability::Not,
- hir::Mutability::Mut => AutoBorrowMutability::Mut {
- // Allow two-phase borrows for binops in initial deployment
- // since they desugar to methods
- allow_two_phase_borrow: AllowTwoPhase::Yes,
- },
- };
+ // Allow two-phase borrows for binops in initial deployment
+ // since they desugar to methods
+ let mutbl = AutoBorrowMutability::new(*mutbl, AllowTwoPhase::Yes);
+
let autoref = Adjustment {
kind: Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)),
target: method.sig.inputs()[1],
@@ -529,8 +518,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
}
- err.emit();
- self.tcx.ty_error()
+ let reported = err.emit();
+ self.tcx.ty_error_with_guaranteed(reported)
}
};
@@ -556,9 +545,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let rm_borrow_msg = "remove the borrow to obtain an owned `String`";
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| self.tcx.is_diagnostic_item(sym::String, ty_def.did()))
+ ty.ty_adt_def().map_or(false, |ty_def| Some(ty_def.did()) == string_type)
};
match (lhs_ty.kind(), rhs_ty.kind()) {
@@ -772,7 +761,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match (method, trait_did) {
(Some(ok), _) => {
let method = self.register_infer_ok_obligations(ok);
- self.select_obligations_where_possible(false, |_| {});
+ self.select_obligations_where_possible(|_| {});
Ok(method)
}
(None, None) => Err(vec![]),
@@ -785,9 +774,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
other_ty_expr,
expected,
);
- let mut fulfill = <dyn TraitEngine<'_>>::new(self.tcx);
- fulfill.register_predicate_obligation(self, obligation);
- Err(fulfill.select_where_possible(&self.infcx))
+ Err(rustc_trait_selection::traits::fully_solve_obligation(self, obligation))
}
}
}
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index ea90da4a6..decd317d9 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -19,7 +19,6 @@ use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::{Span, Spanned};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{BytePos, DUMMY_SP};
-use rustc_trait_selection::autoderef::Autoderef;
use rustc_trait_selection::traits::{ObligationCause, Pattern};
use ty::VariantDef;
@@ -402,6 +401,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
+ if self.tcx.features().string_deref_patterns && let hir::ExprKind::Lit(Spanned { node: ast::LitKind::Str(..), .. }) = lt.kind {
+ let tcx = self.tcx;
+ let expected = self.resolve_vars_if_possible(expected);
+ pat_ty = match expected.kind() {
+ ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().string() => expected,
+ ty::Str => tcx.mk_static_str(),
+ _ => pat_ty,
+ };
+ }
+
// Somewhat surprising: in this case, the subtyping relation goes the
// opposite way as the other cases. Actually what we really want is not
// a subtyping relation at all but rather that there exists a LUB
@@ -693,7 +702,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let mut_var_suggestion = 'block: {
- if !matches!(mutbl, ast::Mutability::Mut) {
+ if mutbl.is_not() {
break 'block None;
}
@@ -740,7 +749,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!("to take parameter `{binding}` by reference, move `&{mutability}` to the type"),
vec![
(pat.span.until(inner.span), "".to_owned()),
- (ty_span.shrink_to_lo(), format!("&{}", mutbl.prefix_str())),
+ (ty_span.shrink_to_lo(), mutbl.ref_prefix_str().to_owned()),
],
Applicability::MachineApplicable
);
@@ -840,12 +849,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let (res, opt_ty, segments) = path_resolution;
match res {
Res::Err => {
- self.set_tainted_by_errors();
- return tcx.ty_error();
+ let e = tcx.sess.delay_span_bug(qpath.span(), "`Res::Err` but no error emitted");
+ self.set_tainted_by_errors(e);
+ return tcx.ty_error_with_guaranteed(e);
}
- Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fictive | CtorKind::Fn), _) => {
- report_unexpected_variant_res(tcx, res, qpath, pat.span);
- return tcx.ty_error();
+ Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => {
+ let expected = "unit struct, unit variant or constant";
+ let e = report_unexpected_variant_res(tcx, res, qpath, pat.span, "E0533", expected);
+ return tcx.ty_error_with_guaranteed(e);
}
Res::SelfCtor(..)
| Res::Def(
@@ -986,65 +997,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ti: TopInfo<'tcx>,
) -> Ty<'tcx> {
let tcx = self.tcx;
- let on_error = || {
+ let on_error = |e| {
for pat in subpats {
- self.check_pat(pat, tcx.ty_error(), def_bm, ti);
+ self.check_pat(pat, tcx.ty_error_with_guaranteed(e), def_bm, ti);
}
};
let report_unexpected_res = |res: Res| {
- let sm = tcx.sess.source_map();
- let path_str = sm
- .span_to_snippet(sm.span_until_char(pat.span, '('))
- .map_or_else(|_| String::new(), |s| format!(" `{}`", s.trim_end()));
- let msg = format!(
- "expected tuple struct or tuple variant, found {}{}",
- res.descr(),
- path_str
- );
-
- let mut err = struct_span_err!(tcx.sess, pat.span, E0164, "{msg}");
- match res {
- Res::Def(DefKind::Fn | DefKind::AssocFn, _) => {
- err.span_label(pat.span, "`fn` calls are not allowed in patterns");
- err.help(
- "for more information, visit \
- https://doc.rust-lang.org/book/ch18-00-patterns.html",
- );
- }
- _ => {
- err.span_label(pat.span, "not a tuple variant or struct");
- }
- }
- err.emit();
- on_error();
+ let expected = "tuple struct or tuple variant";
+ let e = report_unexpected_variant_res(tcx, res, qpath, pat.span, "E0164", expected);
+ on_error(e);
+ e
};
// Resolve the path and check the definition for errors.
let (res, opt_ty, segments) =
self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span);
if res == Res::Err {
- self.set_tainted_by_errors();
- on_error();
- return self.tcx.ty_error();
+ let e = tcx.sess.delay_span_bug(pat.span, "`Res:Err` but no error emitted");
+ self.set_tainted_by_errors(e);
+ on_error(e);
+ return tcx.ty_error_with_guaranteed(e);
}
// Type-check the path.
let (pat_ty, res) =
self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id);
if !pat_ty.is_fn() {
- report_unexpected_res(res);
- return tcx.ty_error();
+ let e = report_unexpected_res(res);
+ return tcx.ty_error_with_guaranteed(e);
}
let variant = match res {
Res::Err => {
- self.set_tainted_by_errors();
- on_error();
- return tcx.ty_error();
+ let e = tcx.sess.delay_span_bug(pat.span, "`Res::Err` but no error emitted");
+ self.set_tainted_by_errors(e);
+ on_error(e);
+ return tcx.ty_error_with_guaranteed(e);
}
Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => {
- report_unexpected_res(res);
- return tcx.ty_error();
+ let e = report_unexpected_res(res);
+ return tcx.ty_error_with_guaranteed(e);
}
Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => tcx.expect_variant_res(res),
_ => bug!("unexpected pattern resolution: {:?}", res),
@@ -1083,9 +1075,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
} else {
// Pattern has wrong number of fields.
- self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected, had_err);
- on_error();
- return tcx.ty_error();
+ let e = self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected, had_err);
+ on_error(e);
+ return tcx.ty_error_with_guaranteed(e);
}
pat_ty
}
@@ -1099,7 +1091,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fields: &'tcx [ty::FieldDef],
expected: Ty<'tcx>,
had_err: bool,
- ) {
+ ) -> ErrorGuaranteed {
let subpats_ending = pluralize!(subpats.len());
let fields_ending = pluralize!(fields.len());
@@ -1246,7 +1238,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- err.emit();
+ err.emit()
}
fn check_pat_tuple(
@@ -1278,12 +1270,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let element_tys = tcx.mk_type_list(element_tys_iter);
let pat_ty = tcx.mk_ty(ty::Tuple(element_tys));
if let Some(mut err) = self.demand_eqtype_pat_diag(span, expected, pat_ty, ti) {
- err.emit();
+ let reported = err.emit();
// Walk subpatterns with an expected type of `err` in this case to silence
// further errors being emitted when using the bindings. #50333
- let element_tys_iter = (0..max_len).map(|_| tcx.ty_error());
+ let element_tys_iter = (0..max_len).map(|_| tcx.ty_error_with_guaranteed(reported));
for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
- self.check_pat(elem, tcx.ty_error(), def_bm, ti);
+ self.check_pat(elem, tcx.ty_error_with_guaranteed(reported), def_bm, ti);
}
tcx.mk_tup(element_tys_iter)
} else {
@@ -1468,8 +1460,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// if this is a tuple struct, then all field names will be numbers
// so if any fields in a struct pattern use shorthand syntax, they will
// be invalid identifiers (for example, Foo { 0, 1 }).
- if let (CtorKind::Fn, PatKind::Struct(qpath, field_patterns, ..)) =
- (variant.ctor_kind, &pat.kind)
+ if let (Some(CtorKind::Fn), PatKind::Struct(qpath, field_patterns, ..)) =
+ (variant.ctor_kind(), &pat.kind)
{
let has_shorthand_field_name = field_patterns.iter().any(|field| field.is_shorthand);
if has_shorthand_field_name {
@@ -1646,7 +1638,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fields: &'tcx [hir::PatField<'tcx>],
variant: &ty::VariantDef,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
- if let (CtorKind::Fn, PatKind::Struct(qpath, ..)) = (variant.ctor_kind, &pat.kind) {
+ if let (Some(CtorKind::Fn), PatKind::Struct(qpath, ..)) = (variant.ctor_kind(), &pat.kind) {
let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
s.print_qpath(qpath, false)
});
@@ -2132,7 +2124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& let ty::Array(..) | ty::Slice(..) = ty.kind()
{
err.help("the semantics of slice patterns changed recently; see issue #62254");
- } else if Autoderef::new(&self.infcx, self.param_env, self.body_id, span, expected_ty, span)
+ } else if self.autoderef(span, expected_ty)
.any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
&& let (Some(span), true) = (ti.span, ti.origin_expr)
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs
index ba8cf6926..952ea1488 100644
--- a/compiler/rustc_hir_typeck/src/place_op.rs
+++ b/compiler/rustc_hir_typeck/src/place_op.rs
@@ -90,8 +90,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Applicability::MachineApplicable,
);
}
- err.emit();
- Some((self.tcx.ty_error(), self.tcx.ty_error()))
+ let reported = err.emit();
+ Some((
+ self.tcx.ty_error_with_guaranteed(reported),
+ self.tcx.ty_error_with_guaranteed(reported),
+ ))
}
/// To type-check `base_expr[index_expr]`, we progressively autoderef
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 4dea40829..0f4697201 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -970,12 +970,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
check_trait
.map(|check_trait| {
self.infcx
- .type_implements_trait(
- check_trait,
- ty,
- self.tcx.mk_substs_trait(ty, &[]),
- self.param_env,
- )
+ .type_implements_trait(check_trait, [ty], self.param_env)
.must_apply_modulo_regions()
})
.unwrap_or(false),
@@ -999,12 +994,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
check_trait
.map(|check_trait| {
self.infcx
- .type_implements_trait(
- check_trait,
- ty,
- self.tcx.mk_substs_trait(ty, &[]),
- self.param_env,
- )
+ .type_implements_trait(check_trait, [ty], self.param_env)
.must_apply_modulo_regions()
})
.unwrap_or(false),
@@ -1347,14 +1337,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let is_drop_defined_for_ty = |ty: Ty<'tcx>| {
let drop_trait = self.tcx.require_lang_item(hir::LangItem::Drop, Some(closure_span));
- let ty_params = self.tcx.mk_substs_trait(base_path_ty, &[]);
self.infcx
- .type_implements_trait(
- drop_trait,
- ty,
- ty_params,
- self.tcx.param_env(closure_def_id),
- )
+ .type_implements_trait(drop_trait, [ty], self.tcx.param_env(closure_def_id))
.must_apply_modulo_regions()
};
@@ -2184,7 +2168,7 @@ fn determine_place_ancestry_relation<'tcx>(
place_a: &Place<'tcx>,
place_b: &Place<'tcx>,
) -> PlaceAncestryRelation {
- // If Place A and Place B, don't start off from the same root variable, they are divergent.
+ // If Place A and Place B don't start off from the same root variable, they are divergent.
if place_a.base != place_b.base {
return PlaceAncestryRelation::Divergent;
}
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 1e26daa9c..52ffd286e 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -83,10 +83,8 @@ 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 self.is_tainted_by_errors() {
- // FIXME(eddyb) keep track of `ErrorGuaranteed` from where the error was emitted.
- wbcx.typeck_results.tainted_by_errors =
- Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
+ 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);
@@ -363,9 +361,12 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) {
intravisit::walk_ty(self, hir_ty);
- let ty = self.fcx.node_ty(hir_ty.hir_id);
- let ty = self.resolve(ty, &hir_ty.span);
- self.write_ty_to_typeck_results(hir_ty.hir_id, ty);
+ // If there are type checking errors, Type privacy pass will stop,
+ // so we may not get the type from hid_id, see #104513
+ if let Some(ty) = self.fcx.node_ty_opt(hir_ty.hir_id) {
+ let ty = self.resolve(ty, &hir_ty.span);
+ self.write_ty_to_typeck_results(hir_ty.hir_id, ty);
+ }
}
fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
@@ -514,7 +515,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
for (&def_id, c_sig) in fcx_typeck_results.user_provided_sigs.iter() {
if cfg!(debug_assertions) && c_sig.needs_infer() {
span_bug!(
- self.fcx.tcx.hir().span_if_local(def_id).unwrap(),
+ self.fcx.tcx.def_span(def_id),
"writeback: `{:?}` has inference variables",
c_sig
);
@@ -564,7 +565,6 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
opaque_type_key,
self.fcx.infcx.tcx,
true,
- decl.origin,
);
self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type);
@@ -674,10 +674,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
// We may have introduced e.g. `ty::Error`, if inference failed, make sure
// to mark the `TypeckResults` as tainted in that case, so that downstream
// users of the typeck results don't produce extra errors, or worse, ICEs.
- if resolver.replaced_with_error {
- // FIXME(eddyb) keep track of `ErrorGuaranteed` from where the error was emitted.
- self.typeck_results.tainted_by_errors =
- Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
+ if let Some(e) = resolver.replaced_with_error {
+ self.typeck_results.tainted_by_errors = Some(e);
}
x
@@ -708,8 +706,8 @@ struct Resolver<'cx, 'tcx> {
span: &'cx dyn Locatable,
body: &'tcx hir::Body<'tcx>,
- /// Set to `true` if any `Ty` or `ty::Const` had to be replaced with an `Error`.
- replaced_with_error: bool,
+ /// Set to `Some` if any `Ty` or `ty::Const` had to be replaced with an `Error`.
+ replaced_with_error: Option<ErrorGuaranteed>,
}
impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
@@ -718,12 +716,14 @@ 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: false }
+ Resolver { tcx: fcx.tcx, infcx: fcx, span, body, replaced_with_error: None }
}
- fn report_error(&self, p: impl Into<ty::GenericArg<'tcx>>) {
- if !self.tcx.sess.has_errors().is_some() {
- self.infcx
+ fn report_error(&self, p: impl Into<ty::GenericArg<'tcx>>) -> ErrorGuaranteed {
+ match self.tcx.sess.has_errors() {
+ Some(e) => e,
+ None => self
+ .infcx
.err_ctxt()
.emit_inference_failure_err(
Some(self.body.id()),
@@ -732,7 +732,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
E0282,
false,
)
- .emit();
+ .emit(),
}
}
}
@@ -773,9 +773,9 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
}
Err(_) => {
debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t);
- self.report_error(t);
- self.replaced_with_error = true;
- self.tcx().ty_error()
+ let e = self.report_error(t);
+ self.replaced_with_error = Some(e);
+ self.tcx().ty_error_with_guaranteed(e)
}
}
}
@@ -790,9 +790,9 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
Ok(ct) => self.tcx.erase_regions(ct),
Err(_) => {
debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct);
- self.report_error(ct);
- self.replaced_with_error = true;
- self.tcx().const_error(ct.ty())
+ let e = self.report_error(ct);
+ self.replaced_with_error = Some(e);
+ self.tcx().const_error_with_guaranteed(ct.ty(), e)
}
}
}