1// ignore-tidy-file-filelength2// FIXME: we should move the field error reporting code somewhere else.34//! Type checking expressions.5//!6//! See [`rustc_hir_analysis::check`] for more context on type checking in general.78use std::borrow::Cow;910use rustc_abi::{FIRST_VARIANT, FieldIdx};11use rustc_ast as ast;12use rustc_ast::util::parser::ExprPrecedence;13use rustc_attr_ir::find_attr;14use rustc_attr_ir::lang_items::LangItem;15use rustc_data_structures::fx::{FxHashMap, FxHashSet};16use rustc_data_structures::thin_vec::ThinVec;17use rustc_data_structures::unord::UnordMap;18use rustc_errors::codes::*;19use rustc_errors::{20 Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, Subdiagnostic, listify, pluralize,21 struct_span_code_err,22};23use rustc_hir as hir;24use rustc_hir::def::{CtorKind, DefKind, Res};25use rustc_hir::def_id::DefId;26use rustc_hir::{ExprKind, HirId, QPath, is_range_literal};27use rustc_hir_analysis::diagnostics::{NoFieldOnType, NoVariantNamed};28use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _;29use rustc_infer::infer::{self, RegionVariableOrigin};30use rustc_infer::traits::WellFormedLoc;31use rustc_infer::traits::query::NoSolution;32use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};33use rustc_middle::ty::error::{ExpectedFound, TypeError};34use rustc_middle::ty::{self, AdtKind, GenericArgsRef, Ty, TypeVisitableExt, Unnormalized};35use rustc_session::diagnostics::feature_err;36use rustc_span::edit_distance::find_best_match_for_name;37use rustc_span::hygiene::DesugaringKind;38use rustc_span::{Ident, Span, Spanned, Symbol, bug, kw, span_bug, sym};39use rustc_trait_selection::infer::InferCtxtExt;40use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt};41use tracing::{debug, instrument, trace};4243use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};44use crate::callee::SplatLoweringInfo;45use crate::coercion::CoerceMany;46use crate::diagnostics::{47 AddressOfTemporaryTaken, BaseExpressionDoubleDot, BaseExpressionDoubleDotAddExpr,48 BaseExpressionDoubleDotRemove, CantDereference, ExprParenthesesNeeded,49 FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct, HelpUseLatestEdition,50 NakedAsmOutsideNakedFn, NoFieldOnVariant, ReturnLikeStatementKind, ReturnStmtOutsideOfFnBody,51 StructExprNonExhaustive, TypeMismatchFruTypo, YieldExprOutsideOfCoroutine,52};53use crate::op::contains_let_in_chain;54use crate::{55 BreakableCtxt, CoroutineTypes, Diverges, FnCtxt, GatherLocalsVisitor, Needs,56 TupleArgumentsFlag, cast, fatally_break_rust, type_error_struct,57};5859impl<'a, 'tcx> FnCtxt<'a, 'tcx> {60 pub(crate) fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence {61 let has_attr = |id: HirId| -> bool {62 self.tcx63 .hir_attrs(id)64 .iter()65 .any(rustc_attr_ir::Attribute::is_prefix_attr_for_suggestions)66 };6768 // Special case: range expressions are desugared to struct literals in HIR,69 // so they would normally return `Unambiguous` precedence in expr.precedence.70 // we should return `Range` precedence for correct parenthesization in suggestions.71 if is_range_literal(expr) {72 return ExprPrecedence::Range;73 }7475 expr.precedence(&has_attr)76 }7778 /// Check an expr with an expectation type, and also demand that the expr's79 /// evaluated type is a subtype of the expectation at the end. This is a80 /// *hard* requirement.81 pub(crate) fn check_expr_has_type_or_error(82 &self,83 expr: &'tcx hir::Expr<'tcx>,84 expected_ty: Ty<'tcx>,85 extend_err: impl FnOnce(&mut Diag<'_>),86 ) -> Ty<'tcx> {87 let mut ty = self.check_expr_with_expectation(expr, ExpectHasType(expected_ty));8889 // While we don't allow *arbitrary* coercions here, we *do* allow90 // coercions from ! to `expected`.91 if self.deeply_resolve_ignoring_regions_with_obligations(ty).is_never()92 && self.tcx.expr_guaranteed_to_constitute_read_for_never(expr)93 {94 if let Some(adjustments) = self.typeck_results.borrow().adjustments().get(expr.hir_id) {95 let reported = self.dcx().span_delayed_bug(96 expr.span,97 "expression with never type wound up being adjusted",98 );99100 return if let [Adjustment { kind: Adjust::NeverToAny, target }] = &adjustments[..] {101 target.to_owned()102 } else {103 Ty::new_error(self.tcx(), reported)104 };105 }106107 let adj_ty = self.next_ty_var(expr.span);108 self.apply_adjustments(109 expr,110 vec![Adjustment { kind: Adjust::NeverToAny, target: adj_ty }],111 );112 ty = adj_ty;113 }114115 if let Err(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) {116 let _ = self.emit_type_mismatch_suggestions(117 &mut err,118 expr.peel_drop_temps(),119 ty,120 expected_ty,121 None,122 None,123 );124 extend_err(&mut err);125 err.emit();126 }127 ty128 }129130 /// Check an expr with an expectation type, and also demand that the expr's131 /// evaluated type is a coercible to the expectation at the end. This is a132 /// *hard* requirement.133 pub(super) fn check_expr_coercible_to_type(134 &self,135 expr: &'tcx hir::Expr<'tcx>,136 expected: Ty<'tcx>,137 expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,138 ) -> Ty<'tcx> {139 self.check_expr_coercible_to_type_or_error(expr, expected, expected_ty_expr, |_, _| {})140 }141142 pub(crate) fn check_expr_coercible_to_type_or_error(143 &self,144 expr: &'tcx hir::Expr<'tcx>,145 expected: Ty<'tcx>,146 expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,147 extend_err: impl FnOnce(&mut Diag<'_>, Ty<'tcx>),148 ) -> Ty<'tcx> {149 let ty = self.check_expr_with_hint(expr, expected);150 // checks don't need two phase151 match self.demand_coerce_diag(expr, ty, expected, expected_ty_expr, AllowTwoPhase::No) {152 Ok(ty) => ty,153 Err(mut err) => {154 extend_err(&mut err, ty);155 err.emit();156 // Return the original type instead of an error type here, otherwise the type of `x` in157 // `let x: u32 = ();` will be a type error, causing all subsequent usages of `x` to not158 // report errors, even though `x` is definitely `u32`.159 expected160 }161 }162 }163164 /// Check an expr with an expectation type. Don't actually enforce that expectation165 /// is related to the expr's evaluated type via subtyping or coercion. This is166 /// usually called because we want to do that subtype/coerce call manually for better167 /// diagnostics.168 pub(super) fn check_expr_with_hint(169 &self,170 expr: &'tcx hir::Expr<'tcx>,171 expected: Ty<'tcx>,172 ) -> Ty<'tcx> {173 self.check_expr_with_expectation(expr, ExpectHasType(expected))174 }175176 /// Check an expr with an expectation type, and also [`Needs`] which will177 /// prompt typeck to convert any implicit immutable derefs to mutable derefs.178 fn check_expr_with_expectation_and_needs(179 &self,180 expr: &'tcx hir::Expr<'tcx>,181 expected: Expectation<'tcx>,182 needs: Needs,183 ) -> Ty<'tcx> {184 let ty = self.check_expr_with_expectation(expr, expected);185186 // If the expression is used in a place whether mutable place is required187 // e.g. LHS of assignment, perform the conversion.188 if let Needs::MutPlace = needs {189 self.convert_place_derefs_to_mutable(expr);190 }191192 ty193 }194195 /// Check an expr with no expectations.196 pub(super) fn check_expr(&self, expr: &'tcx hir::Expr<'tcx>) -> Ty<'tcx> {197 self.check_expr_with_expectation(expr, NoExpectation)198 }199200 /// Check an expr with no expectations, but with [`Needs`] which will201 /// prompt typeck to convert any implicit immutable derefs to mutable derefs.202 pub(super) fn check_expr_with_needs(203 &self,204 expr: &'tcx hir::Expr<'tcx>,205 needs: Needs,206 ) -> Ty<'tcx> {207 self.check_expr_with_expectation_and_needs(expr, NoExpectation, needs)208 }209210 /// Check an expr with an expectation type which may be used to eagerly211 /// guide inference when evaluating that expr.212 #[instrument(skip(self, expr), level = "debug")]213 pub(super) fn check_expr_with_expectation(214 &self,215 expr: &'tcx hir::Expr<'tcx>,216 expected: Expectation<'tcx>,217 ) -> Ty<'tcx> {218 self.check_expr_with_expectation_and_args(expr, expected, None)219 }220221 /// Same as [`Self::check_expr_with_expectation`], but allows us to pass in222 /// the arguments of a [`ExprKind::Call`] when evaluating its callee that223 /// is an [`ExprKind::Path`]. We use this to refine the spans for certain224 /// well-formedness guarantees for the path expr.225 pub(super) fn check_expr_with_expectation_and_args(226 &self,227 expr: &'tcx hir::Expr<'tcx>,228 expected: Expectation<'tcx>,229 call_expr_and_args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,230 ) -> Ty<'tcx> {231 if self.tcx().sess.verbose_internals() {232 // make this code only run with -Zverbose-internals because it is probably slow233 if let Ok(lint_str) = self.tcx.sess.source_map().span_to_snippet(expr.span) {234 if !lint_str.contains('\n') {235 debug!("expr text: {lint_str}");236 } else {237 let mut lines = lint_str.lines();238 if let Some(line0) = lines.next() {239 let remaining_lines = lines.count();240 debug!("expr text: {line0}");241 debug!("expr text: ...(and {remaining_lines} more lines)");242 }243 }244 }245 }246247 // True if `expr` is a `Try::from_ok(())` that is a result of desugaring a try block248 // without the final expr (e.g. `try { return; }`). We don't want to generate an249 // unreachable_code lint for it since warnings for autogenerated code are confusing.250 let is_try_block_generated_unit_expr = match expr.kind {251 ExprKind::Call(_, [arg]) => {252 expr.span.is_desugaring(DesugaringKind::TryBlock)253 && arg.span.is_desugaring(DesugaringKind::TryBlock)254 }255 _ => false,256 };257258 // Warn for expressions after diverging siblings.259 if !is_try_block_generated_unit_expr {260 self.warn_if_unreachable(expr.hir_id, expr.span, "expression");261 }262263 // Whether a past expression diverges doesn't affect typechecking of this expression, so we264 // reset `diverges` while checking `expr`.265 let old_diverges = self.diverges.replace(Diverges::Maybe);266267 if self.is_whole_body.replace(false) {268 // If this expression is the whole body and the function diverges because of its269 // arguments, we check this here to ensure the body is considered to diverge.270 self.diverges.set(self.function_diverges_because_of_empty_arguments.get())271 };272273 let ty = match &expr.kind {274 // Intercept the callee path expr and give it better spans.275 hir::ExprKind::Path(276 qpath @ (hir::QPath::Resolved(..) | hir::QPath::TypeRelative(..)),277 ) => self.check_expr_path(qpath, expr, call_expr_and_args),278 _ => self.check_expr_kind(expr, expected),279 };280 let ty = self.deeply_resolve_ignoring_regions(ty);281282 // Warn for non-block expressions with diverging children.283 match expr.kind {284 ExprKind::Block(..)285 | ExprKind::If(..)286 | ExprKind::Let(..)287 | ExprKind::Loop(..)288 | ExprKind::Match(..) => {}289 // Do not warn on `as` casts from never to any,290 // they are sometimes required to appeal typeck.291 ExprKind::Cast(_, _) => {}292 // If `expr` is a result of desugaring the try block and is an ok-wrapped293 // diverging expression (e.g. it arose from desugaring of `try { return }`),294 // we skip issuing a warning because it is autogenerated code.295 ExprKind::Call(..) if expr.span.is_desugaring(DesugaringKind::TryBlock) => {}296 // Likewise, do not lint unreachable code injected via contracts desugaring.297 ExprKind::Call(..) if expr.span.is_desugaring(DesugaringKind::Contract) => {}298 ExprKind::Call(callee, _) => self.warn_if_unreachable(expr.hir_id, callee.span, "call"),299 ExprKind::MethodCall(segment, ..) => {300 self.warn_if_unreachable(expr.hir_id, segment.ident.span, "call")301 }302 _ => self.warn_if_unreachable(expr.hir_id, expr.span, "expression"),303 }304305 // Any expression that produces a value of type `!` must have diverged,306 // unless it's a place expression that isn't being read from, in which case307 // diverging would be unsound since we may never actually read the `!`.308 // e.g. `let _ = *never_ptr;` with `never_ptr: *const !`.309 if self.deeply_resolve_ignoring_regions_with_obligations(ty).is_never()310 && self.tcx.expr_guaranteed_to_constitute_read_for_never(expr)311 {312 self.diverges.set(self.diverges.get() | Diverges::always(expr.span));313 }314315 // Record the type, which applies it effects.316 // We need to do this after the warning above, so that317 // we don't warn for the diverging expression itself.318 self.write_ty(expr.hir_id, ty);319320 // Combine the diverging and has_error flags.321 self.diverges.set(self.diverges.get() | old_diverges);322323 debug!("type of {} is...", self.tcx.hir_id_to_string(expr.hir_id));324 debug!("... {:?}, expected is {:?}", ty, expected);325326 ty327 }328329 #[instrument(skip(self, expr), level = "debug")]330 fn check_expr_kind(331 &self,332 expr: &'tcx hir::Expr<'tcx>,333 expected: Expectation<'tcx>,334 ) -> Ty<'tcx> {335 trace!("expr={:#?}", expr);336337 let tcx = self.tcx;338 match expr.kind {339 ExprKind::Lit(ref lit) => self.check_expr_lit(lit, expr.hir_id, expected),340 ExprKind::Binary(op, lhs, rhs) => self.check_expr_binop(expr, op, lhs, rhs, expected),341 ExprKind::Assign(lhs, rhs, span) => {342 self.check_expr_assign(expr, expected, lhs, rhs, span)343 }344 ExprKind::AssignOp(op, lhs, rhs) => {345 self.check_expr_assign_op(expr, op, lhs, rhs, expected)346 }347 ExprKind::Unary(unop, oprnd) => self.check_expr_unop(unop, oprnd, expected, expr),348 ExprKind::AddrOf(kind, mutbl, oprnd) => {349 self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr)350 }351 ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, None),352 ExprKind::InlineAsm(asm) => {353 // We defer some asm checks as we may not have resolved the input and output types yet (they may still be infer vars).354 self.deferred_asm_checks.borrow_mut().push((asm, expr.hir_id));355 self.check_expr_asm(asm, expr.span)356 }357 ExprKind::OffsetOf(container, fields) => {358 self.check_expr_offset_of(container, fields, expr)359 }360 ExprKind::Break(destination, ref expr_opt) => {361 self.check_expr_break(destination, expr_opt.as_deref(), expr)362 }363 ExprKind::Continue(destination) => self.check_expr_continue(destination, expr),364 ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr),365 ExprKind::Become(call) => self.check_expr_become(call, expr),366 ExprKind::Let(let_expr) => self.check_expr_let(let_expr, expr.hir_id),367 ExprKind::Loop(body, _, source, _) => {368 self.check_expr_loop(body, source, expected, expr)369 }370 ExprKind::Match(discrim, arms, match_src) => {371 self.check_expr_match(expr, discrim, arms, expected, match_src)372 }373 ExprKind::Closure(closure) => self.check_expr_closure(closure, expr.span, expected),374 ExprKind::Block(body, _) => self.check_expr_block(body, expected),375 ExprKind::Call(callee, args) => self.check_expr_call(expr, callee, args, expected),376 ExprKind::Use(used_expr, _) => self.check_expr_use(used_expr, expected),377 ExprKind::MethodCall(segment, receiver, args, _) => {378 self.check_expr_method_call(expr, segment, receiver, args, expected)379 }380 ExprKind::Cast(e, t) => self.check_expr_cast(e, t, expr),381 ExprKind::Type(e, t) => {382 let ascribed_ty = self.lower_ty_saving_user_provided_ty(t);383 let ty = self.check_expr_with_hint(e, ascribed_ty);384 self.demand_eqtype(e.span, ascribed_ty, ty);385 ascribed_ty386 }387 ExprKind::If(cond, then_expr, opt_else_expr) => {388 self.check_expr_if(expr.hir_id, cond, then_expr, opt_else_expr, expr.span, expected)389 }390 ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected),391 ExprKind::Array(args) => self.check_expr_array(args, expected, expr),392 ExprKind::ConstBlock(ref block) => self.check_expr_const_block(block, expected),393 ExprKind::Repeat(element, ref count) => {394 self.check_expr_repeat(element, count, expected, expr)395 }396 ExprKind::Tup(elts) => self.check_expr_tuple(elts, expected, expr),397 ExprKind::Struct(qpath, fields, ref base_expr) => {398 self.check_expr_struct(expr, expected, qpath, fields, base_expr)399 }400 ExprKind::Field(base, field) => self.check_expr_field(expr, base, field, expected),401 ExprKind::Index(base, idx, brackets_span) => {402 self.check_expr_index(base, idx, expr, brackets_span)403 }404 ExprKind::Yield(value, _) => self.check_expr_yield(value, expr),405 ExprKind::UnsafeBinderCast(kind, inner_expr, ty) => {406 self.check_expr_unsafe_binder_cast(expr.span, kind, inner_expr, ty, expected)407 }408 ExprKind::Err(guar) => Ty::new_error(tcx, guar),409 }410 }411412 fn check_expr_unop(413 &self,414 unop: hir::UnOp,415 oprnd: &'tcx hir::Expr<'tcx>,416 expected: Expectation<'tcx>,417 expr: &'tcx hir::Expr<'tcx>,418 ) -> Ty<'tcx> {419 let tcx = self.tcx;420 let expected_inner = match unop {421 hir::UnOp::Not | hir::UnOp::Neg => expected,422 hir::UnOp::Deref => NoExpectation,423 };424 let oprnd_t = self.check_expr_with_expectation(oprnd, expected_inner);425426 if let Err(guar) = oprnd_t.error_reported() {427 return Ty::new_error(tcx, guar);428 }429430 // Resolve what we can for `Not` and `Neg`, but allow later constraints431 // to determine an unresolved operand type,432 // so we call `deeply_resolve_ignoring_regions_with_obligations` for them.433 match unop {434 hir::UnOp::Deref => {435 // Dereferencing must distinguish builtin pointers from436 // overloaded `Deref`, so it still requires a structurally resolved type.437 //438 // This is necessary as raw pointers do not implement `Deref`.439 let oprnd_t = self.structurally_resolve_type(expr.span, oprnd_t);440 self.lookup_derefing(expr, oprnd, oprnd_t).unwrap_or_else(|| {441 let mut err =442 self.dcx().create_err(CantDereference { span: expr.span, ty: oprnd_t });443 let sp = tcx.sess.source_map().start_point(expr.span).with_parent(None);444 if let Some(sp) =445 tcx.sess.psess.complete_stmt_exprs_before_bin_op_lookalike.borrow().get(&sp)446 {447 err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));448 }449 // The operand may be an uncalled function, in which case it is its return type450 // the user meant to dereference. Only suggest the call when that return type is451 // itself dereferenceable, mirroring the checks `lookup_derefing` just failed.452 self.suggest_fn_call(&mut err, oprnd, oprnd_t, |output| {453 output.builtin_deref(true).is_some()454 || self.tcx.lang_items().deref_trait().is_some_and(|deref_trait| {455 self.type_implements_trait(deref_trait, [output], self.param_env)456 .may_apply()457 })458 });459 Ty::new_error(tcx, err.emit_err())460 })461 }462 hir::UnOp::Not => {463 let oprnd_t = self.deeply_resolve_ignoring_regions_with_obligations(oprnd_t);464 let result = self.check_user_unop(expr, oprnd_t, unop, expected_inner);465 // If it's builtin, we can reuse the type, this helps inference.466 if oprnd_t.is_integral() || *oprnd_t.kind() == ty::Bool { oprnd_t } else { result }467 }468 hir::UnOp::Neg => {469 let oprnd_t = self.deeply_resolve_ignoring_regions_with_obligations(oprnd_t);470 let result = self.check_user_unop(expr, oprnd_t, unop, expected_inner);471 // If it's builtin, we can reuse the type, this helps inference.472 if oprnd_t.is_numeric() { oprnd_t } else { result }473 }474 }475 }476477 fn check_expr_addr_of(478 &self,479 kind: hir::BorrowKind,480 mutbl: hir::Mutability,481 oprnd: &'tcx hir::Expr<'tcx>,482 expected: Expectation<'tcx>,483 expr: &'tcx hir::Expr<'tcx>,484 ) -> Ty<'tcx> {485 let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| {486 match self.deeply_resolve_ignoring_regions_with_obligations(ty).kind() {487 ty::Ref(_, ty, _) | ty::RawPtr(ty, _) => {488 if oprnd.is_syntactic_place_expr() {489 // Places may legitimately have unsized types.490 // For example, dereferences of a wide pointer and491 // the last field of a struct can be unsized.492 ExpectHasType(*ty)493 } else {494 Expectation::rvalue_hint(self, *ty)495 }496 }497 _ => NoExpectation,498 }499 });500 let ty =501 self.check_expr_with_expectation_and_needs(oprnd, hint, Needs::maybe_mut_place(mutbl));502 if let Err(guar) = ty.error_reported() {503 return Ty::new_error(self.tcx, guar);504 }505506 match kind {507 hir::BorrowKind::Raw => {508 self.check_named_place_expr(oprnd);509 Ty::new_ptr(self.tcx, ty, mutbl)510 }511 hir::BorrowKind::Ref | hir::BorrowKind::Pin => {512 // Note: at this point, we cannot say what the best lifetime513 // is to use for resulting pointer. We want to use the514 // shortest lifetime possible so as to avoid spurious borrowck515 // errors. Moreover, the longest lifetime will depend on the516 // precise details of the value whose address is being taken517 // (and how long it is valid), which we don't know yet until518 // type inference is complete.519 //520 // Therefore, here we simply generate a region variable. The521 // region inferencer will then select a suitable value.522 // Finally, borrowck will infer the value of the region again,523 // this time with enough precision to check that the value524 // whose address was taken can actually be made to live as long525 // as it needs to live.526 let region = self.next_region_var(RegionVariableOrigin::BorrowRegion(expr.span));527 match kind {528 hir::BorrowKind::Ref => Ty::new_ref(self.tcx, region, ty, mutbl),529 hir::BorrowKind::Pin => Ty::new_pinned_ref(self.tcx, region, ty, mutbl),530 _ => unreachable!(),531 }532 }533 }534 }535536 /// Does this expression refer to a place that either:537 /// * Is based on a local or static.538 /// * Contains a dereference539 /// Note that the adjustments for the children of `expr` should already540 /// have been resolved.541 fn check_named_place_expr(&self, oprnd: &'tcx hir::Expr<'tcx>) {542 let is_named = oprnd.is_place_expr(|base| {543 // Allow raw borrows if there are any deref adjustments.544 //545 // const VAL: (i32,) = (0,);546 // const REF: &(i32,) = &(0,);547 //548 // &raw const VAL.0; // ERROR549 // &raw const REF.0; // OK, same as &raw const (*REF).0;550 //551 // This is maybe too permissive, since it allows552 // `let u = &raw const Box::new((1,)).0`, which creates an553 // immediately dangling raw pointer.554 self.typeck_results555 .borrow()556 .adjustments()557 .get(base.hir_id)558 .is_some_and(|x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_))))559 });560 if !is_named {561 self.dcx().emit_err(AddressOfTemporaryTaken { span: oprnd.span });562 }563 }564565 pub(crate) fn check_expr_path(566 &self,567 qpath: &'tcx hir::QPath<'tcx>,568 expr: &'tcx hir::Expr<'tcx>,569 call_expr_and_args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,570 ) -> Ty<'tcx> {571 let tcx = self.tcx;572573 if let Some((_, [arg])) = call_expr_and_args574 && let QPath::Resolved(_, path) = qpath575 && let Res::Def(_, def_id) = path.res576 && let Some(lang_item) = tcx.lang_items().from_def_id(def_id)577 {578 let code = match lang_item {579 LangItem::IntoFutureIntoFuture580 if expr.span.is_desugaring(DesugaringKind::Await) =>581 {582 Some(ObligationCauseCode::AwaitableExpr(arg.hir_id))583 }584 LangItem::IntoIterIntoIter | LangItem::IteratorNext585 if expr.span.is_desugaring(DesugaringKind::ForLoop) =>586 {587 Some(ObligationCauseCode::ForLoopIterator(arg.hir_id))588 }589 LangItem::TryTraitFromOutput590 if expr.span.is_desugaring(DesugaringKind::TryBlock) =>591 {592 // FIXME it's a try block, not a question mark593 Some(ObligationCauseCode::QuestionMark)594 }595 LangItem::TryTraitBranch | LangItem::TryTraitFromResidual596 if expr.span.is_desugaring(DesugaringKind::QuestionMark) =>597 {598 Some(ObligationCauseCode::QuestionMark)599 }600 _ => None,601 };602 if let Some(code) = code {603 let args = self.fresh_args_for_item(expr.span, def_id);604 self.add_required_obligations_with_code(expr.span, def_id, args, |_, _| {605 code.clone()606 });607 return tcx.type_of(def_id).instantiate(tcx, args).skip_norm_wip();608 }609 }610611 let (res, opt_ty, segs) =612 self.resolve_ty_and_res_fully_qualified_call(qpath, expr.hir_id, expr.span);613 let ty = match res {614 Res::Err => {615 self.suggest_assoc_method_call(segs);616 let e =617 self.dcx().span_delayed_bug(qpath.span(), "`Res::Err` but no error emitted");618 Ty::new_error(tcx, e)619 }620 Res::Def(DefKind::Variant, _) => {621 let e = self.report_unexpected_variant_res(622 res,623 Some(expr),624 &[],625 qpath,626 expr.span,627 E0533,628 "value",629 );630 Ty::new_error(tcx, e)631 }632 _ => {633 self.instantiate_value_path(634 segs,635 opt_ty,636 res,637 call_expr_and_args.map_or(expr.span, |(e, _)| e.span),638 expr.span,639 expr.hir_id,640 call_expr_and_args.map(|(_, args)| args),641 )642 .0643 }644 };645646 if let ty::FnDef(did, args) = *ty.kind() {647 let fn_sig = ty.fn_sig(tcx);648649 if tcx.is_intrinsic(did, sym::transmute) {650 let Some(from) = fn_sig.inputs().skip_binder().get(0) else {651 span_bug!(652 tcx.def_span(did),653 "intrinsic fn `transmute` defined with no parameters"654 );655 };656 let to = fn_sig.output().skip_binder();657 // We defer the transmute to the end of typeck, once all inference vars have658 // been resolved or we errored. This is important as we can only check transmute659 // on concrete types, but the output type may not be known yet (it would only660 // be known if explicitly specified via turbofish).661 self.deferred_transmute_checks.borrow_mut().push((*from, to, expr.hir_id));662 }663 if !tcx.sess.opts.unstable_opts.offload.is_empty()664 && tcx.is_intrinsic(did, sym::offload)665 {666 let args = args.skip_binder();667 let f = args.type_at(0);668 let t = args.type_at(1);669 let r = args.type_at(2);670 // Defer offload checks to check generics later once types are fully inferred.671 self.deferred_offload_checks.borrow_mut().push((f, t, r, expr.hir_id));672 }673 if !tcx.features().unsized_fn_params() {674 // We want to remove some Sized bounds from std functions,675 // but don't want to expose the removal to stable Rust.676 // i.e., we don't want to allow677 //678 // ```rust679 // drop as fn(str);680 // ```681 //682 // to work in stable even if the Sized bound on `drop` is relaxed.683 for i in 0..fn_sig.inputs().skip_binder().len() {684 // We just want to check sizedness, so instead of introducing685 // placeholder lifetimes with probing, we just replace higher lifetimes686 // with fresh vars.687 let span = call_expr_and_args688 .and_then(|(_, args)| args.get(i))689 .map_or(expr.span, |arg| arg.span);690 let input = self.instantiate_binder_with_fresh_vars(691 span,692 infer::BoundRegionConversionTime::FnCall,693 fn_sig.input(i),694 );695 self.require_type_is_sized_deferred(696 input,697 span,698 ObligationCauseCode::SizedArgumentType(None),699 );700 }701 }702 // Here we want to prevent struct constructors from returning unsized types,703 // which can happen with fn pointer coercion on stable.704 // Also, as we just want to check sizedness, instead of introducing705 // placeholder lifetimes with probing, we just replace higher lifetimes706 // with fresh vars.707 let output = self.instantiate_binder_with_fresh_vars(708 expr.span,709 infer::BoundRegionConversionTime::FnCall,710 fn_sig.output(),711 );712 self.require_type_is_sized_deferred(713 output,714 call_expr_and_args.map_or(expr.span, |(e, _)| e.span),715 ObligationCauseCode::SizedCallReturnType(expr.hir_id),716 );717 }718719 // We always require that the type provided as the value for720 // a type parameter outlives the moment of instantiation.721 let args = self.typeck_results.borrow().node_args(expr.hir_id);722 self.add_wf_bounds(args, expr.span, expr.hir_id);723724 ty725 }726727 fn check_expr_break(728 &self,729 destination: hir::Destination,730 expr_opt: Option<&'tcx hir::Expr<'tcx>>,731 expr: &'tcx hir::Expr<'tcx>,732 ) -> Ty<'tcx> {733 let tcx = self.tcx;734 if let Ok(target_id) = destination.target_id {735 let (e_ty, cause);736 if let Some(e) = expr_opt {737 // If this is a break with a value, we need to type-check738 // the expression. Get an expected type from the loop context.739 let opt_coerce_to = {740 // We should release `enclosing_breakables` before the `check_expr_with_hint`741 // below, so can't move this block of code to the enclosing scope and share742 // `ctxt` with the second `enclosing_breakables` borrow below.743 let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();744 match enclosing_breakables.opt_find_breakable(target_id) {745 Some(ctxt) => ctxt.coerce.as_ref().map(|coerce| coerce.expected_ty()),746 None => {747 // Avoid ICE when `break` is inside a closure (#65383).748 return Ty::new_error_with_message(749 tcx,750 expr.span,751 "break was outside loop, but no error was emitted",752 );753 }754 }755 };756757 // If the loop context is not a `loop { }`, then break with758 // a value is illegal, and `opt_coerce_to` will be `None`.759 // Set expectation to error in that case and set tainted760 // by error (#114529)761 let coerce_to = opt_coerce_to.unwrap_or_else(|| {762 let guar = self.dcx().span_delayed_bug(763 expr.span,764 "illegal break with value found but no error reported",765 );766 self.set_tainted_by_errors(guar);767 Ty::new_error(tcx, guar)768 });769770 // Recurse without `enclosing_breakables` borrowed.771 e_ty = self.check_expr_with_hint(e, coerce_to);772 cause = self.misc(e.span);773 } else {774 // Otherwise, this is a break *without* a value. That's775 // always legal, and is equivalent to `break ()`.776 e_ty = tcx.types.unit;777 cause = self.misc(expr.span);778 }779780 // Now that we have type-checked `expr_opt`, borrow781 // the `enclosing_loops` field and let's coerce the782 // type of `expr_opt` into what is expected.783 let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();784 let Some(ctxt) = enclosing_breakables.opt_find_breakable(target_id) else {785 // Avoid ICE when `break` is inside a closure (#65383).786 return Ty::new_error_with_message(787 tcx,788 expr.span,789 "break was outside loop, but no error was emitted",790 );791 };792793 if let Some(ref mut coerce) = ctxt.coerce {794 if let Some(e) = expr_opt {795 coerce.coerce(self, &cause, e, e_ty);796 } else {797 assert!(e_ty.is_unit());798 let ty = coerce.expected_ty();799 coerce.coerce_forced_unit(800 self,801 &cause,802 |mut err| {803 self.suggest_missing_semicolon(&mut err, expr, e_ty, false, false);804 self.suggest_mismatched_types_on_tail(805 &mut err, expr, ty, e_ty, target_id,806 );807 let error =808 Some(TypeError::Sorts(ExpectedFound { expected: ty, found: e_ty }));809 self.annotate_loop_expected_due_to_inference(err, expr, error);810 if let Some(val) =811 self.err_ctxt().ty_kind_suggestion(self.param_env, ty)812 {813 err.span_suggestion_verbose(814 expr.span.shrink_to_hi(),815 "give the `break` a value of the expected type",816 format!(" {val}"),817 Applicability::HasPlaceholders,818 );819 }820 },821 false,822 );823 }824 } else {825 // If `ctxt.coerce` is `None`, we can just ignore826 // the type of the expression. This is because827 // either this was a break *without* a value, in828 // which case it is always a legal type (`()`), or829 // else an error would have been flagged by the830 // `loops` pass for using break with an expression831 // where you are not supposed to.832 assert!(expr_opt.is_none() || self.tainted_by_errors().is_some());833 }834835 // If we encountered a `break`, then (no surprise) it may be possible to break from the836 // loop... unless the value being returned from the loop diverges itself, e.g.837 // `break return 5` or `break loop {}`.838 ctxt.may_break |= !self.diverges.get().is_always();839840 // the type of a `break` is always `!`, since it diverges841 tcx.types.never842 } else {843 // Otherwise, we failed to find the enclosing loop;844 // this can only happen if the `break` was not845 // inside a loop at all, which is caught by the846 // loop-checking pass.847 let err = Ty::new_error_with_message(848 self.tcx,849 expr.span,850 "break was outside loop, but no error was emitted",851 );852853 // We still need to assign a type to the inner expression to854 // prevent the ICE in #43162.855 if let Some(e) = expr_opt {856 self.check_expr_with_hint(e, err);857858 // ... except when we try to 'break rust;'.859 // ICE this expression in particular (see #43162).860 if let ExprKind::Path(QPath::Resolved(_, path)) = e.kind {861 if let [segment] = path.segments862 && segment.ident.name == sym::rust863 {864 fatally_break_rust(self.tcx, expr.span);865 }866 }867 }868869 // There was an error; make type-check fail.870 err871 }872 }873874 fn check_expr_continue(875 &self,876 destination: hir::Destination,877 expr: &'tcx hir::Expr<'tcx>,878 ) -> Ty<'tcx> {879 if let Ok(target_id) = destination.target_id {880 if let hir::Node::Expr(hir::Expr { kind: ExprKind::Loop(..), .. }) =881 self.tcx.hir_node(target_id)882 {883 self.tcx.types.never884 } else {885 // Liveness linting assumes `continue`s all point to loops. We'll report an error886 // in `check_mod_loops`, but make sure we don't run liveness (#113379, #121623).887 let guar = self.dcx().span_delayed_bug(888 expr.span,889 "found `continue` not pointing to loop, but no error reported",890 );891 Ty::new_error(self.tcx, guar)892 }893 } else {894 // There was an error; make type-check fail.895 Ty::new_misc_error(self.tcx)896 }897 }898899 fn check_expr_return(900 &self,901 expr_opt: Option<&'tcx hir::Expr<'tcx>>,902 expr: &'tcx hir::Expr<'tcx>,903 ) -> Ty<'tcx> {904 if self.ret_coercion.is_none() {905 self.emit_return_outside_of_fn_body(expr, ReturnLikeStatementKind::Return);906907 if let Some(e) = expr_opt {908 // We still have to type-check `e` (issue #86188), but calling909 // `check_return_expr` only works inside fn bodies.910 self.check_expr(e);911 }912 } else if let Some(e) = expr_opt {913 if self.ret_coercion_span.get().is_none() {914 self.ret_coercion_span.set(Some(e.span));915 }916 self.check_return_or_body_tail(e, true);917 } else {918 let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut();919 if self.ret_coercion_span.get().is_none() {920 self.ret_coercion_span.set(Some(expr.span));921 }922 let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression);923 if let Some((_, fn_decl)) = self.get_fn_decl(expr.hir_id) {924 coercion.coerce_forced_unit(925 self,926 &cause,927 |db| {928 let span = fn_decl.output.span();929 if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {930 db.span_label(931 span,932 format!("expected `{snippet}` because of this return type"),933 );934 }935 },936 true,937 );938 } else {939 coercion.coerce_forced_unit(self, &cause, |_| (), true);940 }941 }942 self.tcx.types.never943 }944945 fn check_expr_become(946 &self,947 call: &'tcx hir::Expr<'tcx>,948 expr: &'tcx hir::Expr<'tcx>,949 ) -> Ty<'tcx> {950 match &self.ret_coercion {951 Some(ret_coercion) => {952 let ret_ty = ret_coercion.borrow().expected_ty();953 let call_expr_ty = self.check_expr_with_hint(call, ret_ty);954955 // N.B. don't coerce here, as tail calls can't support most/all coercions956 // FIXME(explicit_tail_calls): add a diagnostic note that `become` doesn't allow coercions957 self.demand_suptype(expr.span, ret_ty, call_expr_ty);958 }959 None => {960 self.emit_return_outside_of_fn_body(expr, ReturnLikeStatementKind::Become);961962 // Fallback to simply type checking `call` without hint/demanding the right types.963 // Best effort to highlight more errors.964 self.check_expr(call);965 }966 }967968 self.tcx.types.never969 }970971 /// Check an expression that _is being returned_.972 /// For example, this is called with `return_expr: $expr` when `return $expr`973 /// is encountered.974 ///975 /// Note that this function must only be called in function bodies.976 ///977 /// `explicit_return` is `true` if we're checking an explicit `return expr`,978 /// and `false` if we're checking a trailing expression.979 pub(super) fn check_return_or_body_tail(980 &self,981 return_expr: &'tcx hir::Expr<'tcx>,982 explicit_return: bool,983 ) {984 let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| {985 span_bug!(return_expr.span, "check_return_expr called outside fn body")986 });987988 let ret_ty = ret_coercion.borrow().expected_ty();989 let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty);990 let mut span = return_expr.span;991 let mut hir_id = return_expr.hir_id;992 // Use the span of the trailing expression for our cause,993 // not the span of the entire function994 if !explicit_return995 && let ExprKind::Block(body, _) = return_expr.kind996 && let Some(last_expr) = body.expr997 {998 span = last_expr.span;999 hir_id = last_expr.hir_id;1000 }1001 ret_coercion.borrow_mut().coerce(1002 self,1003 &self.cause(span, ObligationCauseCode::ReturnValue(return_expr.hir_id)),1004 return_expr,1005 return_expr_ty,1006 );10071008 if let Some(fn_sig) = self.fn_sig()1009 && fn_sig.output().has_opaque_types()1010 {1011 // Point any obligations that were registered due to opaque type1012 // inference at the return expression.1013 self.select_obligations_where_possible(|errors| {1014 self.point_at_return_for_opaque_ty_error(1015 errors,1016 hir_id,1017 span,1018 return_expr_ty,1019 return_expr.span,1020 );1021 });1022 }1023 }10241025 /// Emit an error because `return` or `become` is used outside of a function body.1026 ///1027 /// `expr` is the `return` (`become`) "statement", `kind` is the kind of the statement1028 /// either `Return` or `Become`.1029 fn emit_return_outside_of_fn_body(&self, expr: &hir::Expr<'_>, kind: ReturnLikeStatementKind) {1030 let mut err = ReturnStmtOutsideOfFnBody {1031 span: expr.span,1032 encl_body_span: None,1033 encl_fn_span: None,1034 statement_kind: kind,1035 };10361037 let encl_item_id = self.tcx.hir_get_parent_item(expr.hir_id);10381039 if let hir::Node::Item(hir::Item {1040 kind: hir::ItemKind::Fn { .. },1041 span: encl_fn_span,1042 ..1043 })1044 | hir::Node::TraitItem(hir::TraitItem {1045 kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)),1046 span: encl_fn_span,1047 ..1048 })1049 | hir::Node::ImplItem(hir::ImplItem {1050 kind: hir::ImplItemKind::Fn(..),1051 span: encl_fn_span,1052 ..1053 }) = self.tcx.hir_node_by_def_id(encl_item_id.def_id)1054 {1055 // We are inside a function body, so reporting "return statement1056 // outside of function body" needs an explanation.10571058 let encl_body_owner_id = self.tcx.hir_enclosing_body_owner(expr.hir_id);10591060 // If this didn't hold, we would not have to report an error in1061 // the first place.1062 assert_ne!(encl_item_id.def_id, encl_body_owner_id);10631064 let encl_body = self.tcx.hir_body_owned_by(encl_body_owner_id);10651066 err.encl_body_span = Some(encl_body.value.span);1067 err.encl_fn_span = Some(*encl_fn_span);1068 }10691070 self.dcx().emit_err(err);1071 }10721073 fn point_at_return_for_opaque_ty_error(1074 &self,1075 errors: &mut ThinVec<traits::FulfillmentError<'tcx>>,1076 hir_id: HirId,1077 span: Span,1078 return_expr_ty: Ty<'tcx>,1079 return_span: Span,1080 ) {1081 // Don't point at the whole block if it's empty1082 if span == return_span {1083 return;1084 }1085 for err in errors {1086 let cause = &mut err.obligation.cause;1087 if let ObligationCauseCode::OpaqueReturnType(None) = cause.code() {1088 let new_cause = self.cause(1089 cause.span,1090 ObligationCauseCode::OpaqueReturnType(Some((return_expr_ty, hir_id))),1091 );1092 *cause = new_cause;1093 }1094 }1095 }10961097 pub(crate) fn check_lhs_assignable(1098 &self,1099 lhs: &'tcx hir::Expr<'tcx>,1100 code: ErrCode,1101 op_span: Span,1102 adjust_err: impl FnOnce(&mut Diag<'_>),1103 ) {1104 if lhs.is_syntactic_place_expr() {1105 return;1106 }11071108 // Skip suggestion if LHS contains a let-chain at this would likely be spurious1109 // cc: https://github.com/rust-lang/rust/issues/1476641110 if contains_let_in_chain(lhs) {1111 return;1112 }11131114 let mut err = self.dcx().struct_span_err(op_span, "invalid left-hand side of assignment");1115 err.code(code);1116 err.span_label(lhs.span, "cannot assign to this expression");11171118 self.comes_from_while_condition(lhs.hir_id, |expr| {1119 err.span_suggestion_verbose(1120 expr.span.shrink_to_lo(),1121 "you might have meant to use pattern destructuring",1122 "let ",1123 Applicability::MachineApplicable,1124 );1125 });1126 self.check_for_missing_semi(lhs, &mut err);11271128 adjust_err(&mut err);11291130 err.emit();1131 }11321133 /// Check if the expression that could not be assigned to was a typoed expression that1134 pub(crate) fn check_for_missing_semi(1135 &self,1136 expr: &'tcx hir::Expr<'tcx>,1137 err: &mut Diag<'_>,1138 ) -> bool {1139 if let hir::ExprKind::Binary(binop, lhs, rhs) = expr.kind1140 && let hir::BinOpKind::Mul = binop.node1141 && self.tcx.sess.source_map().is_multiline(lhs.span.between(rhs.span))1142 && rhs.is_syntactic_place_expr()1143 {1144 // v missing semicolon here1145 // foo()1146 // *bar = baz;1147 // (#80446).1148 err.span_suggestion_verbose(1149 lhs.span.shrink_to_hi(),1150 "you might have meant to write a semicolon here",1151 ";",1152 Applicability::MachineApplicable,1153 );1154 return true;1155 }1156 false1157 }11581159 // Check if an expression `original_expr_id` comes from the condition of a while loop,1160 /// as opposed from the body of a while loop, which we can naively check by iterating1161 /// parents until we find a loop...1162 pub(super) fn comes_from_while_condition(1163 &self,1164 original_expr_id: HirId,1165 then: impl FnOnce(&hir::Expr<'_>),1166 ) {1167 let mut parent = self.tcx.parent_hir_id(original_expr_id);1168 loop {1169 let node = self.tcx.hir_node(parent);1170 match node {1171 hir::Node::Expr(hir::Expr {1172 kind:1173 hir::ExprKind::Loop(1174 hir::Block {1175 expr:1176 Some(hir::Expr {1177 kind:1178 hir::ExprKind::Match(expr, ..) | hir::ExprKind::If(expr, ..),1179 ..1180 }),1181 ..1182 },1183 _,1184 hir::LoopSource::While,1185 _,1186 ),1187 ..1188 }) => {1189 // Check if our original expression is a child of the condition of a while loop.1190 // If it is, then we have a situation like `while Some(0) = value.get(0) {`,1191 // where `while let` was more likely intended.1192 if self.tcx.hir_parent_id_iter(original_expr_id).any(|id| id == expr.hir_id) {1193 then(expr);1194 }1195 break;1196 }1197 hir::Node::Item(_)1198 | hir::Node::ImplItem(_)1199 | hir::Node::TraitItem(_)1200 | hir::Node::Crate(_) => break,1201 _ => {1202 parent = self.tcx.parent_hir_id(parent);1203 }1204 }1205 }1206 }12071208 // A generic function for checking the 'then' and 'else' clauses in an 'if'1209 // or 'if-else' expression.1210 fn check_expr_if(1211 &self,1212 expr_id: HirId,1213 cond_expr: &'tcx hir::Expr<'tcx>,1214 then_expr: &'tcx hir::Expr<'tcx>,1215 opt_else_expr: Option<&'tcx hir::Expr<'tcx>>,1216 sp: Span,1217 orig_expected: Expectation<'tcx>,1218 ) -> Ty<'tcx> {1219 let cond_ty = self.check_expr_has_type_or_error(cond_expr, self.tcx.types.bool, |_| {});12201221 self.warn_if_unreachable(1222 cond_expr.hir_id,1223 then_expr.span,1224 "block in `if` or `while` expression",1225 );12261227 let cond_diverges = self.diverges.get();1228 self.diverges.set(Diverges::Maybe);12291230 let expected = orig_expected.try_structurally_resolve_and_adjust_for_branches(self);1231 let then_ty = self.check_expr_with_expectation(then_expr, expected);1232 let then_diverges = self.diverges.get();1233 self.diverges.set(Diverges::Maybe);12341235 // We've already taken the expected type's preferences1236 // into account when typing the `then` branch. To figure1237 // out the initial shot at a LUB, we thus only consider1238 // `expected` if it represents a *hard* constraint1239 // (`only_has_type`); otherwise, we just go with a1240 // fresh type variable.1241 let coerce_to_ty = expected.coercion_target_type(self, sp);1242 let mut coerce = CoerceMany::with_capacity(coerce_to_ty, 2);12431244 coerce.coerce(self, &self.misc(sp), then_expr, then_ty);12451246 if let Some(else_expr) = opt_else_expr {1247 let else_ty = self.check_expr_with_expectation(else_expr, expected);1248 let else_diverges = self.diverges.get();12491250 let tail_defines_return_position_impl_trait =1251 self.return_position_impl_trait_from_match_expectation(orig_expected);1252 let if_cause =1253 self.if_cause(expr_id, else_expr, tail_defines_return_position_impl_trait);12541255 coerce.coerce(self, &if_cause, else_expr, else_ty);12561257 // We won't diverge unless both branches do (or the condition does).1258 self.diverges.set(cond_diverges | then_diverges & else_diverges);1259 } else {1260 self.if_fallback_coercion(sp, cond_expr, then_expr, &mut coerce);12611262 // If the condition is false we can't diverge.1263 self.diverges.set(cond_diverges);1264 }12651266 let result_ty = coerce.complete(self);1267 if let Err(guar) = cond_ty.error_reported() {1268 Ty::new_error(self.tcx, guar)1269 } else {1270 result_ty1271 }1272 }12731274 /// Type check assignment expression `expr` of form `lhs = rhs`.1275 /// The expected type is `()` and is passed to the function for the purposes of diagnostics.1276 fn check_expr_assign(1277 &self,1278 expr: &'tcx hir::Expr<'tcx>,1279 expected: Expectation<'tcx>,1280 lhs: &'tcx hir::Expr<'tcx>,1281 rhs: &'tcx hir::Expr<'tcx>,1282 span: Span,1283 ) -> Ty<'tcx> {1284 let expected_ty = expected.only_has_type(self);1285 if expected_ty == Some(self.tcx.types.bool) {1286 let guar = self.expr_assign_expected_bool_error(expr, lhs, rhs, span);1287 return Ty::new_error(self.tcx, guar);1288 }12891290 let lhs_ty = self.check_expr_with_needs(lhs, Needs::MutPlace);12911292 let suggest_deref_binop = |err: &mut Diag<'_>, rhs_ty: Ty<'tcx>| {1293 if let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) {1294 // Can only assign if the type is sized, so if `DerefMut` yields a type that is1295 // unsized, do not suggest dereferencing it.1296 let lhs_deref_ty_is_sized = self1297 .infcx1298 .type_implements_trait(1299 self.tcx.require_lang_item(LangItem::Sized, span),1300 [lhs_deref_ty],1301 self.param_env,1302 )1303 .may_apply();1304 if lhs_deref_ty_is_sized && self.may_coerce(rhs_ty, lhs_deref_ty) {1305 err.span_suggestion_verbose(1306 lhs.span.shrink_to_lo(),1307 "consider dereferencing here to assign to the mutably borrowed value",1308 "*",1309 Applicability::MachineApplicable,1310 );1311 }1312 }1313 };13141315 // This is (basically) inlined `check_expr_coercible_to_type`, but we want1316 // to suggest an additional fixup here in `suggest_deref_binop`.1317 let rhs_ty = self.check_expr_with_hint(rhs, lhs_ty);1318 if let Err(mut diag) =1319 self.demand_coerce_diag(rhs, rhs_ty, lhs_ty, Some(lhs), AllowTwoPhase::No)1320 {1321 suggest_deref_binop(&mut diag, rhs_ty);1322 diag.emit();1323 }13241325 self.check_lhs_assignable(lhs, E0070, span, |err| {1326 if let Some(rhs_ty) = self.typeck_results.borrow().expr_ty_opt(rhs) {1327 suggest_deref_binop(err, rhs_ty);1328 }1329 });13301331 self.require_type_is_sized(lhs_ty, lhs.span, ObligationCauseCode::AssignmentLhsSized);13321333 if let Err(guar) = (lhs_ty, rhs_ty).error_reported() {1334 Ty::new_error(self.tcx, guar)1335 } else {1336 self.tcx.types.unit1337 }1338 }13391340 /// The expected type is `bool` but this will result in `()` so we can reasonably1341 /// say that the user intended to write `lhs == rhs` instead of `lhs = rhs`.1342 /// The likely cause of this is `if foo = bar { .. }`.1343 fn expr_assign_expected_bool_error(1344 &self,1345 expr: &'tcx hir::Expr<'tcx>,1346 lhs: &'tcx hir::Expr<'tcx>,1347 rhs: &'tcx hir::Expr<'tcx>,1348 span: Span,1349 ) -> ErrorGuaranteed {1350 let actual_ty = self.tcx.types.unit;1351 let expected_ty = self.tcx.types.bool;1352 let mut err = self.demand_suptype_diag(expr.span, expected_ty, actual_ty).unwrap_err();1353 let lhs_ty = self.check_expr(lhs);1354 let rhs_ty = self.check_expr(rhs);1355 let refs_can_coerce = |lhs: Ty<'tcx>, rhs: Ty<'tcx>| {1356 let lhs = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, lhs.peel_refs());1357 let rhs = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, rhs.peel_refs());1358 self.may_coerce(rhs, lhs)1359 };1360 // Never-to-any coercions do not imply that the operands can be compared, e.g. `String == !`.1361 let (applicability, eq) = if self.may_coerce_except_never(rhs_ty, lhs_ty) {1362 (Applicability::MachineApplicable, true)1363 } else if refs_can_coerce(rhs_ty, lhs_ty) {1364 // The lhs and rhs are likely missing some references in either side. Subsequent1365 // suggestions will show up.1366 (Applicability::MaybeIncorrect, true)1367 } else if let ExprKind::Binary(1368 Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. },1369 _,1370 rhs_expr,1371 ) = lhs.kind1372 {1373 // if x == 1 && y == 2 { .. }1374 // +1375 let actual_lhs = self.check_expr(rhs_expr);1376 let may_eq = self.may_coerce_except_never(rhs_ty, actual_lhs)1377 || refs_can_coerce(rhs_ty, actual_lhs);1378 (Applicability::MaybeIncorrect, may_eq)1379 } else if let ExprKind::Binary(1380 Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. },1381 lhs_expr,1382 _,1383 ) = rhs.kind1384 {1385 // if x == 1 && y == 2 { .. }1386 // +1387 let actual_rhs = self.check_expr(lhs_expr);1388 let may_eq = self.may_coerce_except_never(actual_rhs, lhs_ty)1389 || refs_can_coerce(actual_rhs, lhs_ty);1390 (Applicability::MaybeIncorrect, may_eq)1391 } else {1392 (Applicability::MaybeIncorrect, false)1393 };13941395 if !lhs.is_syntactic_place_expr()1396 && lhs.is_approximately_pattern()1397 && !matches!(lhs.kind, hir::ExprKind::Lit(_))1398 {1399 // Do not suggest `if let x = y` as `==` is way more likely to be the intention.1400 if let hir::Node::Expr(hir::Expr { kind: ExprKind::If { .. }, .. }) =1401 self.tcx.parent_hir_node(expr.hir_id)1402 {1403 err.span_suggestion_verbose(1404 expr.span.shrink_to_lo(),1405 "you might have meant to use pattern matching",1406 "let ",1407 applicability,1408 );1409 };1410 }1411 if eq {1412 err.span_suggestion_verbose(1413 span.shrink_to_hi(),1414 "you might have meant to compare for equality",1415 '=',1416 applicability,1417 );1418 }14191420 // If the assignment expression itself is ill-formed, don't1421 // bother emitting another error1422 err.emit_err_unless_delay(lhs_ty.references_error() || rhs_ty.references_error())1423 }14241425 pub(super) fn check_expr_let(1426 &self,1427 let_expr: &'tcx hir::LetExpr<'tcx>,1428 hir_id: HirId,1429 ) -> Ty<'tcx> {1430 GatherLocalsVisitor::gather_from_let_expr(self, let_expr, hir_id);14311432 // for let statements, this is done in check_stmt1433 let init = let_expr.init;1434 self.warn_if_unreachable(init.hir_id, init.span, "block in `let` expression");14351436 // otherwise check exactly as a let statement1437 self.check_decl((let_expr, hir_id).into());14381439 // but return a bool, for this is a boolean expression1440 if let ast::Recovered::Yes(error_guaranteed) = let_expr.recovered {1441 self.set_tainted_by_errors(error_guaranteed);1442 Ty::new_error(self.tcx, error_guaranteed)1443 } else {1444 self.tcx.types.bool1445 }1446 }14471448 fn check_expr_loop(1449 &self,1450 body: &'tcx hir::Block<'tcx>,1451 source: hir::LoopSource,1452 expected: Expectation<'tcx>,1453 expr: &'tcx hir::Expr<'tcx>,1454 ) -> Ty<'tcx> {1455 let coerce = match source {1456 // you can only use break with a value from a normal `loop { }`1457 hir::LoopSource::Loop => {1458 let coerce_to = expected.coercion_target_type(self, body.span);1459 Some(CoerceMany::new(coerce_to))1460 }14611462 hir::LoopSource::While | hir::LoopSource::ForLoop => None,1463 };14641465 let ctxt = BreakableCtxt {1466 coerce,1467 may_break: false, // Will get updated if/when we find a `break`.1468 };14691470 let (ctxt, ()) = self.with_breakable_ctxt(expr.hir_id, ctxt, || {1471 self.check_block_no_value(body);1472 });14731474 if ctxt.may_break {1475 // No way to know whether it's diverging because1476 // of a `break` or an outer `break` or `return`.1477 self.diverges.set(Diverges::Maybe);1478 } else {1479 self.diverges.set(self.diverges.get() | Diverges::always(expr.span));1480 }14811482 // If we permit break with a value, then result type is1483 // the LUB of the breaks (possibly ! if none); else, it1484 // is nil. This makes sense because infinite loops1485 // (which would have type !) are only possible iff we1486 // permit break with a value.1487 if ctxt.coerce.is_none() && !ctxt.may_break {1488 self.dcx().span_bug(body.span, "no coercion, but loop may not break");1489 }1490 ctxt.coerce.map(|c| c.complete(self)).unwrap_or_else(|| self.tcx.types.unit)1491 }14921493 /// Checks a method call.1494 fn check_expr_method_call(1495 &self,1496 expr: &'tcx hir::Expr<'tcx>,1497 segment: &'tcx hir::PathSegment<'tcx>,1498 rcvr: &'tcx hir::Expr<'tcx>,1499 args: &'tcx [hir::Expr<'tcx>],1500 expected: Expectation<'tcx>,1501 ) -> Ty<'tcx> {1502 let rcvr_t = self.check_expr(rcvr);1503 let rcvr_t = self.deeply_resolve_ignoring_regions_with_obligations(rcvr_t);15041505 match self.lookup_method(rcvr_t, segment, segment.ident.span, expr, rcvr, args) {1506 Ok(method) => {1507 self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method);15081509 // Handle splatted method arguments1510 // self is already handled as `rcvr`, so it's never splatted here1511 let mut method_inputs = Cow::Borrowed(&method.sig.inputs()[1..]);1512 for (param, pos) in self.tcx.generics_of(method.def_id).own_arg_pos_consts() {1513 let ty = self1514 .tcx1515 .type_of(param.def_id)1516 .instantiate(self.tcx, method.args)1517 .skip_norm_wip();1518 // Insert function argument const param types back into the inputs.1519 // We use pos - 1 since method_inputs skips self, but arg_pos counts it.1520 method_inputs.to_mut().insert(pos as usize - 1, ty);1521 }15221523 let method_tuple_args_flag =1524 TupleArgumentsFlag::with_fn_sig_kind(method.sig.fn_sig_kind, true);15251526 self.check_argument_types(1527 segment.ident.span,1528 expr,1529 &method_inputs,1530 method.sig.output(),1531 expected,1532 args,1533 method.sig.fn_sig_kind.c_variadic(),1534 method_tuple_args_flag,1535 SplatLoweringInfo::FnDef(method.def_id),1536 Some(method.args),1537 );15381539 self.check_call_abi(method.sig.abi(), expr.span);15401541 method.sig.output()1542 }1543 Err(error) => {1544 let guar = self.report_method_error(expr.hir_id, rcvr_t, error, expected, false);15451546 let err_inputs = self.err_args(args.len(), guar);1547 let err_ty = Ty::new_error(self.tcx, guar);15481549 self.check_argument_types(1550 segment.ident.span,1551 expr,1552 &err_inputs,1553 err_ty,1554 NoExpectation,1555 args,1556 false,1557 TupleArgumentsFlag::DontTupleArguments,1558 SplatLoweringInfo::Error(guar),1559 Some(GenericArgsRef::default()),1560 );15611562 err_ty1563 }1564 }1565 }15661567 /// Checks use `x.use`.1568 fn check_expr_use(1569 &self,1570 used_expr: &'tcx hir::Expr<'tcx>,1571 expected: Expectation<'tcx>,1572 ) -> Ty<'tcx> {1573 self.check_expr_with_expectation(used_expr, expected)1574 }15751576 fn check_expr_cast(1577 &self,1578 e: &'tcx hir::Expr<'tcx>,1579 t: &'tcx hir::Ty<'tcx>,1580 expr: &'tcx hir::Expr<'tcx>,1581 ) -> Ty<'tcx> {1582 // Find the type of `e`. Supply hints based on the type we are casting to,1583 // if appropriate.1584 let t_cast = self.lower_ty_saving_user_provided_ty(t);1585 let t_cast = self.deeply_resolve_ignoring_regions(t_cast);1586 let t_expr = self.check_expr_with_expectation(e, ExpectCastableToType(t_cast));1587 let t_expr = self.deeply_resolve_ignoring_regions(t_expr);15881589 // Eagerly check for some obvious errors.1590 if let Err(guar) = (t_expr, t_cast).error_reported() {1591 Ty::new_error(self.tcx, guar)1592 } else {1593 // Defer other checks until we're done type checking.1594 let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();1595 match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) {1596 Ok(cast_check) => {1597 debug!(1598 "check_expr_cast: deferring cast from {:?} to {:?}: {:?}",1599 t_cast, t_expr, cast_check,1600 );1601 deferred_cast_checks.push(cast_check);1602 t_cast1603 }1604 Err(guar) => Ty::new_error(self.tcx, guar),1605 }1606 }1607 }16081609 fn check_expr_unsafe_binder_cast(1610 &self,1611 span: Span,1612 kind: ast::UnsafeBinderCastKind,1613 inner_expr: &'tcx hir::Expr<'tcx>,1614 hir_ty: Option<&'tcx hir::Ty<'tcx>>,1615 expected: Expectation<'tcx>,1616 ) -> Ty<'tcx> {1617 match kind {1618 ast::UnsafeBinderCastKind::Wrap => {1619 let ascribed_ty =1620 hir_ty.map(|hir_ty| self.lower_ty_saving_user_provided_ty(hir_ty));1621 let expected_ty = expected.only_has_type(self);1622 let binder_ty = match (ascribed_ty, expected_ty) {1623 (Some(ascribed_ty), Some(expected_ty)) => {1624 self.demand_eqtype(inner_expr.span, expected_ty, ascribed_ty);1625 expected_ty1626 }1627 (Some(ty), None) | (None, Some(ty)) => ty,1628 // This will always cause a structural resolve error, but we do it1629 // so we don't need to manually report an E0282 both on this codepath1630 // and in the others; it all happens in `structurally_resolve_type`.1631 (None, None) => self.next_ty_var(inner_expr.span),1632 };16331634 let binder_ty = self.structurally_resolve_type(inner_expr.span, binder_ty);1635 let hint_ty = match *binder_ty.kind() {1636 ty::UnsafeBinder(binder) => self.instantiate_binder_with_fresh_vars(1637 inner_expr.span,1638 infer::BoundRegionConversionTime::HigherRankedType,1639 binder.into(),1640 ),1641 ty::Error(e) => Ty::new_error(self.tcx, e),1642 _ => {1643 let guar = self1644 .dcx()1645 .struct_span_err(1646 hir_ty.map_or(span, |hir_ty| hir_ty.span),1647 format!(1648 "`wrap_binder!()` can only wrap into unsafe binder, not {}",1649 binder_ty.sort_string(self.tcx)1650 ),1651 )1652 .with_note("unsafe binders are the only valid output of wrap")1653 .emit_err();1654 Ty::new_error(self.tcx, guar)1655 }1656 };16571658 self.check_expr_has_type_or_error(inner_expr, hint_ty, |_| {});16591660 binder_ty1661 }1662 ast::UnsafeBinderCastKind::Unwrap => {1663 let ascribed_ty =1664 hir_ty.map(|hir_ty| self.lower_ty_saving_user_provided_ty(hir_ty));1665 let hint_ty = ascribed_ty.unwrap_or_else(|| self.next_ty_var(inner_expr.span));1666 // FIXME(unsafe_binders): coerce here if needed?1667 let binder_ty = self.check_expr_has_type_or_error(inner_expr, hint_ty, |_| {});16681669 // Unwrap the binder. This will be ambiguous if it's an infer var, and will error1670 // if it's not an unsafe binder.1671 let binder_ty = self.structurally_resolve_type(inner_expr.span, binder_ty);1672 match *binder_ty.kind() {1673 ty::UnsafeBinder(binder) => self.instantiate_binder_with_fresh_vars(1674 inner_expr.span,1675 infer::BoundRegionConversionTime::HigherRankedType,1676 binder.into(),1677 ),1678 ty::Error(e) => Ty::new_error(self.tcx, e),1679 _ => {1680 let guar = self1681 .dcx()1682 .struct_span_err(1683 hir_ty.map_or(inner_expr.span, |hir_ty| hir_ty.span),1684 format!(1685 "expected unsafe binder, found {} as input of \1686 `unwrap_binder!()`",1687 binder_ty.sort_string(self.tcx)1688 ),1689 )1690 .with_note("only an unsafe binder type can be unwrapped")1691 .emit_err();1692 Ty::new_error(self.tcx, guar)1693 }1694 }1695 }1696 }1697 }16981699 fn check_expr_array(1700 &self,1701 args: &'tcx [hir::Expr<'tcx>],1702 expected: Expectation<'tcx>,1703 expr: &'tcx hir::Expr<'tcx>,1704 ) -> Ty<'tcx> {1705 let element_ty = if !args.is_empty() {1706 let coerce_to = expected1707 .to_option(self)1708 .and_then(|uty| {1709 self.deeply_resolve_ignoring_regions_with_obligations(uty)1710 .builtin_index()1711 // Avoid using the original type variable as the coerce_to type, as it may resolve1712 // during the first coercion instead of being the LUB type.1713 .filter(|t| {1714 !self.deeply_resolve_ignoring_regions_with_obligations(*t).is_ty_var()1715 })1716 })1717 .unwrap_or_else(|| self.next_ty_var(expr.span));1718 let mut coerce = CoerceMany::with_capacity(coerce_to, args.len());17191720 for e in args {1721 // FIXME: the element expectation should use1722 // `try_structurally_resolve_and_adjust_for_branches` just like in `if` and `match`.1723 // While that fixes nested coercion, it will break [some1724 // code like this](https://github.com/rust-lang/rust/pull/140283#issuecomment-2958776528).1725 // If we find a way to support recursive tuple coercion, this break can be avoided.1726 let e_ty = self.check_expr_with_hint(e, coerce_to);1727 let cause = self.misc(e.span);1728 coerce.coerce(self, &cause, e, e_ty);1729 }1730 coerce.complete(self)1731 } else {1732 self.next_ty_var(expr.span)1733 };1734 let array_len = args.len() as u64;1735 Ty::new_array(self.tcx, element_ty, array_len)1736 }17371738 pub(super) fn check_expr_const_block(1739 &self,1740 block: &'tcx hir::ConstBlock,1741 expected: Expectation<'tcx>,1742 ) -> Ty<'tcx> {1743 let body = self.tcx.hir_body(block.body);17441745 // Create a new function context.1746 let def_id = block.def_id;1747 let fcx = FnCtxt::new(self, self.param_env, def_id);17481749 let ty = fcx.check_expr_with_expectation(&body.value, expected);1750 fcx.require_type_is_sized(ty, body.value.span, ObligationCauseCode::SizedConstOrStatic);1751 fcx.write_ty(block.hir_id, ty);1752 ty1753 }17541755 fn check_expr_repeat(1756 &self,1757 element: &'tcx hir::Expr<'tcx>,1758 count: &'tcx hir::ConstArg<'tcx>,1759 expected: Expectation<'tcx>,1760 expr: &'tcx hir::Expr<'tcx>,1761 ) -> Ty<'tcx> {1762 let tcx = self.tcx;1763 let count_span = count.span;1764 let count = self.try_structurally_resolve_const(1765 count_span,1766 self.normalize(1767 count_span,1768 Unnormalized::new_wip(self.lower_const_arg(count, tcx.types.usize)),1769 ),1770 );17711772 let uty = match expected {1773 ExpectHasType(uty) => uty.builtin_index(),1774 _ => None,1775 };17761777 let (element_ty, t) = match uty {1778 Some(uty) => {1779 self.check_expr_coercible_to_type(element, uty, None);1780 (uty, uty)1781 }1782 None => {1783 let ty = self.next_ty_var(element.span);1784 let element_ty = self.check_expr_has_type_or_error(element, ty, |_| {});1785 (element_ty, ty)1786 }1787 };17881789 if let Err(guar) = element_ty.error_reported() {1790 return Ty::new_error(tcx, guar);1791 }17921793 // We defer checking whether the element type is `Copy` as it is possible to have1794 // an inference variable as a repeat count and it seems unlikely that `Copy` would1795 // have inference side effects required for type checking to succeed.1796 self.deferred_repeat_expr_checks.borrow_mut().push((element, element_ty, count));17971798 let ty = Ty::new_array_with_const_len(tcx, t, count);1799 self.register_wf_obligation(1800 ty.into(),1801 expr.span,1802 ObligationCauseCode::WellFormed(WellFormedLoc::HirId(expr.hir_id)),1803 );1804 ty1805 }18061807 fn check_expr_tuple(1808 &self,1809 elements: &'tcx [hir::Expr<'tcx>],1810 expected: Expectation<'tcx>,1811 expr: &'tcx hir::Expr<'tcx>,1812 ) -> Ty<'tcx> {1813 let mut expectations = expected1814 .only_has_type(self)1815 .and_then(|ty| {1816 self.deeply_resolve_ignoring_regions_with_obligations(ty).opt_tuple_fields()1817 })1818 .unwrap_or_default()1819 .iter();18201821 let elements = elements.iter().map(|e| {1822 let ty = expectations.next().unwrap_or_else(|| self.next_ty_var(e.span));1823 self.check_expr_coercible_to_type(e, ty, None);1824 ty1825 });18261827 let tuple = Ty::new_tup_from_iter(self.tcx, elements);18281829 if let Err(guar) = tuple.error_reported() {1830 Ty::new_error(self.tcx, guar)1831 } else {1832 self.require_type_is_sized(1833 tuple,1834 expr.span,1835 ObligationCauseCode::TupleInitializerSized,1836 );1837 tuple1838 }1839 }18401841 fn check_expr_struct(1842 &self,1843 expr: &hir::Expr<'tcx>,1844 expected: Expectation<'tcx>,1845 qpath: &'tcx QPath<'tcx>,1846 fields: &'tcx [hir::ExprField<'tcx>],1847 base_expr: &'tcx hir::StructTailExpr<'tcx>,1848 ) -> Ty<'tcx> {1849 // Find the relevant variant1850 let (variant, adt_ty) = match self.check_struct_path(qpath, expr.hir_id) {1851 Ok(data) => data,1852 Err(guar) => {1853 self.check_struct_fields_on_error(fields, base_expr);1854 return Ty::new_error(self.tcx, guar);1855 }1856 };18571858 // Prohibit struct expressions when non-exhaustive flag is set.1859 let adt = adt_ty.ty_adt_def().expect("`check_struct_path` returned non-ADT type");1860 if variant.field_list_has_applicable_non_exhaustive() {1861 self.dcx()1862 .emit_err(StructExprNonExhaustive { span: expr.span, what: adt.variant_descr() });1863 }18641865 self.check_expr_struct_fields(1866 adt_ty,1867 expected,1868 expr,1869 qpath.span(),1870 variant,1871 fields,1872 base_expr,1873 );18741875 self.require_type_is_sized(adt_ty, expr.span, ObligationCauseCode::StructInitializerSized);1876 adt_ty1877 }18781879 fn check_expr_struct_fields(1880 &self,1881 adt_ty: Ty<'tcx>,1882 expected: Expectation<'tcx>,1883 expr: &hir::Expr<'_>,1884 path_span: Span,1885 variant: &'tcx ty::VariantDef,1886 hir_fields: &'tcx [hir::ExprField<'tcx>],1887 base_expr: &'tcx hir::StructTailExpr<'tcx>,1888 ) {1889 let tcx = self.tcx;18901891 let adt_ty = self.deeply_resolve_ignoring_regions_with_obligations(adt_ty);1892 let adt_ty_hint = expected.only_has_type(self).and_then(|expected| {1893 self.fudge_inference_if_ok(|| {1894 let ocx = ObligationCtxt::new(self);1895 ocx.sup(&self.misc(path_span), self.param_env, expected, adt_ty)?;1896 if !ocx.try_evaluate_obligations().no_errors() {1897 return Err(TypeError::Mismatch);1898 }1899 Ok(self.deeply_resolve_ignoring_regions(adt_ty))1900 })1901 .ok()1902 });1903 if let Some(adt_ty_hint) = adt_ty_hint {1904 // re-link the variables that the fudging above can create.1905 self.demand_eqtype(path_span, adt_ty_hint, adt_ty);1906 }19071908 let ty::Adt(adt, args) = adt_ty.kind() else {1909 span_bug!(path_span, "non-ADT passed to check_expr_struct_fields");1910 };1911 let adt_kind = adt.adt_kind();19121913 let get_field_ident = |field: &ty::FieldDef| field.ident(tcx).normalize_to_macros_2_0();1914 let mut remaining_fields = variant1915 .fields1916 .iter_enumerated()1917 .map(|(i, field)| (get_field_ident(field), (i, field)))1918 .collect::<UnordMap<_, _>>();19191920 let mut seen_fields = FxHashMap::default();19211922 let mut error_happened = false;19231924 if variant.fields.len() != remaining_fields.len() {1925 // Some field is defined more than once. Make sure we don't try to1926 // instantiate this struct in static/const context.1927 let guar =1928 self.dcx().span_delayed_bug(expr.span, "struct fields have non-unique names");1929 self.set_tainted_by_errors(guar);1930 error_happened = true;1931 }19321933 // Type-check each field.1934 for (idx, field) in hir_fields.iter().enumerate() {1935 let ident = if field.ident.name == kw::Underscore {1936 // We are processing delegation `Self` mapping field, we expect that it is a struct1937 // with one field, so if it is not true we emit an error as we can't infer1938 // what field to use to initialize the struct.1939 // The `_` is a keyword so if user uses it during struct initialization as a field name1940 // it will be error anyway.1941 if let [v_field] = &variant.fields[..] {1942 Ok(get_field_ident(v_field))1943 } else {1944 Err(tcx.dcx().span_delayed_bug(1945 field.ident.span,1946 format!(1947 "can not infer the delegation `Self` mapping field for {:?}",1948 self.body_def_id1949 ),1950 ))1951 }1952 } else {1953 Ok(tcx.adjust_ident(field.ident, variant.def_id))1954 };19551956 let field_type = ident1957 .and_then(|ident| {1958 if let Some((i, v_field)) = remaining_fields.remove(&ident) {1959 seen_fields.insert(ident, field.span);1960 self.write_field_index(field.hir_id, i);19611962 // We don't look at stability attributes on1963 // struct-like enums (yet...), but it's definitely not1964 // a bug to have constructed one.1965 if adt_kind != AdtKind::Enum {1966 tcx.check_stability(v_field.did, Some(field.hir_id), field.span, None);1967 }19681969 Ok(self.field_ty(field.span, v_field, args))1970 } else {1971 error_happened = true;1972 let guar = if let Some(prev_span) = seen_fields.get(&ident) {1973 self.dcx().emit_err(FieldMultiplySpecifiedInInitializer {1974 span: field.ident.span,1975 prev_span: *prev_span,1976 ident,1977 })1978 } else {1979 self.report_unknown_field(1980 adt_ty,1981 variant,1982 expr,1983 field,1984 hir_fields,1985 adt.variant_descr(),1986 )1987 };19881989 Err(guar)1990 }1991 })1992 .unwrap_or_else(|err| Ty::new_error(tcx, err));19931994 // Check that the expected field type is WF. Otherwise, we emit no use-site error1995 // in the case of coercions for non-WF fields, which leads to incorrect error1996 // tainting. See issue #126272.1997 self.register_wf_obligation(1998 field_type.into(),1999 field.expr.span,2000 ObligationCauseCode::WellFormed(WellFormedLoc::HirId(field.expr.hir_id)),
Findings
✓ No findings reported for this file.