]>
Commit | Line | Data |
---|---|---|
dc9dc135 XL |
1 | //! Type checking expressions. |
2 | //! | |
3 | //! See `mod.rs` for more context on type checking in general. | |
4 | ||
dfeec247 | 5 | use crate::astconv::AstConv as _; |
dc9dc135 XL |
6 | use crate::check::cast; |
7 | use crate::check::coercion::CoerceMany; | |
dc9dc135 | 8 | use crate::check::fatally_break_rust; |
cdc7bbd5 | 9 | use crate::check::method::SelfSource; |
dc9dc135 | 10 | use crate::check::report_unexpected_variant_res; |
dfeec247 XL |
11 | use crate::check::BreakableCtxt; |
12 | use crate::check::Diverges; | |
5869c6ff | 13 | use crate::check::DynamicCoerceMany; |
dfeec247 XL |
14 | use crate::check::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation}; |
15 | use crate::check::FnCtxt; | |
dc9dc135 XL |
16 | use crate::check::Needs; |
17 | use crate::check::TupleArgumentsFlag::DontTupleArguments; | |
1b1a35ee XL |
18 | use crate::errors::{ |
19 | FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct, | |
20 | YieldExprOutsideOfGenerator, | |
21 | }; | |
dfeec247 | 22 | use crate::type_error_struct; |
ba9703b0 | 23 | |
04454e1e | 24 | use super::suggest_call_constructor; |
1b1a35ee | 25 | use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive}; |
3dfed10e | 26 | use rustc_ast as ast; |
dfeec247 | 27 | use rustc_data_structures::fx::FxHashMap; |
3dfed10e | 28 | use rustc_data_structures::stack::ensure_sufficient_stack; |
923072b8 FG |
29 | use rustc_errors::{ |
30 | pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId, | |
31 | EmissionGuarantee, ErrorGuaranteed, | |
32 | }; | |
dfeec247 XL |
33 | use rustc_hir as hir; |
34 | use rustc_hir::def::{CtorKind, DefKind, Res}; | |
35 | use rustc_hir::def_id::DefId; | |
3c0e092e | 36 | use rustc_hir::intravisit::Visitor; |
5e7ed085 | 37 | use rustc_hir::lang_items::LangItem; |
064997fb | 38 | use rustc_hir::{Closure, ExprKind, HirId, QPath}; |
74b04a01 XL |
39 | use rustc_infer::infer; |
40 | use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; | |
3c0e092e | 41 | use rustc_infer::infer::InferOk; |
923072b8 | 42 | use rustc_infer::traits::ObligationCause; |
5099ac24 | 43 | use rustc_middle::middle::stability; |
f035d41b | 44 | use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; |
923072b8 | 45 | use rustc_middle::ty::error::TypeError::FieldMisMatch; |
5869c6ff | 46 | use rustc_middle::ty::subst::SubstsRef; |
064997fb | 47 | use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TypeVisitable}; |
3c0e092e | 48 | use rustc_session::parse::feature_err; |
dfeec247 | 49 | use rustc_span::hygiene::DesugaringKind; |
fc512014 | 50 | use rustc_span::lev_distance::find_best_match_for_name; |
064997fb | 51 | use rustc_span::source_map::{Span, Spanned}; |
f9f354fc | 52 | use rustc_span::symbol::{kw, sym, Ident, Symbol}; |
a2a8927a | 53 | use rustc_span::{BytePos, Pos}; |
923072b8 FG |
54 | use rustc_target::spec::abi::Abi::RustIntrinsic; |
55 | use rustc_trait_selection::infer::InferCtxtExt; | |
29967ef6 | 56 | use rustc_trait_selection::traits::{self, ObligationCauseCode}; |
60c5eb7d | 57 | |
dc9dc135 | 58 | impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
dfeec247 | 59 | fn check_expr_eq_type(&self, expr: &'tcx hir::Expr<'tcx>, expected: Ty<'tcx>) { |
dc9dc135 XL |
60 | let ty = self.check_expr_with_hint(expr, expected); |
61 | self.demand_eqtype(expr.span, expected, ty); | |
62 | } | |
63 | ||
64 | pub fn check_expr_has_type_or_error( | |
65 | &self, | |
dfeec247 | 66 | expr: &'tcx hir::Expr<'tcx>, |
dc9dc135 | 67 | expected: Ty<'tcx>, |
923072b8 | 68 | extend_err: impl FnMut(&mut Diagnostic), |
dc9dc135 | 69 | ) -> Ty<'tcx> { |
e74abb32 | 70 | self.check_expr_meets_expectation_or_error(expr, ExpectHasType(expected), extend_err) |
dc9dc135 XL |
71 | } |
72 | ||
73 | fn check_expr_meets_expectation_or_error( | |
74 | &self, | |
dfeec247 | 75 | expr: &'tcx hir::Expr<'tcx>, |
dc9dc135 | 76 | expected: Expectation<'tcx>, |
923072b8 | 77 | mut extend_err: impl FnMut(&mut Diagnostic), |
dc9dc135 XL |
78 | ) -> Ty<'tcx> { |
79 | let expected_ty = expected.to_option(&self).unwrap_or(self.tcx.types.bool); | |
80 | let mut ty = self.check_expr_with_expectation(expr, expected); | |
81 | ||
82 | // While we don't allow *arbitrary* coercions here, we *do* allow | |
83 | // coercions from ! to `expected`. | |
84 | if ty.is_never() { | |
04454e1e FG |
85 | if let Some(adjustments) = self.typeck_results.borrow().adjustments().get(expr.hir_id) { |
86 | self.tcx().sess.delay_span_bug( | |
87 | expr.span, | |
88 | "expression with never type wound up being adjusted", | |
89 | ); | |
90 | return if let [Adjustment { kind: Adjust::NeverToAny, target }] = &adjustments[..] { | |
91 | target.to_owned() | |
92 | } else { | |
93 | self.tcx().ty_error() | |
94 | }; | |
95 | } | |
96 | ||
c295e0f8 | 97 | let adj_ty = self.next_ty_var(TypeVariableOrigin { |
dfeec247 XL |
98 | kind: TypeVariableOriginKind::AdjustmentType, |
99 | span: expr.span, | |
100 | }); | |
101 | self.apply_adjustments( | |
102 | expr, | |
103 | vec![Adjustment { kind: Adjust::NeverToAny, target: adj_ty }], | |
dc9dc135 | 104 | ); |
dc9dc135 XL |
105 | ty = adj_ty; |
106 | } | |
107 | ||
108 | if let Some(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) { | |
e74abb32 | 109 | let expr = expr.peel_drop_temps(); |
f035d41b | 110 | self.suggest_deref_ref_or_into(&mut err, expr, expected_ty, ty, None); |
e74abb32 | 111 | extend_err(&mut err); |
c295e0f8 | 112 | err.emit(); |
dc9dc135 XL |
113 | } |
114 | ty | |
115 | } | |
116 | ||
117 | pub(super) fn check_expr_coercable_to_type( | |
118 | &self, | |
dfeec247 XL |
119 | expr: &'tcx hir::Expr<'tcx>, |
120 | expected: Ty<'tcx>, | |
f035d41b | 121 | expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, |
dc9dc135 XL |
122 | ) -> Ty<'tcx> { |
123 | let ty = self.check_expr_with_hint(expr, expected); | |
124 | // checks don't need two phase | |
f035d41b | 125 | self.demand_coerce(expr, ty, expected, expected_ty_expr, AllowTwoPhase::No) |
dc9dc135 XL |
126 | } |
127 | ||
128 | pub(super) fn check_expr_with_hint( | |
129 | &self, | |
dfeec247 XL |
130 | expr: &'tcx hir::Expr<'tcx>, |
131 | expected: Ty<'tcx>, | |
dc9dc135 XL |
132 | ) -> Ty<'tcx> { |
133 | self.check_expr_with_expectation(expr, ExpectHasType(expected)) | |
134 | } | |
135 | ||
f035d41b | 136 | fn check_expr_with_expectation_and_needs( |
dc9dc135 | 137 | &self, |
dfeec247 | 138 | expr: &'tcx hir::Expr<'tcx>, |
dc9dc135 | 139 | expected: Expectation<'tcx>, |
f035d41b | 140 | needs: Needs, |
dc9dc135 | 141 | ) -> Ty<'tcx> { |
f035d41b XL |
142 | let ty = self.check_expr_with_expectation(expr, expected); |
143 | ||
144 | // If the expression is used in a place whether mutable place is required | |
145 | // e.g. LHS of assignment, perform the conversion. | |
146 | if let Needs::MutPlace = needs { | |
147 | self.convert_place_derefs_to_mutable(expr); | |
148 | } | |
149 | ||
150 | ty | |
dc9dc135 XL |
151 | } |
152 | ||
dfeec247 | 153 | pub(super) fn check_expr(&self, expr: &'tcx hir::Expr<'tcx>) -> Ty<'tcx> { |
dc9dc135 XL |
154 | self.check_expr_with_expectation(expr, NoExpectation) |
155 | } | |
156 | ||
dfeec247 XL |
157 | pub(super) fn check_expr_with_needs( |
158 | &self, | |
159 | expr: &'tcx hir::Expr<'tcx>, | |
160 | needs: Needs, | |
161 | ) -> Ty<'tcx> { | |
dc9dc135 XL |
162 | self.check_expr_with_expectation_and_needs(expr, NoExpectation, needs) |
163 | } | |
164 | ||
165 | /// Invariant: | |
166 | /// If an expression has any sub-expressions that result in a type error, | |
167 | /// inspecting that expression's type with `ty.references_error()` will return | |
168 | /// true. Likewise, if an expression is known to diverge, inspecting its | |
169 | /// type with `ty::type_is_bot` will return true (n.b.: since Rust is | |
170 | /// strict, _|_ can appear in the type of an expression that does not, | |
171 | /// itself, diverge: for example, fn() -> _|_.) | |
172 | /// Note that inspecting a type's structure *directly* may expose the fact | |
173 | /// that there are actually multiple representations for `Error`, so avoid | |
174 | /// that when err needs to be handled differently. | |
c295e0f8 | 175 | #[instrument(skip(self, expr), level = "debug")] |
f035d41b | 176 | pub(super) fn check_expr_with_expectation( |
dc9dc135 | 177 | &self, |
dfeec247 | 178 | expr: &'tcx hir::Expr<'tcx>, |
dc9dc135 | 179 | expected: Expectation<'tcx>, |
c295e0f8 XL |
180 | ) -> Ty<'tcx> { |
181 | self.check_expr_with_expectation_and_args(expr, expected, &[]) | |
182 | } | |
183 | ||
184 | /// Same as `check_expr_with_expectation`, but allows us to pass in the arguments of a | |
185 | /// `ExprKind::Call` when evaluating its callee when it is an `ExprKind::Path`. | |
186 | pub(super) fn check_expr_with_expectation_and_args( | |
187 | &self, | |
188 | expr: &'tcx hir::Expr<'tcx>, | |
189 | expected: Expectation<'tcx>, | |
190 | args: &'tcx [hir::Expr<'tcx>], | |
dc9dc135 | 191 | ) -> Ty<'tcx> { |
94222f64 XL |
192 | if self.tcx().sess.verbose() { |
193 | // make this code only run with -Zverbose because it is probably slow | |
194 | if let Ok(lint_str) = self.tcx.sess.source_map().span_to_snippet(expr.span) { | |
195 | if !lint_str.contains('\n') { | |
04454e1e | 196 | debug!("expr text: {lint_str}"); |
94222f64 XL |
197 | } else { |
198 | let mut lines = lint_str.lines(); | |
199 | if let Some(line0) = lines.next() { | |
200 | let remaining_lines = lines.count(); | |
04454e1e FG |
201 | debug!("expr text: {line0}"); |
202 | debug!("expr text: ...(and {remaining_lines} more lines)"); | |
94222f64 XL |
203 | } |
204 | } | |
205 | } | |
206 | } | |
dc9dc135 | 207 | |
e74abb32 XL |
208 | // True if `expr` is a `Try::from_ok(())` that is a result of desugaring a try block |
209 | // without the final expr (e.g. `try { return; }`). We don't want to generate an | |
210 | // unreachable_code lint for it since warnings for autogenerated code are confusing. | |
211 | let is_try_block_generated_unit_expr = match expr.kind { | |
6a06907d | 212 | ExprKind::Call(_, args) if expr.span.is_desugaring(DesugaringKind::TryBlock) => { |
dfeec247 XL |
213 | args.len() == 1 && args[0].span.is_desugaring(DesugaringKind::TryBlock) |
214 | } | |
e74abb32 XL |
215 | |
216 | _ => false, | |
217 | }; | |
218 | ||
dc9dc135 | 219 | // Warn for expressions after diverging siblings. |
e74abb32 XL |
220 | if !is_try_block_generated_unit_expr { |
221 | self.warn_if_unreachable(expr.hir_id, expr.span, "expression"); | |
222 | } | |
dc9dc135 XL |
223 | |
224 | // Hide the outer diverging and has_errors flags. | |
dfeec247 XL |
225 | let old_diverges = self.diverges.replace(Diverges::Maybe); |
226 | let old_has_errors = self.has_errors.replace(false); | |
dc9dc135 | 227 | |
c295e0f8 XL |
228 | let ty = ensure_sufficient_stack(|| match &expr.kind { |
229 | hir::ExprKind::Path( | |
230 | qpath @ hir::QPath::Resolved(..) | qpath @ hir::QPath::TypeRelative(..), | |
231 | ) => self.check_expr_path(qpath, expr, args), | |
232 | _ => self.check_expr_kind(expr, expected), | |
233 | }); | |
dc9dc135 XL |
234 | |
235 | // Warn for non-block expressions with diverging children. | |
e74abb32 | 236 | match expr.kind { |
94222f64 XL |
237 | ExprKind::Block(..) |
238 | | ExprKind::If(..) | |
239 | | ExprKind::Let(..) | |
240 | | ExprKind::Loop(..) | |
241 | | ExprKind::Match(..) => {} | |
e74abb32 XL |
242 | // If `expr` is a result of desugaring the try block and is an ok-wrapped |
243 | // diverging expression (e.g. it arose from desugaring of `try { return }`), | |
244 | // we skip issuing a warning because it is autogenerated code. | |
dfeec247 | 245 | ExprKind::Call(..) if expr.span.is_desugaring(DesugaringKind::TryBlock) => {} |
6a06907d | 246 | ExprKind::Call(callee, _) => self.warn_if_unreachable(expr.hir_id, callee.span, "call"), |
5099ac24 FG |
247 | ExprKind::MethodCall(segment, ..) => { |
248 | self.warn_if_unreachable(expr.hir_id, segment.ident.span, "call") | |
dfeec247 | 249 | } |
416331ca | 250 | _ => self.warn_if_unreachable(expr.hir_id, expr.span, "expression"), |
dc9dc135 XL |
251 | } |
252 | ||
253 | // Any expression that produces a value of type `!` must have diverged | |
254 | if ty.is_never() { | |
e1599b0c | 255 | self.diverges.set(self.diverges.get() | Diverges::always(expr.span)); |
dc9dc135 XL |
256 | } |
257 | ||
258 | // Record the type, which applies it effects. | |
259 | // We need to do this after the warning above, so that | |
260 | // we don't warn for the diverging expression itself. | |
261 | self.write_ty(expr.hir_id, ty); | |
262 | ||
263 | // Combine the diverging and has_error flags. | |
264 | self.diverges.set(self.diverges.get() | old_diverges); | |
265 | self.has_errors.set(self.has_errors.get() | old_has_errors); | |
266 | ||
267 | debug!("type of {} is...", self.tcx.hir().node_to_string(expr.hir_id)); | |
268 | debug!("... {:?}, expected is {:?}", ty, expected); | |
269 | ||
270 | ty | |
271 | } | |
272 | ||
c295e0f8 | 273 | #[instrument(skip(self, expr), level = "debug")] |
064997fb | 274 | fn check_expr_kind( |
dc9dc135 | 275 | &self, |
dfeec247 | 276 | expr: &'tcx hir::Expr<'tcx>, |
dc9dc135 | 277 | expected: Expectation<'tcx>, |
dc9dc135 | 278 | ) -> Ty<'tcx> { |
c295e0f8 | 279 | trace!("expr={:#?}", expr); |
dc9dc135 XL |
280 | |
281 | let tcx = self.tcx; | |
e74abb32 | 282 | match expr.kind { |
6a06907d | 283 | ExprKind::Box(subexpr) => self.check_expr_box(subexpr, expected), |
dfeec247 | 284 | ExprKind::Lit(ref lit) => self.check_lit(&lit, expected), |
064997fb | 285 | ExprKind::Binary(op, lhs, rhs) => self.check_binop(expr, op, lhs, rhs, expected), |
5e7ed085 | 286 | ExprKind::Assign(lhs, rhs, span) => { |
dfeec247 | 287 | self.check_expr_assign(expr, expected, lhs, rhs, span) |
dc9dc135 | 288 | } |
064997fb FG |
289 | ExprKind::AssignOp(op, lhs, rhs) => { |
290 | self.check_binop_assign(expr, op, lhs, rhs, expected) | |
291 | } | |
6a06907d XL |
292 | ExprKind::Unary(unop, oprnd) => self.check_expr_unary(unop, oprnd, expected, expr), |
293 | ExprKind::AddrOf(kind, mutbl, oprnd) => { | |
60c5eb7d | 294 | self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr) |
dc9dc135 | 295 | } |
a2a8927a XL |
296 | ExprKind::Path(QPath::LangItem(lang_item, _, hir_id)) => { |
297 | self.check_lang_item_path(lang_item, expr, hir_id) | |
3dfed10e | 298 | } |
c295e0f8 | 299 | ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, &[]), |
923072b8 FG |
300 | ExprKind::InlineAsm(asm) => { |
301 | // We defer some asm checks as we may not have resolved the input and output types yet (they may still be infer vars). | |
302 | self.deferred_asm_checks.borrow_mut().push((asm, expr.hir_id)); | |
303 | self.check_expr_asm(asm) | |
304 | } | |
dc9dc135 | 305 | ExprKind::Break(destination, ref expr_opt) => { |
416331ca | 306 | self.check_expr_break(destination, expr_opt.as_deref(), expr) |
dc9dc135 XL |
307 | } |
308 | ExprKind::Continue(destination) => { | |
309 | if destination.target_id.is_ok() { | |
310 | tcx.types.never | |
311 | } else { | |
312 | // There was an error; make type-check fail. | |
f035d41b | 313 | tcx.ty_error() |
dc9dc135 XL |
314 | } |
315 | } | |
dfeec247 | 316 | ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr), |
a2a8927a | 317 | ExprKind::Let(let_expr) => self.check_expr_let(let_expr), |
6a06907d | 318 | ExprKind::Loop(body, _, source, _) => { |
dc9dc135 XL |
319 | self.check_expr_loop(body, source, expected, expr) |
320 | } | |
6a06907d | 321 | ExprKind::Match(discrim, arms, match_src) => { |
dc9dc135 XL |
322 | self.check_match(expr, &discrim, arms, expected, match_src) |
323 | } | |
064997fb | 324 | ExprKind::Closure(&Closure { capture_clause, fn_decl, body, movability, .. }) => { |
923072b8 | 325 | self.check_expr_closure(expr, capture_clause, &fn_decl, body, movability, expected) |
dc9dc135 | 326 | } |
6a06907d XL |
327 | ExprKind::Block(body, _) => self.check_block_with_expected(&body, expected), |
328 | ExprKind::Call(callee, args) => self.check_call(expr, &callee, args, expected), | |
5099ac24 FG |
329 | ExprKind::MethodCall(segment, args, _) => { |
330 | self.check_method_call(expr, segment, args, expected) | |
dc9dc135 | 331 | } |
6a06907d XL |
332 | ExprKind::Cast(e, t) => self.check_expr_cast(e, t, expr), |
333 | ExprKind::Type(e, t) => { | |
dc9dc135 XL |
334 | let ty = self.to_ty_saving_user_provided_ty(&t); |
335 | self.check_expr_eq_type(&e, ty); | |
336 | ty | |
337 | } | |
6a06907d XL |
338 | ExprKind::If(cond, then_expr, opt_else_expr) => { |
339 | self.check_then_else(cond, then_expr, opt_else_expr, expr.span, expected) | |
340 | } | |
341 | ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected), | |
342 | ExprKind::Array(args) => self.check_expr_array(args, expected, expr), | |
3c0e092e XL |
343 | ExprKind::ConstBlock(ref anon_const) => { |
344 | self.check_expr_const_block(anon_const, expected, expr) | |
345 | } | |
6a06907d | 346 | ExprKind::Repeat(element, ref count) => { |
dc9dc135 XL |
347 | self.check_expr_repeat(element, count, expected, expr) |
348 | } | |
6a06907d XL |
349 | ExprKind::Tup(elts) => self.check_expr_tuple(elts, expected, expr), |
350 | ExprKind::Struct(qpath, fields, ref base_expr) => { | |
dc9dc135 XL |
351 | self.check_expr_struct(expr, expected, qpath, fields, base_expr) |
352 | } | |
6a06907d XL |
353 | ExprKind::Field(base, field) => self.check_field(expr, &base, field), |
354 | ExprKind::Index(base, idx) => self.check_expr_index(base, idx, expr), | |
355 | ExprKind::Yield(value, ref src) => self.check_expr_yield(value, expr, src), | |
f035d41b | 356 | hir::ExprKind::Err => tcx.ty_error(), |
dc9dc135 XL |
357 | } |
358 | } | |
359 | ||
dfeec247 | 360 | fn check_expr_box(&self, expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>) -> Ty<'tcx> { |
1b1a35ee | 361 | let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| match ty.kind() { |
dfeec247 XL |
362 | ty::Adt(def, _) if def.is_box() => Expectation::rvalue_hint(self, ty.boxed_ty()), |
363 | _ => NoExpectation, | |
dc9dc135 XL |
364 | }); |
365 | let referent_ty = self.check_expr_with_expectation(expr, expected_inner); | |
94222f64 | 366 | self.require_type_is_sized(referent_ty, expr.span, traits::SizedBoxType); |
dc9dc135 XL |
367 | self.tcx.mk_box(referent_ty) |
368 | } | |
369 | ||
370 | fn check_expr_unary( | |
371 | &self, | |
372 | unop: hir::UnOp, | |
dfeec247 | 373 | oprnd: &'tcx hir::Expr<'tcx>, |
dc9dc135 | 374 | expected: Expectation<'tcx>, |
dfeec247 | 375 | expr: &'tcx hir::Expr<'tcx>, |
dc9dc135 XL |
376 | ) -> Ty<'tcx> { |
377 | let tcx = self.tcx; | |
378 | let expected_inner = match unop { | |
6a06907d XL |
379 | hir::UnOp::Not | hir::UnOp::Neg => expected, |
380 | hir::UnOp::Deref => NoExpectation, | |
dc9dc135 | 381 | }; |
f035d41b | 382 | let mut oprnd_t = self.check_expr_with_expectation(&oprnd, expected_inner); |
dc9dc135 XL |
383 | |
384 | if !oprnd_t.references_error() { | |
385 | oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t); | |
386 | match unop { | |
6a06907d | 387 | hir::UnOp::Deref => { |
f035d41b XL |
388 | if let Some(ty) = self.lookup_derefing(expr, oprnd, oprnd_t) { |
389 | oprnd_t = ty; | |
dc9dc135 XL |
390 | } else { |
391 | let mut err = type_error_struct!( | |
392 | tcx.sess, | |
393 | expr.span, | |
394 | oprnd_t, | |
395 | E0614, | |
04454e1e | 396 | "type `{oprnd_t}` cannot be dereferenced", |
dc9dc135 XL |
397 | ); |
398 | let sp = tcx.sess.source_map().start_point(expr.span); | |
dfeec247 XL |
399 | if let Some(sp) = |
400 | tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) | |
dc9dc135 | 401 | { |
94222f64 | 402 | tcx.sess.parse_sess.expr_parentheses_needed(&mut err, *sp); |
dc9dc135 XL |
403 | } |
404 | err.emit(); | |
f035d41b | 405 | oprnd_t = tcx.ty_error(); |
dc9dc135 XL |
406 | } |
407 | } | |
6a06907d | 408 | hir::UnOp::Not => { |
064997fb | 409 | let result = self.check_user_unop(expr, oprnd_t, unop, expected_inner); |
dc9dc135 | 410 | // If it's builtin, we can reuse the type, this helps inference. |
1b1a35ee | 411 | if !(oprnd_t.is_integral() || *oprnd_t.kind() == ty::Bool) { |
dc9dc135 XL |
412 | oprnd_t = result; |
413 | } | |
414 | } | |
6a06907d | 415 | hir::UnOp::Neg => { |
064997fb | 416 | let result = self.check_user_unop(expr, oprnd_t, unop, expected_inner); |
dc9dc135 XL |
417 | // If it's builtin, we can reuse the type, this helps inference. |
418 | if !oprnd_t.is_numeric() { | |
419 | oprnd_t = result; | |
420 | } | |
421 | } | |
422 | } | |
423 | } | |
424 | oprnd_t | |
425 | } | |
426 | ||
427 | fn check_expr_addr_of( | |
428 | &self, | |
60c5eb7d | 429 | kind: hir::BorrowKind, |
dc9dc135 | 430 | mutbl: hir::Mutability, |
dfeec247 | 431 | oprnd: &'tcx hir::Expr<'tcx>, |
dc9dc135 | 432 | expected: Expectation<'tcx>, |
dfeec247 | 433 | expr: &'tcx hir::Expr<'tcx>, |
dc9dc135 XL |
434 | ) -> Ty<'tcx> { |
435 | let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| { | |
1b1a35ee | 436 | match ty.kind() { |
dc9dc135 | 437 | ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { |
60c5eb7d | 438 | if oprnd.is_syntactic_place_expr() { |
dc9dc135 XL |
439 | // Places may legitimately have unsized types. |
440 | // For example, dereferences of a fat pointer and | |
441 | // the last field of a struct can be unsized. | |
5099ac24 | 442 | ExpectHasType(*ty) |
dc9dc135 | 443 | } else { |
5099ac24 | 444 | Expectation::rvalue_hint(self, *ty) |
dc9dc135 XL |
445 | } |
446 | } | |
dfeec247 | 447 | _ => NoExpectation, |
dc9dc135 XL |
448 | } |
449 | }); | |
f035d41b XL |
450 | let ty = |
451 | self.check_expr_with_expectation_and_needs(&oprnd, hint, Needs::maybe_mut_place(mutbl)); | |
dc9dc135 | 452 | |
74b04a01 | 453 | let tm = ty::TypeAndMut { ty, mutbl }; |
60c5eb7d | 454 | match kind { |
f035d41b | 455 | _ if tm.ty.references_error() => self.tcx.ty_error(), |
60c5eb7d XL |
456 | hir::BorrowKind::Raw => { |
457 | self.check_named_place_expr(oprnd); | |
458 | self.tcx.mk_ptr(tm) | |
459 | } | |
460 | hir::BorrowKind::Ref => { | |
461 | // Note: at this point, we cannot say what the best lifetime | |
462 | // is to use for resulting pointer. We want to use the | |
463 | // shortest lifetime possible so as to avoid spurious borrowck | |
464 | // errors. Moreover, the longest lifetime will depend on the | |
465 | // precise details of the value whose address is being taken | |
466 | // (and how long it is valid), which we don't know yet until | |
467 | // type inference is complete. | |
468 | // | |
469 | // Therefore, here we simply generate a region variable. The | |
470 | // region inferencer will then select a suitable value. | |
471 | // Finally, borrowck will infer the value of the region again, | |
472 | // this time with enough precision to check that the value | |
473 | // whose address was taken can actually be made to live as long | |
474 | // as it needs to live. | |
475 | let region = self.next_region_var(infer::AddrOfRegion(expr.span)); | |
476 | self.tcx.mk_ref(region, tm) | |
477 | } | |
478 | } | |
479 | } | |
480 | ||
481 | /// Does this expression refer to a place that either: | |
482 | /// * Is based on a local or static. | |
483 | /// * Contains a dereference | |
484 | /// Note that the adjustments for the children of `expr` should already | |
485 | /// have been resolved. | |
dfeec247 | 486 | fn check_named_place_expr(&self, oprnd: &'tcx hir::Expr<'tcx>) { |
60c5eb7d XL |
487 | let is_named = oprnd.is_place_expr(|base| { |
488 | // Allow raw borrows if there are any deref adjustments. | |
489 | // | |
490 | // const VAL: (i32,) = (0,); | |
491 | // const REF: &(i32,) = &(0,); | |
dc9dc135 | 492 | // |
60c5eb7d XL |
493 | // &raw const VAL.0; // ERROR |
494 | // &raw const REF.0; // OK, same as &raw const (*REF).0; | |
495 | // | |
496 | // This is maybe too permissive, since it allows | |
497 | // `let u = &raw const Box::new((1,)).0`, which creates an | |
498 | // immediately dangling raw pointer. | |
1b1a35ee XL |
499 | self.typeck_results |
500 | .borrow() | |
501 | .adjustments() | |
502 | .get(base.hir_id) | |
503 | .map_or(false, |x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_)))) | |
60c5eb7d XL |
504 | }); |
505 | if !is_named { | |
5e7ed085 | 506 | self.tcx.sess.emit_err(AddressOfTemporaryTaken { span: oprnd.span }); |
dc9dc135 XL |
507 | } |
508 | } | |
509 | ||
3dfed10e XL |
510 | fn check_lang_item_path( |
511 | &self, | |
512 | lang_item: hir::LangItem, | |
513 | expr: &'tcx hir::Expr<'tcx>, | |
a2a8927a | 514 | hir_id: Option<hir::HirId>, |
3dfed10e | 515 | ) -> Ty<'tcx> { |
a2a8927a | 516 | self.resolve_lang_item_path(lang_item, expr.span, expr.hir_id, hir_id).1 |
3dfed10e XL |
517 | } |
518 | ||
c295e0f8 | 519 | pub(crate) fn check_expr_path( |
cdc7bbd5 XL |
520 | &self, |
521 | qpath: &'tcx hir::QPath<'tcx>, | |
522 | expr: &'tcx hir::Expr<'tcx>, | |
c295e0f8 | 523 | args: &'tcx [hir::Expr<'tcx>], |
cdc7bbd5 | 524 | ) -> Ty<'tcx> { |
dc9dc135 | 525 | let tcx = self.tcx; |
136023e0 XL |
526 | let (res, opt_ty, segs) = |
527 | self.resolve_ty_and_res_fully_qualified_call(qpath, expr.hir_id, expr.span); | |
dc9dc135 XL |
528 | let ty = match res { |
529 | Res::Err => { | |
530 | self.set_tainted_by_errors(); | |
f035d41b | 531 | tcx.ty_error() |
dc9dc135 XL |
532 | } |
533 | Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _) => { | |
064997fb | 534 | report_unexpected_variant_res(tcx, res, qpath, expr.span); |
f035d41b | 535 | tcx.ty_error() |
dc9dc135 XL |
536 | } |
537 | _ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0, | |
538 | }; | |
539 | ||
923072b8 | 540 | if let ty::FnDef(did, ..) = *ty.kind() { |
dc9dc135 | 541 | let fn_sig = ty.fn_sig(tcx); |
923072b8 FG |
542 | if tcx.fn_sig(did).abi() == RustIntrinsic && tcx.item_name(did) == sym::transmute { |
543 | let from = fn_sig.inputs().skip_binder()[0]; | |
544 | let to = fn_sig.output().skip_binder(); | |
545 | // We defer the transmute to the end of typeck, once all inference vars have | |
546 | // been resolved or we errored. This is important as we can only check transmute | |
547 | // on concrete types, but the output type may not be known yet (it would only | |
548 | // be known if explicitly specified via turbofish). | |
549 | self.deferred_transmute_checks.borrow_mut().push((from, to, expr.span)); | |
550 | } | |
29967ef6 | 551 | if !tcx.features().unsized_fn_params { |
dc9dc135 XL |
552 | // We want to remove some Sized bounds from std functions, |
553 | // but don't want to expose the removal to stable Rust. | |
554 | // i.e., we don't want to allow | |
555 | // | |
556 | // ```rust | |
557 | // drop as fn(str); | |
558 | // ``` | |
559 | // | |
560 | // to work in stable even if the Sized bound on `drop` is relaxed. | |
561 | for i in 0..fn_sig.inputs().skip_binder().len() { | |
562 | // We just want to check sizedness, so instead of introducing | |
563 | // placeholder lifetimes with probing, we just replace higher lifetimes | |
564 | // with fresh vars. | |
c295e0f8 | 565 | let span = args.get(i).map(|a| a.span).unwrap_or(expr.span); |
923072b8 FG |
566 | let input = self.replace_bound_vars_with_fresh_vars( |
567 | span, | |
568 | infer::LateBoundRegionConversionTime::FnCall, | |
569 | fn_sig.input(i), | |
570 | ); | |
dfeec247 XL |
571 | self.require_type_is_sized_deferred( |
572 | input, | |
c295e0f8 | 573 | span, |
3dfed10e | 574 | traits::SizedArgumentType(None), |
dfeec247 | 575 | ); |
dc9dc135 XL |
576 | } |
577 | } | |
578 | // Here we want to prevent struct constructors from returning unsized types. | |
579 | // There were two cases this happened: fn pointer coercion in stable | |
60c5eb7d | 580 | // and usual function call in presence of unsized_locals. |
dc9dc135 XL |
581 | // Also, as we just want to check sizedness, instead of introducing |
582 | // placeholder lifetimes with probing, we just replace higher lifetimes | |
583 | // with fresh vars. | |
923072b8 FG |
584 | let output = self.replace_bound_vars_with_fresh_vars( |
585 | expr.span, | |
586 | infer::LateBoundRegionConversionTime::FnCall, | |
587 | fn_sig.output(), | |
588 | ); | |
dc9dc135 XL |
589 | self.require_type_is_sized_deferred(output, expr.span, traits::SizedReturnType); |
590 | } | |
591 | ||
592 | // We always require that the type provided as the value for | |
593 | // a type parameter outlives the moment of instantiation. | |
3dfed10e | 594 | let substs = self.typeck_results.borrow().node_substs(expr.hir_id); |
dc9dc135 XL |
595 | self.add_wf_bounds(substs, expr); |
596 | ||
597 | ty | |
598 | } | |
599 | ||
600 | fn check_expr_break( | |
601 | &self, | |
602 | destination: hir::Destination, | |
dfeec247 XL |
603 | expr_opt: Option<&'tcx hir::Expr<'tcx>>, |
604 | expr: &'tcx hir::Expr<'tcx>, | |
dc9dc135 XL |
605 | ) -> Ty<'tcx> { |
606 | let tcx = self.tcx; | |
607 | if let Ok(target_id) = destination.target_id { | |
608 | let (e_ty, cause); | |
6a06907d | 609 | if let Some(e) = expr_opt { |
dc9dc135 XL |
610 | // If this is a break with a value, we need to type-check |
611 | // the expression. Get an expected type from the loop context. | |
612 | let opt_coerce_to = { | |
60c5eb7d XL |
613 | // We should release `enclosing_breakables` before the `check_expr_with_hint` |
614 | // below, so can't move this block of code to the enclosing scope and share | |
5e7ed085 | 615 | // `ctxt` with the second `enclosing_breakables` borrow below. |
dc9dc135 | 616 | let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); |
60c5eb7d | 617 | match enclosing_breakables.opt_find_breakable(target_id) { |
dfeec247 XL |
618 | Some(ctxt) => ctxt.coerce.as_ref().map(|coerce| coerce.expected_ty()), |
619 | None => { | |
620 | // Avoid ICE when `break` is inside a closure (#65383). | |
f035d41b | 621 | return tcx.ty_error_with_message( |
60c5eb7d XL |
622 | expr.span, |
623 | "break was outside loop, but no error was emitted", | |
624 | ); | |
60c5eb7d XL |
625 | } |
626 | } | |
dc9dc135 XL |
627 | }; |
628 | ||
629 | // If the loop context is not a `loop { }`, then break with | |
630 | // a value is illegal, and `opt_coerce_to` will be `None`. | |
631 | // Just set expectation to error in that case. | |
f035d41b | 632 | let coerce_to = opt_coerce_to.unwrap_or_else(|| tcx.ty_error()); |
dc9dc135 XL |
633 | |
634 | // Recurse without `enclosing_breakables` borrowed. | |
635 | e_ty = self.check_expr_with_hint(e, coerce_to); | |
636 | cause = self.misc(e.span); | |
637 | } else { | |
638 | // Otherwise, this is a break *without* a value. That's | |
639 | // always legal, and is equivalent to `break ()`. | |
640 | e_ty = tcx.mk_unit(); | |
641 | cause = self.misc(expr.span); | |
642 | } | |
643 | ||
644 | // Now that we have type-checked `expr_opt`, borrow | |
645 | // the `enclosing_loops` field and let's coerce the | |
646 | // type of `expr_opt` into what is expected. | |
647 | let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); | |
5e7ed085 FG |
648 | let Some(ctxt) = enclosing_breakables.opt_find_breakable(target_id) else { |
649 | // Avoid ICE when `break` is inside a closure (#65383). | |
650 | return tcx.ty_error_with_message( | |
651 | expr.span, | |
652 | "break was outside loop, but no error was emitted", | |
653 | ); | |
e1599b0c XL |
654 | }; |
655 | ||
dc9dc135 XL |
656 | if let Some(ref mut coerce) = ctxt.coerce { |
657 | if let Some(ref e) = expr_opt { | |
658 | coerce.coerce(self, &cause, e, e_ty); | |
659 | } else { | |
660 | assert!(e_ty.is_unit()); | |
416331ca | 661 | let ty = coerce.expected_ty(); |
dfeec247 XL |
662 | coerce.coerce_forced_unit( |
663 | self, | |
664 | &cause, | |
665 | &mut |mut err| { | |
666 | self.suggest_mismatched_types_on_tail( | |
cdc7bbd5 | 667 | &mut err, expr, ty, e_ty, target_id, |
60c5eb7d | 668 | ); |
dfeec247 XL |
669 | if let Some(val) = ty_kind_suggestion(ty) { |
670 | let label = destination | |
671 | .label | |
672 | .map(|l| format!(" {}", l.ident)) | |
673 | .unwrap_or_else(String::new); | |
674 | err.span_suggestion( | |
675 | expr.span, | |
676 | "give it a value of the expected type", | |
04454e1e | 677 | format!("break{label} {val}"), |
dfeec247 XL |
678 | Applicability::HasPlaceholders, |
679 | ); | |
680 | } | |
681 | }, | |
682 | false, | |
683 | ); | |
dc9dc135 XL |
684 | } |
685 | } else { | |
686 | // If `ctxt.coerce` is `None`, we can just ignore | |
e1599b0c | 687 | // the type of the expression. This is because |
dc9dc135 XL |
688 | // either this was a break *without* a value, in |
689 | // which case it is always a legal type (`()`), or | |
690 | // else an error would have been flagged by the | |
691 | // `loops` pass for using break with an expression | |
692 | // where you are not supposed to. | |
5e7ed085 | 693 | assert!(expr_opt.is_none() || self.tcx.sess.has_errors().is_some()); |
dc9dc135 XL |
694 | } |
695 | ||
29967ef6 XL |
696 | // If we encountered a `break`, then (no surprise) it may be possible to break from the |
697 | // loop... unless the value being returned from the loop diverges itself, e.g. | |
698 | // `break return 5` or `break loop {}`. | |
699 | ctxt.may_break |= !self.diverges.get().is_always(); | |
dc9dc135 XL |
700 | |
701 | // the type of a `break` is always `!`, since it diverges | |
702 | tcx.types.never | |
703 | } else { | |
704 | // Otherwise, we failed to find the enclosing loop; | |
705 | // this can only happen if the `break` was not | |
706 | // inside a loop at all, which is caught by the | |
707 | // loop-checking pass. | |
f035d41b XL |
708 | let err = self.tcx.ty_error_with_message( |
709 | expr.span, | |
710 | "break was outside loop, but no error was emitted", | |
711 | ); | |
dc9dc135 XL |
712 | |
713 | // We still need to assign a type to the inner expression to | |
714 | // prevent the ICE in #43162. | |
6a06907d | 715 | if let Some(e) = expr_opt { |
f035d41b | 716 | self.check_expr_with_hint(e, err); |
dc9dc135 XL |
717 | |
718 | // ... except when we try to 'break rust;'. | |
719 | // ICE this expression in particular (see #43162). | |
6a06907d | 720 | if let ExprKind::Path(QPath::Resolved(_, path)) = e.kind { |
dfeec247 | 721 | if path.segments.len() == 1 && path.segments[0].ident.name == sym::rust { |
dc9dc135 XL |
722 | fatally_break_rust(self.tcx.sess); |
723 | } | |
724 | } | |
725 | } | |
f035d41b | 726 | |
dc9dc135 | 727 | // There was an error; make type-check fail. |
f035d41b | 728 | err |
dc9dc135 XL |
729 | } |
730 | } | |
731 | ||
732 | fn check_expr_return( | |
733 | &self, | |
dfeec247 XL |
734 | expr_opt: Option<&'tcx hir::Expr<'tcx>>, |
735 | expr: &'tcx hir::Expr<'tcx>, | |
dc9dc135 XL |
736 | ) -> Ty<'tcx> { |
737 | if self.ret_coercion.is_none() { | |
136023e0 XL |
738 | let mut err = ReturnStmtOutsideOfFnBody { |
739 | span: expr.span, | |
740 | encl_body_span: None, | |
741 | encl_fn_span: None, | |
742 | }; | |
743 | ||
744 | let encl_item_id = self.tcx.hir().get_parent_item(expr.hir_id); | |
745 | ||
746 | if let Some(hir::Node::Item(hir::Item { | |
747 | kind: hir::ItemKind::Fn(..), | |
748 | span: encl_fn_span, | |
749 | .. | |
750 | })) | |
751 | | Some(hir::Node::TraitItem(hir::TraitItem { | |
752 | kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)), | |
753 | span: encl_fn_span, | |
754 | .. | |
755 | })) | |
756 | | Some(hir::Node::ImplItem(hir::ImplItem { | |
757 | kind: hir::ImplItemKind::Fn(..), | |
758 | span: encl_fn_span, | |
759 | .. | |
5099ac24 | 760 | })) = self.tcx.hir().find_by_def_id(encl_item_id) |
136023e0 XL |
761 | { |
762 | // We are inside a function body, so reporting "return statement | |
763 | // outside of function body" needs an explanation. | |
764 | ||
765 | let encl_body_owner_id = self.tcx.hir().enclosing_body_owner(expr.hir_id); | |
766 | ||
767 | // If this didn't hold, we would not have to report an error in | |
768 | // the first place. | |
064997fb | 769 | assert_ne!(encl_item_id, encl_body_owner_id); |
136023e0 XL |
770 | |
771 | let encl_body_id = self.tcx.hir().body_owned_by(encl_body_owner_id); | |
772 | let encl_body = self.tcx.hir().body(encl_body_id); | |
773 | ||
774 | err.encl_body_span = Some(encl_body.value.span); | |
775 | err.encl_fn_span = Some(*encl_fn_span); | |
776 | } | |
777 | ||
778 | self.tcx.sess.emit_err(err); | |
779 | ||
780 | if let Some(e) = expr_opt { | |
781 | // We still have to type-check `e` (issue #86188), but calling | |
782 | // `check_return_expr` only works inside fn bodies. | |
783 | self.check_expr(e); | |
784 | } | |
6a06907d | 785 | } else if let Some(e) = expr_opt { |
5869c6ff XL |
786 | if self.ret_coercion_span.get().is_none() { |
787 | self.ret_coercion_span.set(Some(e.span)); | |
dc9dc135 | 788 | } |
c295e0f8 | 789 | self.check_return_expr(e, true); |
dc9dc135 XL |
790 | } else { |
791 | let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut(); | |
5869c6ff XL |
792 | if self.ret_coercion_span.get().is_none() { |
793 | self.ret_coercion_span.set(Some(expr.span)); | |
dc9dc135 XL |
794 | } |
795 | let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression); | |
796 | if let Some((fn_decl, _)) = self.get_fn_decl(expr.hir_id) { | |
797 | coercion.coerce_forced_unit( | |
798 | self, | |
799 | &cause, | |
800 | &mut |db| { | |
ba9703b0 XL |
801 | let span = fn_decl.output.span(); |
802 | if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { | |
803 | db.span_label( | |
804 | span, | |
04454e1e | 805 | format!("expected `{snippet}` because of this return type"), |
ba9703b0 XL |
806 | ); |
807 | } | |
dc9dc135 XL |
808 | }, |
809 | true, | |
810 | ); | |
811 | } else { | |
812 | coercion.coerce_forced_unit(self, &cause, &mut |_| (), true); | |
813 | } | |
814 | } | |
815 | self.tcx.types.never | |
816 | } | |
817 | ||
5e7ed085 | 818 | /// `explicit_return` is `true` if we're checking an explicit `return expr`, |
c295e0f8 XL |
819 | /// and `false` if we're checking a trailing expression. |
820 | pub(super) fn check_return_expr( | |
821 | &self, | |
822 | return_expr: &'tcx hir::Expr<'tcx>, | |
823 | explicit_return: bool, | |
824 | ) { | |
dfeec247 XL |
825 | let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| { |
826 | span_bug!(return_expr.span, "check_return_expr called outside fn body") | |
827 | }); | |
dc9dc135 XL |
828 | |
829 | let ret_ty = ret_coercion.borrow().expected_ty(); | |
6a06907d | 830 | let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty); |
c295e0f8 XL |
831 | let mut span = return_expr.span; |
832 | // Use the span of the trailing expression for our cause, | |
833 | // not the span of the entire function | |
834 | if !explicit_return { | |
5e7ed085 FG |
835 | if let ExprKind::Block(body, _) = return_expr.kind && let Some(last_expr) = body.expr { |
836 | span = last_expr.span; | |
c295e0f8 XL |
837 | } |
838 | } | |
e74abb32 XL |
839 | ret_coercion.borrow_mut().coerce( |
840 | self, | |
c295e0f8 | 841 | &self.cause(span, ObligationCauseCode::ReturnValue(return_expr.hir_id)), |
e74abb32 XL |
842 | return_expr, |
843 | return_expr_ty, | |
844 | ); | |
923072b8 FG |
845 | |
846 | if self.return_type_has_opaque { | |
847 | // Point any obligations that were registered due to opaque type | |
848 | // inference at the return expression. | |
849 | self.select_obligations_where_possible(false, |errors| { | |
850 | self.point_at_return_for_opaque_ty_error(errors, span, return_expr_ty); | |
851 | }); | |
852 | } | |
853 | } | |
854 | ||
855 | fn point_at_return_for_opaque_ty_error( | |
856 | &self, | |
857 | errors: &mut Vec<traits::FulfillmentError<'tcx>>, | |
858 | span: Span, | |
859 | return_expr_ty: Ty<'tcx>, | |
860 | ) { | |
861 | // Don't point at the whole block if it's empty | |
862 | if span == self.tcx.hir().span(self.body_id) { | |
863 | return; | |
864 | } | |
865 | for err in errors { | |
866 | let cause = &mut err.obligation.cause; | |
867 | if let ObligationCauseCode::OpaqueReturnType(None) = cause.code() { | |
868 | let new_cause = ObligationCause::new( | |
869 | cause.span, | |
870 | cause.body_id, | |
871 | ObligationCauseCode::OpaqueReturnType(Some((return_expr_ty, span))), | |
872 | ); | |
873 | *cause = new_cause; | |
874 | } | |
875 | } | |
dc9dc135 XL |
876 | } |
877 | ||
dfeec247 XL |
878 | pub(crate) fn check_lhs_assignable( |
879 | &self, | |
880 | lhs: &'tcx hir::Expr<'tcx>, | |
881 | err_code: &'static str, | |
3c0e092e | 882 | op_span: Span, |
923072b8 | 883 | adjust_err: impl FnOnce(&mut DiagnosticBuilder<'tcx, ErrorGuaranteed>), |
dfeec247 | 884 | ) { |
29967ef6 XL |
885 | if lhs.is_syntactic_place_expr() { |
886 | return; | |
dfeec247 | 887 | } |
29967ef6 XL |
888 | |
889 | // FIXME: Make this use SessionDiagnostic once error codes can be dynamically set. | |
890 | let mut err = self.tcx.sess.struct_span_err_with_code( | |
3c0e092e | 891 | op_span, |
29967ef6 XL |
892 | "invalid left-hand side of assignment", |
893 | DiagnosticId::Error(err_code.into()), | |
894 | ); | |
895 | err.span_label(lhs.span, "cannot assign to this expression"); | |
3c0e092e | 896 | |
5e7ed085 FG |
897 | self.comes_from_while_condition(lhs.hir_id, |expr| { |
898 | err.span_suggestion_verbose( | |
899 | expr.span.shrink_to_lo(), | |
900 | "you might have meant to use pattern destructuring", | |
923072b8 | 901 | "let ", |
5e7ed085 FG |
902 | Applicability::MachineApplicable, |
903 | ); | |
904 | }); | |
905 | ||
923072b8 FG |
906 | adjust_err(&mut err); |
907 | ||
5e7ed085 FG |
908 | err.emit(); |
909 | } | |
910 | ||
911 | // Check if an expression `original_expr_id` comes from the condition of a while loop, | |
912 | // as opposed from the body of a while loop, which we can naively check by iterating | |
913 | // parents until we find a loop... | |
914 | pub(super) fn comes_from_while_condition( | |
915 | &self, | |
916 | original_expr_id: HirId, | |
917 | then: impl FnOnce(&hir::Expr<'_>), | |
918 | ) { | |
919 | let mut parent = self.tcx.hir().get_parent_node(original_expr_id); | |
3c0e092e XL |
920 | while let Some(node) = self.tcx.hir().find(parent) { |
921 | match node { | |
922 | hir::Node::Expr(hir::Expr { | |
923 | kind: | |
924 | hir::ExprKind::Loop( | |
925 | hir::Block { | |
926 | expr: | |
927 | Some(hir::Expr { | |
928 | kind: | |
929 | hir::ExprKind::Match(expr, ..) | hir::ExprKind::If(expr, ..), | |
930 | .. | |
931 | }), | |
932 | .. | |
933 | }, | |
934 | _, | |
935 | hir::LoopSource::While, | |
936 | _, | |
937 | ), | |
938 | .. | |
939 | }) => { | |
5e7ed085 FG |
940 | // Check if our original expression is a child of the condition of a while loop |
941 | let expr_is_ancestor = std::iter::successors(Some(original_expr_id), |id| { | |
5099ac24 FG |
942 | self.tcx.hir().find_parent_node(*id) |
943 | }) | |
944 | .take_while(|id| *id != parent) | |
945 | .any(|id| id == expr.hir_id); | |
946 | // if it is, then we have a situation like `while Some(0) = value.get(0) {`, | |
947 | // where `while let` was more likely intended. | |
948 | if expr_is_ancestor { | |
5e7ed085 | 949 | then(expr); |
5099ac24 | 950 | } |
3c0e092e XL |
951 | break; |
952 | } | |
953 | hir::Node::Item(_) | |
954 | | hir::Node::ImplItem(_) | |
955 | | hir::Node::TraitItem(_) | |
956 | | hir::Node::Crate(_) => break, | |
957 | _ => { | |
958 | parent = self.tcx.hir().get_parent_node(parent); | |
959 | } | |
960 | } | |
961 | } | |
dfeec247 XL |
962 | } |
963 | ||
5869c6ff XL |
964 | // A generic function for checking the 'then' and 'else' clauses in an 'if' |
965 | // or 'if-else' expression. | |
966 | fn check_then_else( | |
967 | &self, | |
968 | cond_expr: &'tcx hir::Expr<'tcx>, | |
969 | then_expr: &'tcx hir::Expr<'tcx>, | |
970 | opt_else_expr: Option<&'tcx hir::Expr<'tcx>>, | |
971 | sp: Span, | |
972 | orig_expected: Expectation<'tcx>, | |
973 | ) -> Ty<'tcx> { | |
974 | let cond_ty = self.check_expr_has_type_or_error(cond_expr, self.tcx.types.bool, |_| {}); | |
975 | ||
94222f64 XL |
976 | self.warn_if_unreachable( |
977 | cond_expr.hir_id, | |
978 | then_expr.span, | |
979 | "block in `if` or `while` expression", | |
980 | ); | |
5869c6ff XL |
981 | |
982 | let cond_diverges = self.diverges.get(); | |
983 | self.diverges.set(Diverges::Maybe); | |
984 | ||
985 | let expected = orig_expected.adjust_for_branches(self); | |
986 | let then_ty = self.check_expr_with_expectation(then_expr, expected); | |
987 | let then_diverges = self.diverges.get(); | |
988 | self.diverges.set(Diverges::Maybe); | |
989 | ||
990 | // We've already taken the expected type's preferences | |
991 | // into account when typing the `then` branch. To figure | |
992 | // out the initial shot at a LUB, we thus only consider | |
993 | // `expected` if it represents a *hard* constraint | |
994 | // (`only_has_type`); otherwise, we just go with a | |
995 | // fresh type variable. | |
996 | let coerce_to_ty = expected.coercion_target_type(self, sp); | |
997 | let mut coerce: DynamicCoerceMany<'_> = CoerceMany::new(coerce_to_ty); | |
998 | ||
999 | coerce.coerce(self, &self.misc(sp), then_expr, then_ty); | |
1000 | ||
1001 | if let Some(else_expr) = opt_else_expr { | |
064997fb | 1002 | let else_ty = self.check_expr_with_expectation(else_expr, expected); |
5869c6ff XL |
1003 | let else_diverges = self.diverges.get(); |
1004 | ||
5e7ed085 | 1005 | let opt_suggest_box_span = self.opt_suggest_box_span(else_ty, orig_expected); |
064997fb FG |
1006 | let if_cause = self.if_cause( |
1007 | sp, | |
1008 | cond_expr.span, | |
1009 | then_expr, | |
1010 | else_expr, | |
1011 | then_ty, | |
1012 | else_ty, | |
1013 | opt_suggest_box_span, | |
1014 | ); | |
5869c6ff XL |
1015 | |
1016 | coerce.coerce(self, &if_cause, else_expr, else_ty); | |
1017 | ||
1018 | // We won't diverge unless both branches do (or the condition does). | |
1019 | self.diverges.set(cond_diverges | then_diverges & else_diverges); | |
1020 | } else { | |
94222f64 | 1021 | self.if_fallback_coercion(sp, then_expr, &mut coerce); |
5869c6ff XL |
1022 | |
1023 | // If the condition is false we can't diverge. | |
1024 | self.diverges.set(cond_diverges); | |
1025 | } | |
1026 | ||
1027 | let result_ty = coerce.complete(self); | |
1028 | if cond_ty.references_error() { self.tcx.ty_error() } else { result_ty } | |
1029 | } | |
1030 | ||
dc9dc135 | 1031 | /// Type check assignment expression `expr` of form `lhs = rhs`. |
5869c6ff | 1032 | /// The expected type is `()` and is passed to the function for the purposes of diagnostics. |
dc9dc135 XL |
1033 | fn check_expr_assign( |
1034 | &self, | |
dfeec247 | 1035 | expr: &'tcx hir::Expr<'tcx>, |
dc9dc135 | 1036 | expected: Expectation<'tcx>, |
dfeec247 XL |
1037 | lhs: &'tcx hir::Expr<'tcx>, |
1038 | rhs: &'tcx hir::Expr<'tcx>, | |
5e7ed085 | 1039 | span: Span, |
dc9dc135 | 1040 | ) -> Ty<'tcx> { |
dc9dc135 XL |
1041 | let expected_ty = expected.coercion_target_type(self, expr.span); |
1042 | if expected_ty == self.tcx.types.bool { | |
1043 | // The expected type is `bool` but this will result in `()` so we can reasonably | |
1044 | // say that the user intended to write `lhs == rhs` instead of `lhs = rhs`. | |
1045 | // The likely cause of this is `if foo = bar { .. }`. | |
1046 | let actual_ty = self.tcx.mk_unit(); | |
1047 | let mut err = self.demand_suptype_diag(expr.span, expected_ty, actual_ty).unwrap(); | |
1b1a35ee XL |
1048 | let lhs_ty = self.check_expr(&lhs); |
1049 | let rhs_ty = self.check_expr(&rhs); | |
1050 | let (applicability, eq) = if self.can_coerce(rhs_ty, lhs_ty) { | |
1051 | (Applicability::MachineApplicable, true) | |
1052 | } else { | |
1053 | (Applicability::MaybeIncorrect, false) | |
1054 | }; | |
923072b8 FG |
1055 | if !lhs.is_syntactic_place_expr() |
1056 | && lhs.is_approximately_pattern() | |
1057 | && !matches!(lhs.kind, hir::ExprKind::Lit(_)) | |
1058 | { | |
1b1a35ee | 1059 | // Do not suggest `if let x = y` as `==` is way more likely to be the intention. |
94222f64 XL |
1060 | let hir = self.tcx.hir(); |
1061 | if let hir::Node::Expr(hir::Expr { kind: ExprKind::If { .. }, .. }) = | |
1062 | hir.get(hir.get_parent_node(hir.get_parent_node(expr.hir_id))) | |
1063 | { | |
1b1a35ee XL |
1064 | err.span_suggestion_verbose( |
1065 | expr.span.shrink_to_lo(), | |
1066 | "you might have meant to use pattern matching", | |
923072b8 | 1067 | "let ", |
1b1a35ee XL |
1068 | applicability, |
1069 | ); | |
3c0e092e | 1070 | }; |
1b1a35ee XL |
1071 | } |
1072 | if eq { | |
1073 | err.span_suggestion_verbose( | |
5e7ed085 | 1074 | span, |
1b1a35ee | 1075 | "you might have meant to compare for equality", |
923072b8 | 1076 | "==", |
1b1a35ee XL |
1077 | applicability, |
1078 | ); | |
1079 | } | |
1080 | ||
94222f64 XL |
1081 | // If the assignment expression itself is ill-formed, don't |
1082 | // bother emitting another error | |
1083 | if lhs_ty.references_error() || rhs_ty.references_error() { | |
1084 | err.delay_as_bug() | |
dc9dc135 | 1085 | } else { |
1b1a35ee | 1086 | err.emit(); |
dc9dc135 | 1087 | } |
1b1a35ee | 1088 | return self.tcx.ty_error(); |
dc9dc135 XL |
1089 | } |
1090 | ||
1b1a35ee | 1091 | let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace); |
923072b8 FG |
1092 | |
1093 | let suggest_deref_binop = |err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, | |
1094 | rhs_ty: Ty<'tcx>| { | |
1095 | if let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) { | |
1096 | // Can only assign if the type is sized, so if `DerefMut` yields a type that is | |
1097 | // unsized, do not suggest dereferencing it. | |
1098 | let lhs_deref_ty_is_sized = self | |
1099 | .infcx | |
1100 | .type_implements_trait( | |
1101 | self.tcx.lang_items().sized_trait().unwrap(), | |
1102 | lhs_deref_ty, | |
1103 | ty::List::empty(), | |
1104 | self.param_env, | |
1105 | ) | |
1106 | .may_apply(); | |
1107 | if lhs_deref_ty_is_sized && self.can_coerce(rhs_ty, lhs_deref_ty) { | |
1108 | err.span_suggestion_verbose( | |
1109 | lhs.span.shrink_to_lo(), | |
1110 | "consider dereferencing here to assign to the mutably borrowed value", | |
1111 | "*", | |
1112 | Applicability::MachineApplicable, | |
1113 | ); | |
1114 | } | |
1115 | } | |
1116 | }; | |
1117 | ||
1118 | self.check_lhs_assignable(lhs, "E0070", span, |err| { | |
1119 | let rhs_ty = self.check_expr(&rhs); | |
1120 | suggest_deref_binop(err, rhs_ty); | |
1121 | }); | |
1122 | ||
1123 | // This is (basically) inlined `check_expr_coercable_to_type`, but we want | |
1124 | // to suggest an additional fixup here in `suggest_deref_binop`. | |
1125 | let rhs_ty = self.check_expr_with_hint(&rhs, lhs_ty); | |
1126 | if let (_, Some(mut diag)) = | |
1127 | self.demand_coerce_diag(rhs, rhs_ty, lhs_ty, Some(lhs), AllowTwoPhase::No) | |
1128 | { | |
1129 | suggest_deref_binop(&mut diag, rhs_ty); | |
1130 | diag.emit(); | |
1131 | } | |
1b1a35ee | 1132 | |
dc9dc135 XL |
1133 | self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized); |
1134 | ||
1135 | if lhs_ty.references_error() || rhs_ty.references_error() { | |
f035d41b | 1136 | self.tcx.ty_error() |
dc9dc135 XL |
1137 | } else { |
1138 | self.tcx.mk_unit() | |
1139 | } | |
1140 | } | |
1141 | ||
923072b8 | 1142 | pub(super) fn check_expr_let(&self, let_expr: &'tcx hir::Let<'tcx>) -> Ty<'tcx> { |
a2a8927a XL |
1143 | // for let statements, this is done in check_stmt |
1144 | let init = let_expr.init; | |
1145 | self.warn_if_unreachable(init.hir_id, init.span, "block in `let` expression"); | |
1146 | // otherwise check exactly as a let statement | |
1147 | self.check_decl(let_expr.into()); | |
1148 | // but return a bool, for this is a boolean expression | |
94222f64 XL |
1149 | self.tcx.types.bool |
1150 | } | |
1151 | ||
dc9dc135 XL |
1152 | fn check_expr_loop( |
1153 | &self, | |
dfeec247 | 1154 | body: &'tcx hir::Block<'tcx>, |
dc9dc135 XL |
1155 | source: hir::LoopSource, |
1156 | expected: Expectation<'tcx>, | |
dfeec247 | 1157 | expr: &'tcx hir::Expr<'tcx>, |
dc9dc135 XL |
1158 | ) -> Ty<'tcx> { |
1159 | let coerce = match source { | |
1160 | // you can only use break with a value from a normal `loop { }` | |
1161 | hir::LoopSource::Loop => { | |
1162 | let coerce_to = expected.coercion_target_type(self, body.span); | |
1163 | Some(CoerceMany::new(coerce_to)) | |
1164 | } | |
1165 | ||
94222f64 | 1166 | hir::LoopSource::While | hir::LoopSource::ForLoop => None, |
dc9dc135 XL |
1167 | }; |
1168 | ||
1169 | let ctxt = BreakableCtxt { | |
1170 | coerce, | |
1171 | may_break: false, // Will get updated if/when we find a `break`. | |
1172 | }; | |
1173 | ||
1174 | let (ctxt, ()) = self.with_breakable_ctxt(expr.hir_id, ctxt, || { | |
1175 | self.check_block_no_value(&body); | |
1176 | }); | |
1177 | ||
1178 | if ctxt.may_break { | |
1179 | // No way to know whether it's diverging because | |
1180 | // of a `break` or an outer `break` or `return`. | |
1181 | self.diverges.set(Diverges::Maybe); | |
1182 | } | |
1183 | ||
1184 | // If we permit break with a value, then result type is | |
1185 | // the LUB of the breaks (possibly ! if none); else, it | |
1186 | // is nil. This makes sense because infinite loops | |
1187 | // (which would have type !) are only possible iff we | |
1188 | // permit break with a value [1]. | |
1189 | if ctxt.coerce.is_none() && !ctxt.may_break { | |
1190 | // [1] | |
1191 | self.tcx.sess.delay_span_bug(body.span, "no coercion, but loop may not break"); | |
1192 | } | |
1193 | ctxt.coerce.map(|c| c.complete(self)).unwrap_or_else(|| self.tcx.mk_unit()) | |
1194 | } | |
1195 | ||
1196 | /// Checks a method call. | |
1197 | fn check_method_call( | |
1198 | &self, | |
dfeec247 XL |
1199 | expr: &'tcx hir::Expr<'tcx>, |
1200 | segment: &hir::PathSegment<'_>, | |
dfeec247 | 1201 | args: &'tcx [hir::Expr<'tcx>], |
dc9dc135 | 1202 | expected: Expectation<'tcx>, |
dc9dc135 XL |
1203 | ) -> Ty<'tcx> { |
1204 | let rcvr = &args[0]; | |
f035d41b | 1205 | let rcvr_t = self.check_expr(&rcvr); |
dc9dc135 XL |
1206 | // no need to check for bot/err -- callee does that |
1207 | let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t); | |
5099ac24 | 1208 | let span = segment.ident.span; |
dc9dc135 | 1209 | |
136023e0 | 1210 | let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr, args) { |
dc9dc135 | 1211 | Ok(method) => { |
60c5eb7d | 1212 | // We could add a "consider `foo::<params>`" suggestion here, but I wasn't able to |
5e7ed085 | 1213 | // trigger this codepath causing `structurally_resolved_type` to emit an error. |
60c5eb7d | 1214 | |
dc9dc135 XL |
1215 | self.write_method_call(expr.hir_id, method); |
1216 | Ok(method) | |
1217 | } | |
1218 | Err(error) => { | |
5869c6ff | 1219 | if segment.ident.name != kw::Empty { |
cdc7bbd5 XL |
1220 | if let Some(mut err) = self.report_method_error( |
1221 | span, | |
1222 | rcvr_t, | |
1223 | segment.ident, | |
1224 | SelfSource::MethodCall(&args[0]), | |
1225 | error, | |
1226 | Some(args), | |
1227 | ) { | |
1228 | err.emit(); | |
1229 | } | |
dc9dc135 XL |
1230 | } |
1231 | Err(()) | |
1232 | } | |
1233 | }; | |
1234 | ||
1235 | // Call the generic checker. | |
e1599b0c XL |
1236 | self.check_method_argument_types( |
1237 | span, | |
1238 | expr, | |
1239 | method, | |
1240 | &args[1..], | |
1241 | DontTupleArguments, | |
1242 | expected, | |
1243 | ) | |
1244 | } | |
1245 | ||
dc9dc135 XL |
1246 | fn check_expr_cast( |
1247 | &self, | |
dfeec247 XL |
1248 | e: &'tcx hir::Expr<'tcx>, |
1249 | t: &'tcx hir::Ty<'tcx>, | |
1250 | expr: &'tcx hir::Expr<'tcx>, | |
dc9dc135 XL |
1251 | ) -> Ty<'tcx> { |
1252 | // Find the type of `e`. Supply hints based on the type we are casting to, | |
1253 | // if appropriate. | |
1254 | let t_cast = self.to_ty_saving_user_provided_ty(t); | |
fc512014 | 1255 | let t_cast = self.resolve_vars_if_possible(t_cast); |
dc9dc135 | 1256 | let t_expr = self.check_expr_with_expectation(e, ExpectCastableToType(t_cast)); |
94222f64 | 1257 | let t_expr = self.resolve_vars_if_possible(t_expr); |
dc9dc135 XL |
1258 | |
1259 | // Eagerly check for some obvious errors. | |
1260 | if t_expr.references_error() || t_cast.references_error() { | |
f035d41b | 1261 | self.tcx.ty_error() |
dc9dc135 XL |
1262 | } else { |
1263 | // Defer other checks until we're done type checking. | |
1264 | let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); | |
1265 | match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) { | |
1266 | Ok(cast_check) => { | |
94222f64 XL |
1267 | debug!( |
1268 | "check_expr_cast: deferring cast from {:?} to {:?}: {:?}", | |
1269 | t_cast, t_expr, cast_check, | |
1270 | ); | |
dc9dc135 XL |
1271 | deferred_cast_checks.push(cast_check); |
1272 | t_cast | |
1273 | } | |
5e7ed085 | 1274 | Err(_) => self.tcx.ty_error(), |
dc9dc135 XL |
1275 | } |
1276 | } | |
1277 | } | |
1278 | ||
1279 | fn check_expr_array( | |
1280 | &self, | |
dfeec247 | 1281 | args: &'tcx [hir::Expr<'tcx>], |
dc9dc135 | 1282 | expected: Expectation<'tcx>, |
dfeec247 | 1283 | expr: &'tcx hir::Expr<'tcx>, |
dc9dc135 | 1284 | ) -> Ty<'tcx> { |
dc9dc135 | 1285 | let element_ty = if !args.is_empty() { |
ba9703b0 XL |
1286 | let coerce_to = expected |
1287 | .to_option(self) | |
1b1a35ee | 1288 | .and_then(|uty| match *uty.kind() { |
ba9703b0 XL |
1289 | ty::Array(ty, _) | ty::Slice(ty) => Some(ty), |
1290 | _ => None, | |
dc9dc135 | 1291 | }) |
ba9703b0 XL |
1292 | .unwrap_or_else(|| { |
1293 | self.next_ty_var(TypeVariableOrigin { | |
1294 | kind: TypeVariableOriginKind::TypeInference, | |
1295 | span: expr.span, | |
1296 | }) | |
1297 | }); | |
dc9dc135 XL |
1298 | let mut coerce = CoerceMany::with_coercion_sites(coerce_to, args); |
1299 | assert_eq!(self.diverges.get(), Diverges::Maybe); | |
1300 | for e in args { | |
1301 | let e_ty = self.check_expr_with_hint(e, coerce_to); | |
1302 | let cause = self.misc(e.span); | |
1303 | coerce.coerce(self, &cause, e, e_ty); | |
1304 | } | |
1305 | coerce.complete(self) | |
1306 | } else { | |
1307 | self.next_ty_var(TypeVariableOrigin { | |
1308 | kind: TypeVariableOriginKind::TypeInference, | |
1309 | span: expr.span, | |
1310 | }) | |
1311 | }; | |
1312 | self.tcx.mk_array(element_ty, args.len() as u64) | |
1313 | } | |
1314 | ||
3c0e092e XL |
1315 | fn check_expr_const_block( |
1316 | &self, | |
1317 | anon_const: &'tcx hir::AnonConst, | |
1318 | expected: Expectation<'tcx>, | |
1319 | _expr: &'tcx hir::Expr<'tcx>, | |
1320 | ) -> Ty<'tcx> { | |
1321 | let body = self.tcx.hir().body(anon_const.body); | |
1322 | ||
1323 | // Create a new function context. | |
5099ac24 | 1324 | let fcx = FnCtxt::new(self, self.param_env.with_const(), body.value.hir_id); |
3c0e092e XL |
1325 | crate::check::GatherLocalsVisitor::new(&fcx).visit_body(body); |
1326 | ||
1327 | let ty = fcx.check_expr_with_expectation(&body.value, expected); | |
1328 | fcx.require_type_is_sized(ty, body.value.span, traits::ConstSized); | |
1329 | fcx.write_ty(anon_const.hir_id, ty); | |
1330 | ty | |
1331 | } | |
1332 | ||
dc9dc135 XL |
1333 | fn check_expr_repeat( |
1334 | &self, | |
dfeec247 | 1335 | element: &'tcx hir::Expr<'tcx>, |
a2a8927a | 1336 | count: &'tcx hir::ArrayLen, |
dc9dc135 | 1337 | expected: Expectation<'tcx>, |
dfeec247 | 1338 | _expr: &'tcx hir::Expr<'tcx>, |
dc9dc135 XL |
1339 | ) -> Ty<'tcx> { |
1340 | let tcx = self.tcx; | |
a2a8927a | 1341 | let count = self.array_length_to_const(count); |
dc9dc135 XL |
1342 | |
1343 | let uty = match expected { | |
1b1a35ee | 1344 | ExpectHasType(uty) => match *uty.kind() { |
dfeec247 XL |
1345 | ty::Array(ty, _) | ty::Slice(ty) => Some(ty), |
1346 | _ => None, | |
1347 | }, | |
1348 | _ => None, | |
dc9dc135 XL |
1349 | }; |
1350 | ||
1351 | let (element_ty, t) = match uty { | |
1352 | Some(uty) => { | |
f035d41b | 1353 | self.check_expr_coercable_to_type(&element, uty, None); |
dc9dc135 XL |
1354 | (uty, uty) |
1355 | } | |
1356 | None => { | |
1357 | let ty = self.next_ty_var(TypeVariableOrigin { | |
1358 | kind: TypeVariableOriginKind::MiscVariable, | |
1359 | span: element.span, | |
1360 | }); | |
e74abb32 | 1361 | let element_ty = self.check_expr_has_type_or_error(&element, ty, |_| {}); |
dc9dc135 XL |
1362 | (element_ty, ty) |
1363 | } | |
1364 | }; | |
1365 | ||
dc9dc135 | 1366 | if element_ty.references_error() { |
f035d41b | 1367 | return tcx.ty_error(); |
dc9dc135 | 1368 | } |
ba9703b0 | 1369 | |
04454e1e FG |
1370 | self.check_repeat_element_needs_copy_bound(element, count, element_ty); |
1371 | ||
ba9703b0 | 1372 | tcx.mk_ty(ty::Array(t, count)) |
dc9dc135 XL |
1373 | } |
1374 | ||
04454e1e FG |
1375 | fn check_repeat_element_needs_copy_bound( |
1376 | &self, | |
1377 | element: &hir::Expr<'_>, | |
1378 | count: ty::Const<'tcx>, | |
1379 | element_ty: Ty<'tcx>, | |
1380 | ) { | |
1381 | let tcx = self.tcx; | |
1382 | // Actual constants as the repeat element get inserted repeatedly instead of getting copied via Copy. | |
1383 | match &element.kind { | |
1384 | hir::ExprKind::ConstBlock(..) => return, | |
1385 | hir::ExprKind::Path(qpath) => { | |
1386 | let res = self.typeck_results.borrow().qpath_res(qpath, element.hir_id); | |
1387 | if let Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::AnonConst, _) = res | |
1388 | { | |
1389 | return; | |
1390 | } | |
1391 | } | |
1392 | _ => {} | |
1393 | } | |
1394 | // If someone calls a const fn, they can extract that call out into a separate constant (or a const | |
1395 | // block in the future), so we check that to tell them that in the diagnostic. Does not affect typeck. | |
1396 | let is_const_fn = match element.kind { | |
1397 | hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() { | |
1398 | ty::FnDef(def_id, _) => tcx.is_const_fn(def_id), | |
1399 | _ => false, | |
1400 | }, | |
1401 | _ => false, | |
1402 | }; | |
1403 | ||
1404 | // If the length is 0, we don't create any elements, so we don't copy any. If the length is 1, we | |
1405 | // don't copy that one element, we move it. Only check for Copy if the length is larger. | |
1406 | if count.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) { | |
1407 | let lang_item = self.tcx.require_lang_item(LangItem::Copy, None); | |
1408 | let code = traits::ObligationCauseCode::RepeatElementCopy { is_const_fn }; | |
1409 | self.require_type_meets(element_ty, element.span, code, lang_item); | |
1410 | } | |
1411 | } | |
1412 | ||
dc9dc135 XL |
1413 | fn check_expr_tuple( |
1414 | &self, | |
dfeec247 | 1415 | elts: &'tcx [hir::Expr<'tcx>], |
dc9dc135 | 1416 | expected: Expectation<'tcx>, |
dfeec247 | 1417 | expr: &'tcx hir::Expr<'tcx>, |
dc9dc135 XL |
1418 | ) -> Ty<'tcx> { |
1419 | let flds = expected.only_has_type(self).and_then(|ty| { | |
e74abb32 | 1420 | let ty = self.resolve_vars_with_obligations(ty); |
1b1a35ee | 1421 | match ty.kind() { |
6a06907d | 1422 | ty::Tuple(flds) => Some(&flds[..]), |
dfeec247 | 1423 | _ => None, |
dc9dc135 XL |
1424 | } |
1425 | }); | |
1426 | ||
ba9703b0 | 1427 | let elt_ts_iter = elts.iter().enumerate().map(|(i, e)| match flds { |
6a06907d | 1428 | Some(fs) if i < fs.len() => { |
5e7ed085 | 1429 | let ety = fs[i]; |
f035d41b | 1430 | self.check_expr_coercable_to_type(&e, ety, None); |
ba9703b0 XL |
1431 | ety |
1432 | } | |
1433 | _ => self.check_expr_with_expectation(&e, NoExpectation), | |
dc9dc135 XL |
1434 | }); |
1435 | let tuple = self.tcx.mk_tup(elt_ts_iter); | |
1436 | if tuple.references_error() { | |
f035d41b | 1437 | self.tcx.ty_error() |
dc9dc135 XL |
1438 | } else { |
1439 | self.require_type_is_sized(tuple, expr.span, traits::TupleInitializerSized); | |
1440 | tuple | |
1441 | } | |
1442 | } | |
1443 | ||
1444 | fn check_expr_struct( | |
1445 | &self, | |
dfeec247 | 1446 | expr: &hir::Expr<'_>, |
dc9dc135 | 1447 | expected: Expectation<'tcx>, |
dfeec247 | 1448 | qpath: &QPath<'_>, |
6a06907d | 1449 | fields: &'tcx [hir::ExprField<'tcx>], |
dfeec247 | 1450 | base_expr: &'tcx Option<&'tcx hir::Expr<'tcx>>, |
dc9dc135 XL |
1451 | ) -> Ty<'tcx> { |
1452 | // Find the relevant variant | |
5099ac24 | 1453 | let Some((variant, adt_ty)) = self.check_struct_path(qpath, expr.hir_id) else { |
dfeec247 | 1454 | self.check_struct_fields_on_error(fields, base_expr); |
f035d41b | 1455 | return self.tcx.ty_error(); |
dfeec247 | 1456 | }; |
dc9dc135 | 1457 | |
dc9dc135 XL |
1458 | // Prohibit struct expressions when non-exhaustive flag is set. |
1459 | let adt = adt_ty.ty_adt_def().expect("`check_struct_path` returned non-ADT type"); | |
5e7ed085 | 1460 | if !adt.did().is_local() && variant.is_field_list_non_exhaustive() { |
1b1a35ee XL |
1461 | self.tcx |
1462 | .sess | |
1463 | .emit_err(StructExprNonExhaustive { span: expr.span, what: adt.variant_descr() }); | |
dc9dc135 XL |
1464 | } |
1465 | ||
3c0e092e | 1466 | self.check_expr_struct_fields( |
dfeec247 XL |
1467 | adt_ty, |
1468 | expected, | |
1469 | expr.hir_id, | |
3dfed10e | 1470 | qpath.span(), |
dfeec247 XL |
1471 | variant, |
1472 | fields, | |
3c0e092e | 1473 | base_expr, |
c295e0f8 | 1474 | expr.span, |
dfeec247 | 1475 | ); |
3c0e092e | 1476 | |
dc9dc135 XL |
1477 | self.require_type_is_sized(adt_ty, expr.span, traits::StructInitializerSized); |
1478 | adt_ty | |
1479 | } | |
1480 | ||
1481 | fn check_expr_struct_fields( | |
1482 | &self, | |
1483 | adt_ty: Ty<'tcx>, | |
1484 | expected: Expectation<'tcx>, | |
1485 | expr_id: hir::HirId, | |
1486 | span: Span, | |
1487 | variant: &'tcx ty::VariantDef, | |
6a06907d | 1488 | ast_fields: &'tcx [hir::ExprField<'tcx>], |
3c0e092e | 1489 | base_expr: &'tcx Option<&'tcx hir::Expr<'tcx>>, |
c295e0f8 | 1490 | expr_span: Span, |
3c0e092e | 1491 | ) { |
dc9dc135 XL |
1492 | let tcx = self.tcx; |
1493 | ||
923072b8 FG |
1494 | let expected_inputs = |
1495 | self.expected_inputs_for_expected_output(span, expected, adt_ty, &[adt_ty]); | |
1496 | let adt_ty_hint = if let Some(expected_inputs) = expected_inputs { | |
1497 | expected_inputs.get(0).cloned().unwrap_or(adt_ty) | |
1498 | } else { | |
1499 | adt_ty | |
1500 | }; | |
dc9dc135 XL |
1501 | // re-link the regions that EIfEO can erase. |
1502 | self.demand_eqtype(span, adt_ty_hint, adt_ty); | |
1503 | ||
923072b8 FG |
1504 | let ty::Adt(adt, substs) = adt_ty.kind() else { |
1505 | span_bug!(span, "non-ADT passed to check_expr_struct_fields"); | |
dc9dc135 | 1506 | }; |
923072b8 | 1507 | let adt_kind = adt.adt_kind(); |
dc9dc135 | 1508 | |
dfeec247 XL |
1509 | let mut remaining_fields = variant |
1510 | .fields | |
1511 | .iter() | |
1512 | .enumerate() | |
5099ac24 | 1513 | .map(|(i, field)| (field.ident(tcx).normalize_to_macros_2_0(), (i, field))) |
dfeec247 | 1514 | .collect::<FxHashMap<_, _>>(); |
dc9dc135 XL |
1515 | |
1516 | let mut seen_fields = FxHashMap::default(); | |
1517 | ||
1518 | let mut error_happened = false; | |
1519 | ||
1520 | // Type-check each field. | |
1521 | for field in ast_fields { | |
1522 | let ident = tcx.adjust_ident(field.ident, variant.def_id); | |
1523 | let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) { | |
1524 | seen_fields.insert(ident, field.span); | |
1525 | self.write_field_index(field.hir_id, i); | |
1526 | ||
1527 | // We don't look at stability attributes on | |
1528 | // struct-like enums (yet...), but it's definitely not | |
1529 | // a bug to have constructed one. | |
1530 | if adt_kind != AdtKind::Enum { | |
17df50a5 | 1531 | tcx.check_stability(v_field.did, Some(expr_id), field.span, None); |
dc9dc135 XL |
1532 | } |
1533 | ||
1534 | self.field_ty(field.span, v_field, substs) | |
1535 | } else { | |
1536 | error_happened = true; | |
1537 | if let Some(prev_span) = seen_fields.get(&ident) { | |
1b1a35ee XL |
1538 | tcx.sess.emit_err(FieldMultiplySpecifiedInInitializer { |
1539 | span: field.ident.span, | |
1540 | prev_span: *prev_span, | |
1541 | ident, | |
1542 | }); | |
dc9dc135 | 1543 | } else { |
c295e0f8 | 1544 | self.report_unknown_field( |
923072b8 FG |
1545 | adt_ty, |
1546 | variant, | |
1547 | field, | |
1548 | ast_fields, | |
1549 | adt.variant_descr(), | |
1550 | expr_span, | |
c295e0f8 | 1551 | ); |
dc9dc135 XL |
1552 | } |
1553 | ||
f035d41b | 1554 | tcx.ty_error() |
dc9dc135 XL |
1555 | }; |
1556 | ||
1557 | // Make sure to give a type to the field even if there's | |
1558 | // an error, so we can continue type-checking. | |
f035d41b | 1559 | self.check_expr_coercable_to_type(&field.expr, field_type, None); |
dc9dc135 XL |
1560 | } |
1561 | ||
1562 | // Make sure the programmer specified correct number of fields. | |
923072b8 | 1563 | if adt_kind == AdtKind::Union { |
dc9dc135 | 1564 | if ast_fields.len() != 1 { |
94222f64 XL |
1565 | struct_span_err!( |
1566 | tcx.sess, | |
1567 | span, | |
1568 | E0784, | |
1569 | "union expressions should have exactly one field", | |
1570 | ) | |
1571 | .emit(); | |
dc9dc135 | 1572 | } |
3c0e092e XL |
1573 | } |
1574 | ||
1575 | // If check_expr_struct_fields hit an error, do not attempt to populate | |
1576 | // the fields with the base_expr. This could cause us to hit errors later | |
1577 | // when certain fields are assumed to exist that in fact do not. | |
1578 | if error_happened { | |
1579 | return; | |
1580 | } | |
1581 | ||
1582 | if let Some(base_expr) = base_expr { | |
1583 | // FIXME: We are currently creating two branches here in order to maintain | |
1584 | // consistency. But they should be merged as much as possible. | |
1585 | let fru_tys = if self.tcx.features().type_changing_struct_update { | |
923072b8 FG |
1586 | if adt.is_struct() { |
1587 | // Make some fresh substitutions for our ADT type. | |
1588 | let fresh_substs = self.fresh_substs_for_item(base_expr.span, adt.did()); | |
1589 | // We do subtyping on the FRU fields first, so we can | |
1590 | // learn exactly what types we expect the base expr | |
1591 | // needs constrained to be compatible with the struct | |
1592 | // type we expect from the expectation value. | |
1593 | let fru_tys = variant | |
1594 | .fields | |
1595 | .iter() | |
1596 | .map(|f| { | |
1597 | let fru_ty = self.normalize_associated_types_in( | |
1598 | expr_span, | |
1599 | self.field_ty(base_expr.span, f, fresh_substs), | |
1600 | ); | |
1601 | let ident = self.tcx.adjust_ident(f.ident(self.tcx), variant.def_id); | |
1602 | if let Some(_) = remaining_fields.remove(&ident) { | |
1603 | let target_ty = self.field_ty(base_expr.span, f, substs); | |
1604 | let cause = self.misc(base_expr.span); | |
1605 | match self.at(&cause, self.param_env).sup(target_ty, fru_ty) { | |
1606 | Ok(InferOk { obligations, value: () }) => { | |
1607 | self.register_predicates(obligations) | |
1608 | } | |
1609 | Err(_) => { | |
1610 | // This should never happen, since we're just subtyping the | |
1611 | // remaining_fields, but it's fine to emit this, I guess. | |
1612 | self.report_mismatched_types( | |
1613 | &cause, | |
1614 | target_ty, | |
1615 | fru_ty, | |
1616 | FieldMisMatch(variant.name, ident.name), | |
1617 | ) | |
1618 | .emit(); | |
1619 | } | |
1620 | } | |
3c0e092e | 1621 | } |
923072b8 FG |
1622 | self.resolve_vars_if_possible(fru_ty) |
1623 | }) | |
1624 | .collect(); | |
1625 | // The use of fresh substs that we have subtyped against | |
1626 | // our base ADT type's fields allows us to guide inference | |
1627 | // along so that, e.g. | |
1628 | // ``` | |
1629 | // MyStruct<'a, F1, F2, const C: usize> { | |
1630 | // f: F1, | |
1631 | // // Other fields that reference `'a`, `F2`, and `C` | |
1632 | // } | |
1633 | // | |
1634 | // let x = MyStruct { | |
1635 | // f: 1usize, | |
1636 | // ..other_struct | |
1637 | // }; | |
1638 | // ``` | |
1639 | // will have the `other_struct` expression constrained to | |
1640 | // `MyStruct<'a, _, F2, C>`, as opposed to just `_`... | |
1641 | // This is important to allow coercions to happen in | |
1642 | // `other_struct` itself. See `coerce-in-base-expr.rs`. | |
1643 | let fresh_base_ty = self.tcx.mk_adt(*adt, fresh_substs); | |
1644 | self.check_expr_has_type_or_error( | |
1645 | base_expr, | |
1646 | self.resolve_vars_if_possible(fresh_base_ty), | |
1647 | |_| {}, | |
1648 | ); | |
1649 | fru_tys | |
1650 | } else { | |
1651 | // Check the base_expr, regardless of a bad expected adt_ty, so we can get | |
1652 | // type errors on that expression, too. | |
1653 | self.check_expr(base_expr); | |
1654 | self.tcx | |
1655 | .sess | |
1656 | .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span }); | |
1657 | return; | |
3c0e092e XL |
1658 | } |
1659 | } else { | |
1660 | self.check_expr_has_type_or_error(base_expr, adt_ty, |_| { | |
5099ac24 | 1661 | let base_ty = self.typeck_results.borrow().expr_ty(*base_expr); |
3c0e092e XL |
1662 | let same_adt = match (adt_ty.kind(), base_ty.kind()) { |
1663 | (ty::Adt(adt, _), ty::Adt(base_adt, _)) if adt == base_adt => true, | |
1664 | _ => false, | |
1665 | }; | |
1666 | if self.tcx.sess.is_nightly_build() && same_adt { | |
1667 | feature_err( | |
1668 | &self.tcx.sess.parse_sess, | |
1669 | sym::type_changing_struct_update, | |
1670 | base_expr.span, | |
1671 | "type changing struct updating is experimental", | |
1672 | ) | |
1673 | .emit(); | |
1674 | } | |
1675 | }); | |
1676 | match adt_ty.kind() { | |
1677 | ty::Adt(adt, substs) if adt.is_struct() => variant | |
1678 | .fields | |
1679 | .iter() | |
1680 | .map(|f| { | |
1681 | self.normalize_associated_types_in(expr_span, f.ty(self.tcx, substs)) | |
1682 | }) | |
1683 | .collect(), | |
1684 | _ => { | |
5e7ed085 | 1685 | self.tcx |
3c0e092e XL |
1686 | .sess |
1687 | .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span }); | |
5e7ed085 | 1688 | return; |
3c0e092e XL |
1689 | } |
1690 | } | |
1691 | }; | |
1692 | self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr_id, fru_tys); | |
923072b8 FG |
1693 | } else if adt_kind != AdtKind::Union && !remaining_fields.is_empty() { |
1694 | debug!(?remaining_fields); | |
1695 | let private_fields: Vec<&ty::FieldDef> = variant | |
1696 | .fields | |
1697 | .iter() | |
1698 | .filter(|field| { | |
1699 | !field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx) | |
1700 | }) | |
1701 | .collect(); | |
dc9dc135 | 1702 | |
923072b8 FG |
1703 | if !private_fields.is_empty() { |
1704 | self.report_private_fields(adt_ty, span, private_fields, ast_fields); | |
dc9dc135 | 1705 | } else { |
5e7ed085 FG |
1706 | self.report_missing_fields( |
1707 | adt_ty, | |
1708 | span, | |
1709 | remaining_fields, | |
1710 | variant, | |
1711 | ast_fields, | |
1712 | substs, | |
1713 | ); | |
1b1a35ee | 1714 | } |
dc9dc135 | 1715 | } |
dc9dc135 XL |
1716 | } |
1717 | ||
1718 | fn check_struct_fields_on_error( | |
1719 | &self, | |
6a06907d | 1720 | fields: &'tcx [hir::ExprField<'tcx>], |
dfeec247 | 1721 | base_expr: &'tcx Option<&'tcx hir::Expr<'tcx>>, |
dc9dc135 XL |
1722 | ) { |
1723 | for field in fields { | |
1724 | self.check_expr(&field.expr); | |
1725 | } | |
6a06907d | 1726 | if let Some(base) = *base_expr { |
dc9dc135 XL |
1727 | self.check_expr(&base); |
1728 | } | |
1729 | } | |
1730 | ||
1b1a35ee XL |
1731 | /// Report an error for a struct field expression when there are fields which aren't provided. |
1732 | /// | |
29967ef6 | 1733 | /// ```text |
1b1a35ee XL |
1734 | /// error: missing field `you_can_use_this_field` in initializer of `foo::Foo` |
1735 | /// --> src/main.rs:8:5 | |
1736 | /// | | |
1737 | /// 8 | foo::Foo {}; | |
1738 | /// | ^^^^^^^^ missing `you_can_use_this_field` | |
1739 | /// | |
1740 | /// error: aborting due to previous error | |
1741 | /// ``` | |
fc512014 | 1742 | fn report_missing_fields( |
1b1a35ee XL |
1743 | &self, |
1744 | adt_ty: Ty<'tcx>, | |
1745 | span: Span, | |
1746 | remaining_fields: FxHashMap<Ident, (usize, &ty::FieldDef)>, | |
5e7ed085 FG |
1747 | variant: &'tcx ty::VariantDef, |
1748 | ast_fields: &'tcx [hir::ExprField<'tcx>], | |
1749 | substs: SubstsRef<'tcx>, | |
1b1a35ee | 1750 | ) { |
1b1a35ee XL |
1751 | let len = remaining_fields.len(); |
1752 | ||
5099ac24 FG |
1753 | let mut displayable_field_names: Vec<&str> = |
1754 | remaining_fields.keys().map(|ident| ident.as_str()).collect(); | |
1755 | // sorting &str primitives here, sort_unstable is ok | |
1756 | displayable_field_names.sort_unstable(); | |
1b1a35ee | 1757 | |
6a06907d XL |
1758 | let mut truncated_fields_error = String::new(); |
1759 | let remaining_fields_names = match &displayable_field_names[..] { | |
1760 | [field1] => format!("`{}`", field1), | |
04454e1e FG |
1761 | [field1, field2] => format!("`{field1}` and `{field2}`"), |
1762 | [field1, field2, field3] => format!("`{field1}`, `{field2}` and `{field3}`"), | |
6a06907d XL |
1763 | _ => { |
1764 | truncated_fields_error = | |
1765 | format!(" and {} other field{}", len - 3, pluralize!(len - 3)); | |
1766 | displayable_field_names | |
1767 | .iter() | |
1768 | .take(3) | |
04454e1e | 1769 | .map(|n| format!("`{n}`")) |
6a06907d XL |
1770 | .collect::<Vec<_>>() |
1771 | .join(", ") | |
1772 | } | |
1b1a35ee XL |
1773 | }; |
1774 | ||
5e7ed085 | 1775 | let mut err = struct_span_err!( |
6a06907d | 1776 | self.tcx.sess, |
1b1a35ee XL |
1777 | span, |
1778 | E0063, | |
1779 | "missing field{} {}{} in initializer of `{}`", | |
6a06907d | 1780 | pluralize!(len), |
1b1a35ee XL |
1781 | remaining_fields_names, |
1782 | truncated_fields_error, | |
1783 | adt_ty | |
5e7ed085 | 1784 | ); |
04454e1e | 1785 | err.span_label(span, format!("missing {remaining_fields_names}{truncated_fields_error}")); |
5e7ed085 FG |
1786 | |
1787 | // If the last field is a range literal, but it isn't supposed to be, then they probably | |
1788 | // meant to use functional update syntax. | |
1789 | // | |
1790 | // I don't use 'is_range_literal' because only double-sided, half-open ranges count. | |
1791 | if let Some(( | |
1792 | last, | |
1793 | ExprKind::Struct( | |
1794 | QPath::LangItem(LangItem::Range, ..), | |
1795 | &[ref range_start, ref range_end], | |
1796 | _, | |
1797 | ), | |
1798 | )) = ast_fields.last().map(|last| (last, &last.expr.kind)) && | |
1799 | let variant_field = | |
1800 | variant.fields.iter().find(|field| field.ident(self.tcx) == last.ident) && | |
1801 | let range_def_id = self.tcx.lang_items().range_struct() && | |
1802 | variant_field | |
1803 | .and_then(|field| field.ty(self.tcx, substs).ty_adt_def()) | |
1804 | .map(|adt| adt.did()) | |
1805 | != range_def_id | |
1806 | { | |
1807 | let instead = self | |
1808 | .tcx | |
1809 | .sess | |
1810 | .source_map() | |
1811 | .span_to_snippet(range_end.expr.span) | |
1812 | .map(|s| format!(" from `{s}`")) | |
064997fb | 1813 | .unwrap_or_default(); |
5e7ed085 FG |
1814 | err.span_suggestion( |
1815 | range_start.span.shrink_to_hi(), | |
1816 | &format!("to set the remaining fields{instead}, separate the last named field with a comma"), | |
923072b8 | 1817 | ",", |
5e7ed085 FG |
1818 | Applicability::MaybeIncorrect, |
1819 | ); | |
1820 | } | |
1821 | ||
1822 | err.emit(); | |
1b1a35ee XL |
1823 | } |
1824 | ||
94222f64 | 1825 | /// Report an error for a struct field expression when there are invisible fields. |
1b1a35ee | 1826 | /// |
29967ef6 | 1827 | /// ```text |
923072b8 | 1828 | /// error: cannot construct `Foo` with struct literal syntax due to private fields |
1b1a35ee XL |
1829 | /// --> src/main.rs:8:5 |
1830 | /// | | |
1831 | /// 8 | foo::Foo {}; | |
1832 | /// | ^^^^^^^^ | |
1833 | /// | |
1834 | /// error: aborting due to previous error | |
1835 | /// ``` | |
923072b8 FG |
1836 | fn report_private_fields( |
1837 | &self, | |
1838 | adt_ty: Ty<'tcx>, | |
1839 | span: Span, | |
1840 | private_fields: Vec<&ty::FieldDef>, | |
1841 | used_fields: &'tcx [hir::ExprField<'tcx>], | |
1842 | ) { | |
1843 | let mut err = self.tcx.sess.struct_span_err( | |
1b1a35ee XL |
1844 | span, |
1845 | &format!( | |
923072b8 | 1846 | "cannot construct `{adt_ty}` with struct literal syntax due to private fields", |
1b1a35ee XL |
1847 | ), |
1848 | ); | |
923072b8 FG |
1849 | let (used_private_fields, remaining_private_fields): ( |
1850 | Vec<(Symbol, Span, bool)>, | |
1851 | Vec<(Symbol, Span, bool)>, | |
1852 | ) = private_fields | |
1853 | .iter() | |
1854 | .map(|field| { | |
1855 | match used_fields.iter().find(|used_field| field.name == used_field.ident.name) { | |
1856 | Some(used_field) => (field.name, used_field.span, true), | |
1857 | None => (field.name, self.tcx.def_span(field.did), false), | |
1858 | } | |
1859 | }) | |
1860 | .partition(|field| field.2); | |
1861 | err.span_labels(used_private_fields.iter().map(|(_, span, _)| *span), "private field"); | |
1862 | if !remaining_private_fields.is_empty() { | |
1863 | let remaining_private_fields_len = remaining_private_fields.len(); | |
1864 | let names = match &remaining_private_fields | |
1865 | .iter() | |
064997fb | 1866 | .map(|(name, _, _)| name) |
923072b8 FG |
1867 | .collect::<Vec<_>>()[..] |
1868 | { | |
1869 | _ if remaining_private_fields_len > 6 => String::new(), | |
1870 | [name] => format!("`{name}` "), | |
1871 | [names @ .., last] => { | |
1872 | let names = names.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>(); | |
1873 | format!("{} and `{last}` ", names.join(", ")) | |
1874 | } | |
1875 | [] => unreachable!(), | |
1876 | }; | |
1877 | err.note(format!( | |
1878 | "... and other private field{s} {names}that {were} not provided", | |
1879 | s = pluralize!(remaining_private_fields_len), | |
1880 | were = pluralize!("was", remaining_private_fields_len), | |
1881 | )); | |
1882 | } | |
1883 | err.emit(); | |
1b1a35ee XL |
1884 | } |
1885 | ||
dc9dc135 XL |
1886 | fn report_unknown_field( |
1887 | &self, | |
1888 | ty: Ty<'tcx>, | |
1889 | variant: &'tcx ty::VariantDef, | |
6a06907d XL |
1890 | field: &hir::ExprField<'_>, |
1891 | skip_fields: &[hir::ExprField<'_>], | |
dc9dc135 | 1892 | kind_name: &str, |
c295e0f8 | 1893 | expr_span: Span, |
dc9dc135 | 1894 | ) { |
1b1a35ee | 1895 | if variant.is_recovered() { |
dfeec247 | 1896 | self.set_tainted_by_errors(); |
dc9dc135 XL |
1897 | return; |
1898 | } | |
1899 | let mut err = self.type_error_struct_with_diag( | |
1900 | field.ident.span, | |
1b1a35ee | 1901 | |actual| match ty.kind() { |
dfeec247 XL |
1902 | ty::Adt(adt, ..) if adt.is_enum() => struct_span_err!( |
1903 | self.tcx.sess, | |
1904 | field.ident.span, | |
1905 | E0559, | |
1906 | "{} `{}::{}` has no field named `{}`", | |
1907 | kind_name, | |
1908 | actual, | |
5099ac24 | 1909 | variant.name, |
dfeec247 XL |
1910 | field.ident |
1911 | ), | |
1912 | _ => struct_span_err!( | |
1913 | self.tcx.sess, | |
1914 | field.ident.span, | |
1915 | E0560, | |
1916 | "{} `{}` has no field named `{}`", | |
1917 | kind_name, | |
1918 | actual, | |
1919 | field.ident | |
1920 | ), | |
dc9dc135 | 1921 | }, |
dfeec247 XL |
1922 | ty, |
1923 | ); | |
5099ac24 FG |
1924 | |
1925 | let variant_ident_span = self.tcx.def_ident_span(variant.def_id).unwrap(); | |
dc9dc135 | 1926 | match variant.ctor_kind { |
5869c6ff XL |
1927 | CtorKind::Fn => match ty.kind() { |
1928 | ty::Adt(adt, ..) if adt.is_enum() => { | |
1929 | err.span_label( | |
5099ac24 | 1930 | variant_ident_span, |
5869c6ff XL |
1931 | format!( |
1932 | "`{adt}::{variant}` defined here", | |
1933 | adt = ty, | |
5099ac24 | 1934 | variant = variant.name, |
5869c6ff XL |
1935 | ), |
1936 | ); | |
1937 | err.span_label(field.ident.span, "field does not exist"); | |
c295e0f8 XL |
1938 | err.span_suggestion_verbose( |
1939 | expr_span, | |
6a06907d XL |
1940 | &format!( |
1941 | "`{adt}::{variant}` is a tuple {kind_name}, use the appropriate syntax", | |
1942 | adt = ty, | |
5099ac24 | 1943 | variant = variant.name, |
6a06907d | 1944 | ), |
5869c6ff | 1945 | format!( |
6a06907d | 1946 | "{adt}::{variant}(/* fields */)", |
5869c6ff | 1947 | adt = ty, |
5099ac24 | 1948 | variant = variant.name, |
5869c6ff | 1949 | ), |
6a06907d | 1950 | Applicability::HasPlaceholders, |
5869c6ff XL |
1951 | ); |
1952 | } | |
1953 | _ => { | |
5099ac24 | 1954 | err.span_label(variant_ident_span, format!("`{adt}` defined here", adt = ty)); |
5869c6ff | 1955 | err.span_label(field.ident.span, "field does not exist"); |
c295e0f8 XL |
1956 | err.span_suggestion_verbose( |
1957 | expr_span, | |
6a06907d XL |
1958 | &format!( |
1959 | "`{adt}` is a tuple {kind_name}, use the appropriate syntax", | |
5869c6ff | 1960 | adt = ty, |
6a06907d | 1961 | kind_name = kind_name, |
5869c6ff | 1962 | ), |
6a06907d XL |
1963 | format!("{adt}(/* fields */)", adt = ty), |
1964 | Applicability::HasPlaceholders, | |
5869c6ff XL |
1965 | ); |
1966 | } | |
1967 | }, | |
dc9dc135 XL |
1968 | _ => { |
1969 | // prevent all specified fields from being suggested | |
6a06907d | 1970 | let skip_fields = skip_fields.iter().map(|x| x.ident.name); |
5099ac24 FG |
1971 | if let Some(field_name) = self.suggest_field_name( |
1972 | variant, | |
1973 | field.ident.name, | |
1974 | skip_fields.collect(), | |
1975 | expr_span, | |
1976 | ) { | |
dc9dc135 XL |
1977 | err.span_suggestion( |
1978 | field.ident.span, | |
1979 | "a field with a similar name exists", | |
923072b8 | 1980 | field_name, |
dc9dc135 XL |
1981 | Applicability::MaybeIncorrect, |
1982 | ); | |
1983 | } else { | |
1b1a35ee | 1984 | match ty.kind() { |
dc9dc135 XL |
1985 | ty::Adt(adt, ..) => { |
1986 | if adt.is_enum() { | |
dfeec247 XL |
1987 | err.span_label( |
1988 | field.ident.span, | |
5099ac24 | 1989 | format!("`{}::{}` does not have this field", ty, variant.name), |
dfeec247 | 1990 | ); |
dc9dc135 | 1991 | } else { |
dfeec247 XL |
1992 | err.span_label( |
1993 | field.ident.span, | |
04454e1e | 1994 | format!("`{ty}` does not have this field"), |
dfeec247 | 1995 | ); |
dc9dc135 | 1996 | } |
5099ac24 FG |
1997 | let available_field_names = |
1998 | self.available_field_names(variant, expr_span); | |
dc9dc135 | 1999 | if !available_field_names.is_empty() { |
dfeec247 XL |
2000 | err.note(&format!( |
2001 | "available fields are: {}", | |
2002 | self.name_series_display(available_field_names) | |
2003 | )); | |
dc9dc135 XL |
2004 | } |
2005 | } | |
dfeec247 | 2006 | _ => bug!("non-ADT passed to report_unknown_field"), |
dc9dc135 XL |
2007 | } |
2008 | }; | |
2009 | } | |
2010 | } | |
2011 | err.emit(); | |
2012 | } | |
2013 | ||
5099ac24 | 2014 | // Return a hint about the closest match in field names |
dfeec247 | 2015 | fn suggest_field_name( |
5099ac24 | 2016 | &self, |
dfeec247 | 2017 | variant: &'tcx ty::VariantDef, |
3dfed10e | 2018 | field: Symbol, |
dfeec247 | 2019 | skip: Vec<Symbol>, |
5099ac24 FG |
2020 | // The span where stability will be checked |
2021 | span: Span, | |
dfeec247 | 2022 | ) -> Option<Symbol> { |
fc512014 XL |
2023 | let names = variant |
2024 | .fields | |
2025 | .iter() | |
2026 | .filter_map(|field| { | |
2027 | // ignore already set fields and private fields from non-local crates | |
5099ac24 FG |
2028 | // and unstable fields. |
2029 | if skip.iter().any(|&x| x == field.name) | |
3c0e092e | 2030 | || (!variant.def_id.is_local() && !field.vis.is_public()) |
5099ac24 FG |
2031 | || matches!( |
2032 | self.tcx.eval_stability(field.did, None, span, None), | |
2033 | stability::EvalResult::Deny { .. } | |
2034 | ) | |
fc512014 XL |
2035 | { |
2036 | None | |
2037 | } else { | |
5099ac24 | 2038 | Some(field.name) |
fc512014 XL |
2039 | } |
2040 | }) | |
2041 | .collect::<Vec<Symbol>>(); | |
dc9dc135 | 2042 | |
fc512014 | 2043 | find_best_match_for_name(&names, field, None) |
dc9dc135 XL |
2044 | } |
2045 | ||
5099ac24 FG |
2046 | fn available_field_names( |
2047 | &self, | |
2048 | variant: &'tcx ty::VariantDef, | |
2049 | access_span: Span, | |
2050 | ) -> Vec<Symbol> { | |
dfeec247 XL |
2051 | variant |
2052 | .fields | |
2053 | .iter() | |
2054 | .filter(|field| { | |
2055 | let def_scope = self | |
2056 | .tcx | |
5099ac24 | 2057 | .adjust_ident_and_get_scope(field.ident(self.tcx), variant.def_id, self.body_id) |
dfeec247 XL |
2058 | .1; |
2059 | field.vis.is_accessible_from(def_scope, self.tcx) | |
5099ac24 FG |
2060 | && !matches!( |
2061 | self.tcx.eval_stability(field.did, None, access_span, None), | |
2062 | stability::EvalResult::Deny { .. } | |
2063 | ) | |
dfeec247 | 2064 | }) |
5099ac24 FG |
2065 | .filter(|field| !self.tcx.is_doc_hidden(field.did)) |
2066 | .map(|field| field.name) | |
dfeec247 | 2067 | .collect() |
dc9dc135 XL |
2068 | } |
2069 | ||
f9f354fc | 2070 | fn name_series_display(&self, names: Vec<Symbol>) -> String { |
dc9dc135 XL |
2071 | // dynamic limit, to never omit just one field |
2072 | let limit = if names.len() == 6 { 6 } else { 5 }; | |
dfeec247 XL |
2073 | let mut display = |
2074 | names.iter().take(limit).map(|n| format!("`{}`", n)).collect::<Vec<_>>().join(", "); | |
dc9dc135 XL |
2075 | if names.len() > limit { |
2076 | display = format!("{} ... and {} others", display, names.len() - limit); | |
2077 | } | |
2078 | display | |
2079 | } | |
2080 | ||
2081 | // Check field access expressions | |
2082 | fn check_field( | |
2083 | &self, | |
dfeec247 | 2084 | expr: &'tcx hir::Expr<'tcx>, |
dfeec247 | 2085 | base: &'tcx hir::Expr<'tcx>, |
f9f354fc | 2086 | field: Ident, |
dc9dc135 | 2087 | ) -> Ty<'tcx> { |
5869c6ff | 2088 | debug!("check_field(expr: {:?}, base: {:?}, field: {:?})", expr, base, field); |
f035d41b | 2089 | let expr_t = self.check_expr(base); |
dfeec247 | 2090 | let expr_t = self.structurally_resolved_type(base.span, expr_t); |
dc9dc135 XL |
2091 | let mut private_candidate = None; |
2092 | let mut autoderef = self.autoderef(expr.span, expr_t); | |
2093 | while let Some((base_t, _)) = autoderef.next() { | |
5869c6ff | 2094 | debug!("base_t: {:?}", base_t); |
1b1a35ee | 2095 | match base_t.kind() { |
dc9dc135 | 2096 | ty::Adt(base_def, substs) if !base_def.is_enum() => { |
dfeec247 | 2097 | debug!("struct named {:?}", base_t); |
dc9dc135 | 2098 | let (ident, def_scope) = |
5e7ed085 | 2099 | self.tcx.adjust_ident_and_get_scope(field, base_def.did(), self.body_id); |
dc9dc135 | 2100 | let fields = &base_def.non_enum_variant().fields; |
5099ac24 FG |
2101 | if let Some(index) = fields |
2102 | .iter() | |
2103 | .position(|f| f.ident(self.tcx).normalize_to_macros_2_0() == ident) | |
ba9703b0 | 2104 | { |
dc9dc135 XL |
2105 | let field = &fields[index]; |
2106 | let field_ty = self.field_ty(expr.span, field, substs); | |
2107 | // Save the index of all fields regardless of their visibility in case | |
2108 | // of error recovery. | |
2109 | self.write_field_index(expr.hir_id, index); | |
c295e0f8 | 2110 | let adjustments = self.adjust_steps(&autoderef); |
dc9dc135 | 2111 | if field.vis.is_accessible_from(def_scope, self.tcx) { |
dc9dc135 | 2112 | self.apply_adjustments(base, adjustments); |
f035d41b | 2113 | self.register_predicates(autoderef.into_obligations()); |
dc9dc135 | 2114 | |
17df50a5 | 2115 | self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None); |
dc9dc135 XL |
2116 | return field_ty; |
2117 | } | |
5e7ed085 | 2118 | private_candidate = Some((adjustments, base_def.did(), field_ty)); |
dc9dc135 XL |
2119 | } |
2120 | } | |
6a06907d | 2121 | ty::Tuple(tys) => { |
dc9dc135 XL |
2122 | let fstr = field.as_str(); |
2123 | if let Ok(index) = fstr.parse::<usize>() { | |
2124 | if fstr == index.to_string() { | |
5e7ed085 | 2125 | if let Some(&field_ty) = tys.get(index) { |
f035d41b | 2126 | let adjustments = self.adjust_steps(&autoderef); |
dc9dc135 | 2127 | self.apply_adjustments(base, adjustments); |
f035d41b | 2128 | self.register_predicates(autoderef.into_obligations()); |
dc9dc135 XL |
2129 | |
2130 | self.write_field_index(expr.hir_id, index); | |
5e7ed085 | 2131 | return field_ty; |
dc9dc135 XL |
2132 | } |
2133 | } | |
2134 | } | |
2135 | } | |
2136 | _ => {} | |
2137 | } | |
2138 | } | |
f035d41b | 2139 | self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false)); |
dc9dc135 | 2140 | |
c295e0f8 XL |
2141 | if let Some((adjustments, did, field_ty)) = private_candidate { |
2142 | // (#90483) apply adjustments to avoid ExprUseVisitor from | |
2143 | // creating erroneous projection. | |
2144 | self.apply_adjustments(base, adjustments); | |
e1599b0c XL |
2145 | self.ban_private_field_access(expr, expr_t, field, did); |
2146 | return field_ty; | |
2147 | } | |
2148 | ||
5869c6ff | 2149 | if field.name == kw::Empty { |
dc9dc135 | 2150 | } else if self.method_exists(field, expr_t, expr.hir_id, true) { |
e1599b0c XL |
2151 | self.ban_take_value_of_method(expr, expr_t, field); |
2152 | } else if !expr_t.is_primitive_ty() { | |
e74abb32 | 2153 | self.ban_nonexisting_field(field, base, expr, expr_t); |
dc9dc135 | 2154 | } else { |
064997fb FG |
2155 | let field_name = field.to_string(); |
2156 | let mut err = type_error_struct!( | |
e1599b0c XL |
2157 | self.tcx().sess, |
2158 | field.span, | |
2159 | expr_t, | |
2160 | E0610, | |
04454e1e | 2161 | "`{expr_t}` is a primitive type and therefore doesn't have fields", |
064997fb FG |
2162 | ); |
2163 | let is_valid_suffix = |field: String| { | |
2164 | if field == "f32" || field == "f64" { | |
2165 | return true; | |
2166 | } | |
2167 | let mut chars = field.chars().peekable(); | |
2168 | match chars.peek() { | |
2169 | Some('e') | Some('E') => { | |
2170 | chars.next(); | |
2171 | if let Some(c) = chars.peek() | |
2172 | && !c.is_numeric() && *c != '-' && *c != '+' | |
2173 | { | |
2174 | return false; | |
2175 | } | |
2176 | while let Some(c) = chars.peek() { | |
2177 | if !c.is_numeric() { | |
2178 | break; | |
2179 | } | |
2180 | chars.next(); | |
2181 | } | |
2182 | } | |
2183 | _ => (), | |
2184 | } | |
2185 | let suffix = chars.collect::<String>(); | |
2186 | suffix.is_empty() || suffix == "f32" || suffix == "f64" | |
2187 | }; | |
2188 | if let ty::Infer(ty::IntVar(_)) = expr_t.kind() | |
2189 | && let ExprKind::Lit(Spanned { | |
2190 | node: ast::LitKind::Int(_, ast::LitIntType::Unsuffixed), | |
2191 | .. | |
2192 | }) = base.kind | |
2193 | && !base.span.from_expansion() | |
2194 | && is_valid_suffix(field_name) | |
2195 | { | |
2196 | err.span_suggestion_verbose( | |
2197 | field.span.shrink_to_lo(), | |
2198 | "If the number is meant to be a floating point number, consider adding a `0` after the period", | |
2199 | '0', | |
2200 | Applicability::MaybeIncorrect, | |
2201 | ); | |
2202 | } | |
2203 | err.emit(); | |
e1599b0c XL |
2204 | } |
2205 | ||
f035d41b | 2206 | self.tcx().ty_error() |
e1599b0c XL |
2207 | } |
2208 | ||
04454e1e FG |
2209 | fn check_call_constructor<G: EmissionGuarantee>( |
2210 | &self, | |
2211 | err: &mut DiagnosticBuilder<'_, G>, | |
2212 | base: &'tcx hir::Expr<'tcx>, | |
2213 | def_id: DefId, | |
2214 | ) { | |
2215 | if let Some(local_id) = def_id.as_local() { | |
2216 | let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_id); | |
2217 | let node = self.tcx.hir().get(hir_id); | |
2218 | ||
2219 | if let Some(fields) = node.tuple_fields() { | |
2220 | let kind = match self.tcx.opt_def_kind(local_id) { | |
2221 | Some(DefKind::Ctor(of, _)) => of, | |
2222 | _ => return, | |
2223 | }; | |
2224 | ||
2225 | suggest_call_constructor(base.span, kind, fields.len(), err); | |
2226 | } | |
2227 | } else { | |
2228 | // The logic here isn't smart but `associated_item_def_ids` | |
2229 | // doesn't work nicely on local. | |
2230 | if let DefKind::Ctor(of, _) = self.tcx.def_kind(def_id) { | |
2231 | let parent_def_id = self.tcx.parent(def_id); | |
2232 | let fields = self.tcx.associated_item_def_ids(parent_def_id); | |
2233 | suggest_call_constructor(base.span, of, fields.len(), err); | |
2234 | } | |
2235 | } | |
2236 | } | |
2237 | ||
1b1a35ee XL |
2238 | fn suggest_await_on_field_access( |
2239 | &self, | |
5e7ed085 | 2240 | err: &mut Diagnostic, |
1b1a35ee XL |
2241 | field_ident: Ident, |
2242 | base: &'tcx hir::Expr<'tcx>, | |
29967ef6 | 2243 | ty: Ty<'tcx>, |
1b1a35ee | 2244 | ) { |
064997fb | 2245 | let output_ty = match self.get_impl_future_output_ty(ty) { |
fc512014 | 2246 | Some(output_ty) => self.resolve_vars_if_possible(output_ty), |
29967ef6 XL |
2247 | _ => return, |
2248 | }; | |
2249 | let mut add_label = true; | |
5099ac24 | 2250 | if let ty::Adt(def, _) = output_ty.skip_binder().kind() { |
29967ef6 XL |
2251 | // no field access on enum type |
2252 | if !def.is_enum() { | |
5099ac24 FG |
2253 | if def |
2254 | .non_enum_variant() | |
2255 | .fields | |
2256 | .iter() | |
2257 | .any(|field| field.ident(self.tcx) == field_ident) | |
2258 | { | |
29967ef6 XL |
2259 | add_label = false; |
2260 | err.span_label( | |
2261 | field_ident.span, | |
2262 | "field not available in `impl Future`, but it is available in its `Output`", | |
2263 | ); | |
2264 | err.span_suggestion_verbose( | |
2265 | base.span.shrink_to_hi(), | |
2266 | "consider `await`ing on the `Future` and access the field of its `Output`", | |
923072b8 | 2267 | ".await", |
29967ef6 XL |
2268 | Applicability::MaybeIncorrect, |
2269 | ); | |
1b1a35ee XL |
2270 | } |
2271 | } | |
2272 | } | |
29967ef6 | 2273 | if add_label { |
04454e1e | 2274 | err.span_label(field_ident.span, &format!("field not found in `{ty}`")); |
29967ef6 | 2275 | } |
1b1a35ee XL |
2276 | } |
2277 | ||
e74abb32 XL |
2278 | fn ban_nonexisting_field( |
2279 | &self, | |
f9f354fc | 2280 | field: Ident, |
dfeec247 XL |
2281 | base: &'tcx hir::Expr<'tcx>, |
2282 | expr: &'tcx hir::Expr<'tcx>, | |
e74abb32 XL |
2283 | expr_t: Ty<'tcx>, |
2284 | ) { | |
1b1a35ee XL |
2285 | debug!( |
2286 | "ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, expr_ty={:?}", | |
2287 | field, base, expr, expr_t | |
2288 | ); | |
5099ac24 | 2289 | let mut err = self.no_such_field_err(field, expr_t, base.hir_id); |
e74abb32 | 2290 | |
1b1a35ee | 2291 | match *expr_t.peel_refs().kind() { |
e74abb32 XL |
2292 | ty::Array(_, len) => { |
2293 | self.maybe_suggest_array_indexing(&mut err, expr, base, field, len); | |
2294 | } | |
2295 | ty::RawPtr(..) => { | |
2296 | self.suggest_first_deref_field(&mut err, expr, base, field); | |
2297 | } | |
2298 | ty::Adt(def, _) if !def.is_enum() => { | |
5099ac24 | 2299 | self.suggest_fields_on_recordish(&mut err, def, field, expr.span); |
e74abb32 XL |
2300 | } |
2301 | ty::Param(param_ty) => { | |
2302 | self.point_at_param_definition(&mut err, param_ty); | |
2303 | } | |
29967ef6 XL |
2304 | ty::Opaque(_, _) => { |
2305 | self.suggest_await_on_field_access(&mut err, field, base, expr_t.peel_refs()); | |
1b1a35ee | 2306 | } |
04454e1e FG |
2307 | ty::FnDef(def_id, _) => { |
2308 | self.check_call_constructor(&mut err, base, def_id); | |
2309 | } | |
e74abb32 XL |
2310 | _ => {} |
2311 | } | |
2312 | ||
2313 | if field.name == kw::Await { | |
2314 | // We know by construction that `<expr>.await` is either on Rust 2015 | |
2315 | // or results in `ExprKind::Await`. Suggest switching the edition to 2018. | |
5869c6ff | 2316 | err.note("to `.await` a `Future`, switch to Rust 2018 or later"); |
5e7ed085 | 2317 | err.help_use_latest_edition(); |
e74abb32 XL |
2318 | } |
2319 | ||
2320 | err.emit(); | |
2321 | } | |
2322 | ||
e1599b0c XL |
2323 | fn ban_private_field_access( |
2324 | &self, | |
dfeec247 | 2325 | expr: &hir::Expr<'_>, |
e1599b0c | 2326 | expr_t: Ty<'tcx>, |
f9f354fc | 2327 | field: Ident, |
e1599b0c XL |
2328 | base_did: DefId, |
2329 | ) { | |
2330 | let struct_path = self.tcx().def_path_str(base_did); | |
f9f354fc | 2331 | let kind_name = self.tcx().def_kind(base_did).descr(base_did); |
e1599b0c XL |
2332 | let mut err = struct_span_err!( |
2333 | self.tcx().sess, | |
ba9703b0 | 2334 | field.span, |
e1599b0c | 2335 | E0616, |
04454e1e | 2336 | "field `{field}` of {kind_name} `{struct_path}` is private", |
e1599b0c | 2337 | ); |
ba9703b0 | 2338 | err.span_label(field.span, "private field"); |
e1599b0c | 2339 | // Also check if an accessible method exists, which is often what is meant. |
dfeec247 | 2340 | if self.method_exists(field, expr_t, expr.hir_id, false) && !self.expr_in_place(expr.hir_id) |
e1599b0c XL |
2341 | { |
2342 | self.suggest_method_call( | |
2343 | &mut err, | |
04454e1e | 2344 | &format!("a method `{field}` also exists, call it with parentheses"), |
e1599b0c XL |
2345 | field, |
2346 | expr_t, | |
74b04a01 | 2347 | expr, |
c295e0f8 | 2348 | None, |
e1599b0c XL |
2349 | ); |
2350 | } | |
2351 | err.emit(); | |
2352 | } | |
2353 | ||
f9f354fc | 2354 | fn ban_take_value_of_method(&self, expr: &hir::Expr<'_>, expr_t: Ty<'tcx>, field: Ident) { |
e1599b0c XL |
2355 | let mut err = type_error_struct!( |
2356 | self.tcx().sess, | |
2357 | field.span, | |
2358 | expr_t, | |
2359 | E0615, | |
04454e1e | 2360 | "attempted to take value of method `{field}` on type `{expr_t}`", |
e1599b0c | 2361 | ); |
ba9703b0 | 2362 | err.span_label(field.span, "method, not a field"); |
c295e0f8 XL |
2363 | let expr_is_call = |
2364 | if let hir::Node::Expr(hir::Expr { kind: ExprKind::Call(callee, _args), .. }) = | |
2365 | self.tcx.hir().get(self.tcx.hir().get_parent_node(expr.hir_id)) | |
2366 | { | |
2367 | expr.hir_id == callee.hir_id | |
2368 | } else { | |
2369 | false | |
2370 | }; | |
2371 | let expr_snippet = | |
064997fb | 2372 | self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap_or_default(); |
c295e0f8 XL |
2373 | let is_wrapped = expr_snippet.starts_with('(') && expr_snippet.ends_with(')'); |
2374 | let after_open = expr.span.lo() + rustc_span::BytePos(1); | |
2375 | let before_close = expr.span.hi() - rustc_span::BytePos(1); | |
2376 | ||
2377 | if expr_is_call && is_wrapped { | |
2378 | err.multipart_suggestion( | |
2379 | "remove wrapping parentheses to call the method", | |
2380 | vec![ | |
2381 | (expr.span.with_hi(after_open), String::new()), | |
2382 | (expr.span.with_lo(before_close), String::new()), | |
2383 | ], | |
2384 | Applicability::MachineApplicable, | |
2385 | ); | |
2386 | } else if !self.expr_in_place(expr.hir_id) { | |
2387 | // Suggest call parentheses inside the wrapping parentheses | |
2388 | let span = if is_wrapped { | |
2389 | expr.span.with_lo(after_open).with_hi(before_close) | |
2390 | } else { | |
2391 | expr.span | |
2392 | }; | |
e1599b0c XL |
2393 | self.suggest_method_call( |
2394 | &mut err, | |
2395 | "use parentheses to call the method", | |
2396 | field, | |
2397 | expr_t, | |
74b04a01 | 2398 | expr, |
c295e0f8 | 2399 | Some(span), |
e1599b0c XL |
2400 | ); |
2401 | } else { | |
a2a8927a XL |
2402 | let mut found = false; |
2403 | ||
04454e1e FG |
2404 | if let ty::RawPtr(ty_and_mut) = expr_t.kind() |
2405 | && let ty::Adt(adt_def, _) = ty_and_mut.ty.kind() | |
2406 | { | |
2407 | if adt_def.variants().len() == 1 | |
2408 | && adt_def | |
2409 | .variants() | |
2410 | .iter() | |
2411 | .next() | |
2412 | .unwrap() | |
2413 | .fields | |
2414 | .iter() | |
2415 | .any(|f| f.ident(self.tcx) == field) | |
2416 | { | |
2417 | if let Some(dot_loc) = expr_snippet.rfind('.') { | |
2418 | found = true; | |
2419 | err.span_suggestion( | |
2420 | expr.span.with_hi(expr.span.lo() + BytePos::from_usize(dot_loc)), | |
2421 | "to access the field, dereference first", | |
2422 | format!("(*{})", &expr_snippet[0..dot_loc]), | |
2423 | Applicability::MaybeIncorrect, | |
2424 | ); | |
a2a8927a XL |
2425 | } |
2426 | } | |
2427 | } | |
2428 | ||
2429 | if !found { | |
2430 | err.help("methods are immutable and cannot be assigned to"); | |
2431 | } | |
e1599b0c XL |
2432 | } |
2433 | ||
2434 | err.emit(); | |
2435 | } | |
2436 | ||
5e7ed085 | 2437 | fn point_at_param_definition(&self, err: &mut Diagnostic, param: ty::ParamTy) { |
ba9703b0 | 2438 | let generics = self.tcx.generics_of(self.body_id.owner.to_def_id()); |
e74abb32 | 2439 | let generic_param = generics.type_param(¶m, self.tcx); |
3c0e092e | 2440 | if let ty::GenericParamDefKind::Type { synthetic: true, .. } = generic_param.kind { |
e74abb32 XL |
2441 | return; |
2442 | } | |
2443 | let param_def_id = generic_param.def_id; | |
f9f354fc | 2444 | let param_hir_id = match param_def_id.as_local() { |
3dfed10e | 2445 | Some(x) => self.tcx.hir().local_def_id_to_hir_id(x), |
dfeec247 | 2446 | None => return, |
e74abb32 XL |
2447 | }; |
2448 | let param_span = self.tcx.hir().span(param_hir_id); | |
04454e1e | 2449 | let param_name = self.tcx.hir().ty_param_name(param_def_id.expect_local()); |
e74abb32 | 2450 | |
04454e1e | 2451 | err.span_label(param_span, &format!("type parameter '{param_name}' declared here")); |
e74abb32 XL |
2452 | } |
2453 | ||
e1599b0c XL |
2454 | fn suggest_fields_on_recordish( |
2455 | &self, | |
5e7ed085 FG |
2456 | err: &mut Diagnostic, |
2457 | def: ty::AdtDef<'tcx>, | |
f9f354fc | 2458 | field: Ident, |
5099ac24 | 2459 | access_span: Span, |
e1599b0c XL |
2460 | ) { |
2461 | if let Some(suggested_field_name) = | |
5099ac24 | 2462 | self.suggest_field_name(def.non_enum_variant(), field.name, vec![], access_span) |
e1599b0c XL |
2463 | { |
2464 | err.span_suggestion( | |
2465 | field.span, | |
2466 | "a field with a similar name exists", | |
923072b8 | 2467 | suggested_field_name, |
e1599b0c XL |
2468 | Applicability::MaybeIncorrect, |
2469 | ); | |
2470 | } else { | |
2471 | err.span_label(field.span, "unknown field"); | |
2472 | let struct_variant_def = def.non_enum_variant(); | |
5099ac24 | 2473 | let field_names = self.available_field_names(struct_variant_def, access_span); |
e1599b0c XL |
2474 | if !field_names.is_empty() { |
2475 | err.note(&format!( | |
2476 | "available fields are: {}", | |
2477 | self.name_series_display(field_names), | |
2478 | )); | |
2479 | } | |
2480 | } | |
2481 | } | |
2482 | ||
2483 | fn maybe_suggest_array_indexing( | |
2484 | &self, | |
5e7ed085 | 2485 | err: &mut Diagnostic, |
dfeec247 XL |
2486 | expr: &hir::Expr<'_>, |
2487 | base: &hir::Expr<'_>, | |
f9f354fc | 2488 | field: Ident, |
5099ac24 | 2489 | len: ty::Const<'tcx>, |
e1599b0c | 2490 | ) { |
dfeec247 XL |
2491 | if let (Some(len), Ok(user_index)) = |
2492 | (len.try_eval_usize(self.tcx, self.param_env), field.as_str().parse::<u64>()) | |
04454e1e | 2493 | && let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span) |
dfeec247 | 2494 | { |
04454e1e FG |
2495 | let help = "instead of using tuple indexing, use array indexing"; |
2496 | let suggestion = format!("{base}[{field}]"); | |
2497 | let applicability = if len < user_index { | |
2498 | Applicability::MachineApplicable | |
2499 | } else { | |
2500 | Applicability::MaybeIncorrect | |
2501 | }; | |
2502 | err.span_suggestion(expr.span, help, suggestion, applicability); | |
dc9dc135 XL |
2503 | } |
2504 | } | |
2505 | ||
e1599b0c XL |
2506 | fn suggest_first_deref_field( |
2507 | &self, | |
5e7ed085 | 2508 | err: &mut Diagnostic, |
dfeec247 XL |
2509 | expr: &hir::Expr<'_>, |
2510 | base: &hir::Expr<'_>, | |
f9f354fc | 2511 | field: Ident, |
e1599b0c | 2512 | ) { |
ba9703b0 | 2513 | if let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span) { |
04454e1e FG |
2514 | let msg = format!("`{base}` is a raw pointer; try dereferencing it"); |
2515 | let suggestion = format!("(*{base}).{field}"); | |
ba9703b0 XL |
2516 | err.span_suggestion(expr.span, &msg, suggestion, Applicability::MaybeIncorrect); |
2517 | } | |
e1599b0c XL |
2518 | } |
2519 | ||
5869c6ff | 2520 | fn no_such_field_err( |
dfeec247 | 2521 | &self, |
5869c6ff | 2522 | field: Ident, |
5099ac24 FG |
2523 | expr_t: Ty<'tcx>, |
2524 | id: HirId, | |
5e7ed085 | 2525 | ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { |
5869c6ff XL |
2526 | let span = field.span; |
2527 | debug!("no_such_field_err(span: {:?}, field: {:?}, expr_t: {:?})", span, field, expr_t); | |
2528 | ||
2529 | let mut err = type_error_struct!( | |
dfeec247 | 2530 | self.tcx().sess, |
5869c6ff | 2531 | field.span, |
dfeec247 XL |
2532 | expr_t, |
2533 | E0609, | |
04454e1e | 2534 | "no field `{field}` on type `{expr_t}`", |
5869c6ff XL |
2535 | ); |
2536 | ||
2537 | // try to add a suggestion in case the field is a nested field of a field of the Adt | |
5099ac24 | 2538 | if let Some((fields, substs)) = self.get_field_candidates(span, expr_t) { |
5869c6ff | 2539 | for candidate_field in fields.iter() { |
04454e1e | 2540 | if let Some(mut field_path) = self.check_for_nested_field_satisfying( |
5099ac24 | 2541 | span, |
04454e1e | 2542 | &|candidate_field, _| candidate_field.ident(self.tcx()) == field, |
5099ac24 FG |
2543 | candidate_field, |
2544 | substs, | |
2545 | vec![], | |
2546 | self.tcx.parent_module(id).to_def_id(), | |
2547 | ) { | |
04454e1e FG |
2548 | // field_path includes `field` that we're looking for, so pop it. |
2549 | field_path.pop(); | |
2550 | ||
5869c6ff XL |
2551 | let field_path_str = field_path |
2552 | .iter() | |
2553 | .map(|id| id.name.to_ident_string()) | |
2554 | .collect::<Vec<String>>() | |
2555 | .join("."); | |
2556 | debug!("field_path_str: {:?}", field_path_str); | |
2557 | ||
2558 | err.span_suggestion_verbose( | |
2559 | field.span.shrink_to_lo(), | |
2560 | "one of the expressions' fields has a field of the same name", | |
04454e1e | 2561 | format!("{field_path_str}."), |
5869c6ff XL |
2562 | Applicability::MaybeIncorrect, |
2563 | ); | |
2564 | } | |
2565 | } | |
2566 | } | |
2567 | err | |
2568 | } | |
2569 | ||
923072b8 | 2570 | pub(crate) fn get_field_candidates( |
5869c6ff XL |
2571 | &self, |
2572 | span: Span, | |
2573 | base_t: Ty<'tcx>, | |
923072b8 | 2574 | ) -> Option<(&[ty::FieldDef], SubstsRef<'tcx>)> { |
5869c6ff XL |
2575 | debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_t); |
2576 | ||
3c0e092e | 2577 | for (base_t, _) in self.autoderef(span, base_t) { |
5869c6ff XL |
2578 | match base_t.kind() { |
2579 | ty::Adt(base_def, substs) if !base_def.is_enum() => { | |
2580 | let fields = &base_def.non_enum_variant().fields; | |
2581 | // For compile-time reasons put a limit on number of fields we search | |
2582 | if fields.len() > 100 { | |
2583 | return None; | |
2584 | } | |
2585 | return Some((fields, substs)); | |
2586 | } | |
2587 | _ => {} | |
2588 | } | |
2589 | } | |
2590 | None | |
2591 | } | |
2592 | ||
2593 | /// This method is called after we have encountered a missing field error to recursively | |
2594 | /// search for the field | |
923072b8 | 2595 | pub(crate) fn check_for_nested_field_satisfying( |
5869c6ff XL |
2596 | &self, |
2597 | span: Span, | |
04454e1e | 2598 | matches: &impl Fn(&ty::FieldDef, Ty<'tcx>) -> bool, |
5869c6ff XL |
2599 | candidate_field: &ty::FieldDef, |
2600 | subst: SubstsRef<'tcx>, | |
2601 | mut field_path: Vec<Ident>, | |
5099ac24 | 2602 | id: DefId, |
5869c6ff XL |
2603 | ) -> Option<Vec<Ident>> { |
2604 | debug!( | |
04454e1e | 2605 | "check_for_nested_field_satisfying(span: {:?}, candidate_field: {:?}, field_path: {:?}", |
5869c6ff XL |
2606 | span, candidate_field, field_path |
2607 | ); | |
2608 | ||
04454e1e | 2609 | if field_path.len() > 3 { |
5869c6ff XL |
2610 | // For compile-time reasons and to avoid infinite recursion we only check for fields |
2611 | // up to a depth of three | |
2612 | None | |
2613 | } else { | |
2614 | // recursively search fields of `candidate_field` if it's a ty::Adt | |
5099ac24 | 2615 | field_path.push(candidate_field.ident(self.tcx).normalize_to_macros_2_0()); |
5869c6ff | 2616 | let field_ty = candidate_field.ty(self.tcx, subst); |
5099ac24 | 2617 | if let Some((nested_fields, subst)) = self.get_field_candidates(span, field_ty) { |
5869c6ff | 2618 | for field in nested_fields.iter() { |
04454e1e FG |
2619 | if field.vis.is_accessible_from(id, self.tcx) { |
2620 | if matches(candidate_field, field_ty) { | |
5099ac24 | 2621 | return Some(field_path); |
04454e1e | 2622 | } else if let Some(field_path) = self.check_for_nested_field_satisfying( |
5869c6ff | 2623 | span, |
04454e1e | 2624 | matches, |
5869c6ff XL |
2625 | field, |
2626 | subst, | |
04454e1e | 2627 | field_path.clone(), |
5099ac24 | 2628 | id, |
5869c6ff | 2629 | ) { |
04454e1e | 2630 | return Some(field_path); |
5869c6ff XL |
2631 | } |
2632 | } | |
2633 | } | |
2634 | } | |
2635 | None | |
2636 | } | |
dc9dc135 XL |
2637 | } |
2638 | ||
2639 | fn check_expr_index( | |
2640 | &self, | |
dfeec247 XL |
2641 | base: &'tcx hir::Expr<'tcx>, |
2642 | idx: &'tcx hir::Expr<'tcx>, | |
dfeec247 | 2643 | expr: &'tcx hir::Expr<'tcx>, |
dc9dc135 | 2644 | ) -> Ty<'tcx> { |
f035d41b | 2645 | let base_t = self.check_expr(&base); |
dc9dc135 XL |
2646 | let idx_t = self.check_expr(&idx); |
2647 | ||
2648 | if base_t.references_error() { | |
2649 | base_t | |
2650 | } else if idx_t.references_error() { | |
2651 | idx_t | |
2652 | } else { | |
2653 | let base_t = self.structurally_resolved_type(base.span, base_t); | |
c295e0f8 | 2654 | match self.lookup_indexing(expr, base, base_t, idx, idx_t) { |
dc9dc135 XL |
2655 | Some((index_ty, element_ty)) => { |
2656 | // two-phase not needed because index_ty is never mutable | |
f035d41b | 2657 | self.demand_coerce(idx, idx_t, index_ty, None, AllowTwoPhase::No); |
064997fb FG |
2658 | self.select_obligations_where_possible(false, |errors| { |
2659 | self.point_at_index_if_possible(errors, idx.span) | |
2660 | }); | |
dc9dc135 XL |
2661 | element_ty |
2662 | } | |
2663 | None => { | |
dfeec247 XL |
2664 | let mut err = type_error_struct!( |
2665 | self.tcx.sess, | |
2666 | expr.span, | |
2667 | base_t, | |
2668 | E0608, | |
04454e1e | 2669 | "cannot index into a value of type `{base_t}`", |
dfeec247 | 2670 | ); |
dc9dc135 | 2671 | // Try to give some advice about indexing tuples. |
1b1a35ee | 2672 | if let ty::Tuple(..) = base_t.kind() { |
dc9dc135 XL |
2673 | let mut needs_note = true; |
2674 | // If the index is an integer, we can show the actual | |
2675 | // fixed expression: | |
e74abb32 | 2676 | if let ExprKind::Lit(ref lit) = idx.kind { |
dc9dc135 XL |
2677 | if let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node { |
2678 | let snip = self.tcx.sess.source_map().span_to_snippet(base.span); | |
2679 | if let Ok(snip) = snip { | |
2680 | err.span_suggestion( | |
2681 | expr.span, | |
2682 | "to access tuple elements, use", | |
04454e1e | 2683 | format!("{snip}.{i}"), |
dc9dc135 XL |
2684 | Applicability::MachineApplicable, |
2685 | ); | |
2686 | needs_note = false; | |
2687 | } | |
2688 | } | |
2689 | } | |
2690 | if needs_note { | |
dfeec247 XL |
2691 | err.help( |
2692 | "to access tuple elements, use tuple indexing \ | |
2693 | syntax (e.g., `tuple.0`)", | |
2694 | ); | |
dc9dc135 XL |
2695 | } |
2696 | } | |
2697 | err.emit(); | |
f035d41b | 2698 | self.tcx.ty_error() |
dc9dc135 XL |
2699 | } |
2700 | } | |
2701 | } | |
2702 | } | |
2703 | ||
064997fb FG |
2704 | fn point_at_index_if_possible( |
2705 | &self, | |
2706 | errors: &mut Vec<traits::FulfillmentError<'tcx>>, | |
2707 | span: Span, | |
2708 | ) { | |
2709 | for error in errors { | |
2710 | match error.obligation.predicate.kind().skip_binder() { | |
2711 | ty::PredicateKind::Trait(predicate) | |
2712 | if self.tcx.is_diagnostic_item(sym::SliceIndex, predicate.trait_ref.def_id) => { | |
2713 | } | |
2714 | _ => continue, | |
2715 | } | |
2716 | error.obligation.cause.span = span; | |
2717 | } | |
2718 | } | |
2719 | ||
dc9dc135 XL |
2720 | fn check_expr_yield( |
2721 | &self, | |
dfeec247 XL |
2722 | value: &'tcx hir::Expr<'tcx>, |
2723 | expr: &'tcx hir::Expr<'tcx>, | |
2724 | src: &'tcx hir::YieldSource, | |
dc9dc135 | 2725 | ) -> Ty<'tcx> { |
74b04a01 XL |
2726 | match self.resume_yield_tys { |
2727 | Some((resume_ty, yield_ty)) => { | |
f035d41b | 2728 | self.check_expr_coercable_to_type(&value, yield_ty, None); |
74b04a01 XL |
2729 | |
2730 | resume_ty | |
dc9dc135 XL |
2731 | } |
2732 | // Given that this `yield` expression was generated as a result of lowering a `.await`, | |
2733 | // we know that the yield type must be `()`; however, the context won't contain this | |
2734 | // information. Hence, we check the source of the yield expression here and check its | |
2735 | // value's type against `()` (this check should always hold). | |
ba9703b0 | 2736 | None if src.is_await() => { |
f035d41b | 2737 | self.check_expr_coercable_to_type(&value, self.tcx.mk_unit(), None); |
74b04a01 | 2738 | self.tcx.mk_unit() |
dc9dc135 XL |
2739 | } |
2740 | _ => { | |
1b1a35ee | 2741 | self.tcx.sess.emit_err(YieldExprOutsideOfGenerator { span: expr.span }); |
6a06907d XL |
2742 | // Avoid expressions without types during writeback (#78653). |
2743 | self.check_expr(value); | |
74b04a01 | 2744 | self.tcx.mk_unit() |
dc9dc135 XL |
2745 | } |
2746 | } | |
dc9dc135 | 2747 | } |
f9f354fc XL |
2748 | |
2749 | fn check_expr_asm_operand(&self, expr: &'tcx hir::Expr<'tcx>, is_input: bool) { | |
2750 | let needs = if is_input { Needs::None } else { Needs::MutPlace }; | |
2751 | let ty = self.check_expr_with_needs(expr, needs); | |
2752 | self.require_type_is_sized(ty, expr.span, traits::InlineAsmSized); | |
2753 | ||
2754 | if !is_input && !expr.is_syntactic_place_expr() { | |
2755 | let mut err = self.tcx.sess.struct_span_err(expr.span, "invalid asm output"); | |
2756 | err.span_label(expr.span, "cannot assign to this expression"); | |
2757 | err.emit(); | |
2758 | } | |
2759 | ||
2760 | // If this is an input value, we require its type to be fully resolved | |
2761 | // at this point. This allows us to provide helpful coercions which help | |
f035d41b | 2762 | // pass the type candidate list in a later pass. |
f9f354fc XL |
2763 | // |
2764 | // We don't require output types to be resolved at this point, which | |
2765 | // allows them to be inferred based on how they are used later in the | |
2766 | // function. | |
2767 | if is_input { | |
5099ac24 | 2768 | let ty = self.structurally_resolved_type(expr.span, ty); |
1b1a35ee | 2769 | match *ty.kind() { |
f9f354fc XL |
2770 | ty::FnDef(..) => { |
2771 | let fnptr_ty = self.tcx.mk_fn_ptr(ty.fn_sig(self.tcx)); | |
f035d41b | 2772 | self.demand_coerce(expr, ty, fnptr_ty, None, AllowTwoPhase::No); |
f9f354fc XL |
2773 | } |
2774 | ty::Ref(_, base_ty, mutbl) => { | |
2775 | let ptr_ty = self.tcx.mk_ptr(ty::TypeAndMut { ty: base_ty, mutbl }); | |
f035d41b | 2776 | self.demand_coerce(expr, ty, ptr_ty, None, AllowTwoPhase::No); |
f9f354fc XL |
2777 | } |
2778 | _ => {} | |
2779 | } | |
2780 | } | |
2781 | } | |
2782 | ||
2783 | fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>) -> Ty<'tcx> { | |
fc512014 | 2784 | for (op, _op_sp) in asm.operands { |
f9f354fc | 2785 | match op { |
cdc7bbd5 | 2786 | hir::InlineAsmOperand::In { expr, .. } => { |
f9f354fc XL |
2787 | self.check_expr_asm_operand(expr, true); |
2788 | } | |
94222f64 XL |
2789 | hir::InlineAsmOperand::Out { expr: Some(expr), .. } |
2790 | | hir::InlineAsmOperand::InOut { expr, .. } => { | |
f9f354fc XL |
2791 | self.check_expr_asm_operand(expr, false); |
2792 | } | |
94222f64 | 2793 | hir::InlineAsmOperand::Out { expr: None, .. } => {} |
f9f354fc XL |
2794 | hir::InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => { |
2795 | self.check_expr_asm_operand(in_expr, true); | |
2796 | if let Some(out_expr) = out_expr { | |
2797 | self.check_expr_asm_operand(out_expr, false); | |
2798 | } | |
2799 | } | |
923072b8 FG |
2800 | // `AnonConst`s have their own body and is type-checked separately. |
2801 | // As they don't flow into the type system we don't need them to | |
2802 | // be well-formed. | |
2803 | hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::SymFn { .. } => {} | |
04454e1e | 2804 | hir::InlineAsmOperand::SymStatic { .. } => {} |
f9f354fc XL |
2805 | } |
2806 | } | |
2807 | if asm.options.contains(ast::InlineAsmOptions::NORETURN) { | |
2808 | self.tcx.types.never | |
2809 | } else { | |
2810 | self.tcx.mk_unit() | |
2811 | } | |
2812 | } | |
dc9dc135 | 2813 | } |
60c5eb7d XL |
2814 | |
2815 | pub(super) fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> { | |
1b1a35ee | 2816 | Some(match ty.kind() { |
60c5eb7d XL |
2817 | ty::Bool => "true", |
2818 | ty::Char => "'a'", | |
2819 | ty::Int(_) | ty::Uint(_) => "42", | |
2820 | ty::Float(_) => "3.14159", | |
f035d41b | 2821 | ty::Error(_) | ty::Never => return None, |
60c5eb7d XL |
2822 | _ => "value", |
2823 | }) | |
2824 | } |