diff options
Diffstat (limited to 'compiler/rustc_hir_typeck')
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(¶m.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()) } } } |