summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_typeck
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_typeck')
-rw-r--r--compiler/rustc_hir_typeck/messages.ftl8
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs24
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs133
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs34
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs31
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs34
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs246
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs125
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs50
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs310
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/fallback.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs87
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs18
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs41
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs133
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs12
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs253
-rw-r--r--compiler/rustc_hir_typeck/src/gather_locals.rs35
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/mod.rs20
-rw-r--r--compiler/rustc_hir_typeck/src/inherited.rs12
-rw-r--r--compiler/rustc_hir_typeck/src/intrinsicck.rs15
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs11
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs60
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs35
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs55
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs60
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs54
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs74
-rw-r--r--compiler/rustc_hir_typeck/src/place_op.rs23
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs14
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs119
34 files changed, 1315 insertions, 837 deletions
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index aab432eee..3d012a15a 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -25,6 +25,8 @@ hir_typeck_const_select_must_be_fn = this argument must be a function item
hir_typeck_convert_to_str = try converting the passed type into a `&str`
+hir_typeck_convert_using_method = try using `{$sugg}` to convert `{$found}` to `{$expected}`
+
hir_typeck_ctor_is_private = tuple struct constructor `{$def}` is private
hir_typeck_expected_default_return_type = expected `()` because of default return type
@@ -76,8 +78,8 @@ hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang
hir_typeck_op_trait_generic_params = `{$method_name}` must not have any generic parameters
hir_typeck_return_stmt_outside_of_fn_body =
- return statement outside of function body
- .encl_body_label = the return is part of this body...
+ {$statement_kind} statement outside of function body
+ .encl_body_label = the {$statement_kind} is part of this body...
.encl_fn_label = ...not the enclosing function body
hir_typeck_struct_expr_non_exhaustive =
@@ -87,6 +89,8 @@ hir_typeck_suggest_boxing_note = for more on the distinction between the stack a
hir_typeck_suggest_boxing_when_appropriate = store this in the heap by calling `Box::new`
+hir_typeck_suggest_ptr_null_mut = consider using `core::ptr::null_mut` instead
+
hir_typeck_union_pat_dotdot = `..` cannot be used in union patterns
hir_typeck_union_pat_multiple_fields = union patterns should have exactly one field
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 7d2f7e876..e8720a5da 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -65,7 +65,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// us to give better error messages (pointing to a usually better
// arm for inconsistent arms or to the whole match when a `()` type
// is required).
- Expectation::ExpectHasType(ety) if ety != self.tcx.mk_unit() => ety,
+ Expectation::ExpectHasType(ety) if ety != Ty::new_unit(self.tcx) => ety,
_ => self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::MiscVariable,
span: expr.span,
@@ -510,6 +510,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
..
} = self.type_var_origin(expected)? else { return None; };
+ let Some(rpit_local_def_id) = rpit_def_id.as_local() else { return None; };
+ if !matches!(
+ self.tcx.hir().expect_item(rpit_local_def_id).expect_opaque_ty().origin,
+ hir::OpaqueTyOrigin::FnReturn(..)
+ ) {
+ return None;
+ }
+
let sig = self.body_fn_sig()?;
let substs = sig.output().walk().find_map(|arg| {
@@ -528,31 +536,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
for ty in [first_ty, second_ty] {
- for (pred, _) in self
+ for (clause, _) in self
.tcx
.explicit_item_bounds(rpit_def_id)
.subst_iter_copied(self.tcx, substs)
{
- let pred = pred.kind().rebind(match pred.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => {
+ let pred = clause.kind().rebind(match clause.kind().skip_binder() {
+ ty::ClauseKind::Trait(trait_pred) => {
// FIXME(rpitit): This will need to be fixed when we move to associated types
assert!(matches!(
*trait_pred.trait_ref.self_ty().kind(),
ty::Alias(_, ty::AliasTy { def_id, substs: alias_substs, .. })
if def_id == rpit_def_id && substs == alias_substs
));
- ty::PredicateKind::Clause(ty::Clause::Trait(
- trait_pred.with_self_ty(self.tcx, ty),
- ))
+ ty::ClauseKind::Trait(trait_pred.with_self_ty(self.tcx, ty))
}
- ty::PredicateKind::Clause(ty::Clause::Projection(mut proj_pred)) => {
+ ty::ClauseKind::Projection(mut proj_pred) => {
assert!(matches!(
*proj_pred.projection_ty.self_ty().kind(),
ty::Alias(_, ty::AliasTy { def_id, substs: alias_substs, .. })
if def_id == rpit_def_id && substs == alias_substs
));
proj_pred = proj_pred.with_self_ty(self.tcx, ty);
- ty::PredicateKind::Clause(ty::Clause::Projection(proj_pred))
+ ty::ClauseKind::Projection(proj_pred)
}
_ => continue,
});
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 655ab94eb..f306653c1 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -6,8 +6,9 @@ use crate::type_error_struct;
use rustc_ast::util::parser::PREC_POSTFIX;
use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, StashKey};
use rustc_hir as hir;
-use rustc_hir::def::{self, CtorKind, Namespace, Res};
+use rustc_hir::def::{self, CtorKind, DefKind, Namespace, Res};
use rustc_hir::def_id::DefId;
+use rustc_hir::HirId;
use rustc_hir_analysis::autoderef::Autoderef;
use rustc_infer::{
infer,
@@ -89,7 +90,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => self.check_expr(callee_expr),
};
- let expr_ty = self.structurally_resolved_type(call_expr.span, original_callee_ty);
+ let expr_ty = self.structurally_resolve_type(call_expr.span, original_callee_ty);
let mut autoderef = self.autoderef(callee_expr.span, expr_ty);
let mut result = None;
@@ -138,7 +139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
autoderef: &Autoderef<'a, 'tcx>,
) -> Option<CallStep<'tcx>> {
let adjusted_ty =
- self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
+ self.structurally_resolve_type(autoderef.span(), autoderef.final_ty(false));
// If the callee is a bare function or a closure, then we're all set.
match *adjusted_ty.kind() {
@@ -232,12 +233,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let Some(trait_def_id) = opt_trait_def_id else { continue };
let opt_input_type = opt_arg_exprs.map(|arg_exprs| {
- self.tcx.mk_tup_from_iter(arg_exprs.iter().map(|e| {
- self.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::TypeInference,
- span: e.span,
- })
- }))
+ Ty::new_tup_from_iter(
+ self.tcx,
+ arg_exprs.iter().map(|e| {
+ self.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::TypeInference,
+ span: e.span,
+ })
+ }),
+ )
});
if let Some(ok) = self.lookup_method_in_trait(
@@ -376,15 +380,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Expectation<'tcx>,
) -> Ty<'tcx> {
let (fn_sig, def_id) = match *callee_ty.kind() {
- ty::FnDef(def_id, subst) => {
- let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, subst);
+ ty::FnDef(def_id, substs) => {
+ self.enforce_context_effects(call_expr.hir_id, call_expr.span, def_id, substs);
+ let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, substs);
// Unit testing: function items annotated with
// `#[rustc_evaluate_where_clauses]` trigger special output
// to let us test the trait evaluation system.
if self.tcx.has_attr(def_id, sym::rustc_evaluate_where_clauses) {
let predicates = self.tcx.predicates_of(def_id);
- let predicates = predicates.instantiate(self.tcx, subst);
+ let predicates = predicates.instantiate(self.tcx, substs);
for (predicate, predicate_span) in predicates {
let obligation = Obligation::new(
self.tcx,
@@ -405,6 +410,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
(fn_sig, Some(def_id))
}
+ // FIXME(effects): these arms should error because we can't enforce them
ty::FnPtr(sig) => (sig, None),
_ => {
for arg in arg_exprs {
@@ -420,25 +426,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.steal_diagnostic(segment.ident.span, StashKey::CallIntoMethod)
{
// Try suggesting `foo(a)` -> `a.foo()` if possible.
- if let Some(ty) =
- self.suggest_call_as_method(
- &mut diag,
- segment,
- arg_exprs,
- call_expr,
- expected
- )
- {
- diag.emit();
- return ty;
- } else {
- diag.emit();
- }
+ self.suggest_call_as_method(
+ &mut diag,
+ segment,
+ arg_exprs,
+ call_expr,
+ expected
+ );
+ diag.emit();
}
let err = self.report_invalid_callee(call_expr, callee_expr, callee_ty, arg_exprs);
- return self.tcx.ty_error(err);
+ return Ty::new_error(self.tcx, err);
}
};
@@ -476,6 +476,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.require_lang_item(hir::LangItem::Tuple, Some(sp)),
traits::ObligationCause::new(sp, self.body_id, traits::RustCall),
);
+ self.require_type_is_sized(ty, sp, traits::RustCall);
} else {
self.tcx.sess.span_err(
sp,
@@ -496,9 +497,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
arg_exprs: &'tcx [hir::Expr<'tcx>],
call_expr: &'tcx hir::Expr<'tcx>,
expected: Expectation<'tcx>,
- ) -> Option<Ty<'tcx>> {
+ ) {
if let [callee_expr, rest @ ..] = arg_exprs {
- let callee_ty = self.typeck_results.borrow().expr_ty_adjusted_opt(callee_expr)?;
+ let Some(callee_ty) = self.typeck_results.borrow().expr_ty_adjusted_opt(callee_expr) else {
+ return;
+ };
// First, do a probe with `IsSuggestion(true)` to avoid emitting
// any strange errors. If it's successful, then we'll do a true
@@ -513,7 +516,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ProbeScope::AllTraits,
expected.only_has_type(self),
) else {
- return None;
+ return;
};
let pick = self.confirm_method(
@@ -525,7 +528,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
segment,
);
if pick.illegal_sized_bound.is_some() {
- return None;
+ return;
}
let up_to_rcvr_span = segment.ident.span.until(callee_expr.span);
@@ -567,22 +570,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
sugg,
Applicability::MaybeIncorrect,
);
-
- // Let's check the method fully now
- let return_ty = self.check_method_argument_types(
- segment.ident.span,
- call_expr,
- Ok(pick.callee),
- rest,
- TupleArgumentsFlag::DontTupleArguments,
- expected,
- );
-
- return Some(return_ty);
}
}
-
- None
}
fn report_invalid_callee(
@@ -756,6 +745,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn_sig.output()
}
+ #[tracing::instrument(level = "debug", skip(self, span))]
+ pub(super) fn enforce_context_effects(
+ &self,
+ call_expr_hir: HirId,
+ span: Span,
+ callee_did: DefId,
+ callee_substs: SubstsRef<'tcx>,
+ ) {
+ let tcx = self.tcx;
+
+ if !tcx.features().effects || tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you {
+ return;
+ }
+
+ // Compute the constness required by the context.
+ let context = tcx.hir().enclosing_body_owner(call_expr_hir);
+ let const_context = tcx.hir().body_const_context(context);
+
+ let kind = tcx.def_kind(context.to_def_id());
+ debug_assert_ne!(kind, DefKind::ConstParam);
+
+ if tcx.has_attr(context.to_def_id(), sym::rustc_do_not_const_check) {
+ trace!("do not const check this context");
+ return;
+ }
+
+ let effect = match const_context {
+ Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) => tcx.consts.false_,
+ Some(hir::ConstContext::ConstFn) => {
+ let substs = ty::InternalSubsts::identity_for_item(tcx, context);
+ substs.host_effect_param().expect("ConstContext::Maybe must have host effect param")
+ }
+ None => tcx.consts.true_,
+ };
+
+ let generics = tcx.generics_of(callee_did);
+
+ trace!(?effect, ?generics, ?callee_substs);
+
+ if let Some(idx) = generics.host_effect_index {
+ let param = callee_substs.const_at(idx);
+ let cause = self.misc(span);
+ match self.at(&cause, self.param_env).eq(infer::DefineOpaqueTypes::No, effect, param) {
+ Ok(infer::InferOk { obligations, value: () }) => {
+ self.register_predicates(obligations);
+ }
+ Err(e) => {
+ // FIXME(effects): better diagnostic
+ self.err_ctxt().report_mismatched_consts(&cause, effect, param, e).emit();
+ }
+ }
+ }
+ }
+
fn confirm_overloaded_call(
&self,
call_expr: &'tcx hir::Expr<'tcx>,
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 98c683f02..633933317 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -103,15 +103,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Ok(match *t.kind() {
ty::Slice(_) | ty::Str => Some(PointerKind::Length),
ty::Dynamic(ref tty, _, ty::Dyn) => Some(PointerKind::VTable(tty.principal_def_id())),
- ty::Adt(def, substs) if def.is_struct() => {
- match def.non_enum_variant().fields.raw.last() {
- None => Some(PointerKind::Thin),
- Some(f) => {
- let field_ty = self.field_ty(span, f, substs);
- self.pointer_kind(field_ty, span)?
- }
+ ty::Adt(def, substs) if def.is_struct() => match def.non_enum_variant().tail_opt() {
+ None => Some(PointerKind::Thin),
+ Some(f) => {
+ let field_ty = self.field_ty(span, f, substs);
+ self.pointer_kind(field_ty, span)?
}
- }
+ },
ty::Tuple(fields) => match fields.last() {
None => Some(PointerKind::Thin),
Some(&f) => self.pointer_kind(f, span)?,
@@ -393,7 +391,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
&& fcx
.try_coerce(
self.expr,
- fcx.tcx.mk_ref(
+ Ty::new_ref(fcx.tcx,
fcx.tcx.lifetimes.re_erased,
TypeAndMut { ty: expr_ty, mutbl },
),
@@ -410,7 +408,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
&& fcx
.try_coerce(
self.expr,
- fcx.tcx.mk_ref(
+ Ty::new_ref(fcx.tcx,
expr_reg,
TypeAndMut { ty: expr_ty, mutbl: Mutability::Mut },
),
@@ -428,7 +426,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
&& fcx
.try_coerce(
self.expr,
- fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }),
+ Ty::new_ref(fcx.tcx,reg, TypeAndMut { ty: self.expr_ty, mutbl }),
self.cast_ty,
AllowTwoPhase::No,
None,
@@ -441,7 +439,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
&& fcx
.try_coerce(
self.expr,
- fcx.tcx.mk_ref(
+ Ty::new_ref(fcx.tcx,
fcx.tcx.lifetimes.re_erased,
TypeAndMut { ty: self.expr_ty, mutbl },
),
@@ -689,8 +687,6 @@ impl<'a, 'tcx> CastCheck<'tcx> {
fn trivial_cast_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
let t_cast = self.cast_ty;
let t_expr = self.expr_ty;
- let type_asc_or =
- if fcx.tcx.features().type_ascription { "type ascription or " } else { "" };
let (adjective, lint) = if t_cast.is_numeric() && t_expr.is_numeric() {
("numeric ", lint::builtin::TRIVIAL_NUMERIC_CASTS)
} else {
@@ -711,7 +707,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|lint| {
lint.help(format!(
"cast can be replaced by coercion; this might \
- require {type_asc_or}a temporary variable"
+ require a temporary variable"
))
},
);
@@ -719,8 +715,8 @@ impl<'a, 'tcx> CastCheck<'tcx> {
#[instrument(skip(fcx), level = "debug")]
pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) {
- self.expr_ty = fcx.structurally_resolved_type(self.expr_span, self.expr_ty);
- self.cast_ty = fcx.structurally_resolved_type(self.cast_span, self.cast_ty);
+ self.expr_ty = fcx.structurally_resolve_type(self.expr_span, self.expr_ty);
+ self.cast_ty = fcx.structurally_resolve_type(self.cast_span, self.cast_ty);
debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty);
@@ -767,7 +763,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
let res = fcx.try_coerce(
self.expr,
self.expr_ty,
- fcx.tcx.mk_fn_ptr(f),
+ Ty::new_fn_ptr(fcx.tcx, f),
AllowTwoPhase::No,
None,
);
@@ -959,7 +955,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
// from a region pointer to a vector.
// Coerce to a raw pointer so that we generate AddressOf in MIR.
- let array_ptr_type = fcx.tcx.mk_ptr(m_expr);
+ let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr);
fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None)
.unwrap_or_else(|_| {
bug!(
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index bfabd44bb..8b57e311f 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -62,11 +62,11 @@ pub(super) fn check_fn<'a, 'tcx>(
fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
yield_ty
} else {
- tcx.mk_unit()
+ Ty::new_unit(tcx,)
};
// 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());
+ let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| Ty::new_unit(tcx,));
fcx.resume_yield_tys = Some((resume_ty, yield_ty));
}
@@ -92,11 +92,20 @@ pub(super) fn check_fn<'a, 'tcx>(
fcx.check_pat_top(&param.pat, param_ty, ty_span, None);
// Check that argument is Sized.
- // The check for a non-trivial pattern is a hack to avoid duplicate warnings
- // for simple cases like `fn foo(x: Trait)`,
- // where we would error once on the parameter as a whole, and once on the binding `x`.
- if param.pat.simple_ident().is_none() && !params_can_be_unsized {
- fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
+ if !params_can_be_unsized {
+ fcx.require_type_is_sized(
+ param_ty,
+ param.pat.span,
+ // ty_span == binding_span iff this is a closure parameter with no type ascription,
+ // or if it's an implicit `self` parameter
+ traits::SizedArgumentType(
+ if ty_span == Some(param.span) && tcx.is_closure(fn_def_id.into()) {
+ None
+ } else {
+ ty_span
+ },
+ ),
+ );
}
fcx.write_ty(param.hir_id, param_ty);
@@ -247,10 +256,10 @@ fn check_lang_start_fn<'tcx>(
// for example `start`'s generic should be a type parameter
let generics = tcx.generics_of(def_id);
let fn_generic = generics.param_at(0, tcx);
- let generic_ty = tcx.mk_ty_param(fn_generic.index, fn_generic.name);
+ let generic_ty = Ty::new_param(tcx, fn_generic.index, fn_generic.name);
let expected_fn_sig =
tcx.mk_fn_sig([], generic_ty, false, hir::Unsafety::Normal, Abi::Rust);
- let expected_ty = tcx.mk_fn_ptr(Binder::dummy(expected_fn_sig));
+ let expected_ty = Ty::new_fn_ptr(tcx, Binder::dummy(expected_fn_sig));
// we emit the same error to suggest changing the arg no matter what's wrong with the arg
let emit_main_fn_arg_err = || {
@@ -307,9 +316,9 @@ fn check_lang_start_fn<'tcx>(
if !argv_is_okay {
let inner_ptr_ty =
- tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: tcx.types.u8 });
+ Ty::new_ptr(tcx, ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: tcx.types.u8 });
let expected_ty =
- tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: inner_ptr_ty });
+ Ty::new_ptr(tcx, ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: inner_ptr_ty });
tcx.sess.emit_err(LangStartIncorrectParam {
param_span: decl.inputs[2].span,
param_num: 3,
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 9659a0ec1..78a9ac49d 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -98,7 +98,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.typeck_root_def_id(expr_def_id.to_def_id()),
);
- let tupled_upvars_ty = self.next_ty_var(TypeVariableOrigin {
+ let tupled_upvars_ty = self.next_root_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::ClosureSynthetic,
span: self.tcx.def_span(expr_def_id),
});
@@ -117,7 +117,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
},
);
- return self.tcx.mk_generator(
+ return Ty::new_generator(
+ self.tcx,
expr_def_id.to_def_id(),
generator_substs.substs,
movability,
@@ -128,7 +129,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// the `closures` table.
let sig = bound_sig.map_bound(|sig| {
self.tcx.mk_fn_sig(
- [self.tcx.mk_tup(sig.inputs())],
+ [Ty::new_tup(self.tcx, sig.inputs())],
sig.output(),
sig.c_variadic,
sig.unsafety,
@@ -143,7 +144,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Create a type variable (for now) to represent the closure kind.
// It will be unified during the upvar inference phase (`upvar.rs`)
- None => self.next_ty_var(TypeVariableOrigin {
+ None => self.next_root_ty_var(TypeVariableOrigin {
// FIXME(eddyb) distinguish closure kind inference variables from the rest.
kind: TypeVariableOriginKind::ClosureSynthetic,
span: expr_span,
@@ -155,12 +156,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::ClosureSubstsParts {
parent_substs,
closure_kind_ty,
- closure_sig_as_fn_ptr_ty: self.tcx.mk_fn_ptr(sig),
+ closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(self.tcx, sig),
tupled_upvars_ty,
},
);
- self.tcx.mk_closure(expr_def_id.to_def_id(), closure_substs.substs)
+ Ty::new_closure(self.tcx, expr_def_id.to_def_id(), closure_substs.substs)
}
/// Given the expected type, figures out what it can about this closure we
@@ -174,7 +175,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self
.deduce_closure_signature_from_predicates(
expected_ty,
- self.tcx.explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs),
+ self.tcx
+ .explicit_item_bounds(def_id)
+ .subst_iter_copied(self.tcx, substs)
+ .map(|(c, s)| (c.as_predicate(), s)),
),
ty::Dynamic(ref object_type, ..) => {
let sig = object_type.projection_bounds().find_map(|pb| {
@@ -187,7 +191,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(sig, kind)
}
ty::Infer(ty::TyVar(vid)) => self.deduce_closure_signature_from_predicates(
- self.tcx.mk_ty_var(self.root_var(vid)),
+ Ty::new_var(self.tcx, self.root_var(vid)),
self.obligations_for_self_ty(vid).map(|obl| (obl.predicate, obl.cause.span)),
),
ty::FnPtr(sig) => {
@@ -222,7 +226,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// 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()
+ && let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj_predicate)) = bound_predicate.skip_binder()
{
let inferred_sig = self.normalize(
span,
@@ -258,10 +262,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// 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)) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
Some(data.projection_ty.trait_def_id(self.tcx))
}
- ty::PredicateKind::Clause(ty::Clause::Trait(data)) => Some(data.def_id()),
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => Some(data.def_id()),
_ => None,
};
if let Some(closure_kind) =
@@ -695,7 +699,7 @@ 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::Clause(ty::Clause::Projection(proj_predicate)) =
+ if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj_predicate)) =
bound_predicate.skip_binder()
{
self.deduce_future_output_from_projection(
@@ -717,13 +721,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.tcx
.explicit_item_bounds(def_id)
.subst_iter_copied(self.tcx, substs)
- .find_map(|(p, s)| get_future_output(p, s))?,
+ .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?,
ty::Error(_) => return None,
ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => self
.tcx
.explicit_item_bounds(proj.def_id)
.subst_iter_copied(self.tcx, proj.substs)
- .find_map(|(p, s)| get_future_output(p, s))?,
+ .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?,
_ => span_bug!(
self.tcx.def_span(expr_def_id),
"async fn generator return type not an inference variable: {ret_ty}"
@@ -803,7 +807,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
guar: ErrorGuaranteed,
) -> ty::PolyFnSig<'tcx> {
let astconv: &dyn AstConv<'_> = self;
- let err_ty = self.tcx.ty_error(guar);
+ let err_ty = Ty::new_error(self.tcx, guar);
let supplied_arguments = decl.inputs.iter().map(|a| {
// Convert the types that the user supplied (if any), but ignore them.
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 08c4082e8..dc58d99ed 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -36,9 +36,7 @@
//! ```
use crate::FnCtxt;
-use rustc_errors::{
- struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
-};
+use rustc_errors::{struct_span_err, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{self, Visitor};
@@ -49,7 +47,7 @@ use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult};
use rustc_infer::traits::{Obligation, PredicateObligation};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::adjustment::{
- Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
+ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion,
};
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::relate::RelateResult;
@@ -58,10 +56,11 @@ use rustc_middle::ty::visit::TypeVisitableExt;
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_span::{self, DesugaringKind};
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::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{
self, NormalizeExt, ObligationCause, ObligationCauseCode, ObligationCtxt,
};
@@ -144,12 +143,28 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub);
self.commit_if_ok(|_| {
let at = self.at(&self.cause, self.fcx.param_env);
- if self.use_lub {
+
+ let res = if self.use_lub {
at.lub(DefineOpaqueTypes::Yes, b, a)
} else {
at.sup(DefineOpaqueTypes::Yes, b, a)
.map(|InferOk { value: (), obligations }| InferOk { value: a, obligations })
+ };
+
+ // In the new solver, lazy norm may allow us to shallowly equate
+ // more types, but we emit possibly impossible-to-satisfy obligations.
+ // Filter these cases out to make sure our coercion is more accurate.
+ if self.next_trait_solver() {
+ if let Ok(res) = &res {
+ for obligation in &res.obligations {
+ if !self.predicate_may_hold(&obligation) {
+ return Err(TypeError::Mismatch);
+ }
+ }
+ }
}
+
+ res
})
}
@@ -177,7 +192,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
let _ = self.commit_if_ok(|_| {
self.at(&self.cause, self.param_env).eq(DefineOpaqueTypes::Yes, a, b)
});
- return success(vec![], self.fcx.tcx.ty_error(guar), vec![]);
+ return success(vec![], Ty::new_error(self.fcx.tcx, guar), vec![]);
}
// Coercing from `!` to any type is allowed:
@@ -425,7 +440,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
}
r_borrow_var.unwrap()
};
- let derefd_ty_a = self.tcx.mk_ref(
+ let derefd_ty_a = Ty::new_ref(
+ self.tcx,
r,
TypeAndMut {
ty: referent_ty,
@@ -543,9 +559,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
Adjustment { kind: Adjust::Deref(None), target: ty_a },
Adjustment {
kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mutbl)),
- target: self
- .tcx
- .mk_ref(r_borrow, ty::TypeAndMut { mutbl: mutbl_b, ty: ty_a }),
+ target: Ty::new_ref(
+ self.tcx,
+ r_borrow,
+ ty::TypeAndMut { mutbl: mutbl_b, ty: ty_a },
+ ),
},
))
}
@@ -556,7 +574,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
Adjustment { kind: Adjust::Deref(None), target: ty_a },
Adjustment {
kind: Adjust::Borrow(AutoBorrow::RawPtr(mt_b)),
- target: self.tcx.mk_ptr(ty::TypeAndMut { mutbl: mt_b, ty: ty_a }),
+ target: Ty::new_ptr(self.tcx, ty::TypeAndMut { mutbl: mt_b, ty: ty_a }),
},
))
}
@@ -574,7 +592,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
};
let coerce_target = self.next_ty_var(origin);
let mut coercion = self.unify_and(coerce_target, target, |target| {
- let unsize = Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target };
+ let unsize = Adjustment { kind: Adjust::Pointer(PointerCoercion::Unsize), target };
match reborrow {
None => vec![unsize],
Some((ref deref, ref autoref)) => vec![deref.clone(), autoref.clone(), unsize],
@@ -614,9 +632,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
while !queue.is_empty() {
let obligation = queue.remove(0);
debug!("coerce_unsized resolve step: {:?}", obligation);
- let bound_predicate = obligation.predicate.kind();
- let trait_pred = match bound_predicate.skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred))
+ let trait_pred = match obligation.predicate.kind().no_bound_vars() {
+ Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)))
if traits.contains(&trait_pred.def_id()) =>
{
if unsize_did == trait_pred.def_id() {
@@ -634,7 +651,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
has_unsized_tuple_coercion = true;
}
}
- bound_predicate.rebind(trait_pred)
+ trait_pred
}
_ => {
coercion.obligations.push(obligation);
@@ -646,8 +663,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
Ok(None) => {
if trait_pred.def_id() == unsize_did {
let trait_pred = self.resolve_vars_if_possible(trait_pred);
- let self_ty = trait_pred.skip_binder().self_ty();
- let unsize_ty = trait_pred.skip_binder().trait_ref.substs[1].expect_ty();
+ let self_ty = trait_pred.self_ty();
+ let unsize_ty = trait_pred.trait_ref.substs[1].expect_ty();
debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred);
match (self_ty.kind(), unsize_ty.kind()) {
(&ty::Infer(ty::TyVar(v)), ty::Dynamic(..))
@@ -752,7 +769,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
self.tcx,
self.cause.clone(),
self.param_env,
- ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::TypeOutlives(
+ ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(
ty::OutlivesPredicate(a, b_region),
))),
),
@@ -791,6 +808,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
G: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
{
self.commit_if_ok(|snapshot| {
+ let outer_universe = self.infcx.universe();
+
let result = if let ty::FnPtr(fn_ty_b) = b.kind()
&& let (hir::Unsafety::Normal, hir::Unsafety::Unsafe) =
(fn_ty_a.unsafety(), fn_ty_b.unsafety())
@@ -807,7 +826,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// want the coerced type to be the actual supertype of these two,
// but for now, we want to just error to ensure we don't lock
// ourselves into a specific behavior with NLL.
- self.leak_check(false, snapshot)?;
+ self.leak_check(outer_universe, Some(snapshot))?;
result
})
@@ -830,7 +849,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
a,
fn_ty_a,
b,
- simple(Adjust::Pointer(PointerCast::UnsafeFnPointer)),
+ simple(Adjust::Pointer(PointerCoercion::UnsafeFnPointer)),
identity,
)
}
@@ -866,7 +885,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
self.at(&self.cause, self.param_env).normalize(a_sig);
obligations.extend(o1);
- let a_fn_pointer = self.tcx.mk_fn_ptr(a_sig);
+ let a_fn_pointer = Ty::new_fn_ptr(self.tcx, a_sig);
let InferOk { value, obligations: o2 } = self.coerce_from_safe_fn(
a_fn_pointer,
a_sig,
@@ -874,16 +893,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|unsafe_ty| {
vec![
Adjustment {
- kind: Adjust::Pointer(PointerCast::ReifyFnPointer),
+ kind: Adjust::Pointer(PointerCoercion::ReifyFnPointer),
target: a_fn_pointer,
},
Adjustment {
- kind: Adjust::Pointer(PointerCast::UnsafeFnPointer),
+ kind: Adjust::Pointer(PointerCoercion::UnsafeFnPointer),
target: unsafe_ty,
},
]
},
- simple(Adjust::Pointer(PointerCast::ReifyFnPointer)),
+ simple(Adjust::Pointer(PointerCoercion::ReifyFnPointer)),
)?;
obligations.extend(o2);
@@ -928,12 +947,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
let closure_sig = substs_a.as_closure().sig();
let unsafety = fn_ty.unsafety();
let pointer_ty =
- self.tcx.mk_fn_ptr(self.tcx.signature_unclosure(closure_sig, unsafety));
+ Ty::new_fn_ptr(self.tcx, self.tcx.signature_unclosure(closure_sig, unsafety));
debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", a, b, pointer_ty);
self.unify_and(
pointer_ty,
b,
- simple(Adjust::Pointer(PointerCast::ClosureFnPointer(unsafety))),
+ simple(Adjust::Pointer(PointerCoercion::ClosureFnPointer(unsafety))),
)
}
_ => self.unify_and(a, b, identity),
@@ -956,7 +975,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
coerce_mutbls(mt_a.mutbl, mutbl_b)?;
// Check that the types which they point at are compatible.
- let a_unsafe = self.tcx.mk_ptr(ty::TypeAndMut { mutbl: mutbl_b, ty: mt_a.ty });
+ let a_unsafe = Ty::new_ptr(self.tcx, ty::TypeAndMut { mutbl: mutbl_b, ty: mt_a.ty });
// Although references and unsafe ptrs have the same
// representation, we still register an Adjust::DerefRef so that
// regionck knows that the region for `a` must be valid here.
@@ -968,7 +987,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
]
})
} else if mt_a.mutbl != mutbl_b {
- self.unify_and(a_unsafe, b, simple(Adjust::Pointer(PointerCast::MutToConstPointer)))
+ self.unify_and(a_unsafe, b, simple(Adjust::Pointer(PointerCoercion::MutToConstPointer)))
} else {
self.unify_and(a_unsafe, b, identity)
}
@@ -988,7 +1007,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
allow_two_phase: AllowTwoPhase,
cause: Option<ObligationCause<'tcx>>,
) -> RelateResult<'tcx, Ty<'tcx>> {
- let source = self.resolve_vars_with_obligations(expr_ty);
+ let source = self.try_structurally_resolve_type(expr.span, expr_ty);
debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
let cause =
@@ -998,7 +1017,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let (adjustments, _) = self.register_infer_ok_obligations(ok);
self.apply_adjustments(expr, adjustments);
- Ok(if let Err(guar) = expr_ty.error_reported() { self.tcx.ty_error(guar) } else { target })
+ Ok(if let Err(guar) = expr_ty.error_reported() {
+ Ty::new_error(self.tcx, guar)
+ } else {
+ target
+ })
}
/// Same as `try_coerce()`, but without side-effects.
@@ -1016,7 +1039,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let Ok(ok) = coerce.coerce(source, target) else {
return false;
};
- let ocx = ObligationCtxt::new_in_snapshot(self);
+ let ocx = ObligationCtxt::new(self);
ocx.register_obligations(ok.obligations);
ocx.select_where_possible().is_empty()
})
@@ -1162,15 +1185,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.map(|ok| self.register_infer_ok_obligations(ok))?;
// Reify both sides and return the reified fn pointer type.
- let fn_ptr = self.tcx.mk_fn_ptr(sig);
+ let fn_ptr = Ty::new_fn_ptr(self.tcx, sig);
let prev_adjustment = match prev_ty.kind() {
- ty::Closure(..) => Adjust::Pointer(PointerCast::ClosureFnPointer(a_sig.unsafety())),
- ty::FnDef(..) => Adjust::Pointer(PointerCast::ReifyFnPointer),
+ ty::Closure(..) => {
+ Adjust::Pointer(PointerCoercion::ClosureFnPointer(a_sig.unsafety()))
+ }
+ ty::FnDef(..) => Adjust::Pointer(PointerCoercion::ReifyFnPointer),
_ => unreachable!(),
};
let next_adjustment = match new_ty.kind() {
- ty::Closure(..) => Adjust::Pointer(PointerCast::ClosureFnPointer(b_sig.unsafety())),
- ty::FnDef(..) => Adjust::Pointer(PointerCast::ReifyFnPointer),
+ ty::Closure(..) => {
+ Adjust::Pointer(PointerCoercion::ClosureFnPointer(b_sig.unsafety()))
+ }
+ ty::FnDef(..) => Adjust::Pointer(PointerCoercion::ReifyFnPointer),
_ => unreachable!(),
};
for expr in exprs.iter().map(|e| e.as_coercion_site()) {
@@ -1413,7 +1440,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
fcx,
cause,
None,
- fcx.tcx.mk_unit(),
+ Ty::new_unit(fcx.tcx),
Some(augment_error),
label_unit_as_expected,
)
@@ -1444,7 +1471,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
// If we see any error types, just propagate that error
// upwards.
if let Err(guar) = (expression_ty, self.merged_ty()).error_reported() {
- self.final_ty = Some(fcx.tcx.ty_error(guar));
+ self.final_ty = Some(Ty::new_error(fcx.tcx, guar));
return;
}
@@ -1576,7 +1603,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
Some(blk_id),
);
if !fcx.tcx.features().unsized_locals {
- unsized_return = self.is_return_ty_unsized(fcx, blk_id);
+ unsized_return = self.is_return_ty_definitely_unsized(fcx);
}
if let Some(expression) = expression
&& let hir::ExprKind::Loop(loop_blk, ..) = expression.kind {
@@ -1595,8 +1622,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
None,
);
if !fcx.tcx.features().unsized_locals {
- let id = fcx.tcx.hir().parent_id(id);
- unsized_return = self.is_return_ty_unsized(fcx, id);
+ unsized_return = self.is_return_ty_definitely_unsized(fcx);
}
}
_ => {
@@ -1633,7 +1659,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
let reported = err.emit_unless(unsized_return);
- self.final_ty = Some(fcx.tcx.ty_error(reported));
+ self.final_ty = Some(Ty::new_error(fcx.tcx, reported));
}
}
}
@@ -1684,9 +1710,6 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let mut err = fcx.err_ctxt().report_mismatched_types(cause, expected, found, ty_err);
- let mut pointing_at_return_type = false;
- let mut fn_output = None;
-
let parent_id = fcx.tcx.hir().parent_id(id);
let parent = fcx.tcx.hir().get(parent_id);
if let Some(expr) = expression
@@ -1699,7 +1722,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
// label pointing out the cause for the type coercion will be wrong
// as prior return coercions would not be relevant (#57664).
let fn_decl = if let (Some(expr), Some(blk_id)) = (expression, blk_id) {
- pointing_at_return_type =
+ let pointing_at_return_type =
fcx.suggest_mismatched_types_on_tail(&mut err, expr, expected, found, blk_id);
if let (Some(cond_expr), true, false) = (
fcx.tcx.hir().get_if_cause(expr.hir_id),
@@ -1731,7 +1754,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
if let Some((fn_id, fn_decl, can_suggest)) = fn_decl {
if blk_id.is_none() {
- pointing_at_return_type |= fcx.suggest_missing_return_type(
+ fcx.suggest_missing_return_type(
&mut err,
&fn_decl,
expected,
@@ -1740,9 +1763,6 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
fn_id,
);
}
- if !pointing_at_return_type {
- fn_output = Some(&fn_decl.output); // `impl Trait` return type
- }
}
let parent_id = fcx.tcx.hir().get_parent_item(id);
@@ -1777,115 +1797,27 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
);
}
- if let (Some(sp), Some(fn_output)) = (ret_coercion_span, fn_output) {
- self.add_impl_trait_explanation(&mut err, cause, fcx, expected, sp, fn_output);
- }
-
err
}
- fn add_impl_trait_explanation<'a>(
- &self,
- err: &mut Diagnostic,
- cause: &ObligationCause<'tcx>,
- fcx: &FnCtxt<'a, 'tcx>,
- expected: Ty<'tcx>,
- sp: Span,
- fn_output: &hir::FnRetTy<'_>,
- ) {
- let return_sp = fn_output.span();
- err.span_label(return_sp, "expected because this return type...");
- err.span_label(
- sp,
- format!("...is found to be `{}` here", fcx.resolve_vars_with_obligations(expected)),
- );
- let impl_trait_msg = "for information on `impl Trait`, see \
- <https://doc.rust-lang.org/book/ch10-02-traits.html\
- #returning-types-that-implement-traits>";
- let trait_obj_msg = "for information on trait objects, see \
- <https://doc.rust-lang.org/book/ch17-02-trait-objects.html\
- #using-trait-objects-that-allow-for-values-of-different-types>";
- err.note("to return `impl Trait`, all returned values must be of the same type");
- err.note(impl_trait_msg);
- let snippet = fcx
- .tcx
- .sess
- .source_map()
- .span_to_snippet(return_sp)
- .unwrap_or_else(|_| "dyn Trait".to_string());
- let mut snippet_iter = snippet.split_whitespace();
- let has_impl = snippet_iter.next().is_some_and(|s| s == "impl");
- // Only suggest `Box<dyn Trait>` if `Trait` in `impl Trait` is object safe.
- let mut is_object_safe = false;
- if let hir::FnRetTy::Return(ty) = fn_output
- // Get the return type.
- && let hir::TyKind::OpaqueDef(..) = ty.kind
- {
- let ty = fcx.astconv().ast_ty_to_ty( ty);
- // Get the `impl Trait`'s `DefId`.
- if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind()
- // Get the `impl Trait`'s `Item` so that we can get its trait bounds and
- // get the `Trait`'s `DefId`.
- && let hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, .. }) =
- fcx.tcx.hir().expect_item(def_id.expect_local()).kind
- {
- // Are of this `impl Trait`'s traits object safe?
- is_object_safe = bounds.iter().all(|bound| {
- bound
- .trait_ref()
- .and_then(|t| t.trait_def_id())
- .is_some_and(|def_id| {
- fcx.tcx.check_is_object_safe(def_id)
- })
- })
- }
- };
- if has_impl {
- if is_object_safe {
- err.multipart_suggestion(
- "you could change the return type to be a boxed trait object",
- vec![
- (return_sp.with_hi(return_sp.lo() + BytePos(4)), "Box<dyn".to_string()),
- (return_sp.shrink_to_hi(), ">".to_string()),
- ],
- Applicability::MachineApplicable,
- );
- let sugg = [sp, cause.span]
- .into_iter()
- .flat_map(|sp| {
- [
- (sp.shrink_to_lo(), "Box::new(".to_string()),
- (sp.shrink_to_hi(), ")".to_string()),
- ]
- .into_iter()
- })
- .collect::<Vec<_>>();
- err.multipart_suggestion(
- "if you change the return type to expect trait objects, box the returned \
- expressions",
- sugg,
- Applicability::MaybeIncorrect,
- );
- } else {
- err.help(format!(
- "if the trait `{}` were object safe, you could return a boxed trait object",
- &snippet[5..]
- ));
- }
- err.note(trait_obj_msg);
- }
- err.help("you could instead create a new `enum` with a variant for each returned type");
- }
-
- fn is_return_ty_unsized<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool {
- if let Some((_, fn_decl, _)) = fcx.get_fn_decl(blk_id)
- && let hir::FnRetTy::Return(ty) = fn_decl.output
- && let ty = fcx.astconv().ast_ty_to_ty( ty)
- && let ty::Dynamic(..) = ty.kind()
- {
- return true;
+ /// Checks whether the return type is unsized via an obligation, which makes
+ /// sure we consider `dyn Trait: Sized` where clauses, which are trivially
+ /// false but technically valid for typeck.
+ fn is_return_ty_definitely_unsized(&self, fcx: &FnCtxt<'_, 'tcx>) -> bool {
+ if let Some(sig) = fcx.body_fn_sig() {
+ !fcx.predicate_may_hold(&Obligation::new(
+ fcx.tcx,
+ ObligationCause::dummy(),
+ fcx.param_env,
+ ty::TraitRef::new(
+ fcx.tcx,
+ fcx.tcx.require_lang_item(hir::LangItem::Sized, None),
+ [sig.output()],
+ ),
+ ))
+ } else {
+ false
}
- false
}
pub fn complete<'a>(self, fcx: &FnCtxt<'a, 'tcx>) -> Ty<'tcx> {
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index b50630e63..cc8198aab 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -3,7 +3,7 @@ use rustc_ast::util::parser::PREC_POSTFIX;
use rustc_errors::MultiSpan;
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
-use rustc_hir::def::CtorKind;
+use rustc_hir::def::{CtorKind, Res};
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{is_range_literal, Node};
@@ -83,6 +83,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
self.annotate_expected_due_to_let_ty(err, expr, error);
+
+ if self.is_destruct_assignment_desugaring(expr) {
+ return;
+ }
self.emit_type_mismatch_suggestions(err, expr, expr_ty, expected, expected_ty_expr, error);
self.note_type_is_not_clone(err, expected, expr_ty, expr);
self.note_internal_mutation_in_method(err, expr, Some(expected), expr_ty);
@@ -91,6 +95,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.note_wrong_return_ty_due_to_generic_arg(err, expr, expr_ty);
}
+ /// Really hacky heuristic to remap an `assert_eq!` error to the user
+ /// expressions provided to the macro.
+ fn adjust_expr_for_assert_eq_macro(
+ &self,
+ found_expr: &mut &'tcx hir::Expr<'tcx>,
+ expected_expr: &mut Option<&'tcx hir::Expr<'tcx>>,
+ ) {
+ let Some(expected_expr) = expected_expr else { return; };
+
+ if !found_expr.span.eq_ctxt(expected_expr.span) {
+ return;
+ }
+
+ if !found_expr
+ .span
+ .ctxt()
+ .outer_expn_data()
+ .macro_def_id
+ .is_some_and(|def_id| self.tcx.is_diagnostic_item(sym::assert_eq_macro, def_id))
+ {
+ return;
+ }
+
+ let hir::ExprKind::Unary(
+ hir::UnOp::Deref,
+ hir::Expr { kind: hir::ExprKind::Path(found_path), .. },
+ ) = found_expr.kind else { return; };
+ let hir::ExprKind::Unary(
+ hir::UnOp::Deref,
+ hir::Expr { kind: hir::ExprKind::Path(expected_path), .. },
+ ) = expected_expr.kind else { return; };
+
+ for (path, name, idx, var) in [
+ (expected_path, "left_val", 0, expected_expr),
+ (found_path, "right_val", 1, found_expr),
+ ] {
+ if let hir::QPath::Resolved(_, path) = path
+ && let [segment] = path.segments
+ && segment.ident.name.as_str() == name
+ && let Res::Local(hir_id) = path.res
+ && let Some((_, hir::Node::Expr(match_expr))) = self.tcx.hir().parent_iter(hir_id).nth(2)
+ && let hir::ExprKind::Match(scrutinee, _, _) = match_expr.kind
+ && let hir::ExprKind::Tup(exprs) = scrutinee.kind
+ && let hir::ExprKind::AddrOf(_, _, macro_arg) = exprs[idx].kind
+ {
+ *var = macro_arg;
+ }
+ }
+ }
+
/// 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>) {
@@ -156,7 +210,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn demand_coerce(
&self,
- expr: &hir::Expr<'tcx>,
+ expr: &'tcx hir::Expr<'tcx>,
checked_ty: Ty<'tcx>,
expected: Ty<'tcx>,
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
@@ -177,10 +231,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
#[instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))]
pub fn demand_coerce_diag(
&self,
- expr: &hir::Expr<'tcx>,
+ mut expr: &'tcx hir::Expr<'tcx>,
checked_ty: Ty<'tcx>,
expected: Ty<'tcx>,
- expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
+ mut expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
allow_two_phase: AllowTwoPhase,
) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>) {
let expected = self.resolve_vars_with_obligations(expected);
@@ -190,6 +244,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Err(e) => e,
};
+ self.adjust_expr_for_assert_eq_macro(&mut expr, &mut expected_ty_expr);
+
self.set_tainted_by_errors(self.tcx.sess.delay_span_bug(
expr.span,
"`TypeError` when attempting coercion but no error emitted",
@@ -318,13 +374,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Fudge the receiver, so we can do new inference on it.
let possible_rcvr_ty = possible_rcvr_ty.fold_with(&mut fudger);
let method = self
- .lookup_method(
+ .lookup_method_for_diagnostic(
possible_rcvr_ty,
segment,
DUMMY_SP,
call_expr,
binding,
- args,
)
.ok()?;
// Unify the method signature with our incompatible arg, to
@@ -383,14 +438,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let Some(rcvr_ty) = self.node_ty_opt(rcvr.hir_id) else { continue; };
let rcvr_ty = rcvr_ty.fold_with(&mut fudger);
let Ok(method) =
- self.lookup_method(rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr, args)
+ self.lookup_method_for_diagnostic(rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr)
else {
continue;
};
let ideal_rcvr_ty = rcvr_ty.fold_with(&mut fudger);
let ideal_method = self
- .lookup_method(ideal_rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr, args)
+ .lookup_method_for_diagnostic(ideal_rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr)
.ok()
.and_then(|method| {
let _ = self.at(&ObligationCause::dummy(), self.param_env)
@@ -1202,6 +1257,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
false
}
+ // Returns whether the given expression is a destruct assignment desugaring.
+ // For example, `(a, b) = (1, &2);`
+ // Here we try to find the pattern binding of the expression,
+ // `default_binding_modes` is false only for destruct assignment desugaring.
+ pub(crate) fn is_destruct_assignment_desugaring(&self, expr: &hir::Expr<'_>) -> bool {
+ if let hir::ExprKind::Path(hir::QPath::Resolved(
+ _,
+ hir::Path { res: hir::def::Res::Local(bind_hir_id), .. },
+ )) = expr.kind
+ {
+ let bind = self.tcx.hir().find(*bind_hir_id);
+ let parent = self.tcx.hir().find(self.tcx.hir().parent_id(*bind_hir_id));
+ if let Some(hir::Node::Pat(hir::Pat { kind: hir::PatKind::Binding(_, _hir_id, _, _), .. })) = bind &&
+ let Some(hir::Node::Pat(hir::Pat { default_binding_modes: false, .. })) = parent {
+ return true;
+ }
+ }
+ return false;
+ }
+
/// This function is used to determine potential "simple" improvements or users' errors and
/// provide them useful help. For example:
///
@@ -1291,10 +1366,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// ```
let ref_ty = match mutability {
hir::Mutability::Mut => {
- self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, checked_ty)
+ Ty::new_mut_ref(self.tcx,self.tcx.lifetimes.re_static, checked_ty)
}
hir::Mutability::Not => {
- self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, checked_ty)
+ Ty::new_imm_ref(self.tcx,self.tcx.lifetimes.re_static, checked_ty)
}
};
if self.can_coerce(ref_ty, expected) {
@@ -1392,6 +1467,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_,
&ty::Ref(_, checked, _),
) if self.can_sub(self.param_env, checked, expected) => {
+ let make_sugg = |start: Span, end: BytePos| {
+ // skip `(` for tuples such as `(c) = (&123)`.
+ // make sure we won't suggest like `(c) = 123)` which is incorrect.
+ let sp = sm.span_extend_while(start.shrink_to_lo(), |c| c == '(' || c.is_whitespace())
+ .map_or(start, |s| s.shrink_to_hi());
+ Some((
+ vec![(sp.with_hi(end), String::new())],
+ "consider removing the borrow".to_string(),
+ Applicability::MachineApplicable,
+ true,
+ true,
+ ))
+ };
+
// We have `&T`, check if what was expected was `T`. If so,
// we may want to suggest removing a `&`.
if sm.is_imported(expr.span) {
@@ -1405,24 +1494,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.find(|&s| sp.contains(s))
&& sm.is_span_accessible(call_span)
{
- return Some((
- vec![(sp.with_hi(call_span.lo()), String::new())],
- "consider removing the borrow".to_string(),
- Applicability::MachineApplicable,
- true,
- true,
- ));
+ return make_sugg(sp, call_span.lo())
}
return None;
}
if sp.contains(expr.span) && sm.is_span_accessible(expr.span) {
- return Some((
- vec![(sp.with_hi(expr.span.lo()), String::new())],
- "consider removing the borrow".to_string(),
- Applicability::MachineApplicable,
- true,
- true,
- ));
+ return make_sugg(sp, expr.span.lo())
}
}
(
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 4222205c8..05906a4b9 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -2,7 +2,10 @@
use std::borrow::Cow;
use crate::fluent_generated as fluent;
-use rustc_errors::{AddToDiagnostic, Applicability, Diagnostic, MultiSpan, SubdiagnosticMessage};
+use rustc_errors::{
+ AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg, MultiSpan,
+ SubdiagnosticMessage,
+};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_middle::ty::Ty;
use rustc_span::{
@@ -31,6 +34,24 @@ pub struct ReturnStmtOutsideOfFnBody {
pub encl_body_span: Option<Span>,
#[label(hir_typeck_encl_fn_label)]
pub encl_fn_span: Option<Span>,
+ pub statement_kind: ReturnLikeStatementKind,
+}
+
+pub enum ReturnLikeStatementKind {
+ Return,
+ Become,
+}
+
+impl IntoDiagnosticArg for ReturnLikeStatementKind {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ let kind = match self {
+ Self::Return => "return",
+ Self::Become => "become",
+ }
+ .into();
+
+ DiagnosticArgValue::Str(kind)
+ }
}
#[derive(Diagnostic)]
@@ -298,6 +319,17 @@ pub enum SuggestBoxing {
},
}
+#[derive(Subdiagnostic)]
+#[suggestion(
+ hir_typeck_suggest_ptr_null_mut,
+ applicability = "maybe-incorrect",
+ code = "core::ptr::null_mut()"
+)]
+pub struct SuggestPtrNullMut {
+ #[primary_span]
+ pub span: Span,
+}
+
#[derive(Diagnostic)]
#[diag(hir_typeck_no_associated_item, code = "E0599")]
pub struct NoAssociatedItem {
@@ -327,3 +359,19 @@ pub struct CtorIsPrivate {
pub span: Span,
pub def: String,
}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+ hir_typeck_convert_using_method,
+ applicability = "machine-applicable",
+ style = "verbose"
+)]
+pub struct SuggestConvertViaMethod<'tcx> {
+ #[suggestion_part(code = "{sugg}")]
+ pub span: Span,
+ #[suggestion_part(code = "")]
+ pub borrow_removal_span: Option<Span>,
+ pub sugg: &'static str,
+ pub expected: Ty<'tcx>,
+ pub found: Ty<'tcx>,
+}
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 19ff77d83..72b29f7b6 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::ReturnLikeStatementKind;
use crate::errors::TypeMismatchFruTypo;
use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
use crate::errors::{
@@ -93,7 +94,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return if let [Adjustment { kind: Adjust::NeverToAny, target }] = &adjustments[..] {
target.to_owned()
} else {
- self.tcx().ty_error(reported)
+ Ty::new_error(self.tcx(), reported)
};
}
@@ -320,10 +321,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
tcx.types.never
} else {
// There was an error; make type-check fail.
- tcx.ty_error_misc()
+ Ty::new_misc_error(tcx)
}
}
ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr),
+ ExprKind::Become(call) => self.check_expr_become(call, expr),
ExprKind::Let(let_expr) => self.check_expr_let(let_expr),
ExprKind::Loop(body, _, source, _) => {
self.check_expr_loop(body, source, expected, expr)
@@ -348,9 +350,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected),
ExprKind::Array(args) => self.check_expr_array(args, expected, expr),
- ExprKind::ConstBlock(ref anon_const) => {
- self.check_expr_const_block(anon_const, expected, expr)
- }
+ ExprKind::ConstBlock(ref block) => self.check_expr_const_block(block, expected, expr),
ExprKind::Repeat(element, ref count) => {
self.check_expr_repeat(element, count, expected, expr)
}
@@ -361,7 +361,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ExprKind::Field(base, field) => self.check_field(expr, &base, field, expected),
ExprKind::Index(base, idx) => self.check_expr_index(base, idx, expr),
ExprKind::Yield(value, ref src) => self.check_expr_yield(value, expr, src),
- hir::ExprKind::Err(guar) => tcx.ty_error(guar),
+ hir::ExprKind::Err(guar) => Ty::new_error(tcx, guar),
}
}
@@ -380,7 +380,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut oprnd_t = self.check_expr_with_expectation(&oprnd, expected_inner);
if !oprnd_t.references_error() {
- oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t);
+ oprnd_t = self.structurally_resolve_type(expr.span, oprnd_t);
match unop {
hir::UnOp::Deref => {
if let Some(ty) = self.lookup_derefing(expr, oprnd, oprnd_t) {
@@ -399,7 +399,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
}
- oprnd_t = tcx.ty_error(err.emit());
+ oprnd_t = Ty::new_error(tcx, err.emit());
}
}
hir::UnOp::Not => {
@@ -449,10 +449,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let tm = ty::TypeAndMut { ty, mutbl };
match kind {
- _ if tm.ty.references_error() => self.tcx.ty_error_misc(),
+ _ if tm.ty.references_error() => Ty::new_misc_error(self.tcx),
hir::BorrowKind::Raw => {
self.check_named_place_expr(oprnd);
- self.tcx.mk_ptr(tm)
+ Ty::new_ptr(self.tcx, tm)
}
hir::BorrowKind::Ref => {
// Note: at this point, we cannot say what the best lifetime
@@ -470,7 +470,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// whose address was taken can actually be made to live as long
// as it needs to live.
let region = self.next_region_var(infer::AddrOfRegion(expr.span));
- self.tcx.mk_ref(region, tm)
+ Ty::new_ref(self.tcx, region, tm)
}
}
}
@@ -528,11 +528,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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(e)
+ Ty::new_error(tcx, e)
}
Res::Def(DefKind::Variant, _) => {
let e = report_unexpected_variant_res(tcx, res, qpath, expr.span, "E0533", "value");
- tcx.ty_error(e)
+ Ty::new_error(tcx, e)
}
_ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0,
};
@@ -620,7 +620,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Some(ctxt) => ctxt.coerce.as_ref().map(|coerce| coerce.expected_ty()),
None => {
// Avoid ICE when `break` is inside a closure (#65383).
- return tcx.ty_error_with_message(
+ return Ty::new_error_with_message(
+ tcx,
expr.span,
"break was outside loop, but no error was emitted",
);
@@ -631,7 +632,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If the loop context is not a `loop { }`, then break with
// a value is illegal, and `opt_coerce_to` will be `None`.
// Just set expectation to error in that case.
- let coerce_to = opt_coerce_to.unwrap_or_else(|| tcx.ty_error_misc());
+ let coerce_to = opt_coerce_to.unwrap_or_else(|| Ty::new_misc_error(tcx));
// Recurse without `enclosing_breakables` borrowed.
e_ty = self.check_expr_with_hint(e, coerce_to);
@@ -639,7 +640,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
// Otherwise, this is a break *without* a value. That's
// always legal, and is equivalent to `break ()`.
- e_ty = tcx.mk_unit();
+ e_ty = Ty::new_unit(tcx);
cause = self.misc(expr.span);
}
@@ -649,7 +650,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
let Some(ctxt) = enclosing_breakables.opt_find_breakable(target_id) else {
// Avoid ICE when `break` is inside a closure (#65383).
- return tcx.ty_error_with_message(
+ return Ty::new_error_with_message(tcx,
expr.span,
"break was outside loop, but no error was emitted",
);
@@ -707,7 +708,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// this can only happen if the `break` was not
// inside a loop at all, which is caught by the
// loop-checking pass.
- let err = self.tcx.ty_error_with_message(
+ let err = Ty::new_error_with_message(
+ self.tcx,
expr.span,
"break was outside loop, but no error was emitted",
);
@@ -737,47 +739,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &'tcx hir::Expr<'tcx>,
) -> Ty<'tcx> {
if self.ret_coercion.is_none() {
- let mut err = ReturnStmtOutsideOfFnBody {
- span: expr.span,
- encl_body_span: None,
- encl_fn_span: None,
- };
-
- let encl_item_id = self.tcx.hir().get_parent_item(expr.hir_id);
-
- if let Some(hir::Node::Item(hir::Item {
- kind: hir::ItemKind::Fn(..),
- span: encl_fn_span,
- ..
- }))
- | Some(hir::Node::TraitItem(hir::TraitItem {
- kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)),
- span: encl_fn_span,
- ..
- }))
- | Some(hir::Node::ImplItem(hir::ImplItem {
- kind: hir::ImplItemKind::Fn(..),
- span: encl_fn_span,
- ..
- })) = self.tcx.hir().find_by_def_id(encl_item_id.def_id)
- {
- // We are inside a function body, so reporting "return statement
- // outside of function body" needs an explanation.
-
- let encl_body_owner_id = self.tcx.hir().enclosing_body_owner(expr.hir_id);
-
- // If this didn't hold, we would not have to report an error in
- // the first place.
- assert_ne!(encl_item_id.def_id, encl_body_owner_id);
-
- let encl_body_id = self.tcx.hir().body_owned_by(encl_body_owner_id);
- let encl_body = self.tcx.hir().body(encl_body_id);
-
- err.encl_body_span = Some(encl_body.value.span);
- err.encl_fn_span = Some(*encl_fn_span);
- }
-
- self.tcx.sess.emit_err(err);
+ self.emit_return_outside_of_fn_body(expr, ReturnLikeStatementKind::Return);
if let Some(e) = expr_opt {
// We still have to type-check `e` (issue #86188), but calling
@@ -817,6 +779,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.types.never
}
+ fn check_expr_become(
+ &self,
+ call: &'tcx hir::Expr<'tcx>,
+ expr: &'tcx hir::Expr<'tcx>,
+ ) -> Ty<'tcx> {
+ match &self.ret_coercion {
+ Some(ret_coercion) => {
+ let ret_ty = ret_coercion.borrow().expected_ty();
+ let call_expr_ty = self.check_expr_with_hint(call, ret_ty);
+
+ // N.B. don't coerce here, as tail calls can't support most/all coercions
+ // FIXME(explicit_tail_calls): add a diagnostic note that `become` doesn't allow coercions
+ self.demand_suptype(expr.span, ret_ty, call_expr_ty);
+ }
+ None => {
+ self.emit_return_outside_of_fn_body(expr, ReturnLikeStatementKind::Become);
+
+ // Fallback to simply type checking `call` without hint/demanding the right types.
+ // Best effort to highlight more errors.
+ self.check_expr(call);
+ }
+ }
+
+ self.tcx.types.never
+ }
+
+ /// Check an expression that _is being returned_.
+ /// For example, this is called with `return_expr: $expr` when `return $expr`
+ /// is encountered.
+ ///
+ /// Note that this function must only be called in function bodies.
+ ///
/// `explicit_return` is `true` if we're checking an explicit `return expr`,
/// and `false` if we're checking a trailing expression.
pub(super) fn check_return_expr(
@@ -833,10 +827,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut span = return_expr.span;
// Use the span of the trailing expression for our cause,
// not the span of the entire function
- if !explicit_return {
- if let ExprKind::Block(body, _) = return_expr.kind && let Some(last_expr) = body.expr {
+ if !explicit_return
+ && let ExprKind::Block(body, _) = return_expr.kind
+ && let Some(last_expr) = body.expr
+ {
span = last_expr.span;
- }
}
ret_coercion.borrow_mut().coerce(
self,
@@ -856,6 +851,55 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
+ /// Emit an error because `return` or `become` is used outside of a function body.
+ ///
+ /// `expr` is the `return` (`become`) "statement", `kind` is the kind of the statement
+ /// either `Return` or `Become`.
+ fn emit_return_outside_of_fn_body(&self, expr: &hir::Expr<'_>, kind: ReturnLikeStatementKind) {
+ let mut err = ReturnStmtOutsideOfFnBody {
+ span: expr.span,
+ encl_body_span: None,
+ encl_fn_span: None,
+ statement_kind: kind,
+ };
+
+ let encl_item_id = self.tcx.hir().get_parent_item(expr.hir_id);
+
+ if let Some(hir::Node::Item(hir::Item {
+ kind: hir::ItemKind::Fn(..),
+ span: encl_fn_span,
+ ..
+ }))
+ | Some(hir::Node::TraitItem(hir::TraitItem {
+ kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)),
+ span: encl_fn_span,
+ ..
+ }))
+ | Some(hir::Node::ImplItem(hir::ImplItem {
+ kind: hir::ImplItemKind::Fn(..),
+ span: encl_fn_span,
+ ..
+ })) = self.tcx.hir().find_by_def_id(encl_item_id.def_id)
+ {
+ // We are inside a function body, so reporting "return statement
+ // outside of function body" needs an explanation.
+
+ let encl_body_owner_id = self.tcx.hir().enclosing_body_owner(expr.hir_id);
+
+ // If this didn't hold, we would not have to report an error in
+ // the first place.
+ assert_ne!(encl_item_id.def_id, encl_body_owner_id);
+
+ let encl_body_id = self.tcx.hir().body_owned_by(encl_body_owner_id);
+ let encl_body = self.tcx.hir().body(encl_body_id);
+
+ err.encl_body_span = Some(encl_body.value.span);
+ err.encl_fn_span = Some(*encl_fn_span);
+ }
+
+ self.tcx.sess.emit_err(err);
+ }
+
fn point_at_return_for_opaque_ty_error(
&self,
errors: &mut Vec<traits::FulfillmentError<'tcx>>,
@@ -1030,7 +1074,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
let result_ty = coerce.complete(self);
- if let Err(guar) = cond_ty.error_reported() { self.tcx.ty_error(guar) } else { result_ty }
+ if let Err(guar) = cond_ty.error_reported() {
+ Ty::new_error(self.tcx, guar)
+ } else {
+ result_ty
+ }
}
/// Type check assignment expression `expr` of form `lhs = rhs`.
@@ -1048,7 +1096,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// The expected type is `bool` but this will result in `()` so we can reasonably
// say that the user intended to write `lhs == rhs` instead of `lhs = rhs`.
// The likely cause of this is `if foo = bar { .. }`.
- let actual_ty = self.tcx.mk_unit();
+ let actual_ty = Ty::new_unit(self.tcx);
let mut err = self.demand_suptype_diag(expr.span, expected_ty, actual_ty).unwrap();
let lhs_ty = self.check_expr(&lhs);
let rhs_ty = self.check_expr(&rhs);
@@ -1106,7 +1154,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If the assignment expression itself is ill-formed, don't
// bother emitting another error
let reported = err.emit_unless(lhs_ty.references_error() || rhs_ty.references_error());
- return self.tcx.ty_error(reported);
+ return Ty::new_error(self.tcx, reported);
}
let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace);
@@ -1153,9 +1201,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized);
if let Err(guar) = (lhs_ty, rhs_ty).error_reported() {
- self.tcx.ty_error(guar)
+ Ty::new_error(self.tcx, guar)
} else {
- self.tcx.mk_unit()
+ Ty::new_unit(self.tcx)
}
}
@@ -1210,7 +1258,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// [1]
self.tcx.sess.delay_span_bug(body.span, "no coercion, but loop may not break");
}
- ctxt.coerce.map(|c| c.complete(self)).unwrap_or_else(|| self.tcx.mk_unit())
+ ctxt.coerce.map(|c| c.complete(self)).unwrap_or_else(|| Ty::new_unit(self.tcx))
}
/// Checks a method call.
@@ -1224,14 +1272,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> Ty<'tcx> {
let rcvr_t = self.check_expr(&rcvr);
// no need to check for bot/err -- callee does that
- let rcvr_t = self.structurally_resolved_type(rcvr.span, rcvr_t);
+ let rcvr_t = self.structurally_resolve_type(rcvr.span, rcvr_t);
let span = segment.ident.span;
let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr, args) {
Ok(method) => {
// We could add a "consider `foo::<params>`" suggestion here, but I wasn't able to
- // trigger this codepath causing `structurally_resolved_type` to emit an error.
+ // trigger this codepath causing `structurally_resolve_type` to emit an error.
+ self.enforce_context_effects(expr.hir_id, expr.span, method.def_id, method.substs);
self.write_method_call(expr.hir_id, method);
Ok(method)
}
@@ -1273,7 +1322,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Eagerly check for some obvious errors.
if let Err(guar) = (t_expr, t_cast).error_reported() {
- self.tcx.ty_error(guar)
+ Ty::new_error(self.tcx, guar)
} else {
// Defer other checks until we're done type checking.
let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
@@ -1294,7 +1343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
deferred_cast_checks.push(cast_check);
t_cast
}
- Err(guar) => self.tcx.ty_error(guar),
+ Err(guar) => Ty::new_error(self.tcx, guar),
}
}
}
@@ -1334,7 +1383,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let array_len = args.len() as u64;
self.suggest_array_len(expr, array_len);
- self.tcx.mk_array(element_ty, array_len)
+ Ty::new_array(self.tcx, element_ty, array_len)
}
fn suggest_array_len(&self, expr: &'tcx hir::Expr<'tcx>, array_len: u64) {
@@ -1368,20 +1417,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn check_expr_const_block(
&self,
- anon_const: &'tcx hir::AnonConst,
+ block: &'tcx hir::ConstBlock,
expected: Expectation<'tcx>,
_expr: &'tcx hir::Expr<'tcx>,
) -> Ty<'tcx> {
- let body = self.tcx.hir().body(anon_const.body);
+ let body = self.tcx.hir().body(block.body);
// Create a new function context.
- let def_id = anon_const.def_id;
+ let def_id = block.def_id;
let fcx = FnCtxt::new(self, self.param_env.with_const(), def_id);
crate::GatherLocalsVisitor::new(&fcx).visit_body(body);
let ty = fcx.check_expr_with_expectation(&body.value, expected);
fcx.require_type_is_sized(ty, body.value.span, traits::ConstSized);
- fcx.write_ty(anon_const.hir_id, ty);
+ fcx.write_ty(block.hir_id, ty);
ty
}
@@ -1422,18 +1471,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
if let Err(guar) = element_ty.error_reported() {
- return tcx.ty_error(guar);
+ return Ty::new_error(tcx, guar);
}
self.check_repeat_element_needs_copy_bound(element, count, element_ty);
self.register_wf_obligation(
- tcx.mk_array_with_const_len(t, count).into(),
+ Ty::new_array_with_const_len(tcx, t, count).into(),
expr.span,
traits::WellFormed(None),
);
- tcx.mk_array_with_const_len(t, count)
+ Ty::new_array_with_const_len(tcx, t, count)
}
fn check_repeat_element_needs_copy_bound(
@@ -1496,9 +1545,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
_ => self.check_expr_with_expectation(&e, NoExpectation),
});
- let tuple = self.tcx.mk_tup_from_iter(elt_ts_iter);
+ let tuple = Ty::new_tup_from_iter(self.tcx, elt_ts_iter);
if let Err(guar) = tuple.error_reported() {
- self.tcx.ty_error(guar)
+ Ty::new_error(self.tcx, guar)
} else {
self.require_type_is_sized(tuple, expr.span, traits::TupleInitializerSized);
tuple
@@ -1518,7 +1567,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Ok(data) => data,
Err(guar) => {
self.check_struct_fields_on_error(fields, base_expr);
- return self.tcx.ty_error(guar);
+ return Ty::new_error(self.tcx, guar);
}
};
@@ -1617,7 +1666,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
};
- tcx.ty_error(guar)
+ Ty::new_error(tcx, guar)
};
// Make sure to give a type to the field even if there's
@@ -1729,7 +1778,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// `MyStruct<'a, _, F2, C>`, as opposed to just `_`...
// This is important to allow coercions to happen in
// `other_struct` itself. See `coerce-in-base-expr.rs`.
- let fresh_base_ty = self.tcx.mk_adt(*adt, fresh_substs);
+ let fresh_base_ty = Ty::new_adt(self.tcx, *adt, fresh_substs);
self.check_expr_has_type_or_error(
base_expr,
self.resolve_vars_if_possible(fresh_base_ty),
@@ -2083,13 +2132,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
},
_ => {
// prevent all specified fields from being suggested
- let skip_fields = skip_fields.iter().map(|x| x.ident.name);
- if let Some(field_name) = self.suggest_field_name(
- variant,
- field.ident.name,
- skip_fields.collect(),
- expr_span,
- ) {
+ let skip_fields: Vec<_> = skip_fields.iter().map(|x| x.ident.name).collect();
+ if let Some(field_name) =
+ self.suggest_field_name(variant, field.ident.name, &skip_fields, expr_span)
+ {
err.span_suggestion(
field.ident.span,
"a field with a similar name exists",
@@ -2110,9 +2156,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!("`{ty}` does not have this field"),
);
}
- let available_field_names =
+ let mut available_field_names =
self.available_field_names(variant, expr_span);
- if !available_field_names.is_empty() {
+ available_field_names
+ .retain(|name| skip_fields.iter().all(|skip| name != skip));
+ if available_field_names.is_empty() {
+ err.note("all struct fields are already assigned");
+ } else {
err.note(format!(
"available fields are: {}",
self.name_series_display(available_field_names)
@@ -2132,7 +2182,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
variant: &'tcx ty::VariantDef,
field: Symbol,
- skip: Vec<Symbol>,
+ skip: &[Symbol],
// The span where stability will be checked
span: Span,
) -> Option<Symbol> {
@@ -2209,7 +2259,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> Ty<'tcx> {
debug!("check_field(expr: {:?}, base: {:?}, field: {:?})", expr, base, field);
let base_ty = self.check_expr(base);
- let base_ty = self.structurally_resolved_type(base.span, base_ty);
+ let base_ty = self.structurally_resolve_type(base.span, base_ty);
let mut private_candidate = None;
let mut autoderef = self.autoderef(expr.span, base_ty);
while let Some((deref_base_ty, _)) = autoderef.next() {
@@ -2257,7 +2307,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => {}
}
}
- self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
+ self.structurally_resolve_type(autoderef.span(), autoderef.final_ty(false));
if let Some((adjustments, did)) = private_candidate {
// (#90483) apply adjustments to avoid ExprUseVisitor from
@@ -2270,7 +2320,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
did,
expected.only_has_type(self),
);
- return self.tcx().ty_error(guar);
+ return Ty::new_error(self.tcx(), guar);
}
let guar = if field.name == kw::Empty {
@@ -2356,7 +2406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.emit()
};
- self.tcx().ty_error(guar)
+ Ty::new_error(self.tcx(), guar)
}
fn suggest_await_on_field_access(
@@ -2584,7 +2634,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
access_span: Span,
) {
if let Some(suggested_field_name) =
- self.suggest_field_name(def.non_enum_variant(), field.name, vec![], access_span)
+ self.suggest_field_name(def.non_enum_variant(), field.name, &[], access_span)
{
err.span_suggestion(
field.span,
@@ -2814,7 +2864,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else if idx_t.references_error() {
idx_t
} else {
- let base_t = self.structurally_resolved_type(base.span, base_t);
+ let base_t = self.structurally_resolve_type(base.span, base_t);
match self.lookup_indexing(expr, base, base_t, idx, idx_t) {
Some((index_ty, element_ty)) => {
// two-phase not needed because index_ty is never mutable
@@ -2872,8 +2922,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
}
+
+ if base_t.is_unsafe_ptr() && idx_t.is_integral() {
+ err.multipart_suggestion(
+ "consider using `wrapping_add` or `add` for indexing into raw pointer",
+ vec![
+ (base.span.between(idx.span), ".wrapping_add(".to_owned()),
+ (
+ idx.span.shrink_to_hi().until(expr.span.shrink_to_hi()),
+ ")".to_owned(),
+ ),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ }
+
let reported = err.emit();
- self.tcx.ty_error(reported)
+ Ty::new_error(self.tcx, reported)
}
}
}
@@ -2904,7 +2969,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
self.commit_if_ok(|_| {
- let ocx = ObligationCtxt::new_in_snapshot(self);
+ let ocx = ObligationCtxt::new(self);
let impl_substs = self.fresh_substs_for_item(base_expr.span, impl_def_id);
let impl_trait_ref =
self.tcx.impl_trait_ref(impl_def_id).unwrap().subst(self.tcx, impl_substs);
@@ -2947,7 +3012,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let element_ty = ocx.normalize(
&cause,
self.param_env,
- self.tcx.mk_projection(index_trait_output_def_id, impl_trait_ref.substs),
+ Ty::new_projection(self.tcx, index_trait_output_def_id, impl_trait_ref.substs),
);
let errors = ocx.select_where_possible();
@@ -2969,7 +3034,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) {
for error in errors {
match error.obligation.predicate.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Trait(predicate))
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate))
if self.tcx.is_diagnostic_item(sym::SliceIndex, predicate.trait_ref.def_id) => {
}
_ => continue,
@@ -2995,14 +3060,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// information. Hence, we check the source of the yield expression here and check its
// value's type against `()` (this check should always hold).
None if src.is_await() => {
- self.check_expr_coercible_to_type(&value, self.tcx.mk_unit(), None);
- self.tcx.mk_unit()
+ self.check_expr_coercible_to_type(&value, Ty::new_unit(self.tcx), None);
+ Ty::new_unit(self.tcx)
}
_ => {
self.tcx.sess.emit_err(YieldExprOutsideOfGenerator { span: expr.span });
// Avoid expressions without types during writeback (#78653).
self.check_expr(value);
- self.tcx.mk_unit()
+ Ty::new_unit(self.tcx)
}
}
}
@@ -3026,14 +3091,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// allows them to be inferred based on how they are used later in the
// function.
if is_input {
- let ty = self.structurally_resolved_type(expr.span, ty);
+ let ty = self.structurally_resolve_type(expr.span, ty);
match *ty.kind() {
ty::FnDef(..) => {
- let fnptr_ty = self.tcx.mk_fn_ptr(ty.fn_sig(self.tcx));
+ let fnptr_ty = Ty::new_fn_ptr(self.tcx, ty.fn_sig(self.tcx));
self.demand_coerce(expr, ty, fnptr_ty, None, AllowTwoPhase::No);
}
ty::Ref(_, base_ty, mutbl) => {
- let ptr_ty = self.tcx.mk_ptr(ty::TypeAndMut { ty: base_ty, mutbl });
+ let ptr_ty = Ty::new_ptr(self.tcx, ty::TypeAndMut { ty: base_ty, mutbl });
self.demand_coerce(expr, ty, ptr_ty, None, AllowTwoPhase::No);
}
_ => {}
@@ -3068,7 +3133,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if asm.options.contains(ast::InlineAsmOptions::NORETURN) {
self.tcx.types.never
} else {
- self.tcx.mk_unit()
+ Ty::new_unit(self.tcx)
}
}
@@ -3084,7 +3149,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut current_container = container;
for &field in fields {
- let container = self.structurally_resolved_type(expr.span, current_container);
+ let container = self.structurally_resolve_type(expr.span, current_container);
match container.kind() {
ty::Adt(container_def, substs) if !container_def.is_enum() => {
@@ -3117,16 +3182,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
ty::Tuple(tys) => {
- let fstr = field.as_str();
-
- if let Ok(index) = fstr.parse::<usize>() {
- if fstr == index.to_string() {
- if let Some(&field_ty) = tys.get(index) {
- field_indices.push(index.into());
- current_container = field_ty;
+ if let Ok(index) = field.as_str().parse::<usize>()
+ && field.name == sym::integer(index)
+ {
+ for ty in tys.iter().take(index + 1) {
+ self.require_type_is_sized(ty, expr.span, traits::MiscObligation);
+ }
+ if let Some(&field_ty) = tys.get(index) {
+ field_indices.push(index.into());
+ current_container = field_ty;
- continue;
- }
+ continue;
}
}
}
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index e14e8ac2c..0d2e0602e 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -326,6 +326,10 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
}
}
+ hir::ExprKind::Become(call) => {
+ self.consume_expr(call);
+ }
+
hir::ExprKind::Assign(lhs, rhs, _) => {
self.mutate_expr(lhs);
self.consume_expr(rhs);
@@ -443,7 +447,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
if matches!((lhs, wild, rhs), (&[], Some(_), &[]))
// Arrays have a statically known size, so
// there is no need to read their length
- || discr_place.place.base_ty.is_array()
+ || place.place.ty().peel_refs().is_array()
{
} else {
needs_to_be_read = true;
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index b7ae621c6..a76db6e73 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -104,7 +104,7 @@ 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 let Some(e) = self.tainted_by_errors() => self.tcx.ty_error(e),
+ _ if let Some(e) = self.tainted_by_errors() => Ty::new_error(self.tcx,e),
ty::Infer(ty::IntVar(_)) => self.tcx.types.i32,
ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64,
_ => match diverging_fallback.get(&ty) {
@@ -287,7 +287,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
let mut diverging_fallback = FxHashMap::default();
diverging_fallback.reserve(diverging_vids.len());
for &diverging_vid in &diverging_vids {
- let diverging_ty = self.tcx.mk_ty_var(diverging_vid);
+ let diverging_ty = Ty::new_var(self.tcx, diverging_vid);
let root_vid = self.root_var(diverging_vid);
let can_reach_non_diverging = coercion_graph
.depth_first_search(root_vid)
@@ -334,7 +334,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
} else {
debug!("fallback to ! - all diverging: {:?}", diverging_vid);
- diverging_fallback.insert(diverging_ty, self.tcx.mk_diverging_default());
+ diverging_fallback.insert(diverging_ty, Ty::new_diverging_default(self.tcx));
}
}
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 557950338..9a80a9c93 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -2,7 +2,7 @@ use crate::callee::{self, DeferredCallResolution};
use crate::errors::CtorIsPrivate;
use crate::method::{self, MethodCallee, SelfSource};
use crate::rvalue_scopes;
-use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, RawTy};
+use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, RawTy};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan, StashKey};
@@ -83,6 +83,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// version (resolve_vars_if_possible), this version will
/// also select obligations if it seems useful, in an effort
/// to get more type information.
+ // FIXME(-Ztrait-solver=next): A lot of the calls to this method should
+ // probably be `try_structurally_resolve_type` or `structurally_resolve_type` instead.
pub(in super::super) fn resolve_vars_with_obligations(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
self.resolve_vars_with_obligations_and_mutate_fulfillment(ty, |_| {})
}
@@ -135,7 +137,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!("{:p}", self)
}
- pub fn local_ty(&self, span: Span, nid: hir::HirId) -> LocalTy<'tcx> {
+ pub fn local_ty(&self, span: Span, nid: hir::HirId) -> Ty<'tcx> {
self.locals.borrow().get(&nid).cloned().unwrap_or_else(|| {
span_bug!(span, "no type for local variable {}", self.tcx.hir().node_to_string(nid))
})
@@ -451,7 +453,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 let Some(e) = self.tainted_by_errors() => self.tcx.ty_error(e),
+ None if let Some(e) = self.tainted_by_errors() => Ty::new_error(self.tcx,e),
None => {
bug!(
"no type for node {} in fcx {}",
@@ -465,7 +467,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 let Some(e) = self.tainted_by_errors() => Some(self.tcx.ty_error(e)),
+ None if let Some(e) = self.tainted_by_errors() => Some(Ty::new_error(self.tcx,e)),
None => None,
}
}
@@ -483,7 +485,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx,
cause,
self.param_env,
- ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)),
+ ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg))),
));
}
@@ -556,7 +558,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx,
self.tcx.typeck_root_def_id(expr_def_id.to_def_id()),
);
- let witness = self.tcx.mk_generator_witness_mir(expr_def_id.to_def_id(), substs);
+ let witness = Ty::new_generator_witness_mir(self.tcx, expr_def_id.to_def_id(), substs);
// Unify `interior` with `witness` and collect all the resulting obligations.
let span = self.tcx.hir().body(body_id).value.span;
@@ -647,7 +649,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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))
+ ty::PredicateKind::Clause(ty::ClauseKind::Projection(data))
if self.self_type_matches_expected_vid(
data.projection_ty.self_ty(),
ty_var_root,
@@ -655,23 +657,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
Some(obligation)
}
- ty::PredicateKind::Clause(ty::Clause::Trait(data))
+ ty::PredicateKind::Clause(ty::ClauseKind::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::Clause(ty::Clause::ConstArgHasType(..))
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(..))
+ | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..))
+ | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
- | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))
- | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
- | ty::PredicateKind::WellFormed(..)
+ | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..))
+ | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..))
+ | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..))
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::AliasRelate(..)
- | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
| ty::PredicateKind::ConstEquate(..)
// N.B., this predicate is created by breaking down a
// `ClosureType: FnFoo()` predicate, where
@@ -683,7 +685,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// inference variable.
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Ambiguous
- | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
+ => None,
},
)
}
@@ -692,7 +694,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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)) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
Some(data.def_id()) == sized_did
}
_ => false,
@@ -701,7 +703,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
pub(in super::super) fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> {
- let ty_error = self.tcx.ty_error_misc();
+ let ty_error = Ty::new_misc_error(self.tcx);
vec![ty_error; len]
}
@@ -746,7 +748,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let expect_args = self
.fudge_inference_if_ok(|| {
- let ocx = ObligationCtxt::new_in_snapshot(self);
+ let ocx = ObligationCtxt::new(self);
// Attempt to apply a subtyping relationship between the formal
// return type (likely containing type variables if the function
@@ -1152,7 +1154,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.local_ty(span, hid);
let ty = self.normalize(span, ty);
self.write_ty(hir_id, ty);
return (ty, res);
@@ -1240,7 +1242,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
let reported = err.emit();
- return (tcx.ty_error(reported), res);
+ return (Ty::new_error(tcx, reported), res);
}
}
} else {
@@ -1386,7 +1388,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// the referenced item.
let ty = tcx.type_of(def_id);
assert!(!substs.has_escaping_bound_vars());
- assert!(!ty.0.has_escaping_bound_vars());
+ assert!(!ty.skip_binder().has_escaping_bound_vars());
let ty_substituted = self.normalize(span, ty.subst(tcx, substs));
if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
@@ -1465,33 +1467,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- /// Resolves `typ` by a single level if `typ` is a type variable.
+ /// Try to resolve `ty` to a structural type, normalizing aliases.
///
- /// When the new solver is enabled, this will also attempt to normalize
- /// the type if it's a projection (note that it will not deeply normalize
- /// projections within the type, just the outermost layer of the type).
- ///
- /// If no resolution is possible, then an error is reported.
- /// Numeric inference variables may be left unresolved.
- pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
- let mut ty = self.resolve_vars_with_obligations(ty);
+ /// In case there is still ambiguity, the returned type may be an inference
+ /// variable. This is different from `structurally_resolve_type` which errors
+ /// in this case.
+ pub fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
+ let ty = self.resolve_vars_with_obligations(ty);
- if self.tcx.trait_solver_next()
+ if self.next_trait_solver()
&& let ty::Alias(ty::Projection, _) = ty.kind()
{
match self
.at(&self.misc(sp), self.param_env)
.structurally_normalize(ty, &mut **self.fulfillment_cx.borrow_mut())
{
- Ok(normalized_ty) => {
- ty = normalized_ty;
- },
+ Ok(normalized_ty) => normalized_ty,
Err(errors) => {
let guar = self.err_ctxt().report_fulfillment_errors(&errors);
- return self.tcx.ty_error(guar);
+ return Ty::new_error(self.tcx,guar);
}
}
- }
+ } else {
+ ty
+ }
+ }
+
+ /// Resolves `ty` by a single level if `ty` is a type variable.
+ ///
+ /// When the new solver is enabled, this will also attempt to normalize
+ /// the type if it's a projection (note that it will not deeply normalize
+ /// projections within the type, just the outermost layer of the type).
+ ///
+ /// If no resolution is possible, then an error is reported.
+ /// Numeric inference variables may be left unresolved.
+ pub fn structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
+ let ty = self.try_structurally_resolve_type(sp, ty);
if !ty.is_ty_var() {
ty
@@ -1501,7 +1512,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.emit_inference_failure_err(self.body_id, sp, ty.into(), E0282, true)
.emit()
});
- let err = self.tcx.ty_error(e);
+ let err = Ty::new_error(self.tcx, e);
self.demand_suptype(sp, err, ty);
err
}
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
index 3efdab534..ed9bb4945 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
@@ -25,14 +25,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let generics = self.tcx.generics_of(def_id);
let predicate_substs = match unsubstituted_pred.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs.to_vec(),
- ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => {
- pred.projection_ty.substs.to_vec()
- }
- ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(arg, ty)) => {
+ ty::ClauseKind::Trait(pred) => pred.trait_ref.substs.to_vec(),
+ ty::ClauseKind::Projection(pred) => pred.projection_ty.substs.to_vec(),
+ ty::ClauseKind::ConstArgHasType(arg, ty) => {
vec![ty.into(), arg.into()]
}
- ty::PredicateKind::ConstEvaluatable(e) => vec![e.into()],
+ ty::ClauseKind::ConstEvaluatable(e) => vec![e.into()],
_ => return false,
};
@@ -256,7 +254,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
type BreakTy = ty::GenericArg<'tcx>;
fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
if let Some(origin) = self.0.type_var_origin(ty)
- && let rustc_infer::infer::type_variable::TypeVariableOriginKind::TypeParameterDefinition(_, Some(def_id)) =
+ && let rustc_infer::infer::type_variable::TypeVariableOriginKind::TypeParameterDefinition(_, def_id) =
origin.kind
&& let generics = self.0.tcx.generics_of(self.1)
&& let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id)
@@ -510,11 +508,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// This shouldn't happen, but since this is only a diagnostic improvement, avoid breaking things.
return Err(expr);
}
- let relevant_broken_predicate: ty::PredicateKind<'tcx> =
- impl_predicates.predicates[impl_predicate_index].0.kind().skip_binder();
- match relevant_broken_predicate {
- ty::PredicateKind::Clause(ty::Clause::Trait(broken_trait)) => {
+ match impl_predicates.predicates[impl_predicate_index].0.kind().skip_binder() {
+ ty::ClauseKind::Trait(broken_trait) => {
// ...
self.blame_specific_part_of_expr_corresponding_to_generic_param(
broken_trait.trait_ref.self_ty().into(),
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
index d45e3d395..7aadb95d9 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
@@ -1,7 +1,7 @@
-use std::cmp;
-
+use core::cmp::Ordering;
use rustc_index::IndexVec;
use rustc_middle::ty::error::TypeError;
+use std::cmp;
rustc_index::newtype_index! {
#[debug_format = "ExpectedIdx({})"]
@@ -34,14 +34,14 @@ enum Issue {
Permutation(Vec<Option<usize>>),
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) enum Compatibility<'tcx> {
Compatible,
Incompatible(Option<TypeError<'tcx>>),
}
/// Similar to `Issue`, but contains some extra information
-#[derive(Debug)]
+#[derive(Debug, PartialEq, Eq)]
pub(crate) enum Error<'tcx> {
/// The provided argument is the invalid type for the expected input
Invalid(ProvidedIdx, ExpectedIdx, Compatibility<'tcx>),
@@ -55,6 +55,34 @@ pub(crate) enum Error<'tcx> {
Permutation(Vec<(ExpectedIdx, ProvidedIdx)>),
}
+impl Ord for Error<'_> {
+ fn cmp(&self, other: &Self) -> Ordering {
+ let key = |error: &Error<'_>| -> usize {
+ match error {
+ Error::Invalid(..) => 0,
+ Error::Extra(_) => 1,
+ Error::Missing(_) => 2,
+ Error::Swap(..) => 3,
+ Error::Permutation(..) => 4,
+ }
+ };
+ match (self, other) {
+ (Error::Invalid(a, _, _), Error::Invalid(b, _, _)) => a.cmp(b),
+ (Error::Extra(a), Error::Extra(b)) => a.cmp(b),
+ (Error::Missing(a), Error::Missing(b)) => a.cmp(b),
+ (Error::Swap(a, b, ..), Error::Swap(c, d, ..)) => a.cmp(c).then(b.cmp(d)),
+ (Error::Permutation(a), Error::Permutation(b)) => a.cmp(b),
+ _ => key(self).cmp(&key(other)),
+ }
+ }
+}
+
+impl PartialOrd for Error<'_> {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
pub(crate) struct ArgMatrix<'tcx> {
/// Maps the indices in the `compatibility_matrix` rows to the indices of
/// the *user provided* inputs
@@ -177,7 +205,7 @@ impl<'tcx> ArgMatrix<'tcx> {
// If an argument is unsatisfied, and the input in its position is useless
// then the most likely explanation is that we just got the types wrong
(true, true, true, true) => return Some(Issue::Invalid(i)),
- // Otherwise, if an input is useless, then indicate that this is an extra argument
+ // Otherwise, if an input is useless then indicate that this is an extra input
(true, _, true, _) => return Some(Issue::Extra(i)),
// Otherwise, if an argument is unsatisfiable, indicate that it's missing
(_, true, _, true) => return Some(Issue::Missing(i)),
@@ -376,6 +404,9 @@ impl<'tcx> ArgMatrix<'tcx> {
};
}
+ // sort errors with same type by the order they appear in the source
+ // so that suggestion will be handled properly, see #112507
+ errors.sort();
return (errors, matched_inputs);
}
}
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index eba5c829e..41f5fafe7 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1,12 +1,12 @@
use crate::coercion::CoerceMany;
+use crate::errors::SuggestPtrNullMut;
use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx};
use crate::gather_locals::Declaration;
use crate::method::MethodCallee;
use crate::TupleArgumentsFlag::*;
use crate::{errors, Expectation::*};
use crate::{
- struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, Needs, RawTy,
- TupleArgumentsFlag,
+ struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, Needs, RawTy, TupleArgumentsFlag,
};
use rustc_ast as ast;
use rustc_data_structures::fx::FxIndexSet;
@@ -73,7 +73,7 @@ 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() {
- self.tcx.ty_error_misc()
+ Ty::new_misc_error(self.tcx)
} else {
self.tcx.erase_regions(ty)
}
@@ -101,7 +101,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let err_inputs = match tuple_arguments {
DontTupleArguments => err_inputs,
- TupleArguments => vec![self.tcx.mk_tup(&err_inputs)],
+ TupleArguments => vec![Ty::new_tup(self.tcx, &err_inputs)],
};
self.check_argument_types(
@@ -114,7 +114,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
tuple_arguments,
method.ok().map(|method| method.def_id),
);
- return self.tcx.ty_error_misc();
+ return Ty::new_misc_error(self.tcx);
}
let method = method.unwrap();
@@ -184,7 +184,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If the arguments should be wrapped in a tuple (ex: closures), unwrap them here
let (formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments {
- let tuple_type = self.structurally_resolved_type(call_span, formal_input_tys[0]);
+ let tuple_type = self.structurally_resolve_type(call_span, formal_input_tys[0]);
match tuple_type.kind() {
// We expected a tuple and got a tuple
ty::Tuple(arg_types) => {
@@ -412,7 +412,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// There are a few types which get autopromoted when passed via varargs
// in C but we just error out instead and require explicit casts.
- let arg_ty = self.structurally_resolved_type(arg.span, arg_ty);
+ let arg_ty = self.structurally_resolve_type(arg.span, arg_ty);
match arg_ty.kind() {
ty::Float(ty::FloatTy::F32) => {
variadic_error(tcx.sess, arg.span, arg_ty, "c_double");
@@ -424,7 +424,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
variadic_error(tcx.sess, arg.span, arg_ty, "c_uint");
}
ty::FnDef(..) => {
- let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx));
+ let ptr_ty = Ty::new_fn_ptr(self.tcx, arg_ty.fn_sig(self.tcx));
let ptr_ty = self.resolve_vars_if_possible(ptr_ty);
variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string());
}
@@ -539,7 +539,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.typeck_results
.borrow()
.expr_ty_adjusted_opt(*expr)
- .unwrap_or_else(|| tcx.ty_error_misc());
+ .unwrap_or_else(|| Ty::new_misc_error(tcx));
(self.resolve_vars_if_possible(ty), normalize_span(expr.span))
})
.collect();
@@ -648,7 +648,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len()
{
// Wrap up the N provided arguments starting at this position in a tuple.
- let provided_as_tuple = tcx.mk_tup_from_iter(
+ let provided_as_tuple = Ty::new_tup_from_iter(tcx,
provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx).take(tys.len()),
);
@@ -752,20 +752,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
}
- errors.drain_filter(|error| {
+ errors.retain(|error| {
let Error::Invalid(
provided_idx,
expected_idx,
Compatibility::Incompatible(Some(e)),
- ) = error else { return false };
+ ) = error else { return true };
let (provided_ty, provided_span) = provided_arg_tys[*provided_idx];
let trace =
mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty);
if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) {
self.err_ctxt().report_and_explain_type_error(trace, *e).emit();
- return true;
+ return false;
}
- false
+ true
});
// We're done if we found errors, but we already emitted them.
@@ -814,6 +814,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
+ self.suggest_ptr_null_mut(
+ expected_ty,
+ provided_ty,
+ provided_args[*provided_idx],
+ &mut err,
+ );
+
// Call out where the function is defined
self.label_fn_like(
&mut err,
@@ -947,9 +954,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// - f(0, 1,)
// + f()
if only_extras_so_far
- && errors
+ && !errors
.peek()
- .map_or(true, |next_error| !matches!(next_error, Error::Extra(_)))
+ .is_some_and(|next_error| matches!(next_error, Error::Extra(_)))
{
let next = provided_arg_tys
.get(arg_idx + 1)
@@ -1271,6 +1278,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.emit();
}
+ fn suggest_ptr_null_mut(
+ &self,
+ expected_ty: Ty<'tcx>,
+ provided_ty: Ty<'tcx>,
+ arg: &hir::Expr<'tcx>,
+ err: &mut rustc_errors::DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ ) {
+ if let ty::RawPtr(ty::TypeAndMut { mutbl: hir::Mutability::Mut, .. }) = expected_ty.kind()
+ && let ty::RawPtr(ty::TypeAndMut { mutbl: hir::Mutability::Not, .. }) = provided_ty.kind()
+ && let hir::ExprKind::Call(callee, _) = arg.kind
+ && let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = callee.kind
+ && let Res::Def(_, def_id) = path.res
+ && self.tcx.get_diagnostic_item(sym::ptr_null) == Some(def_id)
+ {
+ // The user provided `ptr::null()`, but the function expects
+ // `ptr::null_mut()`.
+ err.subdiagnostic(SuggestPtrNullMut {
+ span: arg.span
+ });
+ }
+ }
+
// AST fragment checking
pub(in super::super) fn check_lit(
&self,
@@ -1280,14 +1309,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let tcx = self.tcx;
match lit.node {
- ast::LitKind::Str(..) => tcx.mk_static_str(),
- ast::LitKind::ByteStr(ref v, _) => {
- tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.u8, v.len() as u64))
- }
+ ast::LitKind::Str(..) => Ty::new_static_str(tcx),
+ ast::LitKind::ByteStr(ref v, _) => Ty::new_imm_ref(
+ tcx,
+ tcx.lifetimes.re_static,
+ Ty::new_array(tcx, tcx.types.u8, v.len() as u64),
+ ),
ast::LitKind::Byte(_) => tcx.types.u8,
ast::LitKind::Char(_) => tcx.types.char,
- ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(ty::int_ty(t)),
- ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(ty::uint_ty(t)),
+ ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => Ty::new_int(tcx, ty::int_ty(t)),
+ ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => Ty::new_uint(tcx, ty::uint_ty(t)),
ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() {
ty::Int(_) | ty::Uint(_) => Some(ty),
@@ -1299,7 +1330,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
opt_ty.unwrap_or_else(|| self.next_int_var())
}
ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => {
- tcx.mk_mach_float(ty::float_ty(t))
+ Ty::new_float(tcx, ty::float_ty(t))
}
ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => {
let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() {
@@ -1309,12 +1340,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
opt_ty.unwrap_or_else(|| self.next_float_var())
}
ast::LitKind::Bool(_) => tcx.types.bool,
- ast::LitKind::CStr(_, _) => tcx.mk_imm_ref(
+ ast::LitKind::CStr(_, _) => Ty::new_imm_ref(
+ tcx,
tcx.lifetimes.re_static,
tcx.type_of(tcx.require_lang_item(hir::LangItem::CStr, Some(lit.span)))
.skip_binder(),
),
- ast::LitKind::Err => tcx.ty_error_misc(),
+ ast::LitKind::Err => Ty::new_misc_error(tcx),
}
}
@@ -1393,7 +1425,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// See #44848.
let ref_bindings = pat.contains_explicit_ref_binding();
- let local_ty = self.local_ty(init.span, hir_id).revealed_ty;
+ let local_ty = self.local_ty(init.span, hir_id);
if let Some(m) = ref_bindings {
// Somewhat subtle: if we have a `ref` binding in the pattern,
// we want to avoid introducing coercions for the RHS. This is
@@ -1404,7 +1436,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// type of the place it is referencing, and not some
// supertype thereof.
let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m));
- self.demand_eqtype(init.span, local_ty, init_ty);
+ if let Some(mut diag) = self.demand_eqtype_diag(init.span, local_ty, init_ty) {
+ self.emit_type_mismatch_suggestions(
+ &mut diag,
+ init.peel_drop_temps(),
+ init_ty,
+ local_ty,
+ None,
+ None,
+ );
+ diag.emit();
+ }
init_ty
} else {
self.check_expr_coercible_to_type(init, local_ty, None)
@@ -1413,7 +1455,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(in super::super) fn check_decl(&self, decl: Declaration<'tcx>) {
// Determine and write the type which we'll check the pattern against.
- let decl_ty = self.local_ty(decl.span, decl.hir_id).decl_ty;
+ let decl_ty = self.local_ty(decl.span, decl.hir_id);
self.write_ty(decl.hir_id, decl_ty);
// Type check the initializer.
@@ -1474,7 +1516,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
hir::StmtKind::Item(_) => {}
hir::StmtKind::Expr(ref expr) => {
// Check with expected type of `()`.
- self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| {
+ self.check_expr_has_type_or_error(&expr, Ty::new_unit(self.tcx), |err| {
if expr.can_have_side_effects() {
self.suggest_semicolon_at_end(expr.span, err);
}
@@ -1497,7 +1539,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
pub fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) {
- let unit = self.tcx.mk_unit();
+ let unit = Ty::new_unit(self.tcx);
let ty = self.check_block_with_expected(blk, ExpectHasType(unit));
// if the block produces a `!` value, that can always be
@@ -1610,7 +1652,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
blk.span,
blk.hir_id,
expected_ty,
- self.tcx.mk_unit(),
+ Ty::new_unit(self.tcx),
);
}
if !self.consider_removing_semicolon(blk, expected_ty, err) {
@@ -1640,7 +1682,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
hir::Stmt {
kind:
hir::StmtKind::Expr(hir::Expr {
- kind: hir::ExprKind::Assign(..),
+ kind: hir::ExprKind::Assign(lhs, ..),
..
}),
..
@@ -1650,7 +1692,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} = blk
{
self.comes_from_while_condition(blk.hir_id, |_| {
- err.downgrade_to_delayed_bug();
+ // We cannot suppress the error if the LHS of assignment
+ // is a syntactic place expression because E0070 would
+ // not be emitted by `check_lhs_assignable`.
+ let res = self.typeck_results.borrow().expr_ty_opt(lhs);
+
+ if !lhs.is_syntactic_place_expr()
+ || res.references_error()
+ {
+ err.downgrade_to_delayed_bug();
+ }
})
}
}
@@ -1747,12 +1798,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) {
if let Err(guar) = ty.error_reported() {
// Override the types everywhere with `err()` to avoid knock on errors.
- let err = self.tcx.ty_error(guar);
+ let err = Ty::new_error(self.tcx, guar);
self.write_ty(hir_id, err);
self.write_ty(pat.hir_id, err);
- let local_ty = LocalTy { decl_ty: err, revealed_ty: err };
- self.locals.borrow_mut().insert(hir_id, local_ty);
- self.locals.borrow_mut().insert(pat.hir_id, local_ty);
+ self.locals.borrow_mut().insert(hir_id, err);
+ self.locals.borrow_mut().insert(pat.hir_id, err);
}
}
@@ -1776,8 +1826,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let result = self
.astconv()
.associated_path_to_ty(hir_id, path_span, ty.raw, qself, segment, true);
- let ty =
- result.map(|(ty, _, _)| ty).unwrap_or_else(|guar| self.tcx().ty_error(guar));
+ let ty = result
+ .map(|(ty, _, _)| ty)
+ .unwrap_or_else(|guar| Ty::new_error(self.tcx(), guar));
let ty = self.handle_raw_ty(path_span, ty);
let result = result.map(|(_, kind, def_id)| (kind, def_id));
@@ -1899,7 +1950,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// do that, so it's OK.
for (predicate, span) in instantiated
{
- if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = predicate.kind().skip_binder()
+ if let ty::ClauseKind::Trait(pred) = predicate.kind().skip_binder()
&& pred.self_ty().peel_refs() == callee_ty
&& self.tcx.is_fn_trait(pred.def_id())
{
@@ -1931,7 +1982,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx,
traits::ObligationCause::dummy(),
self.param_env,
- ty::Binder::dummy(trait_ref),
+ 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 67f45f9aa..20b34df99 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -163,7 +163,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return fn_sig;
}
self.probe(|_| {
- let ocx = ObligationCtxt::new_in_snapshot(self);
+ let ocx = ObligationCtxt::new(self);
let normalized_fn_sig =
ocx.normalize(&ObligationCause::dummy(), self.param_env, fn_sig);
if ocx.select_all_or_error().is_empty() {
@@ -189,6 +189,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn errors_reported_since_creation(&self) -> bool {
self.tcx.sess.err_count() > self.err_count_on_creation
}
+
+ pub fn next_root_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
+ Ty::new_var(self.tcx, self.next_ty_var_id_in_universe(origin, ty::UniverseIndex::ROOT))
+ }
}
impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
@@ -222,9 +226,7 @@ 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::Clause(ty::Clause::Trait(data))
- if data.self_ty().is_param(index) =>
- {
+ ty::ClauseKind::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))
@@ -293,7 +295,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
trait_ref.substs,
);
- self.tcx().mk_projection(item_def_id, item_substs)
+ Ty::new_projection(self.tcx(), item_def_id, item_substs)
}
fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>> {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index c4add4dbd..79a7c0161 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -1,6 +1,8 @@
use super::FnCtxt;
-use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel, SuggestBoxing};
+use crate::errors::{
+ AddReturnTypeSuggestion, ExpectedReturnTypeLabel, SuggestBoxing, SuggestConvertViaMethod,
+};
use crate::fluent_generated as fluent;
use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
@@ -275,6 +277,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
) -> bool {
let expr = expr.peel_blocks();
+ let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
+
if let Some((suggestion, msg, applicability, verbose, annotation)) =
self.suggest_deref_or_ref(expr, found, expected)
{
@@ -325,9 +329,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
return true;
- } else if self.suggest_else_fn_with_closure(err, expr, found, expected) {
+ }
+
+ if self.suggest_else_fn_with_closure(err, expr, found, expected) {
return true;
- } else if self.suggest_fn_call(err, expr, found, |output| self.can_coerce(output, expected))
+ }
+
+ if self.suggest_fn_call(err, expr, found, |output| self.can_coerce(output, expected))
&& let ty::FnDef(def_id, ..) = *found.kind()
&& let Some(sp) = self.tcx.hir().span_if_local(def_id)
{
@@ -343,97 +351,156 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_label(sp, format!("{descr} `{name}` defined here"));
}
return true;
- } else if self.suggest_cast(err, expr, found, expected, expected_ty_expr) {
+ }
+
+ if self.suggest_cast(err, expr, found, expected, expected_ty_expr) {
return true;
- } else {
- let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
- if !methods.is_empty() {
- let mut suggestions = methods.iter()
- .filter_map(|conversion_method| {
- let receiver_method_ident = expr.method_ident();
- if let Some(method_ident) = receiver_method_ident
- && method_ident.name == conversion_method.name
- {
- return None // do not suggest code that is already there (#53348)
- }
+ }
- let method_call_list = [sym::to_vec, sym::to_string];
- let mut sugg = if let ExprKind::MethodCall(receiver_method, ..) = expr.kind
- && receiver_method.ident.name == sym::clone
- && method_call_list.contains(&conversion_method.name)
- // If receiver is `.clone()` and found type has one of those methods,
- // we guess that the user wants to convert from a slice type (`&[]` or `&str`)
- // to an owned type (`Vec` or `String`). These conversions clone internally,
- // so we remove the user's `clone` call.
- {
- vec![(
- receiver_method.ident.span,
- conversion_method.name.to_string()
- )]
- } else if expr.precedence().order()
- < ExprPrecedence::MethodCall.order()
- {
- vec![
- (expr.span.shrink_to_lo(), "(".to_string()),
- (expr.span.shrink_to_hi(), format!(").{}()", conversion_method.name)),
- ]
- } else {
- vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method.name))]
- };
- let struct_pat_shorthand_field = self.maybe_get_struct_pattern_shorthand_field(expr);
- if let Some(name) = struct_pat_shorthand_field {
- sugg.insert(
- 0,
- (expr.span.shrink_to_lo(), format!("{}: ", name)),
- );
- }
- Some(sugg)
- })
- .peekable();
- if suggestions.peek().is_some() {
- err.multipart_suggestions(
- "try using a conversion method",
- suggestions,
- Applicability::MaybeIncorrect,
- );
- return true;
- }
- } else if let ty::Adt(found_adt, found_substs) = found.kind()
- && self.tcx.is_diagnostic_item(sym::Option, found_adt.did())
- && let ty::Adt(expected_adt, expected_substs) = expected.kind()
- && self.tcx.is_diagnostic_item(sym::Option, expected_adt.did())
- && let ty::Ref(_, inner_ty, _) = expected_substs.type_at(0).kind()
- && inner_ty.is_str()
- {
- let ty = found_substs.type_at(0);
- let mut peeled = ty;
- let mut ref_cnt = 0;
- while let ty::Ref(_, inner, _) = peeled.kind() {
- peeled = *inner;
- ref_cnt += 1;
- }
- if let ty::Adt(adt, _) = peeled.kind()
- && Some(adt.did()) == self.tcx.lang_items().string()
- {
- let sugg = if ref_cnt == 0 {
- ".as_deref()"
+ if !methods.is_empty() {
+ let mut suggestions = methods
+ .iter()
+ .filter_map(|conversion_method| {
+ let receiver_method_ident = expr.method_ident();
+ if let Some(method_ident) = receiver_method_ident
+ && method_ident.name == conversion_method.name
+ {
+ return None // do not suggest code that is already there (#53348)
+ }
+
+ let method_call_list = [sym::to_vec, sym::to_string];
+ let mut sugg = if let ExprKind::MethodCall(receiver_method, ..) = expr.kind
+ && receiver_method.ident.name == sym::clone
+ && method_call_list.contains(&conversion_method.name)
+ // If receiver is `.clone()` and found type has one of those methods,
+ // we guess that the user wants to convert from a slice type (`&[]` or `&str`)
+ // to an owned type (`Vec` or `String`). These conversions clone internally,
+ // so we remove the user's `clone` call.
+ {
+ vec![(
+ receiver_method.ident.span,
+ conversion_method.name.to_string()
+ )]
+ } else if expr.precedence().order()
+ < ExprPrecedence::MethodCall.order()
+ {
+ vec![
+ (expr.span.shrink_to_lo(), "(".to_string()),
+ (expr.span.shrink_to_hi(), format!(").{}()", conversion_method.name)),
+ ]
} else {
- ".map(|x| x.as_str())"
+ vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method.name))]
};
- err.span_suggestion_verbose(
- expr.span.shrink_to_hi(),
- fluent::hir_typeck_convert_to_str,
- sugg,
- Applicability::MachineApplicable,
- );
- return true;
- }
+ let struct_pat_shorthand_field =
+ self.maybe_get_struct_pattern_shorthand_field(expr);
+ if let Some(name) = struct_pat_shorthand_field {
+ sugg.insert(0, (expr.span.shrink_to_lo(), format!("{}: ", name)));
+ }
+ Some(sugg)
+ })
+ .peekable();
+ if suggestions.peek().is_some() {
+ err.multipart_suggestions(
+ "try using a conversion method",
+ suggestions,
+ Applicability::MaybeIncorrect,
+ );
+ return true;
+ }
+ }
+
+ if let Some((found_ty_inner, expected_ty_inner, error_tys)) =
+ self.deconstruct_option_or_result(found, expected)
+ && let ty::Ref(_, peeled, hir::Mutability::Not) = *expected_ty_inner.kind()
+ {
+ // Suggest removing any stray borrows (unless there's macro shenanigans involved).
+ let inner_expr = expr.peel_borrows();
+ if !inner_expr.span.eq_ctxt(expr.span) {
+ return false;
+ }
+ let borrow_removal_span = if inner_expr.hir_id == expr.hir_id {
+ None
+ } else {
+ Some(expr.span.shrink_to_lo().until(inner_expr.span))
+ };
+ // Given `Result<_, E>`, check our expected ty is `Result<_, &E>` for
+ // `as_ref` and `as_deref` compatibility.
+ let error_tys_equate_as_ref = error_tys.map_or(true, |(found, expected)| {
+ self.can_eq(self.param_env, Ty::new_imm_ref(self.tcx,self.tcx.lifetimes.re_erased, found), expected)
+ });
+ // FIXME: This could/should be extended to suggest `as_mut` and `as_deref_mut`,
+ // but those checks need to be a bit more delicate and the benefit is diminishing.
+ if self.can_eq(self.param_env, found_ty_inner, peeled) && error_tys_equate_as_ref {
+ err.subdiagnostic(SuggestConvertViaMethod {
+ span: expr.span.shrink_to_hi(),
+ sugg: ".as_ref()",
+ expected,
+ found,
+ borrow_removal_span,
+ });
+ return true;
+ } else if let Some((deref_ty, _)) =
+ self.autoderef(expr.span, found_ty_inner).silence_errors().nth(1)
+ && self.can_eq(self.param_env, deref_ty, peeled)
+ && error_tys_equate_as_ref
+ {
+ err.subdiagnostic(SuggestConvertViaMethod {
+ span: expr.span.shrink_to_hi(),
+ sugg: ".as_deref()",
+ expected,
+ found,
+ borrow_removal_span,
+ });
+ return true;
+ } else if let ty::Adt(adt, _) = found_ty_inner.peel_refs().kind()
+ && Some(adt.did()) == self.tcx.lang_items().string()
+ && peeled.is_str()
+ // `Result::map`, conversely, does not take ref of the error type.
+ && error_tys.map_or(true, |(found, expected)| {
+ self.can_eq(self.param_env, found, expected)
+ })
+ {
+ err.span_suggestion_verbose(
+ expr.span.shrink_to_hi(),
+ fluent::hir_typeck_convert_to_str,
+ ".map(|x| x.as_str())",
+ Applicability::MachineApplicable,
+ );
+ return true;
}
}
false
}
+ fn deconstruct_option_or_result(
+ &self,
+ found_ty: Ty<'tcx>,
+ expected_ty: Ty<'tcx>,
+ ) -> Option<(Ty<'tcx>, Ty<'tcx>, Option<(Ty<'tcx>, Ty<'tcx>)>)> {
+ let ty::Adt(found_adt, found_substs) = found_ty.peel_refs().kind() else {
+ return None;
+ };
+ let ty::Adt(expected_adt, expected_substs) = expected_ty.kind() else {
+ return None;
+ };
+ if self.tcx.is_diagnostic_item(sym::Option, found_adt.did())
+ && self.tcx.is_diagnostic_item(sym::Option, expected_adt.did())
+ {
+ Some((found_substs.type_at(0), expected_substs.type_at(0), None))
+ } else if self.tcx.is_diagnostic_item(sym::Result, found_adt.did())
+ && self.tcx.is_diagnostic_item(sym::Result, expected_adt.did())
+ {
+ Some((
+ found_substs.type_at(0),
+ expected_substs.type_at(0),
+ Some((found_substs.type_at(1), expected_substs.type_at(1))),
+ ))
+ } else {
+ None
+ }
+ }
+
/// When encountering the expected boxed value allocated in the stack, suggest allocating it
/// in the heap by calling `Box::new()`.
pub(in super::super) fn suggest_boxing_when_appropriate(
@@ -448,7 +515,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if self.tcx.hir().is_inside_const_context(hir_id) || !expected.is_box() || found.is_box() {
return false;
}
- if self.can_coerce(self.tcx.mk_box(found), expected) {
+ if self.can_coerce(Ty::new_box(self.tcx, found), expected) {
let suggest_boxing = match found.kind() {
ty::Tuple(tuple) if tuple.is_empty() => {
SuggestBoxing::Unit { start: span.shrink_to_lo(), end: span }
@@ -528,9 +595,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() {
return false;
}
- let box_found = self.tcx.mk_box(found);
- let pin_box_found = self.tcx.mk_lang_item(box_found, LangItem::Pin).unwrap();
- let pin_found = self.tcx.mk_lang_item(found, LangItem::Pin).unwrap();
+ let box_found = Ty::new_box(self.tcx, found);
+ let pin_box_found = Ty::new_lang_item(self.tcx, box_found, LangItem::Pin).unwrap();
+ let pin_found = Ty::new_lang_item(self.tcx, found, LangItem::Pin).unwrap();
match expected.kind() {
ty::Adt(def, _) if Some(def.did()) == pin_did => {
if self.can_coerce(pin_box_found, expected) {
@@ -874,7 +941,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let found = self.resolve_vars_with_obligations(found);
let in_loop = self.is_loop(id)
- || self.tcx.hir().parent_iter(id).any(|(parent_id, _)| self.is_loop(parent_id));
+ || self
+ .tcx
+ .hir()
+ .parent_iter(id)
+ .take_while(|(_, node)| {
+ // look at parents until we find the first body owner
+ node.body_id().is_none()
+ })
+ .any(|(parent_id, _)| self.is_loop(parent_id));
let in_local_statement = self.is_local_statement(id)
|| self
diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs
index 38445f284..4f45a24b2 100644
--- a/compiler/rustc_hir_typeck/src/gather_locals.rs
+++ b/compiler/rustc_hir_typeck/src/gather_locals.rs
@@ -1,4 +1,4 @@
-use crate::{FnCtxt, LocalTy};
+use crate::FnCtxt;
use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::PatKind;
@@ -48,7 +48,7 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
Self { fcx, outermost_fn_param_pat: None }
}
- fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option<LocalTy<'tcx>>) -> Ty<'tcx> {
+ fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option<Ty<'tcx>>) -> Ty<'tcx> {
match ty_opt {
None => {
// Infer the variable's type.
@@ -56,23 +56,20 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
kind: TypeVariableOriginKind::TypeInference,
span,
});
- self.fcx
- .locals
- .borrow_mut()
- .insert(nid, LocalTy { decl_ty: var_ty, revealed_ty: var_ty });
+ self.fcx.locals.borrow_mut().insert(nid, var_ty);
var_ty
}
Some(typ) => {
// Take type that the user specified.
self.fcx.locals.borrow_mut().insert(nid, typ);
- typ.revealed_ty
+ typ
}
}
}
- /// Allocates a [LocalTy] for a declaration, which may have a type annotation. If it does have
- /// a type annotation, then the LocalTy stored will be the resolved type. This may be found
- /// again during type checking by querying [FnCtxt::local_ty] for the same hir_id.
+ /// Allocates a type for a declaration, which may have a type annotation. If it does have
+ /// a type annotation, then the [`Ty`] stored will be the resolved type. This may be found
+ /// again during type checking by querying [`FnCtxt::local_ty`] for the same hir_id.
fn declare(&mut self, decl: Declaration<'tcx>) {
let local_ty = match decl.ty {
Some(ref ty) => {
@@ -87,7 +84,7 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
.user_provided_types_mut()
.insert(ty.hir_id, c_ty);
- Some(LocalTy { decl_ty: o_ty.normalized, revealed_ty: o_ty.normalized })
+ Some(o_ty.normalized)
}
None => None,
};
@@ -96,7 +93,7 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
debug!(
"local variable {:?} is assigned type {}",
decl.pat,
- self.fcx.ty_to_string(self.fcx.locals.borrow().get(&decl.hir_id).unwrap().decl_ty)
+ self.fcx.ty_to_string(*self.fcx.locals.borrow().get(&decl.hir_id).unwrap())
);
}
}
@@ -129,7 +126,17 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
self.fcx.require_type_is_sized(
var_ty,
p.span,
- traits::SizedArgumentType(Some(ty_span)),
+ // ty_span == ident.span iff this is a closure parameter with no type
+ // ascription, or if it's an implicit `self` parameter
+ traits::SizedArgumentType(
+ if ty_span == ident.span
+ && self.fcx.tcx.is_closure(self.fcx.body_id.into())
+ {
+ None
+ } else {
+ Some(ty_span)
+ },
+ ),
);
}
} else {
@@ -141,7 +148,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
debug!(
"pattern binding {} is assigned to {} with type {:?}",
ident,
- self.fcx.ty_to_string(self.fcx.locals.borrow().get(&p.hir_id).unwrap().decl_ty),
+ self.fcx.ty_to_string(*self.fcx.locals.borrow().get(&p.hir_id).unwrap()),
var_ty
);
}
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 e4a62ec05..b84c49186 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
@@ -214,6 +214,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
| ExprKind::Break(..)
| ExprKind::Continue(..)
| ExprKind::Ret(..)
+ | ExprKind::Become(..)
| ExprKind::InlineAsm(..)
| ExprKind::OffsetOf(..)
| ExprKind::Struct(..)
@@ -270,6 +271,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
| hir::Node::Variant(..)
| hir::Node::Field(..)
| hir::Node::AnonConst(..)
+ | hir::Node::ConstBlock(..)
| hir::Node::Stmt(..)
| hir::Node::PathSegment(..)
| hir::Node::Ty(..)
@@ -450,6 +452,8 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
}
}
+ ExprKind::Become(_call) => bug!("encountered a tail-call inside a generator"),
+
ExprKind::Call(f, args) => {
self.visit_expr(f);
for arg in args {
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
index 019fb86f5..86ea092bc 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
@@ -122,7 +122,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
self.fcx
.need_type_info_err_in_generator(self.kind, span, unresolved_term)
- .span_note(yield_data.span, &*note)
+ .span_note(yield_data.span, note)
.emit();
}
} else {
@@ -269,7 +269,7 @@ pub fn resolve_interior<'a, 'tcx>(
},
_ => mk_bound_region(ty::BrAnon(None)),
};
- let r = fcx.tcx.mk_re_late_bound(current_depth, br);
+ let r = ty::Region::new_late_bound(fcx.tcx, current_depth, br);
r
});
captured_tys.insert(ty).then(|| {
@@ -295,7 +295,11 @@ pub fn resolve_interior<'a, 'tcx>(
let var = ty::BoundVar::from_usize(bound_vars.len());
bound_vars.push(ty::BoundVariableKind::Region(kind));
counter += 1;
- fcx.tcx.mk_re_late_bound(ty::INNERMOST, ty::BoundRegion { var, kind })
+ ty::Region::new_late_bound(
+ fcx.tcx,
+ 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}"),
@@ -308,7 +312,8 @@ pub fn resolve_interior<'a, 'tcx>(
// Extract type components to build the witness type.
let type_list = fcx.tcx.mk_type_list_from_iter(type_causes.iter().map(|cause| cause.ty));
let bound_vars = fcx.tcx.mk_bound_variable_kinds(&bound_vars);
- let witness = fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars));
+ let witness =
+ Ty::new_generator_witness(fcx.tcx, ty::Binder::bind_with_vars(type_list, bound_vars));
drop(typeck_results);
// Store the generator types and spans into the typeck results for this generator.
@@ -357,7 +362,8 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
let ty =
self.interior_visitor.fcx.typeck_results.borrow().node_type(id);
let tcx = self.interior_visitor.fcx.tcx;
- let ty = tcx.mk_ref(
+ let ty = Ty::new_ref(
+ tcx,
// Use `ReErased` as `resolve_interior` is going to replace all the
// regions anyway.
tcx.lifetimes.re_erased,
@@ -573,7 +579,7 @@ fn check_must_not_suspend_ty<'tcx>(
let mut has_emitted = false;
for &(predicate, _) in fcx.tcx.explicit_item_bounds(def).skip_binder() {
// We only look at the `DefId`, so it is safe to skip the binder here.
- if let ty::PredicateKind::Clause(ty::Clause::Trait(ref poly_trait_predicate)) =
+ if let ty::ClauseKind::Trait(ref poly_trait_predicate) =
predicate.kind().skip_binder()
{
let def_id = poly_trait_predicate.trait_ref.def_id;
@@ -686,7 +692,7 @@ fn check_must_not_suspend_def(
// Add optional reason note
if let Some(note) = attr.value_str() {
// FIXME(guswynn): consider formatting this better
- lint.span_note(data.source_span, note.as_str());
+ lint.span_note(data.source_span, note.to_string());
}
// Add some quick suggestions on what to do
diff --git a/compiler/rustc_hir_typeck/src/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs
index 294c3bb78..d5619af2a 100644
--- a/compiler/rustc_hir_typeck/src/inherited.rs
+++ b/compiler/rustc_hir_typeck/src/inherited.rs
@@ -30,7 +30,7 @@ pub struct Inherited<'tcx> {
pub(super) typeck_results: RefCell<ty::TypeckResults<'tcx>>,
- pub(super) locals: RefCell<HirIdMap<super::LocalTy<'tcx>>>,
+ pub(super) locals: RefCell<HirIdMap<Ty<'tcx>>>,
pub(super) fulfillment_cx: RefCell<Box<dyn TraitEngine<'tcx>>>,
@@ -80,14 +80,14 @@ impl<'tcx> Inherited<'tcx> {
let infcx = tcx
.infer_ctxt()
.ignoring_regions()
- .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id))
+ .with_opaque_type_inference(DefiningAnchor::Bind(def_id))
.build();
let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner));
Inherited {
typeck_results,
+ fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new(&infcx)),
infcx,
- fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new(tcx)),
locals: RefCell::new(Default::default()),
deferred_sized_obligations: RefCell::new(Vec::new()),
deferred_call_resolutions: RefCell::new(Default::default()),
@@ -129,7 +129,7 @@ impl<'tcx> Inherited<'tcx> {
let infer_var_info = &mut self.infer_var_info.borrow_mut();
// (*) binder skipped
- if let ty::PredicateKind::Clause(ty::Clause::Trait(tpred)) = obligation.predicate.kind().skip_binder()
+ if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(tpred)) = obligation.predicate.kind().skip_binder()
&& let Some(ty) = self.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| self.root_var(t))
&& self.tcx.lang_items().sized_trait().is_some_and(|st| st != tpred.trait_ref.def_id)
{
@@ -143,7 +143,7 @@ impl<'tcx> Inherited<'tcx> {
.kind()
.rebind(
// (*) binder moved here
- ty::PredicateKind::Clause(ty::Clause::Trait(tpred.with_self_ty(self.tcx, new_self_ty)))
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(tpred.with_self_ty(self.tcx, new_self_ty)))
),
);
// Don't report overflow errors. Otherwise equivalent to may_hold.
@@ -152,7 +152,7 @@ impl<'tcx> Inherited<'tcx> {
}
}
- if let ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) =
+ if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) =
obligation.predicate.kind().skip_binder()
{
// If the projection predicate (Foo::Bar == X) has X as a non-TyVid,
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
index 3c5eafd94..e58efc9d1 100644
--- a/compiler/rustc_hir_typeck/src/intrinsicck.rs
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -81,9 +81,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
// Try to display a sensible error with as much information as possible.
- let skeleton_string = |ty: Ty<'tcx>, sk| match sk {
- Ok(SizeSkeleton::Known(size)) => format!("{} bits", size.bits()),
+ let skeleton_string = |ty: Ty<'tcx>, sk: Result<_, &_>| match sk {
Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"),
+ Ok(SizeSkeleton::Known(size)) => {
+ if let Some(v) = u128::from(size.bytes()).checked_mul(8) {
+ format!("{} bits", v)
+ } else {
+ // `u128` should definitely be able to hold the size of different architectures
+ // larger sizes should be reported as error `are too big for the current architecture`
+ // otherwise we have a bug somewhere
+ bug!("{:?} overflow for u128", size)
+ }
+ }
Ok(SizeSkeleton::Generic(size)) => {
if let Some(size) = size.try_eval_target_usize(tcx, self.param_env) {
format!("{size} bytes")
@@ -92,7 +101,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
Err(LayoutError::Unknown(bad)) => {
- if bad == ty {
+ if *bad == ty {
"this type does not have a fixed size".to_owned()
} else {
format!("size can vary because of {bad}")
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index b97b55d8f..6f82ffcfe 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -5,7 +5,6 @@
#![feature(box_patterns)]
#![feature(min_specialization)]
#![feature(control_flow_enum)]
-#![feature(drain_filter)]
#![feature(option_as_slice)]
#![allow(rustc::potential_query_instability)]
#![recursion_limit = "256"]
@@ -90,13 +89,6 @@ macro_rules! type_error_struct {
})
}
-/// The type of a local binding, including the revealed type for anon types.
-#[derive(Copy, Clone, Debug)]
-pub struct LocalTy<'tcx> {
- decl_ty: Ty<'tcx>,
- revealed_ty: Ty<'tcx>,
-}
-
/// If this `DefId` is a "primary tables entry", returns
/// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
///
@@ -162,7 +154,7 @@ fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tc
fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
let fallback = move || {
let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id));
- tcx.ty_error_with_message(span, "diagnostic only typeck table used")
+ Ty::new_error_with_message(tcx, span, "diagnostic only typeck table used")
};
typeck_with_fallback(tcx, def_id, fallback)
}
diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index 78171e0b2..a1aa09084 100644
--- a/compiler/rustc_hir_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -277,9 +277,11 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
adjustment::Adjust::Deref(overloaded) => {
// Equivalent to *expr or something similar.
let base = if let Some(deref) = overloaded {
- let ref_ty = self
- .tcx()
- .mk_ref(deref.region, ty::TypeAndMut { ty: target, mutbl: deref.mutbl });
+ let ref_ty = Ty::new_ref(
+ self.tcx(),
+ deref.region,
+ ty::TypeAndMut { ty: target, mutbl: deref.mutbl },
+ );
self.cat_rvalue(expr.hir_id, expr.span, ref_ty)
} else {
previous()?
@@ -361,6 +363,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
| hir::ExprKind::AssignOp(..)
| hir::ExprKind::Closure { .. }
| hir::ExprKind::Ret(..)
+ | hir::ExprKind::Become(..)
| hir::ExprKind::Unary(..)
| hir::ExprKind::Yield(..)
| hir::ExprKind::MethodCall(..)
@@ -488,7 +491,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
let ty::Ref(region, _, mutbl) = *base_ty.kind() else {
span_bug!(expr.span, "cat_overloaded_place: base is not a reference");
};
- let ref_ty = self.tcx().mk_ref(region, ty::TypeAndMut { ty: place_ty, mutbl });
+ let ref_ty = Ty::new_ref(self.tcx(), region, ty::TypeAndMut { ty: place_ty, mutbl });
let base = self.cat_rvalue(expr.hir_id, expr.span, ref_ty);
self.cat_deref(expr, base)
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 98529b666..87edb8031 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -10,7 +10,7 @@ use rustc_hir_analysis::astconv::generics::{
use rustc_hir_analysis::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk};
use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
-use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{self, SubstsRef};
@@ -26,6 +26,7 @@ struct ConfirmContext<'a, 'tcx> {
span: Span,
self_expr: &'tcx hir::Expr<'tcx>,
call_expr: &'tcx hir::Expr<'tcx>,
+ skip_record_for_diagnostics: bool,
}
impl<'a, 'tcx> Deref for ConfirmContext<'a, 'tcx> {
@@ -59,6 +60,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut confirm_cx = ConfirmContext::new(self, span, self_expr, call_expr);
confirm_cx.confirm(unadjusted_self_ty, pick, segment)
}
+
+ pub fn confirm_method_for_diagnostic(
+ &self,
+ span: Span,
+ self_expr: &'tcx hir::Expr<'tcx>,
+ call_expr: &'tcx hir::Expr<'tcx>,
+ unadjusted_self_ty: Ty<'tcx>,
+ pick: &probe::Pick<'tcx>,
+ segment: &hir::PathSegment<'_>,
+ ) -> ConfirmResult<'tcx> {
+ let mut confirm_cx = ConfirmContext::new(self, span, self_expr, call_expr);
+ confirm_cx.skip_record_for_diagnostics = true;
+ confirm_cx.confirm(unadjusted_self_ty, pick, segment)
+ }
}
impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
@@ -68,7 +83,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
self_expr: &'tcx hir::Expr<'tcx>,
call_expr: &'tcx hir::Expr<'tcx>,
) -> ConfirmContext<'a, 'tcx> {
- ConfirmContext { fcx, span, self_expr, call_expr }
+ ConfirmContext { fcx, span, self_expr, call_expr, skip_record_for_diagnostics: false }
}
fn confirm(
@@ -128,7 +143,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
// a custom error in that case.
if illegal_sized_bound.is_none() {
self.add_obligations(
- self.tcx.mk_fn_ptr(method_sig),
+ Ty::new_fn_ptr(self.tcx, method_sig),
all_substs,
method_predicates,
pick.item.def_id,
@@ -156,7 +171,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
// time writing the results into the various typeck results.
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(
+ return Ty::new_error_with_message(self.tcx,
rustc_span::DUMMY_SP,
format!("failed autoderef {}", pick.autoderefs),
);
@@ -164,7 +179,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
assert_eq!(n, pick.autoderefs);
let mut adjustments = self.adjust_steps(&autoderef);
- let mut target = self.structurally_resolved_type(autoderef.span(), ty);
+ let mut target = self.structurally_resolve_type(autoderef.span(), ty);
match pick.autoref_or_ptr_adjustment {
Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => {
@@ -172,7 +187,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
// Type we're wrapping in a reference, used later for unsizing
let base_ty = target;
- target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl, ty: target });
+ target = Ty::new_ref(self.tcx, region, ty::TypeAndMut { mutbl, ty: target });
// Method call receivers are the primary use case
// for two-phase borrows.
@@ -185,31 +200,35 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
if unsize {
let unsized_ty = if let ty::Array(elem_ty, _) = base_ty.kind() {
- self.tcx.mk_slice(*elem_ty)
+ Ty::new_slice(self.tcx, *elem_ty)
} else {
bug!(
"AutorefOrPtrAdjustment's unsize flag should only be set for array ty, found {}",
base_ty
)
};
- target = self
- .tcx
- .mk_ref(region, ty::TypeAndMut { mutbl: mutbl.into(), ty: unsized_ty });
- adjustments
- .push(Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target });
+ target = Ty::new_ref(
+ self.tcx,
+ region,
+ ty::TypeAndMut { mutbl: mutbl.into(), ty: unsized_ty },
+ );
+ adjustments.push(Adjustment {
+ kind: Adjust::Pointer(PointerCoercion::Unsize),
+ target,
+ });
}
}
Some(probe::AutorefOrPtrAdjustment::ToConstPtr) => {
target = match target.kind() {
&ty::RawPtr(ty::TypeAndMut { ty, mutbl }) => {
assert!(mutbl.is_mut());
- self.tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty })
+ Ty::new_ptr(self.tcx, ty::TypeAndMut { mutbl: hir::Mutability::Not, ty })
}
other => panic!("Cannot adjust receiver type {:?} to const ptr", other),
};
adjustments.push(Adjustment {
- kind: Adjust::Pointer(PointerCast::MutToConstPointer),
+ kind: Adjust::Pointer(PointerCoercion::MutToConstPointer),
target,
});
}
@@ -219,7 +238,9 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
self.register_predicates(autoderef.into_obligations());
// Write out the final adjustments.
- self.apply_adjustments(self.self_expr, adjustments);
+ if !self.skip_record_for_diagnostics {
+ self.apply_adjustments(self.self_expr, adjustments);
+ }
target
}
@@ -453,7 +474,10 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
});
debug!("instantiate_method_substs: user_type_annotation={:?}", user_type_annotation);
- self.fcx.write_user_type_annotation(self.call_expr.hir_id, user_type_annotation);
+
+ if !self.skip_record_for_diagnostics {
+ self.fcx.write_user_type_annotation(self.call_expr.hir_id, user_type_annotation);
+ }
}
self.normalize(self.span, substs)
@@ -586,9 +610,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
traits::elaborate(self.tcx, predicates.predicates.iter().copied())
// We don't care about regions here.
.filter_map(|pred| match pred.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred))
- if trait_pred.def_id() == sized_def_id =>
- {
+ ty::ClauseKind::Trait(trait_pred) if trait_pred.def_id() == sized_def_id => {
let span = predicates
.iter()
.find_map(|(p, span)| if p == pred { Some(span) } else { None })
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index 6f4d674ba..e52cea188 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -205,9 +205,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some(span) = result.illegal_sized_bound {
let mut needs_mut = false;
if let ty::Ref(region, t_type, mutability) = self_ty.kind() {
- let trait_type = self
- .tcx
- .mk_ref(*region, ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() });
+ let trait_type = Ty::new_ref(
+ self.tcx,
+ *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(
segment.ident,
@@ -254,6 +256,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Ok(result.callee)
}
+ pub fn lookup_method_for_diagnostic(
+ &self,
+ self_ty: Ty<'tcx>,
+ segment: &hir::PathSegment<'_>,
+ span: Span,
+ call_expr: &'tcx hir::Expr<'tcx>,
+ self_expr: &'tcx hir::Expr<'tcx>,
+ ) -> Result<MethodCallee<'tcx>, MethodError<'tcx>> {
+ let pick = self.lookup_probe_for_diagnostic(
+ segment.ident,
+ self_ty,
+ call_expr,
+ ProbeScope::TraitsInScope,
+ None,
+ )?;
+
+ Ok(self
+ .confirm_method_for_diagnostic(span, self_expr, call_expr, self_ty, &pick, segment)
+ .callee)
+ }
+
#[instrument(level = "debug", skip(self, call_expr))]
pub fn lookup_probe(
&self,
@@ -443,7 +466,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
));
// Also add an obligation for the method type being well-formed.
- let method_ty = tcx.mk_fn_ptr(ty::Binder::dummy(fn_sig));
+ let method_ty = Ty::new_fn_ptr(tcx, ty::Binder::dummy(fn_sig));
debug!(
"lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}",
method_ty, obligation
@@ -452,7 +475,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
tcx,
obligation.cause,
self.param_env,
- ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())),
+ ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(
+ method_ty.into(),
+ ))),
));
let callee = MethodCallee { def_id, substs, sig: fn_sig };
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 9f3d35a77..03a3eebbd 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -9,10 +9,10 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
-use rustc_hir_analysis::astconv::InferCtxtExt as _;
use rustc_hir_analysis::autoderef::{self, Autoderef};
use rustc_infer::infer::canonical::OriginalQueryValues;
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
+use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
use rustc_middle::middle::stability;
@@ -449,15 +449,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
} else {
- // Encountered a real ambiguity, so abort the lookup. If `ty` is not
- // an `Err`, report the right "type annotations needed" error pointing
- // to it.
+ // Ended up encountering a type variable when doing autoderef,
+ // but it may not be a type variable after processing obligations
+ // in our local `FnCtxt`, so don't call `structurally_resolve_type`.
let ty = &bad_ty.ty;
let ty = self
.probe_instantiate_query_response(span, &orig_values, ty)
.unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty));
- let ty = self.structurally_resolved_type(span, ty.value);
- assert!(matches!(ty.kind(), ty::Error(_)));
+ let ty = self.resolve_vars_if_possible(ty.value);
+ let guar = match *ty.kind() {
+ ty::Infer(ty::TyVar(_)) => self
+ .err_ctxt()
+ .emit_inference_failure_err(self.body_id, span, ty.into(), E0282, true)
+ .emit(),
+ ty::Error(guar) => guar,
+ _ => bug!("unexpected bad final type in method autoderef"),
+ };
+ self.demand_eqtype(span, ty, Ty::new_error(self.tcx, guar));
return Err(MethodError::NoMatch(NoMatchData {
static_candidates: Vec::new(),
unsatisfied_predicates: Vec::new(),
@@ -543,7 +551,7 @@ fn method_autoderef_steps<'tcx>(
steps.push(CandidateStep {
self_ty: infcx.make_query_response_ignoring_pending_obligations(
inference_vars,
- infcx.tcx.mk_slice(*elem_ty),
+ Ty::new_slice(infcx.tcx, *elem_ty),
),
autoderefs: dereferences,
// this could be from an unsafe deref if we had
@@ -826,7 +834,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::Clause(ty::Clause::Trait(trait_predicate)) => {
+ ty::ClauseKind::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))
@@ -834,20 +842,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
_ => None,
}
}
- ty::PredicateKind::Subtype(..)
- | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
- | ty::PredicateKind::Coerce(..)
- | ty::PredicateKind::Clause(ty::Clause::Projection(..))
- | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))
- | ty::PredicateKind::WellFormed(..)
- | ty::PredicateKind::ObjectSafe(..)
- | ty::PredicateKind::ClosureKind(..)
- | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
- | ty::PredicateKind::ConstEvaluatable(..)
- | ty::PredicateKind::ConstEquate(..)
- | ty::PredicateKind::Ambiguous
- | ty::PredicateKind::AliasRelate(..)
- | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
+ ty::ClauseKind::RegionOutlives(_)
+ | ty::ClauseKind::TypeOutlives(_)
+ | ty::ClauseKind::Projection(_)
+ | ty::ClauseKind::ConstArgHasType(_, _)
+ | ty::ClauseKind::WellFormed(_)
+ | ty::ClauseKind::ConstEvaluatable(_) => None,
}
});
@@ -954,7 +954,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
trait_def_id: DefId,
) {
debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id);
- let trait_substs = self.fresh_item_substs(trait_def_id);
+ let trait_substs = self.fresh_substs_for_item(self.span, trait_def_id);
let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, trait_substs);
if self.tcx.is_trait_alias(trait_def_id) {
@@ -1215,7 +1215,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// In general, during probing we erase regions.
let region = tcx.lifetimes.re_erased;
- let autoref_ty = tcx.mk_ref(region, ty::TypeAndMut { ty: self_ty, mutbl });
+ let autoref_ty = Ty::new_ref(tcx, region, ty::TypeAndMut { ty: self_ty, mutbl });
self.pick_method(autoref_ty, unstable_candidates).map(|r| {
r.map(|mut pick| {
pick.autoderefs = step.autoderefs;
@@ -1245,7 +1245,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
};
let const_self_ty = ty::TypeAndMut { ty, mutbl: hir::Mutability::Not };
- let const_ptr_ty = self.tcx.mk_ptr(const_self_ty);
+ let const_ptr_ty = Ty::new_ptr(self.tcx, const_self_ty);
self.pick_method(const_ptr_ty, unstable_candidates).map(|r| {
r.map(|mut pick| {
pick.autoderefs = step.autoderefs;
@@ -1441,8 +1441,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
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);
- let obligation = traits::Obligation::new(self.tcx, cause, self.param_env, predicate);
+ let obligation = traits::Obligation::new(self.tcx, cause, self.param_env, trait_ref);
traits::SelectionContext::new(self).select(&obligation)
}
@@ -1899,7 +1898,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
&self,
impl_def_id: DefId,
) -> (ty::EarlyBinder<Ty<'tcx>>, SubstsRef<'tcx>) {
- (self.tcx.type_of(impl_def_id), self.fresh_item_substs(impl_def_id))
+ (self.tcx.type_of(impl_def_id), self.fresh_substs_for_item(self.span, impl_def_id))
}
/// Replaces late-bound-regions bound by `value` with `'static` using
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index e04cc44b5..5f924f309 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -211,7 +211,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind() {
if needs_mut {
- let trait_type = self.tcx.mk_ref(
+ let trait_type = Ty::new_ref(
+ self.tcx,
*region,
ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() },
);
@@ -473,6 +474,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut custom_span_label = false;
let static_candidates = &mut no_match_data.static_candidates;
+
+ // `static_candidates` may have same candidates appended by
+ // inherent and extension, which may result in incorrect
+ // diagnostic.
+ static_candidates.dedup();
+
if !static_candidates.is_empty() {
err.note(
"found the following associated functions; to be used as methods, \
@@ -536,7 +543,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::Clause(ty::Clause::Trait(p)), Some(cause)) =
+ if let (ty::PredicateKind::Clause(ty::ClauseKind::Trait(p)), Some(cause)) =
(predicate.kind().skip_binder(), cause.as_ref())
{
if p.trait_ref.self_ty() != rcvr_ty {
@@ -563,7 +570,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::Clause(ty::Clause::Trait(p))
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(p))
if unimplemented_traits.contains_key(&p.trait_ref.def_id) => {}
_ => {
unimplemented_traits_only = false;
@@ -575,7 +582,7 @@ 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::Clause(ty::Clause::Trait(p))) =
+ if let (ty::Param(_), ty::PredicateKind::Clause(ty::ClauseKind::Trait(p))) =
(self_ty.kind(), parent_pred.kind().skip_binder())
{
let hir = self.tcx.hir();
@@ -635,13 +642,13 @@ 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::Clause(ty::Clause::Projection(pred)) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
let pred = bound_predicate.rebind(pred);
// `<Foo as Iterator>::Item = String`.
let projection_ty = pred.skip_binder().projection_ty;
let substs_with_infer_self = tcx.mk_substs_from_iter(
- iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into())
+ iter::once(Ty::new_var(tcx, ty::TyVid::from_u32(0)).into())
.chain(projection_ty.substs.iter().skip(1)),
);
@@ -659,7 +666,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
Some((obligation, projection_ty.self_ty()))
}
- ty::PredicateKind::Clause(ty::Clause::Trait(poly_trait_ref)) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(poly_trait_ref)) => {
let p = poly_trait_ref.trait_ref;
let self_ty = p.self_ty();
let path = p.print_only_trait_path();
@@ -690,7 +697,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
// Don't point out the span of `WellFormed` predicates.
- if !matches!(p.kind().skip_binder(), ty::PredicateKind::Clause(_)) {
+ if !matches!(
+ p.kind().skip_binder(),
+ ty::PredicateKind::Clause(
+ ty::ClauseKind::Projection(..) | ty::ClauseKind::Trait(..)
+ )
+ ) {
continue;
};
@@ -731,7 +743,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let sized_pred =
unsatisfied_predicates.iter().any(|(pred, _, _)| {
match pred.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
Some(pred.def_id()) == self.tcx.lang_items().sized_trait()
&& pred.polarity == ty::ImplPolarity::Positive
}
@@ -2003,16 +2015,18 @@ 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::Clause(ty::Clause::Trait(pred)) => match pred.self_ty().kind() {
- ty::Adt(def, _) => def.did().is_local(),
- _ => false,
- },
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
+ match pred.self_ty().kind() {
+ ty::Adt(def, _) => def.did().is_local(),
+ _ => false,
+ }
+ }
_ => false,
});
let mut preds: Vec<_> = errors
.iter()
.filter_map(|e| match e.obligation.predicate.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => Some(pred),
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => Some(pred),
_ => None,
})
.collect();
@@ -2083,7 +2097,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut derives = Vec::<(String, Span, Symbol)>::new();
let mut traits = Vec::new();
for (pred, _, _) in unsatisfied_predicates {
- let Some(ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred))) =
+ let Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred))) =
pred.kind().no_bound_vars()
else {
continue
@@ -2395,8 +2409,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// just this list.
for (rcvr_ty, post) in &[
(rcvr_ty, ""),
- (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), "&"),
+ (Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty), "&mut "),
+ (Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty), "&"),
] {
match self.lookup_probe_for_diagnostic(
item_name,
@@ -2431,10 +2445,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
for (rcvr_ty, pre) in &[
- (self.tcx.mk_lang_item(*rcvr_ty, LangItem::OwnedBox), "Box::new"),
- (self.tcx.mk_lang_item(*rcvr_ty, LangItem::Pin), "Pin::new"),
- (self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Arc), "Arc::new"),
- (self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Rc), "Rc::new"),
+ (Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::OwnedBox), "Box::new"),
+ (Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::Pin), "Pin::new"),
+ (Ty::new_diagnostic_item(self.tcx, *rcvr_ty, sym::Arc), "Arc::new"),
+ (Ty::new_diagnostic_item(self.tcx, *rcvr_ty, sym::Rc), "Rc::new"),
] {
if let Some(new_rcvr_t) = *rcvr_ty
&& let Ok(pick) = self.lookup_probe_for_diagnostic(
@@ -2518,10 +2532,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::Clause(ty::Clause::Trait(t)) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => {
t.def_id() == info.def_id
}
- ty::PredicateKind::Clause(ty::Clause::Projection(p)) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => {
p.projection_ty.def_id == info.def_id
}
_ => false,
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index b8bf2b691..1eae258c1 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -38,7 +38,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ty =
if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) {
self.enforce_builtin_binop_types(lhs.span, lhs_ty, rhs.span, rhs_ty, op);
- self.tcx.mk_unit()
+ Ty::new_unit(self.tcx)
} else {
return_ty
};
@@ -297,7 +297,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
// error types are considered "builtin"
Err(_) if lhs_ty.references_error() || rhs_ty.references_error() => {
- self.tcx.ty_error_misc()
+ Ty::new_misc_error(self.tcx)
}
Err(errors) => {
let (_, trait_def_id) =
@@ -521,8 +521,54 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
}
+
+ // Suggest using `add`, `offset` or `offset_from` for pointer - {integer},
+ // pointer + {integer} or pointer - pointer.
+ if op.span.can_be_used_for_suggestions() {
+ match op.node {
+ hir::BinOpKind::Add if lhs_ty.is_unsafe_ptr() && rhs_ty.is_integral() => {
+ err.multipart_suggestion(
+ "consider using `wrapping_add` or `add` for pointer + {integer}",
+ vec![
+ (
+ lhs_expr.span.between(rhs_expr.span),
+ ".wrapping_add(".to_owned(),
+ ),
+ (rhs_expr.span.shrink_to_hi(), ")".to_owned()),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ }
+ hir::BinOpKind::Sub => {
+ if lhs_ty.is_unsafe_ptr() && rhs_ty.is_integral() {
+ err.multipart_suggestion(
+ "consider using `wrapping_sub` or `sub` for pointer - {integer}",
+ vec![
+ (lhs_expr.span.between(rhs_expr.span), ".wrapping_sub(".to_owned()),
+ (rhs_expr.span.shrink_to_hi(), ")".to_owned()),
+ ],
+ Applicability::MaybeIncorrect
+ );
+ }
+
+ if lhs_ty.is_unsafe_ptr() && rhs_ty.is_unsafe_ptr() {
+ err.multipart_suggestion(
+ "consider using `offset_from` for pointer - pointer if the pointers point to the same allocation",
+ vec![
+ (lhs_expr.span.shrink_to_lo(), "unsafe { ".to_owned()),
+ (lhs_expr.span.between(rhs_expr.span), ".offset_from(".to_owned()),
+ (rhs_expr.span.shrink_to_hi(), ") }".to_owned()),
+ ],
+ Applicability::MaybeIncorrect
+ );
+ }
+ }
+ _ => {}
+ }
+ }
+
let reported = err.emit();
- self.tcx.ty_error(reported)
+ Ty::new_error(self.tcx, reported)
}
};
@@ -706,7 +752,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
err.emit()
});
- self.tcx.ty_error(guar)
+ Ty::new_error(self.tcx, guar)
}
}
}
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 5af955d31..42f4531c0 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -393,9 +393,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// They can denote both statically and dynamically-sized byte arrays.
let mut pat_ty = ty;
if let hir::ExprKind::Lit(Spanned { node: ast::LitKind::ByteStr(..), .. }) = lt.kind {
- let expected = self.structurally_resolved_type(span, expected);
- if let ty::Ref(_, inner_ty, _) = expected.kind()
- && matches!(inner_ty.kind(), ty::Slice(_))
+ let expected = self.structurally_resolve_type(span, expected);
+ if let ty::Ref(_, inner_ty, _) = *expected.kind()
+ && self.try_structurally_resolve_type(span, inner_ty).is_slice()
{
let tcx = self.tcx;
trace!(?lt.hir_id.local_id, "polymorphic byte string lit");
@@ -403,7 +403,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.borrow_mut()
.treat_byte_string_as_slice
.insert(lt.hir_id.local_id);
- pat_ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_slice(tcx.types.u8));
+ pat_ty = Ty::new_imm_ref(tcx,tcx.lifetimes.re_static, Ty::new_slice(tcx,tcx.types.u8));
}
}
@@ -412,7 +412,7 @@ impl<'a, 'tcx> FnCtxt<'a, '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(),
+ ty::Str => Ty::new_static_str(tcx,),
_ => pat_ty,
};
}
@@ -474,7 +474,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// There exists a side that didn't meet our criteria that the end-point
// be of a numeric or char type, as checked in `calc_side` above.
let guar = self.emit_err_pat_range(span, lhs, rhs);
- return self.tcx.ty_error(guar);
+ return Ty::new_error(self.tcx, guar);
}
// Unify each side with `expected`.
@@ -494,14 +494,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
demand_eqtype(&mut rhs, lhs);
if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
- return self.tcx.ty_error_misc();
+ return Ty::new_misc_error(self.tcx);
}
// Find the unified type and check if it's of numeric or char type again.
// This check is needed if both sides are inference variables.
// We require types to be resolved here so that we emit inference failure
// rather than "_ is not a char or numeric".
- let ty = self.structurally_resolved_type(span, expected);
+ let ty = self.structurally_resolve_type(span, expected);
if !(ty.is_numeric() || ty.is_char() || ty.references_error()) {
if let Some((ref mut fail, _, _)) = lhs {
*fail = true;
@@ -510,7 +510,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
*fail = true;
}
let guar = self.emit_err_pat_range(span, lhs, rhs);
- return self.tcx.ty_error(guar);
+ return Ty::new_error(self.tcx, guar);
}
ty
}
@@ -594,7 +594,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
debug!("check_pat_ident: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
- let local_ty = self.local_ty(pat.span, pat.hir_id).decl_ty;
+ let local_ty = self.local_ty(pat.span, pat.hir_id);
let eq_ty = match bm {
ty::BindByReference(mutbl) => {
// If the binding is like `ref x | ref mut x`,
@@ -635,7 +635,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty: Ty<'tcx>,
ti: TopInfo<'tcx>,
) {
- let var_ty = self.local_ty(span, var_id).decl_ty;
+ let var_ty = self.local_ty(span, var_id);
if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
let hir = self.tcx.hir();
let var_ty = self.resolve_vars_with_obligations(var_ty);
@@ -848,7 +848,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let (variant, pat_ty) = match self.check_struct_path(qpath, pat.hir_id) {
Ok(data) => data,
Err(guar) => {
- let err = self.tcx.ty_error(guar);
+ let err = Ty::new_error(self.tcx, guar);
for field in fields {
let ti = ti;
self.check_pat(field.pat, err, def_bm, ti);
@@ -864,7 +864,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, has_rest_pat, def_bm, ti) {
pat_ty
} else {
- self.tcx.ty_error_misc()
+ Ty::new_misc_error(self.tcx)
}
}
@@ -884,12 +884,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Res::Err => {
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(e);
+ return Ty::new_error(tcx, e);
}
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(e);
+ return Ty::new_error(tcx, e);
}
Res::SelfCtor(..)
| Res::Def(
@@ -1032,7 +1032,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let tcx = self.tcx;
let on_error = |e| {
for pat in subpats {
- self.check_pat(pat, tcx.ty_error(e), def_bm, ti);
+ self.check_pat(pat, Ty::new_error(tcx, e), def_bm, ti);
}
};
let report_unexpected_res = |res: Res| {
@@ -1049,7 +1049,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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(e);
+ return Ty::new_error(tcx, e);
}
// Type-check the path.
@@ -1057,7 +1057,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id);
if !pat_ty.is_fn() {
let e = report_unexpected_res(res);
- return tcx.ty_error(e);
+ return Ty::new_error(tcx, e);
}
let variant = match res {
@@ -1065,11 +1065,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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(e);
+ return Ty::new_error(tcx, e);
}
Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => {
let e = report_unexpected_res(res);
- return tcx.ty_error(e);
+ return Ty::new_error(tcx, e);
}
Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => tcx.expect_variant_res(res),
_ => bug!("unexpected pattern resolution: {:?}", res),
@@ -1112,7 +1112,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let e =
self.e0023(pat.span, res, qpath, subpats, &variant.fields.raw, expected, had_err);
on_error(e);
- return tcx.ty_error(e);
+ return Ty::new_error(tcx, e);
}
pat_ty
}
@@ -1289,7 +1289,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut expected_len = elements.len();
if ddpos.as_opt_usize().is_some() {
// Require known type only when `..` is present.
- if let ty::Tuple(tys) = self.structurally_resolved_type(span, expected).kind() {
+ if let ty::Tuple(tys) = self.structurally_resolve_type(span, expected).kind() {
expected_len = tys.len();
}
}
@@ -1303,16 +1303,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
});
let element_tys = tcx.mk_type_list_from_iter(element_tys_iter);
- let pat_ty = tcx.mk_tup(element_tys);
+ let pat_ty = Ty::new_tup(tcx, element_tys);
if let Some(mut err) = self.demand_eqtype_pat_diag(span, expected, pat_ty, ti) {
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(reported));
+ let element_tys_iter = (0..max_len).map(|_| Ty::new_error(tcx, reported));
for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
- self.check_pat(elem, tcx.ty_error(reported), def_bm, ti);
+ self.check_pat(elem, Ty::new_error(tcx, reported), def_bm, ti);
}
- tcx.mk_tup_from_iter(element_tys_iter)
+ Ty::new_tup_from_iter(tcx, element_tys_iter)
} else {
for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
self.check_pat(elem, element_tys[i], def_bm, ti);
@@ -1357,7 +1357,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Occupied(occupied) => {
no_field_errors = false;
let guar = self.error_field_already_bound(span, field.ident, *occupied.get());
- tcx.ty_error(guar)
+ Ty::new_error(tcx, guar)
}
Vacant(vacant) => {
vacant.insert(span);
@@ -1371,7 +1371,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.unwrap_or_else(|| {
inexistent_fields.push(field);
no_field_errors = false;
- tcx.ty_error_misc()
+ Ty::new_misc_error(tcx)
})
}
};
@@ -1951,12 +1951,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
kind: TypeVariableOriginKind::TypeInference,
span: inner.span,
});
- let box_ty = tcx.mk_box(inner_ty);
+ let box_ty = Ty::new_box(tcx, inner_ty);
self.demand_eqtype_pat(span, expected, box_ty, ti);
(box_ty, inner_ty)
}
Err(guar) => {
- let err = tcx.ty_error(guar);
+ let err = Ty::new_error(tcx, guar);
(err, err)
}
};
@@ -2007,7 +2007,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
Err(guar) => {
- let err = tcx.ty_error(guar);
+ let err = Ty::new_error(tcx, guar);
(err, err)
}
};
@@ -2019,7 +2019,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn new_ref_ty(&self, span: Span, mutbl: hir::Mutability, ty: Ty<'tcx>) -> Ty<'tcx> {
let region = self.next_region_var(infer::PatternRegion(span));
let mt = ty::TypeAndMut { ty, mutbl };
- self.tcx.mk_ref(region, mt)
+ Ty::new_ref(self.tcx, region, mt)
}
/// Type check a slice pattern.
@@ -2042,7 +2042,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
def_bm: BindingMode,
ti: TopInfo<'tcx>,
) -> Ty<'tcx> {
- let expected = self.structurally_resolved_type(span, expected);
+ let expected = self.structurally_resolve_type(span, expected);
let (element_ty, opt_slice_ty, inferred) = match *expected.kind() {
// An array, so we might have something like `let [a, b, c] = [0, 1, 2];`.
ty::Array(element_ty, len) => {
@@ -2061,7 +2061,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.error_reported()
.err()
.unwrap_or_else(|| self.error_expected_array_or_slice(span, expected, ti));
- let err = self.tcx.ty_error(guar);
+ let err = Ty::new_error(self.tcx, guar);
(err, Some(err), err)
}
};
@@ -2108,7 +2108,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else if let Some(pat_len) = len.checked_sub(min_len) {
// The variable-length pattern was there,
// so it has an array type with the remaining elements left as its size...
- return (Some(self.tcx.mk_array(element_ty, pat_len)), arr_ty);
+ return (Some(Ty::new_array(self.tcx, element_ty, pat_len)), arr_ty);
} else {
// ...however, in this case, there were no remaining elements.
// That is, the slice pattern requires more than the array type offers.
@@ -2117,7 +2117,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else if slice.is_none() {
// We have a pattern with a fixed length,
// which we can use to infer the length of the array.
- let updated_arr_ty = self.tcx.mk_array(element_ty, min_len);
+ let updated_arr_ty = Ty::new_array(self.tcx, element_ty, min_len);
self.demand_eqtype(span, updated_arr_ty, arr_ty);
return (None, updated_arr_ty);
} else {
@@ -2128,7 +2128,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
// If we get here, we must have emitted an error.
- (Some(self.tcx.ty_error(guar)), arr_ty)
+ (Some(Ty::new_error(self.tcx, guar)), arr_ty)
}
fn error_scrutinee_inconsistent_length(
diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs
index e2b1dc007..fd43b475e 100644
--- a/compiler/rustc_hir_typeck/src/place_op.rs
+++ b/compiler/rustc_hir_typeck/src/place_op.rs
@@ -6,7 +6,7 @@ use rustc_hir as hir;
use rustc_hir_analysis::autoderef::Autoderef;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::InferOk;
-use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref, PointerCast};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref, PointerCoercion};
use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::{self, Ty};
use rustc_span::symbol::{sym, Ident};
@@ -90,7 +90,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
let reported = err.emit();
- Some((self.tcx.ty_error(reported), self.tcx.ty_error(reported)))
+ Some((Ty::new_error(self.tcx, reported), Ty::new_error(self.tcx, reported)))
}
/// To type-check `base_expr[index_expr]`, we progressively autoderef
@@ -107,7 +107,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
index_expr: &hir::Expr<'_>,
) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> {
let adjusted_ty =
- self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
+ self.structurally_resolve_type(autoderef.span(), autoderef.final_ty(false));
debug!(
"try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \
index_ty={:?})",
@@ -138,7 +138,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if unsize {
// We only unsize arrays here.
if let ty::Array(element_ty, _) = adjusted_ty.kind() {
- self_ty = self.tcx.mk_slice(*element_ty);
+ self_ty = Ty::new_slice(self.tcx, *element_ty);
} else {
continue;
}
@@ -162,7 +162,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind() {
adjustments.push(Adjustment {
kind: Adjust::Borrow(AutoBorrow::Ref(*region, AutoBorrowMutability::Not)),
- target: self.tcx.mk_ref(
+ target: Ty::new_ref(
+ self.tcx,
*region,
ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: adjusted_ty },
),
@@ -172,7 +173,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
if unsize {
adjustments.push(Adjustment {
- kind: Adjust::Pointer(PointerCast::Unsize),
+ kind: Adjust::Pointer(PointerCoercion::Unsize),
target: method.sig.inputs()[0],
});
}
@@ -427,9 +428,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
allow_two_phase_borrow: AllowTwoPhase::No,
};
adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(*region, mutbl));
- adjustment.target = self
- .tcx
- .mk_ref(*region, ty::TypeAndMut { ty: source, mutbl: mutbl.into() });
+ adjustment.target = Ty::new_ref(
+ self.tcx,
+ *region,
+ ty::TypeAndMut { ty: source, mutbl: mutbl.into() },
+ );
}
source = adjustment.target;
}
@@ -438,7 +441,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let [
..,
Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. },
- Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), ref mut target },
+ Adjustment { kind: Adjust::Pointer(PointerCoercion::Unsize), ref mut target },
] = adjustments[..]
{
*target = method.sig.inputs()[0];
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 9458099f5..208c40a39 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -300,7 +300,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Build a tuple (U0..Un) of the final upvar types U0..Un
// and unify the upvar tuple type in the closure with it:
- let final_tupled_upvars_type = self.tcx.mk_tup(&final_upvar_tys);
+ let final_tupled_upvars_type = Ty::new_tup(self.tcx, &final_upvar_tys);
self.demand_suptype(span, substs.tupled_upvars_ty(), final_tupled_upvars_type);
let fake_reads = delegate
@@ -314,8 +314,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.typeck_results.borrow_mut().closure_size_eval.insert(
closure_def_id,
ClosureSizeProfileData {
- before_feature_tys: self.tcx.mk_tup(&before_feature_tys),
- after_feature_tys: self.tcx.mk_tup(&after_feature_tys),
+ before_feature_tys: Ty::new_tup(self.tcx, &before_feature_tys),
+ after_feature_tys: Ty::new_tup(self.tcx, &after_feature_tys),
},
);
}
@@ -1665,9 +1665,11 @@ fn apply_capture_kind_on_capture_ty<'tcx>(
) -> Ty<'tcx> {
match capture_kind {
ty::UpvarCapture::ByValue => ty,
- ty::UpvarCapture::ByRef(kind) => {
- tcx.mk_ref(region.unwrap(), ty::TypeAndMut { ty: ty, mutbl: kind.to_mutbl_lossy() })
- }
+ ty::UpvarCapture::ByRef(kind) => Ty::new_ref(
+ tcx,
+ region.unwrap(),
+ ty::TypeAndMut { ty: ty, mutbl: kind.to_mutbl_lossy() },
+ ),
}
}
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 0f21fc1e6..106457536 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -11,10 +11,9 @@ use rustc_hir::intravisit::{self, Visitor};
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
use rustc_middle::hir::place::Place as HirPlace;
use rustc_middle::mir::FakeReadCause;
-use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt};
-use rustc_middle::ty::TypeckResults;
use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt};
use rustc_span::symbol::sym;
use rustc_span::Span;
@@ -137,7 +136,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
fn write_ty_to_typeck_results(&mut self, hir_id: hir::HirId, ty: Ty<'tcx>) {
debug!("write_ty_to_typeck_results({:?}, {:?})", hir_id, ty);
- assert!(!ty.has_infer() && !ty.has_placeholders() && !ty.has_free_regions());
+ assert!(
+ !ty.has_infer() && !ty.has_placeholders() && !ty.has_free_regions(),
+ "{ty} can't be put into typeck results"
+ );
self.typeck_results.node_types_mut().insert(hir_id, ty);
}
@@ -148,31 +150,25 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
fn fix_scalar_builtin_expr(&mut self, e: &hir::Expr<'_>) {
match e.kind {
hir::ExprKind::Unary(hir::UnOp::Neg | hir::UnOp::Not, inner) => {
- let inner_ty = self.fcx.node_ty(inner.hir_id);
- let inner_ty = self.fcx.resolve_vars_if_possible(inner_ty);
+ let inner_ty = self.typeck_results.node_type(inner.hir_id);
if inner_ty.is_scalar() {
- let mut typeck_results = self.fcx.typeck_results.borrow_mut();
- typeck_results.type_dependent_defs_mut().remove(e.hir_id);
- typeck_results.node_substs_mut().remove(e.hir_id);
+ self.typeck_results.type_dependent_defs_mut().remove(e.hir_id);
+ self.typeck_results.node_substs_mut().remove(e.hir_id);
}
}
hir::ExprKind::Binary(ref op, lhs, rhs) | hir::ExprKind::AssignOp(ref op, lhs, rhs) => {
- let lhs_ty = self.fcx.node_ty(lhs.hir_id);
- let lhs_ty = self.fcx.resolve_vars_if_possible(lhs_ty);
-
- let rhs_ty = self.fcx.node_ty(rhs.hir_id);
- let rhs_ty = self.fcx.resolve_vars_if_possible(rhs_ty);
+ let lhs_ty = self.typeck_results.node_type(lhs.hir_id);
+ let rhs_ty = self.typeck_results.node_type(rhs.hir_id);
if lhs_ty.is_scalar() && rhs_ty.is_scalar() {
- let mut typeck_results = self.fcx.typeck_results.borrow_mut();
- typeck_results.type_dependent_defs_mut().remove(e.hir_id);
- typeck_results.node_substs_mut().remove(e.hir_id);
+ self.typeck_results.type_dependent_defs_mut().remove(e.hir_id);
+ self.typeck_results.node_substs_mut().remove(e.hir_id);
match e.kind {
hir::ExprKind::Binary(..) => {
if !op.node.is_by_value() {
- let mut adjustments = typeck_results.adjustments_mut();
+ let mut adjustments = self.typeck_results.adjustments_mut();
if let Some(a) = adjustments.get_mut(lhs.hir_id) {
a.pop();
}
@@ -182,7 +178,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
}
}
hir::ExprKind::AssignOp(..)
- if let Some(a) = typeck_results.adjustments_mut().get_mut(lhs.hir_id) =>
+ if let Some(a) = self.typeck_results.adjustments_mut().get_mut(lhs.hir_id) =>
{
a.pop();
}
@@ -200,16 +196,14 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
// if they are not we don't modify the expr, hence we bypass the ICE
fn is_builtin_index(
&mut self,
- typeck_results: &TypeckResults<'tcx>,
e: &hir::Expr<'_>,
base_ty: Ty<'tcx>,
index_ty: Ty<'tcx>,
) -> bool {
- if let Some(elem_ty) = base_ty.builtin_index() {
- let Some(exp_ty) = typeck_results.expr_ty_opt(e) else {return false;};
- let resolved_exp_ty = self.resolve(exp_ty, &e.span);
-
- elem_ty == resolved_exp_ty && index_ty == self.fcx.tcx.types.usize
+ if let Some(elem_ty) = base_ty.builtin_index()
+ && let Some(exp_ty) = self.typeck_results.expr_ty_opt(e)
+ {
+ elem_ty == exp_ty && index_ty == self.fcx.tcx.types.usize
} else {
false
}
@@ -221,38 +215,35 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
// usize-ish
fn fix_index_builtin_expr(&mut self, e: &hir::Expr<'_>) {
if let hir::ExprKind::Index(ref base, ref index) = e.kind {
- let mut typeck_results = self.fcx.typeck_results.borrow_mut();
-
// All valid indexing looks like this; might encounter non-valid indexes at this point.
- let base_ty = typeck_results
- .expr_ty_adjusted_opt(base)
- .map(|t| self.fcx.resolve_vars_if_possible(t).kind());
+ let base_ty = self.typeck_results.expr_ty_adjusted_opt(base);
if base_ty.is_none() {
// When encountering `return [0][0]` outside of a `fn` body we can encounter a base
// that isn't in the type table. We assume more relevant errors have already been
// emitted, so we delay an ICE if none have. (#64638)
self.tcx().sess.delay_span_bug(e.span, format!("bad base: `{:?}`", base));
}
- if let Some(ty::Ref(_, base_ty, _)) = base_ty {
- let index_ty = typeck_results.expr_ty_adjusted_opt(index).unwrap_or_else(|| {
- // When encountering `return [0][0]` outside of a `fn` body we would attempt
- // to access an nonexistent index. We assume that more relevant errors will
- // already have been emitted, so we only gate on this with an ICE if no
- // error has been emitted. (#64638)
- self.fcx.tcx.ty_error_with_message(
- e.span,
- format!("bad index {:?} for base: `{:?}`", index, base),
- )
- });
- let index_ty = self.fcx.resolve_vars_if_possible(index_ty);
- let resolved_base_ty = self.resolve(*base_ty, &base.span);
-
- if self.is_builtin_index(&typeck_results, e, resolved_base_ty, index_ty) {
+ if let Some(base_ty) = base_ty
+ && let ty::Ref(_, base_ty_inner, _) = *base_ty.kind()
+ {
+ let index_ty =
+ self.typeck_results.expr_ty_adjusted_opt(index).unwrap_or_else(|| {
+ // When encountering `return [0][0]` outside of a `fn` body we would attempt
+ // to access an nonexistent index. We assume that more relevant errors will
+ // already have been emitted, so we only gate on this with an ICE if no
+ // error has been emitted. (#64638)
+ Ty::new_error_with_message(
+ self.fcx.tcx,
+ e.span,
+ format!("bad index {:?} for base: `{:?}`", index, base),
+ )
+ });
+ if self.is_builtin_index(e, base_ty_inner, index_ty) {
// Remove the method call record
- typeck_results.type_dependent_defs_mut().remove(e.hir_id);
- typeck_results.node_substs_mut().remove(e.hir_id);
+ self.typeck_results.type_dependent_defs_mut().remove(e.hir_id);
+ self.typeck_results.node_substs_mut().remove(e.hir_id);
- if let Some(a) = typeck_results.adjustments_mut().get_mut(base.hir_id) {
+ if let Some(a) = self.typeck_results.adjustments_mut().get_mut(base.hir_id) {
// Discard the need for a mutable borrow
// Extra adjustment made when indexing causes a drop
@@ -260,7 +251,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
// Since this is "after" the other adjustment to be
// discarded, we do an extra `pop()`
if let Some(Adjustment {
- kind: Adjust::Pointer(PointerCast::Unsize), ..
+ kind: Adjust::Pointer(PointerCoercion::Unsize), ..
}) = a.pop()
{
// So the borrow discard actually happens here
@@ -283,9 +274,6 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
- self.fix_scalar_builtin_expr(e);
- self.fix_index_builtin_expr(e);
-
match e.kind {
hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
let body = self.fcx.tcx.hir().body(body);
@@ -314,6 +302,9 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
self.visit_node_id(e.span, e.hir_id);
intravisit::walk_expr(self, e);
+
+ self.fix_scalar_builtin_expr(e);
+ self.fix_index_builtin_expr(e);
}
fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
@@ -358,7 +349,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
intravisit::walk_local(self, l);
- let var_ty = self.fcx.local_ty(l.span, l.hir_id).decl_ty;
+ let var_ty = self.fcx.local_ty(l.span, l.hir_id);
let var_ty = self.resolve(var_ty, &l.span);
self.write_ty_to_typeck_results(l.hir_id, var_ty);
}
@@ -583,19 +574,15 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
continue;
}
- let hidden_type =
- self.tcx().erase_regions(hidden_type.remap_generic_params_to_declaration_params(
- opaque_type_key,
- self.tcx(),
- true,
- ));
-
+ // Here we only detect impl trait definition conflicts when they
+ // are equal modulo regions.
if let Some(last_opaque_ty) = self
.typeck_results
.concrete_opaque_types
- .insert(opaque_type_key.def_id, hidden_type)
+ .insert(opaque_type_key, hidden_type)
&& last_opaque_ty.ty != hidden_type.ty
{
+ assert!(!self.fcx.next_trait_solver());
hidden_type
.report_mismatch(&last_opaque_ty, opaque_type_key.def_id, self.tcx())
.stash(
@@ -816,11 +803,15 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> {
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
match self.fcx.fully_resolve(t) {
- Ok(t) if self.fcx.tcx.trait_solver_next() => {
+ Ok(t) if self.fcx.next_trait_solver() => {
// We must normalize erasing regions here, since later lints
// expect that types that show up in the typeck are fully
// normalized.
- self.fcx.tcx.try_normalize_erasing_regions(self.fcx.param_env, t).unwrap_or(t)
+ if let Ok(t) = self.fcx.tcx.try_normalize_erasing_regions(self.fcx.param_env, t) {
+ t
+ } else {
+ EraseEarlyRegions { tcx: self.fcx.tcx }.fold_ty(t)
+ }
}
Ok(t) => {
// Do not anonymize late-bound regions
@@ -833,7 +824,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> {
debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t);
let e = self.report_error(t);
self.replaced_with_error = Some(e);
- self.fcx.tcx.ty_error(e)
+ Ty::new_error(self.fcx.tcx, e)
}
}
}
@@ -850,7 +841,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> {
debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct);
let e = self.report_error(ct);
self.replaced_with_error = Some(e);
- self.fcx.tcx.const_error(ct.ty(), e)
+ ty::Const::new_error(self.fcx.tcx, e, ct.ty())
}
}
}