]>
Commit | Line | Data |
---|---|---|
2b03887a FG |
1 | use crate::coercion::CoerceMany; |
2 | use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx}; | |
3 | use crate::gather_locals::Declaration; | |
4 | use crate::method::MethodCallee; | |
5 | use crate::Expectation::*; | |
6 | use crate::TupleArgumentsFlag::*; | |
7 | use crate::{ | |
8 | struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, Needs, | |
9 | TupleArgumentsFlag, | |
064997fb | 10 | }; |
29967ef6 | 11 | use rustc_ast as ast; |
f2b60f7d | 12 | use rustc_data_structures::fx::FxHashSet; |
064997fb | 13 | use rustc_errors::{pluralize, Applicability, Diagnostic, DiagnosticId, MultiSpan}; |
29967ef6 | 14 | use rustc_hir as hir; |
136023e0 | 15 | use rustc_hir::def::{CtorOf, DefKind, Res}; |
29967ef6 XL |
16 | use rustc_hir::def_id::DefId; |
17 | use rustc_hir::{ExprKind, Node, QPath}; | |
2b03887a FG |
18 | use rustc_hir_analysis::astconv::AstConv; |
19 | use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt; | |
20 | use rustc_hir_analysis::check::potentially_plural_count; | |
21 | use rustc_hir_analysis::structured_errors::StructuredDiagnostic; | |
064997fb | 22 | use rustc_index::vec::IndexVec; |
923072b8 | 23 | use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt}; |
064997fb | 24 | use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; |
923072b8 FG |
25 | use rustc_infer::infer::InferOk; |
26 | use rustc_infer::infer::TypeTrace; | |
29967ef6 | 27 | use rustc_middle::ty::adjustment::AllowTwoPhase; |
064997fb | 28 | use rustc_middle::ty::visit::TypeVisitable; |
f2b60f7d | 29 | use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty, TypeSuperVisitable, TypeVisitor}; |
29967ef6 | 30 | use rustc_session::Session; |
17df50a5 | 31 | use rustc_span::symbol::Ident; |
f2b60f7d | 32 | use rustc_span::{self, sym, Span}; |
064997fb | 33 | use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}; |
29967ef6 | 34 | |
cdc7bbd5 | 35 | use std::iter; |
2b03887a | 36 | use std::mem; |
f2b60f7d | 37 | use std::ops::ControlFlow; |
29967ef6 XL |
38 | use std::slice; |
39 | ||
40 | impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |
2b03887a FG |
41 | pub(in super::super) fn check_casts(&mut self) { |
42 | // don't hold the borrow to deferred_cast_checks while checking to avoid borrow checker errors | |
43 | // when writing to `self.param_env`. | |
44 | let mut deferred_cast_checks = mem::take(&mut *self.deferred_cast_checks.borrow_mut()); | |
45 | ||
94222f64 | 46 | debug!("FnCtxt::check_casts: {} deferred checks", deferred_cast_checks.len()); |
29967ef6 | 47 | for cast in deferred_cast_checks.drain(..) { |
2b03887a FG |
48 | let prev_env = self.param_env; |
49 | self.param_env = self.param_env.with_constness(cast.constness); | |
50 | ||
29967ef6 | 51 | cast.check(self); |
2b03887a FG |
52 | |
53 | self.param_env = prev_env; | |
29967ef6 | 54 | } |
2b03887a FG |
55 | |
56 | *self.deferred_cast_checks.borrow_mut() = deferred_cast_checks; | |
29967ef6 XL |
57 | } |
58 | ||
923072b8 FG |
59 | pub(in super::super) fn check_transmutes(&self) { |
60 | let mut deferred_transmute_checks = self.deferred_transmute_checks.borrow_mut(); | |
61 | debug!("FnCtxt::check_transmutes: {} deferred checks", deferred_transmute_checks.len()); | |
2b03887a FG |
62 | for (from, to, hir_id) in deferred_transmute_checks.drain(..) { |
63 | self.check_transmute(from, to, hir_id); | |
923072b8 FG |
64 | } |
65 | } | |
66 | ||
67 | pub(in super::super) fn check_asms(&self) { | |
68 | let mut deferred_asm_checks = self.deferred_asm_checks.borrow_mut(); | |
69 | debug!("FnCtxt::check_asm: {} deferred checks", deferred_asm_checks.len()); | |
70 | for (asm, hir_id) in deferred_asm_checks.drain(..) { | |
71 | let enclosing_id = self.tcx.hir().enclosing_body_owner(hir_id); | |
f2b60f7d FG |
72 | let get_operand_ty = |expr| { |
73 | let ty = self.typeck_results.borrow().expr_ty_adjusted(expr); | |
74 | let ty = self.resolve_vars_if_possible(ty); | |
2b03887a | 75 | if ty.has_non_region_infer() { |
f2b60f7d FG |
76 | self.tcx.ty_error() |
77 | } else { | |
78 | self.tcx.erase_regions(ty) | |
79 | } | |
80 | }; | |
81 | InlineAsmCtxt::new_in_fn(self.tcx, self.param_env, get_operand_ty) | |
064997fb | 82 | .check_asm(asm, self.tcx.hir().local_def_id_to_hir_id(enclosing_id)); |
923072b8 FG |
83 | } |
84 | } | |
85 | ||
29967ef6 XL |
86 | pub(in super::super) fn check_method_argument_types( |
87 | &self, | |
88 | sp: Span, | |
89 | expr: &'tcx hir::Expr<'tcx>, | |
90 | method: Result<MethodCallee<'tcx>, ()>, | |
91 | args_no_rcvr: &'tcx [hir::Expr<'tcx>], | |
92 | tuple_arguments: TupleArgumentsFlag, | |
93 | expected: Expectation<'tcx>, | |
94 | ) -> Ty<'tcx> { | |
95 | let has_error = match method { | |
96 | Ok(method) => method.substs.references_error() || method.sig.references_error(), | |
97 | Err(_) => true, | |
98 | }; | |
99 | if has_error { | |
100 | let err_inputs = self.err_args(args_no_rcvr.len()); | |
101 | ||
102 | let err_inputs = match tuple_arguments { | |
103 | DontTupleArguments => err_inputs, | |
a2a8927a | 104 | TupleArguments => vec![self.tcx.intern_tup(&err_inputs)], |
29967ef6 XL |
105 | }; |
106 | ||
107 | self.check_argument_types( | |
108 | sp, | |
109 | expr, | |
a2a8927a | 110 | &err_inputs, |
923072b8 | 111 | None, |
29967ef6 XL |
112 | args_no_rcvr, |
113 | false, | |
114 | tuple_arguments, | |
064997fb | 115 | method.ok().map(|method| method.def_id), |
29967ef6 XL |
116 | ); |
117 | return self.tcx.ty_error(); | |
118 | } | |
119 | ||
120 | let method = method.unwrap(); | |
121 | // HACK(eddyb) ignore self in the definition (see above). | |
a2a8927a | 122 | let expected_input_tys = self.expected_inputs_for_expected_output( |
29967ef6 XL |
123 | sp, |
124 | expected, | |
125 | method.sig.output(), | |
126 | &method.sig.inputs()[1..], | |
127 | ); | |
128 | self.check_argument_types( | |
129 | sp, | |
130 | expr, | |
131 | &method.sig.inputs()[1..], | |
a2a8927a | 132 | expected_input_tys, |
29967ef6 XL |
133 | args_no_rcvr, |
134 | method.sig.c_variadic, | |
135 | tuple_arguments, | |
136 | Some(method.def_id), | |
137 | ); | |
487cf647 | 138 | |
29967ef6 XL |
139 | method.sig.output() |
140 | } | |
141 | ||
142 | /// Generic function that factors out common logic from function calls, | |
143 | /// method calls and overloaded operators. | |
144 | pub(in super::super) fn check_argument_types( | |
145 | &self, | |
a2a8927a XL |
146 | // Span enclosing the call site |
147 | call_span: Span, | |
148 | // Expression of the call site | |
149 | call_expr: &'tcx hir::Expr<'tcx>, | |
150 | // Types (as defined in the *signature* of the target function) | |
151 | formal_input_tys: &[Ty<'tcx>], | |
152 | // More specific expected types, after unifying with caller output types | |
923072b8 | 153 | expected_input_tys: Option<Vec<Ty<'tcx>>>, |
a2a8927a XL |
154 | // The expressions for each provided argument |
155 | provided_args: &'tcx [hir::Expr<'tcx>], | |
156 | // Whether the function is variadic, for example when imported from C | |
29967ef6 | 157 | c_variadic: bool, |
a2a8927a | 158 | // Whether the arguments have been bundled in a tuple (ex: closures) |
29967ef6 | 159 | tuple_arguments: TupleArgumentsFlag, |
a2a8927a XL |
160 | // The DefId for the function being called, for better error messages |
161 | fn_def_id: Option<DefId>, | |
29967ef6 XL |
162 | ) { |
163 | let tcx = self.tcx; | |
923072b8 | 164 | |
f2b60f7d | 165 | // Conceptually, we've got some number of expected inputs, and some number of provided arguments |
923072b8 FG |
166 | // and we can form a grid of whether each argument could satisfy a given input: |
167 | // in1 | in2 | in3 | ... | |
168 | // arg1 ? | | | | |
169 | // arg2 | ? | | | |
170 | // arg3 | | ? | | |
171 | // ... | |
172 | // Initially, we just check the diagonal, because in the case of correct code | |
173 | // these are the only checks that matter | |
174 | // However, in the unhappy path, we'll fill in this whole grid to attempt to provide | |
175 | // better error messages about invalid method calls. | |
29967ef6 XL |
176 | |
177 | // All the input types from the fn signature must outlive the call | |
178 | // so as to validate implied bounds. | |
a2a8927a | 179 | for (&fn_input_ty, arg_expr) in iter::zip(formal_input_tys, provided_args) { |
29967ef6 XL |
180 | self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation); |
181 | } | |
182 | ||
923072b8 | 183 | let mut err_code = "E0061"; |
29967ef6 | 184 | |
5099ac24 | 185 | // If the arguments should be wrapped in a tuple (ex: closures), unwrap them here |
a2a8927a XL |
186 | let (formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments { |
187 | let tuple_type = self.structurally_resolved_type(call_span, formal_input_tys[0]); | |
29967ef6 | 188 | match tuple_type.kind() { |
5099ac24 | 189 | // We expected a tuple and got a tuple |
29967ef6 | 190 | ty::Tuple(arg_types) => { |
5099ac24 FG |
191 | // Argument length differs |
192 | if arg_types.len() != provided_args.len() { | |
923072b8 | 193 | err_code = "E0057"; |
5099ac24 | 194 | } |
923072b8 FG |
195 | let expected_input_tys = match expected_input_tys { |
196 | Some(expected_input_tys) => match expected_input_tys.get(0) { | |
197 | Some(ty) => match ty.kind() { | |
198 | ty::Tuple(tys) => Some(tys.iter().collect()), | |
199 | _ => None, | |
200 | }, | |
201 | None => None, | |
29967ef6 | 202 | }, |
923072b8 | 203 | None => None, |
29967ef6 | 204 | }; |
5e7ed085 | 205 | (arg_types.iter().collect(), expected_input_tys) |
29967ef6 XL |
206 | } |
207 | _ => { | |
5099ac24 | 208 | // Otherwise, there's a mismatch, so clear out what we're expecting, and set |
5e7ed085 | 209 | // our input types to err_args so we don't blow up the error messages |
29967ef6 XL |
210 | struct_span_err!( |
211 | tcx.sess, | |
a2a8927a | 212 | call_span, |
29967ef6 XL |
213 | E0059, |
214 | "cannot use call notation; the first type parameter \ | |
215 | for the function trait is neither a tuple nor unit" | |
216 | ) | |
487cf647 | 217 | .delay_as_bug(); |
923072b8 | 218 | (self.err_args(provided_args.len()), None) |
29967ef6 XL |
219 | } |
220 | } | |
29967ef6 | 221 | } else { |
923072b8 | 222 | (formal_input_tys.to_vec(), expected_input_tys) |
29967ef6 XL |
223 | }; |
224 | ||
923072b8 FG |
225 | // If there are no external expectations at the call site, just use the types from the function defn |
226 | let expected_input_tys = if let Some(expected_input_tys) = expected_input_tys { | |
227 | assert_eq!(expected_input_tys.len(), formal_input_tys.len()); | |
a2a8927a XL |
228 | expected_input_tys |
229 | } else { | |
230 | formal_input_tys.clone() | |
231 | }; | |
29967ef6 | 232 | |
923072b8 FG |
233 | let minimum_input_count = expected_input_tys.len(); |
234 | let provided_arg_count = provided_args.len(); | |
5099ac24 | 235 | |
f2b60f7d FG |
236 | let is_const_eval_select = matches!(fn_def_id, Some(def_id) if |
237 | self.tcx.def_kind(def_id) == hir::def::DefKind::Fn | |
238 | && self.tcx.is_intrinsic(def_id) | |
239 | && self.tcx.item_name(def_id) == sym::const_eval_select); | |
240 | ||
a2a8927a XL |
241 | // We introduce a helper function to demand that a given argument satisfy a given input |
242 | // This is more complicated than just checking type equality, as arguments could be coerced | |
243 | // This version writes those types back so further type checking uses the narrowed types | |
064997fb | 244 | let demand_compatible = |idx| { |
a2a8927a XL |
245 | let formal_input_ty: Ty<'tcx> = formal_input_tys[idx]; |
246 | let expected_input_ty: Ty<'tcx> = expected_input_tys[idx]; | |
247 | let provided_arg = &provided_args[idx]; | |
248 | ||
249 | debug!("checking argument {}: {:?} = {:?}", idx, provided_arg, formal_input_ty); | |
250 | ||
923072b8 FG |
251 | // We're on the happy path here, so we'll do a more involved check and write back types |
252 | // To check compatibility, we'll do 3 things: | |
253 | // 1. Unify the provided argument with the expected type | |
a2a8927a XL |
254 | let expectation = Expectation::rvalue_hint(self, expected_input_ty); |
255 | ||
256 | let checked_ty = self.check_expr_with_expectation(provided_arg, expectation); | |
257 | ||
258 | // 2. Coerce to the most detailed type that could be coerced | |
259 | // to, which is `expected_ty` if `rvalue_hint` returns an | |
260 | // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. | |
261 | let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty); | |
262 | ||
a2a8927a | 263 | // Cause selection errors caused by resolving a single argument to point at the |
923072b8 | 264 | // argument and not the call. This lets us customize the span pointed to in the |
a2a8927a | 265 | // fulfillment error to be more accurate. |
f2b60f7d | 266 | let coerced_ty = self.resolve_vars_with_obligations(coerced_ty); |
a2a8927a | 267 | |
923072b8 FG |
268 | let coerce_error = self |
269 | .try_coerce(provided_arg, checked_ty, coerced_ty, AllowTwoPhase::Yes, None) | |
270 | .err(); | |
271 | ||
272 | if coerce_error.is_some() { | |
273 | return Compatibility::Incompatible(coerce_error); | |
274 | } | |
275 | ||
f2b60f7d FG |
276 | // Check that second and third argument of `const_eval_select` must be `FnDef`, and additionally that |
277 | // the second argument must be `const fn`. The first argument must be a tuple, but this is already expressed | |
278 | // in the function signature (`F: FnOnce<ARG>`), so I did not bother to add another check here. | |
279 | // | |
280 | // This check is here because there is currently no way to express a trait bound for `FnDef` types only. | |
281 | if is_const_eval_select && (1..=2).contains(&idx) { | |
282 | if let ty::FnDef(def_id, _) = checked_ty.kind() { | |
283 | if idx == 1 && !self.tcx.is_const_fn_raw(*def_id) { | |
284 | self.tcx | |
285 | .sess | |
286 | .struct_span_err(provided_arg.span, "this argument must be a `const fn`") | |
287 | .help("consult the documentation on `const_eval_select` for more information") | |
288 | .emit(); | |
289 | } | |
290 | } else { | |
291 | self.tcx | |
292 | .sess | |
293 | .struct_span_err(provided_arg.span, "this argument must be a function item") | |
294 | .note(format!("expected a function item, found {checked_ty}")) | |
295 | .help( | |
296 | "consult the documentation on `const_eval_select` for more information", | |
297 | ) | |
298 | .emit(); | |
299 | } | |
300 | } | |
301 | ||
923072b8 FG |
302 | // 3. Check if the formal type is a supertype of the checked one |
303 | // and register any such obligations for future type checks | |
304 | let supertype_error = self | |
305 | .at(&self.misc(provided_arg.span), self.param_env) | |
306 | .sup(formal_input_ty, coerced_ty); | |
307 | let subtyping_error = match supertype_error { | |
308 | Ok(InferOk { obligations, value: () }) => { | |
309 | self.register_predicates(obligations); | |
310 | None | |
311 | } | |
312 | Err(err) => Some(err), | |
313 | }; | |
314 | ||
315 | // If neither check failed, the types are compatible | |
316 | match subtyping_error { | |
317 | None => Compatibility::Compatible, | |
318 | Some(_) => Compatibility::Incompatible(subtyping_error), | |
319 | } | |
320 | }; | |
321 | ||
923072b8 FG |
322 | // To start, we only care "along the diagonal", where we expect every |
323 | // provided arg to be in the right spot | |
064997fb FG |
324 | let mut compatibility_diagonal = |
325 | vec![Compatibility::Incompatible(None); provided_args.len()]; | |
923072b8 FG |
326 | |
327 | // Keep track of whether we *could possibly* be satisfied, i.e. whether we're on the happy path | |
328 | // if the wrong number of arguments were supplied, we CAN'T be satisfied, | |
329 | // and if we're c_variadic, the supplied arguments must be >= the minimum count from the function | |
330 | // otherwise, they need to be identical, because rust doesn't currently support variadic functions | |
331 | let mut call_appears_satisfied = if c_variadic { | |
332 | provided_arg_count >= minimum_input_count | |
333 | } else { | |
334 | provided_arg_count == minimum_input_count | |
335 | }; | |
5e7ed085 | 336 | |
29967ef6 XL |
337 | // Check the arguments. |
338 | // We do this in a pretty awful way: first we type-check any arguments | |
339 | // that are not closures, then we type-check the closures. This is so | |
340 | // that we have more information about the types of arguments when we | |
341 | // type-check the functions. This isn't really the right way to do this. | |
136023e0 | 342 | for check_closures in [false, true] { |
29967ef6 XL |
343 | // More awful hacks: before we check argument types, try to do |
344 | // an "opportunistic" trait resolution of any trait bounds on | |
345 | // the call. This helps coercions. | |
346 | if check_closures { | |
487cf647 | 347 | self.select_obligations_where_possible(|_| {}) |
29967ef6 XL |
348 | } |
349 | ||
923072b8 FG |
350 | // Check each argument, to satisfy the input it was provided for |
351 | // Visually, we're traveling down the diagonal of the compatibility matrix | |
a2a8927a | 352 | for (idx, arg) in provided_args.iter().enumerate() { |
29967ef6 XL |
353 | // Warn only for the first loop (the "no closures" one). |
354 | // Closure arguments themselves can't be diverging, but | |
355 | // a previous argument can, e.g., `foo(panic!(), || {})`. | |
356 | if !check_closures { | |
357 | self.warn_if_unreachable(arg.hir_id, arg.span, "expression"); | |
358 | } | |
359 | ||
a2a8927a XL |
360 | // For C-variadic functions, we don't have a declared type for all of |
361 | // the arguments hence we only do our usual type checking with | |
362 | // the arguments who's types we do know. However, we *can* check | |
363 | // for unreachable expressions (see above). | |
364 | // FIXME: unreachable warning current isn't emitted | |
365 | if idx >= minimum_input_count { | |
366 | continue; | |
367 | } | |
29967ef6 | 368 | |
923072b8 | 369 | let is_closure = matches!(arg.kind, ExprKind::Closure { .. }); |
29967ef6 XL |
370 | if is_closure != check_closures { |
371 | continue; | |
372 | } | |
373 | ||
064997fb | 374 | let compatible = demand_compatible(idx); |
923072b8 | 375 | let is_compatible = matches!(compatible, Compatibility::Compatible); |
064997fb | 376 | compatibility_diagonal[idx] = compatible; |
923072b8 FG |
377 | |
378 | if !is_compatible { | |
379 | call_appears_satisfied = false; | |
380 | } | |
29967ef6 XL |
381 | } |
382 | } | |
383 | ||
064997fb FG |
384 | if c_variadic && provided_arg_count < minimum_input_count { |
385 | err_code = "E0060"; | |
386 | } | |
387 | ||
388 | for arg in provided_args.iter().skip(minimum_input_count) { | |
389 | // Make sure we've checked this expr at least once. | |
390 | let arg_ty = self.check_expr(&arg); | |
391 | ||
392 | // If the function is c-style variadic, we skipped a bunch of arguments | |
393 | // so we need to check those, and write out the types | |
394 | // Ideally this would be folded into the above, for uniform style | |
395 | // but c-variadic is already a corner case | |
396 | if c_variadic { | |
397 | fn variadic_error<'tcx>( | |
398 | sess: &'tcx Session, | |
399 | span: Span, | |
400 | ty: Ty<'tcx>, | |
401 | cast_ty: &str, | |
402 | ) { | |
2b03887a | 403 | use rustc_hir_analysis::structured_errors::MissingCastForVariadicArg; |
064997fb FG |
404 | |
405 | MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit(); | |
406 | } | |
407 | ||
408 | // There are a few types which get autopromoted when passed via varargs | |
409 | // in C but we just error out instead and require explicit casts. | |
410 | let arg_ty = self.structurally_resolved_type(arg.span, arg_ty); | |
411 | match arg_ty.kind() { | |
412 | ty::Float(ty::FloatTy::F32) => { | |
413 | variadic_error(tcx.sess, arg.span, arg_ty, "c_double"); | |
414 | } | |
415 | ty::Int(ty::IntTy::I8 | ty::IntTy::I16) | ty::Bool => { | |
416 | variadic_error(tcx.sess, arg.span, arg_ty, "c_int"); | |
417 | } | |
418 | ty::Uint(ty::UintTy::U8 | ty::UintTy::U16) => { | |
419 | variadic_error(tcx.sess, arg.span, arg_ty, "c_uint"); | |
420 | } | |
421 | ty::FnDef(..) => { | |
422 | let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx)); | |
423 | let ptr_ty = self.resolve_vars_if_possible(ptr_ty); | |
424 | variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string()); | |
425 | } | |
426 | _ => {} | |
427 | } | |
923072b8 | 428 | } |
064997fb | 429 | } |
923072b8 | 430 | |
064997fb FG |
431 | if !call_appears_satisfied { |
432 | let compatibility_diagonal = IndexVec::from_raw(compatibility_diagonal); | |
433 | let provided_args = IndexVec::from_iter(provided_args.iter().take(if c_variadic { | |
434 | minimum_input_count | |
435 | } else { | |
436 | provided_arg_count | |
437 | })); | |
438 | debug_assert_eq!( | |
439 | formal_input_tys.len(), | |
440 | expected_input_tys.len(), | |
441 | "expected formal_input_tys to be the same size as expected_input_tys" | |
442 | ); | |
443 | let formal_and_expected_inputs = IndexVec::from_iter( | |
444 | formal_input_tys | |
445 | .iter() | |
446 | .copied() | |
447 | .zip(expected_input_tys.iter().copied()) | |
448 | .map(|vars| self.resolve_vars_if_possible(vars)), | |
449 | ); | |
923072b8 | 450 | |
064997fb FG |
451 | self.report_arg_errors( |
452 | compatibility_diagonal, | |
453 | formal_and_expected_inputs, | |
454 | provided_args, | |
455 | c_variadic, | |
456 | err_code, | |
457 | fn_def_id, | |
458 | call_span, | |
459 | call_expr, | |
460 | ); | |
461 | } | |
462 | } | |
923072b8 | 463 | |
064997fb FG |
464 | fn report_arg_errors( |
465 | &self, | |
466 | compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>, | |
467 | formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>, | |
468 | provided_args: IndexVec<ProvidedIdx, &'tcx hir::Expr<'tcx>>, | |
469 | c_variadic: bool, | |
470 | err_code: &str, | |
471 | fn_def_id: Option<DefId>, | |
472 | call_span: Span, | |
473 | call_expr: &hir::Expr<'tcx>, | |
474 | ) { | |
475 | // Next, let's construct the error | |
f2b60f7d | 476 | let (error_span, full_call_span, ctor_of, is_method) = match &call_expr.kind { |
064997fb FG |
477 | hir::ExprKind::Call( |
478 | hir::Expr { hir_id, span, kind: hir::ExprKind::Path(qpath), .. }, | |
479 | _, | |
480 | ) => { | |
481 | if let Res::Def(DefKind::Ctor(of, _), _) = | |
482 | self.typeck_results.borrow().qpath_res(qpath, *hir_id) | |
483 | { | |
f2b60f7d | 484 | (call_span, *span, Some(of), false) |
064997fb | 485 | } else { |
f2b60f7d | 486 | (call_span, *span, None, false) |
064997fb FG |
487 | } |
488 | } | |
f2b60f7d FG |
489 | hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None, false), |
490 | hir::ExprKind::MethodCall(path_segment, _, _, span) => { | |
064997fb FG |
491 | let ident_span = path_segment.ident.span; |
492 | let ident_span = if let Some(args) = path_segment.args { | |
493 | ident_span.with_hi(args.span_ext.hi()) | |
494 | } else { | |
495 | ident_span | |
496 | }; | |
f2b60f7d FG |
497 | // methods are never ctors |
498 | (*span, ident_span, None, true) | |
064997fb FG |
499 | } |
500 | k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k), | |
501 | }; | |
502 | let args_span = error_span.trim_start(full_call_span).unwrap_or(error_span); | |
503 | let call_name = match ctor_of { | |
504 | Some(CtorOf::Struct) => "struct", | |
505 | Some(CtorOf::Variant) => "enum variant", | |
506 | None => "function", | |
507 | }; | |
923072b8 | 508 | |
064997fb FG |
509 | // Don't print if it has error types or is just plain `_` |
510 | fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool { | |
511 | tys.into_iter().any(|ty| ty.references_error() || ty.is_ty_var()) | |
512 | } | |
513 | ||
064997fb | 514 | let tcx = self.tcx; |
487cf647 FG |
515 | // FIXME: taint after emitting errors and pass through an `ErrorGuaranteed` |
516 | self.set_tainted_by_errors( | |
517 | tcx.sess.delay_span_bug(call_span, "no errors reported for args"), | |
518 | ); | |
064997fb FG |
519 | |
520 | // Get the argument span in the context of the call span so that | |
521 | // suggestions and labels are (more) correct when an arg is a | |
522 | // macro invocation. | |
523 | let normalize_span = |span: Span| -> Span { | |
524 | let normalized_span = span.find_ancestor_inside(error_span).unwrap_or(span); | |
525 | // Sometimes macros mess up the spans, so do not normalize the | |
526 | // arg span to equal the error span, because that's less useful | |
527 | // than pointing out the arg expr in the wrong context. | |
528 | if normalized_span.source_equal(error_span) { span } else { normalized_span } | |
529 | }; | |
530 | ||
531 | // Precompute the provided types and spans, since that's all we typically need for below | |
532 | let provided_arg_tys: IndexVec<ProvidedIdx, (Ty<'tcx>, Span)> = provided_args | |
533 | .iter() | |
534 | .map(|expr| { | |
535 | let ty = self | |
536 | .typeck_results | |
537 | .borrow() | |
538 | .expr_ty_adjusted_opt(*expr) | |
539 | .unwrap_or_else(|| tcx.ty_error()); | |
540 | (self.resolve_vars_if_possible(ty), normalize_span(expr.span)) | |
541 | }) | |
542 | .collect(); | |
543 | let callee_expr = match &call_expr.peel_blocks().kind { | |
544 | hir::ExprKind::Call(callee, _) => Some(*callee), | |
f2b60f7d | 545 | hir::ExprKind::MethodCall(_, receiver, ..) => { |
064997fb FG |
546 | if let Some((DefKind::AssocFn, def_id)) = |
547 | self.typeck_results.borrow().type_dependent_def(call_expr.hir_id) | |
548 | && let Some(assoc) = tcx.opt_associated_item(def_id) | |
549 | && assoc.fn_has_self_parameter | |
550 | { | |
f2b60f7d | 551 | Some(*receiver) |
064997fb FG |
552 | } else { |
553 | None | |
923072b8 | 554 | } |
064997fb FG |
555 | } |
556 | _ => None, | |
557 | }; | |
558 | let callee_ty = callee_expr | |
559 | .and_then(|callee_expr| self.typeck_results.borrow().expr_ty_adjusted_opt(callee_expr)); | |
560 | ||
561 | // A "softer" version of the `demand_compatible`, which checks types without persisting them, | |
562 | // and treats error types differently | |
563 | // This will allow us to "probe" for other argument orders that would likely have been correct | |
564 | let check_compatible = |provided_idx: ProvidedIdx, expected_idx: ExpectedIdx| { | |
565 | if provided_idx.as_usize() == expected_idx.as_usize() { | |
566 | return compatibility_diagonal[provided_idx].clone(); | |
567 | } | |
568 | ||
569 | let (formal_input_ty, expected_input_ty) = formal_and_expected_inputs[expected_idx]; | |
570 | // If either is an error type, we defy the usual convention and consider them to *not* be | |
571 | // coercible. This prevents our error message heuristic from trying to pass errors into | |
572 | // every argument. | |
573 | if (formal_input_ty, expected_input_ty).references_error() { | |
574 | return Compatibility::Incompatible(None); | |
575 | } | |
576 | ||
577 | let (arg_ty, arg_span) = provided_arg_tys[provided_idx]; | |
578 | ||
579 | let expectation = Expectation::rvalue_hint(self, expected_input_ty); | |
580 | let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty); | |
581 | let can_coerce = self.can_coerce(arg_ty, coerced_ty); | |
582 | if !can_coerce { | |
f2b60f7d FG |
583 | return Compatibility::Incompatible(Some(ty::error::TypeError::Sorts( |
584 | ty::error::ExpectedFound::new(true, coerced_ty, arg_ty), | |
585 | ))); | |
064997fb FG |
586 | } |
587 | ||
588 | // Using probe here, since we don't want this subtyping to affect inference. | |
589 | let subtyping_error = self.probe(|_| { | |
590 | self.at(&self.misc(arg_span), self.param_env).sup(formal_input_ty, coerced_ty).err() | |
923072b8 FG |
591 | }); |
592 | ||
064997fb FG |
593 | // Same as above: if either the coerce type or the checked type is an error type, |
594 | // consider them *not* compatible. | |
595 | let references_error = (coerced_ty, arg_ty).references_error(); | |
596 | match (references_error, subtyping_error) { | |
597 | (false, None) => Compatibility::Compatible, | |
598 | (_, subtyping_error) => Compatibility::Incompatible(subtyping_error), | |
923072b8 | 599 | } |
064997fb | 600 | }; |
923072b8 | 601 | |
487cf647 FG |
602 | let mk_trace = |span, (formal_ty, expected_ty), provided_ty| { |
603 | let mismatched_ty = if expected_ty == provided_ty { | |
604 | // If expected == provided, then we must have failed to sup | |
605 | // the formal type. Avoid printing out "expected Ty, found Ty" | |
606 | // in that case. | |
607 | formal_ty | |
608 | } else { | |
609 | expected_ty | |
610 | }; | |
611 | TypeTrace::types(&self.misc(span), true, mismatched_ty, provided_ty) | |
612 | }; | |
613 | ||
064997fb FG |
614 | // The algorithm here is inspired by levenshtein distance and longest common subsequence. |
615 | // We'll try to detect 4 different types of mistakes: | |
616 | // - An extra parameter has been provided that doesn't satisfy *any* of the other inputs | |
617 | // - An input is missing, which isn't satisfied by *any* of the other arguments | |
618 | // - Some number of arguments have been provided in the wrong order | |
619 | // - A type is straight up invalid | |
620 | ||
621 | // First, let's find the errors | |
622 | let (mut errors, matched_inputs) = | |
623 | ArgMatrix::new(provided_args.len(), formal_and_expected_inputs.len(), check_compatible) | |
624 | .find_errors(); | |
625 | ||
626 | // First, check if we just need to wrap some arguments in a tuple. | |
627 | if let Some((mismatch_idx, terr)) = | |
628 | compatibility_diagonal.iter().enumerate().find_map(|(i, c)| { | |
f2b60f7d FG |
629 | if let Compatibility::Incompatible(Some(terr)) = c { |
630 | Some((i, *terr)) | |
631 | } else { | |
632 | None | |
633 | } | |
064997fb FG |
634 | }) |
635 | { | |
636 | // Is the first bad expected argument a tuple? | |
637 | // Do we have as many extra provided arguments as the tuple's length? | |
638 | // If so, we might have just forgotten to wrap some args in a tuple. | |
639 | if let Some(ty::Tuple(tys)) = | |
640 | formal_and_expected_inputs.get(mismatch_idx.into()).map(|tys| tys.1.kind()) | |
641 | // If the tuple is unit, we're not actually wrapping any arguments. | |
642 | && !tys.is_empty() | |
643 | && provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len() | |
644 | { | |
645 | // Wrap up the N provided arguments starting at this position in a tuple. | |
646 | let provided_as_tuple = tcx.mk_tup( | |
647 | provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx).take(tys.len()), | |
648 | ); | |
649 | ||
650 | let mut satisfied = true; | |
651 | // Check if the newly wrapped tuple + rest of the arguments are compatible. | |
652 | for ((_, expected_ty), provided_ty) in std::iter::zip( | |
653 | formal_and_expected_inputs.iter().skip(mismatch_idx), | |
654 | [provided_as_tuple].into_iter().chain( | |
655 | provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx + tys.len()), | |
656 | ), | |
657 | ) { | |
658 | if !self.can_coerce(provided_ty, *expected_ty) { | |
659 | satisfied = false; | |
660 | break; | |
661 | } | |
5099ac24 | 662 | } |
5e7ed085 | 663 | |
064997fb FG |
664 | // If they're compatible, suggest wrapping in an arg, and we're done! |
665 | // Take some care with spans, so we don't suggest wrapping a macro's | |
666 | // innards in parenthesis, for example. | |
667 | if satisfied | |
668 | && let Some((_, lo)) = | |
669 | provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx)) | |
670 | && let Some((_, hi)) = | |
671 | provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx + tys.len() - 1)) | |
672 | { | |
673 | let mut err; | |
674 | if tys.len() == 1 { | |
675 | // A tuple wrap suggestion actually occurs within, | |
676 | // so don't do anything special here. | |
2b03887a | 677 | err = self.err_ctxt().report_and_explain_type_error( |
487cf647 FG |
678 | mk_trace( |
679 | *lo, | |
680 | formal_and_expected_inputs[mismatch_idx.into()], | |
064997fb FG |
681 | provided_arg_tys[mismatch_idx.into()].0, |
682 | ), | |
683 | terr, | |
684 | ); | |
685 | err.span_label( | |
686 | full_call_span, | |
687 | format!("arguments to this {} are incorrect", call_name), | |
688 | ); | |
689 | } else { | |
690 | err = tcx.sess.struct_span_err_with_code( | |
691 | full_call_span, | |
692 | &format!( | |
693 | "this {} takes {}{} but {} {} supplied", | |
694 | call_name, | |
695 | if c_variadic { "at least " } else { "" }, | |
696 | potentially_plural_count( | |
697 | formal_and_expected_inputs.len(), | |
698 | "argument" | |
699 | ), | |
700 | potentially_plural_count(provided_args.len(), "argument"), | |
701 | pluralize!("was", provided_args.len()) | |
702 | ), | |
703 | DiagnosticId::Error(err_code.to_owned()), | |
704 | ); | |
705 | err.multipart_suggestion_verbose( | |
706 | "wrap these arguments in parentheses to construct a tuple", | |
707 | vec![ | |
708 | (lo.shrink_to_lo(), "(".to_string()), | |
709 | (hi.shrink_to_hi(), ")".to_string()), | |
710 | ], | |
711 | Applicability::MachineApplicable, | |
712 | ); | |
923072b8 | 713 | }; |
f2b60f7d FG |
714 | self.label_fn_like( |
715 | &mut err, | |
716 | fn_def_id, | |
717 | callee_ty, | |
718 | Some(mismatch_idx), | |
719 | is_method, | |
720 | ); | |
923072b8 | 721 | err.emit(); |
064997fb | 722 | return; |
04454e1e | 723 | } |
923072b8 | 724 | } |
064997fb FG |
725 | } |
726 | ||
727 | // Okay, so here's where it gets complicated in regards to what errors | |
728 | // we emit and how. | |
729 | // There are 3 different "types" of errors we might encounter. | |
730 | // 1) Missing/extra/swapped arguments | |
731 | // 2) Valid but incorrect arguments | |
732 | // 3) Invalid arguments | |
733 | // - Currently I think this only comes up with `CyclicTy` | |
734 | // | |
735 | // We first need to go through, remove those from (3) and emit those | |
736 | // as their own error, particularly since they're error code and | |
737 | // message is special. From what I can tell, we *must* emit these | |
738 | // here (vs somewhere prior to this function) since the arguments | |
739 | // become invalid *because* of how they get used in the function. | |
740 | // It is what it is. | |
741 | ||
742 | if errors.is_empty() { | |
743 | if cfg!(debug_assertions) { | |
744 | span_bug!(error_span, "expected errors from argument matrix"); | |
745 | } else { | |
746 | tcx.sess | |
747 | .struct_span_err( | |
748 | error_span, | |
749 | "argument type mismatch was detected, \ | |
750 | but rustc had trouble determining where", | |
751 | ) | |
752 | .note( | |
753 | "we would appreciate a bug report: \ | |
754 | https://github.com/rust-lang/rust/issues/new", | |
755 | ) | |
756 | .emit(); | |
757 | } | |
758 | return; | |
759 | } | |
760 | ||
761 | errors.drain_filter(|error| { | |
f2b60f7d | 762 | let Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(e))) = error else { return false }; |
064997fb | 763 | let (provided_ty, provided_span) = provided_arg_tys[*provided_idx]; |
487cf647 | 764 | let trace = mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty); |
f2b60f7d | 765 | if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308(_)) { |
2b03887a | 766 | self.err_ctxt().report_and_explain_type_error(trace, *e).emit(); |
f2b60f7d | 767 | return true; |
064997fb FG |
768 | } |
769 | false | |
770 | }); | |
771 | ||
772 | // We're done if we found errors, but we already emitted them. | |
773 | if errors.is_empty() { | |
774 | return; | |
775 | } | |
776 | ||
777 | // Okay, now that we've emitted the special errors separately, we | |
778 | // are only left missing/extra/swapped and mismatched arguments, both | |
779 | // can be collated pretty easily if needed. | |
780 | ||
781 | // Next special case: if there is only one "Incompatible" error, just emit that | |
782 | if let [ | |
783 | Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(err))), | |
784 | ] = &errors[..] | |
785 | { | |
786 | let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx]; | |
787 | let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx]; | |
487cf647 | 788 | let trace = mk_trace(provided_arg_span, (formal_ty, expected_ty), provided_ty); |
2b03887a | 789 | let mut err = self.err_ctxt().report_and_explain_type_error(trace, *err); |
064997fb FG |
790 | self.emit_coerce_suggestions( |
791 | &mut err, | |
792 | &provided_args[*provided_idx], | |
793 | provided_ty, | |
794 | Expectation::rvalue_hint(self, expected_ty) | |
795 | .only_has_type(self) | |
796 | .unwrap_or(formal_ty), | |
797 | None, | |
798 | None, | |
799 | ); | |
800 | err.span_label( | |
801 | full_call_span, | |
802 | format!("arguments to this {} are incorrect", call_name), | |
803 | ); | |
804 | // Call out where the function is defined | |
f2b60f7d FG |
805 | self.label_fn_like( |
806 | &mut err, | |
807 | fn_def_id, | |
808 | callee_ty, | |
809 | Some(expected_idx.as_usize()), | |
810 | is_method, | |
811 | ); | |
064997fb FG |
812 | err.emit(); |
813 | return; | |
814 | } | |
815 | ||
816 | let mut err = if formal_and_expected_inputs.len() == provided_args.len() { | |
817 | struct_span_err!( | |
818 | tcx.sess, | |
819 | full_call_span, | |
820 | E0308, | |
821 | "arguments to this {} are incorrect", | |
822 | call_name, | |
823 | ) | |
824 | } else { | |
825 | tcx.sess.struct_span_err_with_code( | |
826 | full_call_span, | |
827 | &format!( | |
828 | "this {} takes {}{} but {} {} supplied", | |
829 | call_name, | |
830 | if c_variadic { "at least " } else { "" }, | |
831 | potentially_plural_count(formal_and_expected_inputs.len(), "argument"), | |
832 | potentially_plural_count(provided_args.len(), "argument"), | |
833 | pluralize!("was", provided_args.len()) | |
834 | ), | |
835 | DiagnosticId::Error(err_code.to_owned()), | |
836 | ) | |
837 | }; | |
838 | ||
839 | // As we encounter issues, keep track of what we want to provide for the suggestion | |
840 | let mut labels = vec![]; | |
841 | // If there is a single error, we give a specific suggestion; otherwise, we change to | |
842 | // "did you mean" with the suggested function call | |
843 | enum SuggestionText { | |
844 | None, | |
845 | Provide(bool), | |
846 | Remove(bool), | |
847 | Swap, | |
848 | Reorder, | |
849 | DidYouMean, | |
850 | } | |
851 | let mut suggestion_text = SuggestionText::None; | |
852 | ||
853 | let mut errors = errors.into_iter().peekable(); | |
854 | while let Some(error) = errors.next() { | |
855 | match error { | |
856 | Error::Invalid(provided_idx, expected_idx, compatibility) => { | |
857 | let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx]; | |
858 | let (provided_ty, provided_span) = provided_arg_tys[provided_idx]; | |
f2b60f7d | 859 | if let Compatibility::Incompatible(error) = compatibility { |
487cf647 | 860 | let trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty); |
064997fb | 861 | if let Some(e) = error { |
2b03887a | 862 | self.err_ctxt().note_type_err( |
064997fb FG |
863 | &mut err, |
864 | &trace.cause, | |
865 | None, | |
866 | Some(trace.values), | |
867 | e, | |
868 | false, | |
869 | true, | |
870 | ); | |
871 | } | |
872 | } | |
923072b8 | 873 | |
923072b8 FG |
874 | self.emit_coerce_suggestions( |
875 | &mut err, | |
064997fb | 876 | &provided_args[provided_idx], |
923072b8 | 877 | provided_ty, |
064997fb FG |
878 | Expectation::rvalue_hint(self, expected_ty) |
879 | .only_has_type(self) | |
880 | .unwrap_or(formal_ty), | |
923072b8 FG |
881 | None, |
882 | None, | |
883 | ); | |
923072b8 | 884 | } |
064997fb FG |
885 | Error::Extra(arg_idx) => { |
886 | let (provided_ty, provided_span) = provided_arg_tys[arg_idx]; | |
887 | let provided_ty_name = if !has_error_or_infer([provided_ty]) { | |
888 | // FIXME: not suggestable, use something else | |
889 | format!(" of type `{}`", provided_ty) | |
890 | } else { | |
891 | "".to_string() | |
892 | }; | |
893 | labels | |
894 | .push((provided_span, format!("argument{} unexpected", provided_ty_name))); | |
895 | suggestion_text = match suggestion_text { | |
896 | SuggestionText::None => SuggestionText::Remove(false), | |
897 | SuggestionText::Remove(_) => SuggestionText::Remove(true), | |
898 | _ => SuggestionText::DidYouMean, | |
899 | }; | |
900 | } | |
901 | Error::Missing(expected_idx) => { | |
902 | // If there are multiple missing arguments adjacent to each other, | |
903 | // then we can provide a single error. | |
904 | ||
905 | let mut missing_idxs = vec![expected_idx]; | |
906 | while let Some(e) = errors.next_if(|e| { | |
907 | matches!(e, Error::Missing(next_expected_idx) | |
908 | if *next_expected_idx == *missing_idxs.last().unwrap() + 1) | |
909 | }) { | |
910 | match e { | |
911 | Error::Missing(expected_idx) => missing_idxs.push(expected_idx), | |
912 | _ => unreachable!(), | |
923072b8 | 913 | } |
923072b8 | 914 | } |
064997fb FG |
915 | |
916 | // NOTE: Because we might be re-arranging arguments, might have extra | |
917 | // arguments, etc. it's hard to *really* know where we should provide | |
918 | // this error label, so as a heuristic, we point to the provided arg, or | |
919 | // to the call if the missing inputs pass the provided args. | |
920 | match &missing_idxs[..] { | |
921 | &[expected_idx] => { | |
922 | let (_, input_ty) = formal_and_expected_inputs[expected_idx]; | |
923 | let span = if let Some((_, arg_span)) = | |
924 | provided_arg_tys.get(expected_idx.to_provided_idx()) | |
925 | { | |
926 | *arg_span | |
923072b8 | 927 | } else { |
064997fb FG |
928 | args_span |
929 | }; | |
930 | let rendered = if !has_error_or_infer([input_ty]) { | |
931 | format!(" of type `{}`", input_ty) | |
932 | } else { | |
933 | "".to_string() | |
934 | }; | |
935 | labels.push((span, format!("an argument{} is missing", rendered))); | |
936 | suggestion_text = match suggestion_text { | |
937 | SuggestionText::None => SuggestionText::Provide(false), | |
938 | SuggestionText::Provide(_) => SuggestionText::Provide(true), | |
939 | _ => SuggestionText::DidYouMean, | |
940 | }; | |
923072b8 | 941 | } |
064997fb FG |
942 | &[first_idx, second_idx] => { |
943 | let (_, first_expected_ty) = formal_and_expected_inputs[first_idx]; | |
944 | let (_, second_expected_ty) = formal_and_expected_inputs[second_idx]; | |
945 | let span = if let (Some((_, first_span)), Some((_, second_span))) = ( | |
946 | provided_arg_tys.get(first_idx.to_provided_idx()), | |
947 | provided_arg_tys.get(second_idx.to_provided_idx()), | |
948 | ) { | |
949 | first_span.to(*second_span) | |
950 | } else { | |
951 | args_span | |
952 | }; | |
953 | let rendered = | |
954 | if !has_error_or_infer([first_expected_ty, second_expected_ty]) { | |
923072b8 FG |
955 | format!( |
956 | " of type `{}` and `{}`", | |
064997fb | 957 | first_expected_ty, second_expected_ty |
923072b8 FG |
958 | ) |
959 | } else { | |
064997fb | 960 | "".to_string() |
923072b8 | 961 | }; |
064997fb FG |
962 | labels.push((span, format!("two arguments{} are missing", rendered))); |
963 | suggestion_text = match suggestion_text { | |
964 | SuggestionText::None | SuggestionText::Provide(_) => { | |
965 | SuggestionText::Provide(true) | |
966 | } | |
967 | _ => SuggestionText::DidYouMean, | |
968 | }; | |
923072b8 | 969 | } |
064997fb FG |
970 | &[first_idx, second_idx, third_idx] => { |
971 | let (_, first_expected_ty) = formal_and_expected_inputs[first_idx]; | |
972 | let (_, second_expected_ty) = formal_and_expected_inputs[second_idx]; | |
973 | let (_, third_expected_ty) = formal_and_expected_inputs[third_idx]; | |
974 | let span = if let (Some((_, first_span)), Some((_, third_span))) = ( | |
975 | provided_arg_tys.get(first_idx.to_provided_idx()), | |
976 | provided_arg_tys.get(third_idx.to_provided_idx()), | |
977 | ) { | |
978 | first_span.to(*third_span) | |
923072b8 | 979 | } else { |
064997fb | 980 | args_span |
923072b8 | 981 | }; |
064997fb FG |
982 | let rendered = if !has_error_or_infer([ |
983 | first_expected_ty, | |
984 | second_expected_ty, | |
985 | third_expected_ty, | |
986 | ]) { | |
987 | format!( | |
988 | " of type `{}`, `{}`, and `{}`", | |
989 | first_expected_ty, second_expected_ty, third_expected_ty | |
990 | ) | |
923072b8 | 991 | } else { |
064997fb FG |
992 | "".to_string() |
993 | }; | |
994 | labels.push((span, format!("three arguments{} are missing", rendered))); | |
995 | suggestion_text = match suggestion_text { | |
996 | SuggestionText::None | SuggestionText::Provide(_) => { | |
997 | SuggestionText::Provide(true) | |
998 | } | |
999 | _ => SuggestionText::DidYouMean, | |
1000 | }; | |
1001 | } | |
1002 | missing_idxs => { | |
1003 | let first_idx = *missing_idxs.first().unwrap(); | |
1004 | let last_idx = *missing_idxs.last().unwrap(); | |
1005 | // NOTE: Because we might be re-arranging arguments, might have extra arguments, etc. | |
1006 | // It's hard to *really* know where we should provide this error label, so this is a | |
1007 | // decent heuristic | |
1008 | let span = if let (Some((_, first_span)), Some((_, last_span))) = ( | |
1009 | provided_arg_tys.get(first_idx.to_provided_idx()), | |
1010 | provided_arg_tys.get(last_idx.to_provided_idx()), | |
1011 | ) { | |
1012 | first_span.to(*last_span) | |
1013 | } else { | |
1014 | args_span | |
1015 | }; | |
1016 | labels.push((span, format!("multiple arguments are missing"))); | |
1017 | suggestion_text = match suggestion_text { | |
1018 | SuggestionText::None | SuggestionText::Provide(_) => { | |
1019 | SuggestionText::Provide(true) | |
1020 | } | |
1021 | _ => SuggestionText::DidYouMean, | |
923072b8 | 1022 | }; |
923072b8 | 1023 | } |
923072b8 FG |
1024 | } |
1025 | } | |
064997fb FG |
1026 | Error::Swap( |
1027 | first_provided_idx, | |
1028 | second_provided_idx, | |
1029 | first_expected_idx, | |
1030 | second_expected_idx, | |
1031 | ) => { | |
1032 | let (first_provided_ty, first_span) = provided_arg_tys[first_provided_idx]; | |
1033 | let (_, first_expected_ty) = formal_and_expected_inputs[first_expected_idx]; | |
1034 | let first_provided_ty_name = if !has_error_or_infer([first_provided_ty]) { | |
1035 | format!(", found `{}`", first_provided_ty) | |
923072b8 | 1036 | } else { |
064997fb FG |
1037 | String::new() |
1038 | }; | |
1039 | labels.push(( | |
1040 | first_span, | |
1041 | format!("expected `{}`{}", first_expected_ty, first_provided_ty_name), | |
1042 | )); | |
1043 | ||
1044 | let (second_provided_ty, second_span) = provided_arg_tys[second_provided_idx]; | |
1045 | let (_, second_expected_ty) = formal_and_expected_inputs[second_expected_idx]; | |
1046 | let second_provided_ty_name = if !has_error_or_infer([second_provided_ty]) { | |
1047 | format!(", found `{}`", second_provided_ty) | |
1048 | } else { | |
1049 | String::new() | |
923072b8 | 1050 | }; |
064997fb FG |
1051 | labels.push(( |
1052 | second_span, | |
1053 | format!("expected `{}`{}", second_expected_ty, second_provided_ty_name), | |
1054 | )); | |
1055 | ||
1056 | suggestion_text = match suggestion_text { | |
1057 | SuggestionText::None => SuggestionText::Swap, | |
1058 | _ => SuggestionText::DidYouMean, | |
1059 | }; | |
1060 | } | |
1061 | Error::Permutation(args) => { | |
1062 | for (dst_arg, dest_input) in args { | |
1063 | let (_, expected_ty) = formal_and_expected_inputs[dst_arg]; | |
1064 | let (provided_ty, provided_span) = provided_arg_tys[dest_input]; | |
1065 | let provided_ty_name = if !has_error_or_infer([provided_ty]) { | |
1066 | format!(", found `{}`", provided_ty) | |
1067 | } else { | |
1068 | String::new() | |
1069 | }; | |
1070 | labels.push(( | |
1071 | provided_span, | |
1072 | format!("expected `{}`{}", expected_ty, provided_ty_name), | |
1073 | )); | |
923072b8 | 1074 | } |
064997fb FG |
1075 | |
1076 | suggestion_text = match suggestion_text { | |
1077 | SuggestionText::None => SuggestionText::Reorder, | |
1078 | _ => SuggestionText::DidYouMean, | |
1079 | }; | |
04454e1e | 1080 | } |
5099ac24 | 1081 | } |
5099ac24 FG |
1082 | } |
1083 | ||
064997fb FG |
1084 | // If we have less than 5 things to say, it would be useful to call out exactly what's wrong |
1085 | if labels.len() <= 5 { | |
1086 | for (span, label) in labels { | |
1087 | err.span_label(span, label); | |
1088 | } | |
1089 | } | |
5869c6ff | 1090 | |
064997fb | 1091 | // Call out where the function is defined |
f2b60f7d | 1092 | self.label_fn_like(&mut err, fn_def_id, callee_ty, None, is_method); |
29967ef6 | 1093 | |
064997fb FG |
1094 | // And add a suggestion block for all of the parameters |
1095 | let suggestion_text = match suggestion_text { | |
1096 | SuggestionText::None => None, | |
1097 | SuggestionText::Provide(plural) => { | |
1098 | Some(format!("provide the argument{}", if plural { "s" } else { "" })) | |
1099 | } | |
1100 | SuggestionText::Remove(plural) => { | |
1101 | Some(format!("remove the extra argument{}", if plural { "s" } else { "" })) | |
1102 | } | |
1103 | SuggestionText::Swap => Some("swap these arguments".to_string()), | |
1104 | SuggestionText::Reorder => Some("reorder these arguments".to_string()), | |
1105 | SuggestionText::DidYouMean => Some("did you mean".to_string()), | |
1106 | }; | |
1107 | if let Some(suggestion_text) = suggestion_text { | |
1108 | let source_map = self.sess().source_map(); | |
f2b60f7d FG |
1109 | let (mut suggestion, suggestion_span) = |
1110 | if let Some(call_span) = full_call_span.find_ancestor_inside(error_span) { | |
1111 | ("(".to_string(), call_span.shrink_to_hi().to(error_span.shrink_to_hi())) | |
1112 | } else { | |
1113 | ( | |
1114 | format!( | |
1115 | "{}(", | |
1116 | source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| { | |
1117 | fn_def_id.map_or("".to_string(), |fn_def_id| { | |
1118 | tcx.item_name(fn_def_id).to_string() | |
1119 | }) | |
1120 | }) | |
1121 | ), | |
1122 | error_span, | |
1123 | ) | |
1124 | }; | |
064997fb FG |
1125 | let mut needs_comma = false; |
1126 | for (expected_idx, provided_idx) in matched_inputs.iter_enumerated() { | |
1127 | if needs_comma { | |
1128 | suggestion += ", "; | |
1129 | } else { | |
1130 | needs_comma = true; | |
5e7ed085 | 1131 | } |
064997fb FG |
1132 | let suggestion_text = if let Some(provided_idx) = provided_idx |
1133 | && let (_, provided_span) = provided_arg_tys[*provided_idx] | |
f2b60f7d | 1134 | && let Ok(arg_text) = source_map.span_to_snippet(provided_span) |
064997fb FG |
1135 | { |
1136 | arg_text | |
1137 | } else { | |
1138 | // Propose a placeholder of the correct type | |
1139 | let (_, expected_ty) = formal_and_expected_inputs[expected_idx]; | |
1140 | if expected_ty.is_unit() { | |
1141 | "()".to_string() | |
1142 | } else if expected_ty.is_suggestable(tcx, false) { | |
1143 | format!("/* {} */", expected_ty) | |
1144 | } else { | |
1145 | "/* value */".to_string() | |
29967ef6 | 1146 | } |
064997fb FG |
1147 | }; |
1148 | suggestion += &suggestion_text; | |
29967ef6 | 1149 | } |
064997fb FG |
1150 | suggestion += ")"; |
1151 | err.span_suggestion_verbose( | |
f2b60f7d | 1152 | suggestion_span, |
064997fb FG |
1153 | &suggestion_text, |
1154 | suggestion, | |
1155 | Applicability::HasPlaceholders, | |
1156 | ); | |
29967ef6 | 1157 | } |
5099ac24 | 1158 | |
064997fb | 1159 | err.emit(); |
5099ac24 FG |
1160 | } |
1161 | ||
29967ef6 XL |
1162 | // AST fragment checking |
1163 | pub(in super::super) fn check_lit( | |
1164 | &self, | |
1165 | lit: &hir::Lit, | |
1166 | expected: Expectation<'tcx>, | |
1167 | ) -> Ty<'tcx> { | |
1168 | let tcx = self.tcx; | |
1169 | ||
1170 | match lit.node { | |
1171 | ast::LitKind::Str(..) => tcx.mk_static_str(), | |
1172 | ast::LitKind::ByteStr(ref v) => { | |
1173 | tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.u8, v.len() as u64)) | |
1174 | } | |
1175 | ast::LitKind::Byte(_) => tcx.types.u8, | |
1176 | ast::LitKind::Char(_) => tcx.types.char, | |
5869c6ff XL |
1177 | ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(ty::int_ty(t)), |
1178 | ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(ty::uint_ty(t)), | |
29967ef6 XL |
1179 | ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => { |
1180 | let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { | |
1181 | ty::Int(_) | ty::Uint(_) => Some(ty), | |
1182 | ty::Char => Some(tcx.types.u8), | |
1183 | ty::RawPtr(..) => Some(tcx.types.usize), | |
1184 | ty::FnDef(..) | ty::FnPtr(_) => Some(tcx.types.usize), | |
1185 | _ => None, | |
1186 | }); | |
1187 | opt_ty.unwrap_or_else(|| self.next_int_var()) | |
1188 | } | |
5869c6ff XL |
1189 | ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => { |
1190 | tcx.mk_mach_float(ty::float_ty(t)) | |
1191 | } | |
29967ef6 XL |
1192 | ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => { |
1193 | let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { | |
1194 | ty::Float(_) => Some(ty), | |
1195 | _ => None, | |
1196 | }); | |
1197 | opt_ty.unwrap_or_else(|| self.next_float_var()) | |
1198 | } | |
1199 | ast::LitKind::Bool(_) => tcx.types.bool, | |
f2b60f7d | 1200 | ast::LitKind::Err => tcx.ty_error(), |
29967ef6 XL |
1201 | } |
1202 | } | |
1203 | ||
1204 | pub fn check_struct_path( | |
1205 | &self, | |
1206 | qpath: &QPath<'_>, | |
1207 | hir_id: hir::HirId, | |
1208 | ) -> Option<(&'tcx ty::VariantDef, Ty<'tcx>)> { | |
6a06907d | 1209 | let path_span = qpath.span(); |
29967ef6 XL |
1210 | let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id); |
1211 | let variant = match def { | |
1212 | Res::Err => { | |
487cf647 FG |
1213 | self.set_tainted_by_errors( |
1214 | self.tcx.sess.delay_span_bug(path_span, "`Res::Err` but no error emitted"), | |
1215 | ); | |
29967ef6 XL |
1216 | return None; |
1217 | } | |
1218 | Res::Def(DefKind::Variant, _) => match ty.kind() { | |
5e7ed085 | 1219 | ty::Adt(adt, substs) => Some((adt.variant_of_res(def), adt.did(), substs)), |
29967ef6 XL |
1220 | _ => bug!("unexpected type: {:?}", ty), |
1221 | }, | |
1222 | Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) | |
2b03887a FG |
1223 | | Res::SelfTyParam { .. } |
1224 | | Res::SelfTyAlias { .. } => match ty.kind() { | |
29967ef6 | 1225 | ty::Adt(adt, substs) if !adt.is_enum() => { |
5e7ed085 | 1226 | Some((adt.non_enum_variant(), adt.did(), substs)) |
29967ef6 XL |
1227 | } |
1228 | _ => None, | |
1229 | }, | |
1230 | _ => bug!("unexpected definition: {:?}", def), | |
1231 | }; | |
1232 | ||
1233 | if let Some((variant, did, substs)) = variant { | |
1234 | debug!("check_struct_path: did={:?} substs={:?}", did, substs); | |
1235 | self.write_user_type_annotation_from_substs(hir_id, did, substs, None); | |
1236 | ||
1237 | // Check bounds on type arguments used in the path. | |
f2b60f7d | 1238 | self.add_required_obligations_for_hir(path_span, did, substs, hir_id); |
29967ef6 XL |
1239 | |
1240 | Some((variant, ty)) | |
1241 | } else { | |
c295e0f8 XL |
1242 | match ty.kind() { |
1243 | ty::Error(_) => { | |
1244 | // E0071 might be caused by a spelling error, which will have | |
1245 | // already caused an error message and probably a suggestion | |
1246 | // elsewhere. Refrain from emitting more unhelpful errors here | |
1247 | // (issue #88844). | |
1248 | } | |
1249 | _ => { | |
1250 | struct_span_err!( | |
1251 | self.tcx.sess, | |
1252 | path_span, | |
1253 | E0071, | |
1254 | "expected struct, variant or union type, found {}", | |
1255 | ty.sort_string(self.tcx) | |
1256 | ) | |
1257 | .span_label(path_span, "not a struct") | |
1258 | .emit(); | |
1259 | } | |
1260 | } | |
29967ef6 XL |
1261 | None |
1262 | } | |
1263 | } | |
1264 | ||
1265 | pub fn check_decl_initializer( | |
1266 | &self, | |
a2a8927a XL |
1267 | hir_id: hir::HirId, |
1268 | pat: &'tcx hir::Pat<'tcx>, | |
29967ef6 XL |
1269 | init: &'tcx hir::Expr<'tcx>, |
1270 | ) -> Ty<'tcx> { | |
1271 | // FIXME(tschottdorf): `contains_explicit_ref_binding()` must be removed | |
1272 | // for #42640 (default match binding modes). | |
1273 | // | |
1274 | // See #44848. | |
a2a8927a | 1275 | let ref_bindings = pat.contains_explicit_ref_binding(); |
29967ef6 | 1276 | |
a2a8927a | 1277 | let local_ty = self.local_ty(init.span, hir_id).revealed_ty; |
29967ef6 XL |
1278 | if let Some(m) = ref_bindings { |
1279 | // Somewhat subtle: if we have a `ref` binding in the pattern, | |
1280 | // we want to avoid introducing coercions for the RHS. This is | |
1281 | // both because it helps preserve sanity and, in the case of | |
1282 | // ref mut, for soundness (issue #23116). In particular, in | |
1283 | // the latter case, we need to be clear that the type of the | |
1284 | // referent for the reference that results is *equal to* the | |
1285 | // type of the place it is referencing, and not some | |
1286 | // supertype thereof. | |
1287 | let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m)); | |
1288 | self.demand_eqtype(init.span, local_ty, init_ty); | |
1289 | init_ty | |
1290 | } else { | |
1291 | self.check_expr_coercable_to_type(init, local_ty, None) | |
1292 | } | |
1293 | } | |
1294 | ||
a2a8927a | 1295 | pub(in super::super) fn check_decl(&self, decl: Declaration<'tcx>) { |
29967ef6 | 1296 | // Determine and write the type which we'll check the pattern against. |
a2a8927a XL |
1297 | let decl_ty = self.local_ty(decl.span, decl.hir_id).decl_ty; |
1298 | self.write_ty(decl.hir_id, decl_ty); | |
29967ef6 XL |
1299 | |
1300 | // Type check the initializer. | |
a2a8927a XL |
1301 | if let Some(ref init) = decl.init { |
1302 | let init_ty = self.check_decl_initializer(decl.hir_id, decl.pat, &init); | |
1303 | self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, decl_ty, init_ty); | |
29967ef6 XL |
1304 | } |
1305 | ||
1306 | // Does the expected pattern type originate from an expression and what is the span? | |
a2a8927a | 1307 | let (origin_expr, ty_span) = match (decl.ty, decl.init) { |
29967ef6 | 1308 | (Some(ty), _) => (false, Some(ty.span)), // Bias towards the explicit user type. |
064997fb FG |
1309 | (_, Some(init)) => { |
1310 | (true, Some(init.span.find_ancestor_inside(decl.span).unwrap_or(init.span))) | |
1311 | } // No explicit type; so use the scrutinee. | |
29967ef6 XL |
1312 | _ => (false, None), // We have `let $pat;`, so the expected type is unconstrained. |
1313 | }; | |
1314 | ||
1315 | // Type check the pattern. Override if necessary to avoid knock-on errors. | |
a2a8927a XL |
1316 | self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr); |
1317 | let pat_ty = self.node_ty(decl.pat.hir_id); | |
1318 | self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, decl_ty, pat_ty); | |
064997fb FG |
1319 | |
1320 | if let Some(blk) = decl.els { | |
1321 | let previous_diverges = self.diverges.get(); | |
1322 | let else_ty = self.check_block_with_expected(blk, NoExpectation); | |
1323 | let cause = self.cause(blk.span, ObligationCauseCode::LetElse); | |
1324 | if let Some(mut err) = | |
1325 | self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty) | |
1326 | { | |
1327 | err.emit(); | |
1328 | } | |
1329 | self.diverges.set(previous_diverges); | |
1330 | } | |
a2a8927a XL |
1331 | } |
1332 | ||
1333 | /// Type check a `let` statement. | |
1334 | pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) { | |
1335 | self.check_decl(local.into()); | |
29967ef6 XL |
1336 | } |
1337 | ||
6a06907d | 1338 | pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>, is_last: bool) { |
29967ef6 XL |
1339 | // Don't do all the complex logic below for `DeclItem`. |
1340 | match stmt.kind { | |
1341 | hir::StmtKind::Item(..) => return, | |
1342 | hir::StmtKind::Local(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {} | |
1343 | } | |
1344 | ||
1345 | self.warn_if_unreachable(stmt.hir_id, stmt.span, "statement"); | |
1346 | ||
1347 | // Hide the outer diverging and `has_errors` flags. | |
1348 | let old_diverges = self.diverges.replace(Diverges::Maybe); | |
29967ef6 XL |
1349 | |
1350 | match stmt.kind { | |
064997fb FG |
1351 | hir::StmtKind::Local(l) => { |
1352 | self.check_decl_local(l); | |
29967ef6 XL |
1353 | } |
1354 | // Ignore for now. | |
1355 | hir::StmtKind::Item(_) => {} | |
1356 | hir::StmtKind::Expr(ref expr) => { | |
1357 | // Check with expected type of `()`. | |
1358 | self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| { | |
6a06907d XL |
1359 | if expr.can_have_side_effects() { |
1360 | self.suggest_semicolon_at_end(expr.span, err); | |
1361 | } | |
29967ef6 XL |
1362 | }); |
1363 | } | |
1364 | hir::StmtKind::Semi(ref expr) => { | |
6a06907d XL |
1365 | // All of this is equivalent to calling `check_expr`, but it is inlined out here |
1366 | // in order to capture the fact that this `match` is the last statement in its | |
1367 | // function. This is done for better suggestions to remove the `;`. | |
1368 | let expectation = match expr.kind { | |
1369 | hir::ExprKind::Match(..) if is_last => IsLast(stmt.span), | |
1370 | _ => NoExpectation, | |
1371 | }; | |
1372 | self.check_expr_with_expectation(expr, expectation); | |
29967ef6 XL |
1373 | } |
1374 | } | |
1375 | ||
1376 | // Combine the diverging and `has_error` flags. | |
1377 | self.diverges.set(self.diverges.get() | old_diverges); | |
29967ef6 XL |
1378 | } |
1379 | ||
1380 | pub fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) { | |
1381 | let unit = self.tcx.mk_unit(); | |
1382 | let ty = self.check_block_with_expected(blk, ExpectHasType(unit)); | |
1383 | ||
1384 | // if the block produces a `!` value, that can always be | |
1385 | // (effectively) coerced to unit. | |
1386 | if !ty.is_never() { | |
1387 | self.demand_suptype(blk.span, unit, ty); | |
1388 | } | |
1389 | } | |
1390 | ||
1391 | pub(in super::super) fn check_block_with_expected( | |
1392 | &self, | |
1393 | blk: &'tcx hir::Block<'tcx>, | |
1394 | expected: Expectation<'tcx>, | |
1395 | ) -> Ty<'tcx> { | |
29967ef6 XL |
1396 | // In some cases, blocks have just one exit, but other blocks |
1397 | // can be targeted by multiple breaks. This can happen both | |
1398 | // with labeled blocks as well as when we desugar | |
1399 | // a `try { ... }` expression. | |
1400 | // | |
1401 | // Example 1: | |
1402 | // | |
1403 | // 'a: { if true { break 'a Err(()); } Ok(()) } | |
1404 | // | |
1405 | // Here we would wind up with two coercions, one from | |
1406 | // `Err(())` and the other from the tail expression | |
1407 | // `Ok(())`. If the tail expression is omitted, that's a | |
1408 | // "forced unit" -- unless the block diverges, in which | |
1409 | // case we can ignore the tail expression (e.g., `'a: { | |
1410 | // break 'a 22; }` would not force the type of the block | |
1411 | // to be `()`). | |
1412 | let tail_expr = blk.expr.as_ref(); | |
1413 | let coerce_to_ty = expected.coercion_target_type(self, blk.span); | |
1414 | let coerce = if blk.targeted_by_break { | |
1415 | CoerceMany::new(coerce_to_ty) | |
1416 | } else { | |
1417 | let tail_expr: &[&hir::Expr<'_>] = match tail_expr { | |
1418 | Some(e) => slice::from_ref(e), | |
1419 | None => &[], | |
1420 | }; | |
1421 | CoerceMany::with_coercion_sites(coerce_to_ty, tail_expr) | |
1422 | }; | |
1423 | ||
1424 | let prev_diverges = self.diverges.get(); | |
1425 | let ctxt = BreakableCtxt { coerce: Some(coerce), may_break: false }; | |
1426 | ||
1427 | let (ctxt, ()) = self.with_breakable_ctxt(blk.hir_id, ctxt, || { | |
6a06907d XL |
1428 | for (pos, s) in blk.stmts.iter().enumerate() { |
1429 | self.check_stmt(s, blk.stmts.len() - 1 == pos); | |
29967ef6 XL |
1430 | } |
1431 | ||
1432 | // check the tail expression **without** holding the | |
1433 | // `enclosing_breakables` lock below. | |
1434 | let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected)); | |
1435 | ||
1436 | let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); | |
1437 | let ctxt = enclosing_breakables.find_breakable(blk.hir_id); | |
1438 | let coerce = ctxt.coerce.as_mut().unwrap(); | |
1439 | if let Some(tail_expr_ty) = tail_expr_ty { | |
1440 | let tail_expr = tail_expr.unwrap(); | |
1441 | let span = self.get_expr_coercion_span(tail_expr); | |
1442 | let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id)); | |
5e7ed085 FG |
1443 | let ty_for_diagnostic = coerce.merged_ty(); |
1444 | // We use coerce_inner here because we want to augment the error | |
1445 | // suggesting to wrap the block in square brackets if it might've | |
1446 | // been mistaken array syntax | |
1447 | coerce.coerce_inner( | |
1448 | self, | |
1449 | &cause, | |
1450 | Some(tail_expr), | |
1451 | tail_expr_ty, | |
1452 | Some(&mut |diag: &mut Diagnostic| { | |
1453 | self.suggest_block_to_brackets(diag, blk, tail_expr_ty, ty_for_diagnostic); | |
1454 | }), | |
1455 | false, | |
1456 | ); | |
29967ef6 XL |
1457 | } else { |
1458 | // Subtle: if there is no explicit tail expression, | |
1459 | // that is typically equivalent to a tail expression | |
1460 | // of `()` -- except if the block diverges. In that | |
1461 | // case, there is no value supplied from the tail | |
1462 | // expression (assuming there are no other breaks, | |
1463 | // this implies that the type of the block will be | |
1464 | // `!`). | |
1465 | // | |
1466 | // #41425 -- label the implicit `()` as being the | |
1467 | // "found type" here, rather than the "expected type". | |
1468 | if !self.diverges.get().is_always() { | |
1469 | // #50009 -- Do not point at the entire fn block span, point at the return type | |
1470 | // span, as it is the cause of the requirement, and | |
1471 | // `consider_hint_about_removing_semicolon` will point at the last expression | |
1472 | // if it were a relevant part of the error. This improves usability in editors | |
1473 | // that highlight errors inline. | |
1474 | let mut sp = blk.span; | |
1475 | let mut fn_span = None; | |
1476 | if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) { | |
1477 | let ret_sp = decl.output.span(); | |
1478 | if let Some(block_sp) = self.parent_item_span(blk.hir_id) { | |
1479 | // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the | |
1480 | // output would otherwise be incorrect and even misleading. Make sure | |
1481 | // the span we're aiming at correspond to a `fn` body. | |
1482 | if block_sp == blk.span { | |
1483 | sp = ret_sp; | |
1484 | fn_span = Some(ident.span); | |
1485 | } | |
1486 | } | |
1487 | } | |
1488 | coerce.coerce_forced_unit( | |
1489 | self, | |
1490 | &self.misc(sp), | |
1491 | &mut |err| { | |
1492 | if let Some(expected_ty) = expected.only_has_type(self) { | |
064997fb | 1493 | if !self.consider_removing_semicolon(blk, expected_ty, err) { |
2b03887a FG |
1494 | self.err_ctxt().consider_returning_binding( |
1495 | blk, | |
1496 | expected_ty, | |
1497 | err, | |
1498 | ); | |
064997fb | 1499 | } |
3c0e092e XL |
1500 | if expected_ty == self.tcx.types.bool { |
1501 | // If this is caused by a missing `let` in a `while let`, | |
1502 | // silence this redundant error, as we already emit E0070. | |
5e7ed085 FG |
1503 | |
1504 | // Our block must be a `assign desugar local; assignment` | |
1505 | if let Some(hir::Node::Block(hir::Block { | |
1506 | stmts: | |
1507 | [ | |
1508 | hir::Stmt { | |
1509 | kind: | |
1510 | hir::StmtKind::Local(hir::Local { | |
1511 | source: | |
1512 | hir::LocalSource::AssignDesugar(_), | |
1513 | .. | |
1514 | }), | |
1515 | .. | |
1516 | }, | |
1517 | hir::Stmt { | |
1518 | kind: | |
1519 | hir::StmtKind::Expr(hir::Expr { | |
1520 | kind: hir::ExprKind::Assign(..), | |
1521 | .. | |
1522 | }), | |
1523 | .. | |
1524 | }, | |
1525 | ], | |
1526 | .. | |
1527 | })) = self.tcx.hir().find(blk.hir_id) | |
1528 | { | |
1529 | self.comes_from_while_condition(blk.hir_id, |_| { | |
1530 | err.downgrade_to_delayed_bug(); | |
1531 | }) | |
3c0e092e XL |
1532 | } |
1533 | } | |
29967ef6 XL |
1534 | } |
1535 | if let Some(fn_span) = fn_span { | |
1536 | err.span_label( | |
1537 | fn_span, | |
1538 | "implicitly returns `()` as its body has no tail or `return` \ | |
1539 | expression", | |
1540 | ); | |
1541 | } | |
1542 | }, | |
1543 | false, | |
1544 | ); | |
1545 | } | |
1546 | } | |
1547 | }); | |
1548 | ||
1549 | if ctxt.may_break { | |
1550 | // If we can break from the block, then the block's exit is always reachable | |
1551 | // (... as long as the entry is reachable) - regardless of the tail of the block. | |
1552 | self.diverges.set(prev_diverges); | |
1553 | } | |
1554 | ||
487cf647 | 1555 | let ty = ctxt.coerce.unwrap().complete(self); |
29967ef6 XL |
1556 | |
1557 | self.write_ty(blk.hir_id, ty); | |
1558 | ||
29967ef6 XL |
1559 | ty |
1560 | } | |
1561 | ||
29967ef6 | 1562 | fn parent_item_span(&self, id: hir::HirId) -> Option<Span> { |
2b03887a | 1563 | let node = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(id).def_id); |
29967ef6 XL |
1564 | match node { |
1565 | Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. }) | |
1566 | | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => { | |
1567 | let body = self.tcx.hir().body(body_id); | |
1568 | if let ExprKind::Block(block, _) = &body.value.kind { | |
1569 | return Some(block.span); | |
1570 | } | |
1571 | } | |
1572 | _ => {} | |
1573 | } | |
1574 | None | |
1575 | } | |
1576 | ||
1577 | /// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise. | |
1578 | fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> { | |
2b03887a | 1579 | let parent = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(blk_id).def_id); |
29967ef6 XL |
1580 | self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident)) |
1581 | } | |
1582 | ||
1583 | /// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail | |
1584 | /// expression's `Span`, otherwise return `expr.span`. This is done to give better errors | |
1585 | /// when given code like the following: | |
1586 | /// ```text | |
1587 | /// if false { return 0i32; } else { 1u32 } | |
1588 | /// // ^^^^ point at this instead of the whole `if` expression | |
1589 | /// ``` | |
1590 | fn get_expr_coercion_span(&self, expr: &hir::Expr<'_>) -> rustc_span::Span { | |
5869c6ff | 1591 | let check_in_progress = |elem: &hir::Expr<'_>| { |
064997fb FG |
1592 | self.typeck_results.borrow().node_type_opt(elem.hir_id).filter(|ty| !ty.is_never()).map( |
1593 | |_| match elem.kind { | |
1594 | // Point at the tail expression when possible. | |
1595 | hir::ExprKind::Block(block, _) => block.expr.map_or(block.span, |e| e.span), | |
1596 | _ => elem.span, | |
1597 | }, | |
1598 | ) | |
5869c6ff XL |
1599 | }; |
1600 | ||
1601 | if let hir::ExprKind::If(_, _, Some(el)) = expr.kind { | |
1602 | if let Some(rslt) = check_in_progress(el) { | |
1603 | return rslt; | |
29967ef6 XL |
1604 | } |
1605 | } | |
5869c6ff XL |
1606 | |
1607 | if let hir::ExprKind::Match(_, arms, _) = expr.kind { | |
1608 | let mut iter = arms.iter().filter_map(|arm| check_in_progress(arm.body)); | |
1609 | if let Some(span) = iter.next() { | |
1610 | if iter.next().is_none() { | |
1611 | return span; | |
1612 | } | |
1613 | } | |
1614 | } | |
1615 | ||
29967ef6 XL |
1616 | expr.span |
1617 | } | |
1618 | ||
1619 | fn overwrite_local_ty_if_err( | |
1620 | &self, | |
a2a8927a XL |
1621 | hir_id: hir::HirId, |
1622 | pat: &'tcx hir::Pat<'tcx>, | |
29967ef6 XL |
1623 | decl_ty: Ty<'tcx>, |
1624 | ty: Ty<'tcx>, | |
1625 | ) { | |
1626 | if ty.references_error() { | |
1627 | // Override the types everywhere with `err()` to avoid knock on errors. | |
a2a8927a XL |
1628 | self.write_ty(hir_id, ty); |
1629 | self.write_ty(pat.hir_id, ty); | |
29967ef6 | 1630 | let local_ty = LocalTy { decl_ty, revealed_ty: ty }; |
a2a8927a XL |
1631 | self.locals.borrow_mut().insert(hir_id, local_ty); |
1632 | self.locals.borrow_mut().insert(pat.hir_id, local_ty); | |
29967ef6 XL |
1633 | } |
1634 | } | |
1635 | ||
1636 | // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary. | |
1637 | // The newly resolved definition is written into `type_dependent_defs`. | |
1638 | fn finish_resolving_struct_path( | |
1639 | &self, | |
1640 | qpath: &QPath<'_>, | |
1641 | path_span: Span, | |
1642 | hir_id: hir::HirId, | |
1643 | ) -> (Res, Ty<'tcx>) { | |
1644 | match *qpath { | |
1645 | QPath::Resolved(ref maybe_qself, ref path) => { | |
1646 | let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself)); | |
6a06907d | 1647 | let ty = <dyn AstConv<'_>>::res_to_ty(self, self_ty, path, true); |
29967ef6 XL |
1648 | (path.res, ty) |
1649 | } | |
1650 | QPath::TypeRelative(ref qself, ref segment) => { | |
1651 | let ty = self.to_ty(qself); | |
1652 | ||
6a06907d | 1653 | let result = <dyn AstConv<'_>>::associated_path_to_ty( |
923072b8 | 1654 | self, hir_id, path_span, ty, qself, segment, true, |
6a06907d | 1655 | ); |
29967ef6 XL |
1656 | let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error()); |
1657 | let result = result.map(|(_, kind, def_id)| (kind, def_id)); | |
1658 | ||
1659 | // Write back the new resolution. | |
1660 | self.write_resolution(hir_id, result); | |
1661 | ||
5869c6ff | 1662 | (result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), ty) |
29967ef6 | 1663 | } |
a2a8927a XL |
1664 | QPath::LangItem(lang_item, span, id) => { |
1665 | self.resolve_lang_item_path(lang_item, span, hir_id, id) | |
29967ef6 XL |
1666 | } |
1667 | } | |
1668 | } | |
1669 | ||
f2b60f7d FG |
1670 | /// Given a vector of fulfillment errors, try to adjust the spans of the |
1671 | /// errors to more accurately point at the cause of the failure. | |
1672 | /// | |
1673 | /// This applies to calls, methods, and struct expressions. This will also | |
1674 | /// try to deduplicate errors that are due to the same cause but might | |
1675 | /// have been created with different [`ObligationCause`][traits::ObligationCause]s. | |
1676 | pub(super) fn adjust_fulfillment_errors_for_expr_obligation( | |
29967ef6 XL |
1677 | &self, |
1678 | errors: &mut Vec<traits::FulfillmentError<'tcx>>, | |
29967ef6 | 1679 | ) { |
f2b60f7d FG |
1680 | // Store a mapping from `(Span, Predicate) -> ObligationCause`, so that |
1681 | // other errors that have the same span and predicate can also get fixed, | |
1682 | // even if their `ObligationCauseCode` isn't an `Expr*Obligation` kind. | |
1683 | // This is important since if we adjust one span but not the other, then | |
1684 | // we will have "duplicated" the error on the UI side. | |
1685 | let mut remap_cause = FxHashSet::default(); | |
1686 | let mut not_adjusted = vec![]; | |
1687 | ||
1688 | for error in errors { | |
1689 | let before_span = error.obligation.cause.span; | |
1690 | if self.adjust_fulfillment_error_for_expr_obligation(error) | |
1691 | || before_span != error.obligation.cause.span | |
1692 | { | |
1693 | // Store both the predicate and the predicate *without constness* | |
1694 | // since sometimes we instantiate and check both of these in a | |
1695 | // method call, for example. | |
1696 | remap_cause.insert(( | |
1697 | before_span, | |
1698 | error.obligation.predicate, | |
1699 | error.obligation.cause.clone(), | |
1700 | )); | |
1701 | remap_cause.insert(( | |
1702 | before_span, | |
1703 | error.obligation.predicate.without_const(self.tcx), | |
1704 | error.obligation.cause.clone(), | |
1705 | )); | |
1706 | } else { | |
1707 | // If it failed to be adjusted once around, it may be adjusted | |
1708 | // via the "remap cause" mapping the second time... | |
1709 | not_adjusted.push(error); | |
29967ef6 | 1710 | } |
f2b60f7d | 1711 | } |
29967ef6 | 1712 | |
f2b60f7d FG |
1713 | for error in not_adjusted { |
1714 | for (span, predicate, cause) in &remap_cause { | |
1715 | if *predicate == error.obligation.predicate | |
1716 | && span.contains(error.obligation.cause.span) | |
1717 | { | |
1718 | error.obligation.cause = cause.clone(); | |
1719 | continue; | |
3c0e092e | 1720 | } |
3c0e092e | 1721 | } |
f2b60f7d FG |
1722 | } |
1723 | } | |
1724 | ||
1725 | fn adjust_fulfillment_error_for_expr_obligation( | |
1726 | &self, | |
1727 | error: &mut traits::FulfillmentError<'tcx>, | |
1728 | ) -> bool { | |
1729 | let (traits::ExprItemObligation(def_id, hir_id, idx) | traits::ExprBindingObligation(def_id, _, hir_id, idx)) | |
1730 | = *error.obligation.cause.code().peel_derives() else { return false; }; | |
1731 | let hir = self.tcx.hir(); | |
1732 | let hir::Node::Expr(expr) = hir.get(hir_id) else { return false; }; | |
1733 | ||
f2b60f7d FG |
1734 | let Some(unsubstituted_pred) = |
1735 | self.tcx.predicates_of(def_id).instantiate_identity(self.tcx).predicates.into_iter().nth(idx) | |
1736 | else { return false; }; | |
1737 | ||
1738 | let generics = self.tcx.generics_of(def_id); | |
1739 | let predicate_substs = match unsubstituted_pred.kind().skip_binder() { | |
487cf647 FG |
1740 | ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs, |
1741 | ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => pred.projection_ty.substs, | |
f2b60f7d FG |
1742 | _ => ty::List::empty(), |
1743 | }; | |
1744 | ||
1745 | let find_param_matching = |matches: &dyn Fn(&ty::ParamTy) -> bool| { | |
1746 | predicate_substs.types().find_map(|ty| { | |
1747 | ty.walk().find_map(|arg| { | |
1748 | if let ty::GenericArgKind::Type(ty) = arg.unpack() | |
1749 | && let ty::Param(param_ty) = ty.kind() | |
1750 | && matches(param_ty) | |
1751 | { | |
1752 | Some(arg) | |
1753 | } else { | |
1754 | None | |
064997fb | 1755 | } |
f2b60f7d FG |
1756 | }) |
1757 | }) | |
1758 | }; | |
1759 | ||
1760 | // Prefer generics that are local to the fn item, since these are likely | |
1761 | // to be the cause of the unsatisfied predicate. | |
1762 | let mut param_to_point_at = find_param_matching(&|param_ty| { | |
1763 | self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) == def_id | |
1764 | }); | |
1765 | // Fall back to generic that isn't local to the fn item. This will come | |
1766 | // from a trait or impl, for example. | |
1767 | let mut fallback_param_to_point_at = find_param_matching(&|param_ty| { | |
1768 | self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) != def_id | |
1769 | && param_ty.name != rustc_span::symbol::kw::SelfUpper | |
1770 | }); | |
1771 | // Finally, the `Self` parameter is possibly the reason that the predicate | |
1772 | // is unsatisfied. This is less likely to be true for methods, because | |
1773 | // method probe means that we already kinda check that the predicates due | |
1774 | // to the `Self` type are true. | |
1775 | let mut self_param_to_point_at = | |
1776 | find_param_matching(&|param_ty| param_ty.name == rustc_span::symbol::kw::SelfUpper); | |
1777 | ||
1778 | // Finally, for ambiguity-related errors, we actually want to look | |
1779 | // for a parameter that is the source of the inference type left | |
1780 | // over in this predicate. | |
1781 | if let traits::FulfillmentErrorCode::CodeAmbiguity = error.code { | |
1782 | fallback_param_to_point_at = None; | |
1783 | self_param_to_point_at = None; | |
1784 | param_to_point_at = | |
1785 | self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate); | |
1786 | } | |
1787 | ||
1788 | if self.closure_span_overlaps_error(error, expr.span) { | |
1789 | return false; | |
1790 | } | |
1791 | ||
1792 | match &expr.kind { | |
1793 | hir::ExprKind::Path(qpath) => { | |
1794 | if let hir::Node::Expr(hir::Expr { | |
1795 | kind: hir::ExprKind::Call(callee, args), | |
1796 | hir_id: call_hir_id, | |
1797 | span: call_span, | |
1798 | .. | |
1799 | }) = hir.get(hir.get_parent_node(expr.hir_id)) | |
1800 | && callee.hir_id == expr.hir_id | |
1801 | { | |
1802 | if self.closure_span_overlaps_error(error, *call_span) { | |
1803 | return false; | |
064997fb | 1804 | } |
f2b60f7d FG |
1805 | |
1806 | for param in | |
1807 | [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] | |
1808 | .into_iter() | |
1809 | .flatten() | |
064997fb | 1810 | { |
f2b60f7d FG |
1811 | if self.point_at_arg_if_possible( |
1812 | error, | |
1813 | def_id, | |
1814 | param, | |
1815 | *call_hir_id, | |
1816 | callee.span, | |
1817 | None, | |
1818 | args, | |
1819 | ) | |
1820 | { | |
1821 | return true; | |
1822 | } | |
3c0e092e | 1823 | } |
f2b60f7d FG |
1824 | } |
1825 | // Notably, we only point to params that are local to the | |
1826 | // item we're checking, since those are the ones we are able | |
1827 | // to look in the final `hir::PathSegment` for. Everything else | |
1828 | // would require a deeper search into the `qpath` than I think | |
1829 | // is worthwhile. | |
1830 | if let Some(param_to_point_at) = param_to_point_at | |
1831 | && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath) | |
1832 | { | |
1833 | return true; | |
1834 | } | |
1835 | } | |
1836 | hir::ExprKind::MethodCall(segment, receiver, args, ..) => { | |
1837 | for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] | |
1838 | .into_iter() | |
1839 | .flatten() | |
1840 | { | |
1841 | if self.point_at_arg_if_possible( | |
1842 | error, | |
1843 | def_id, | |
1844 | param, | |
1845 | hir_id, | |
1846 | segment.ident.span, | |
1847 | Some(receiver), | |
1848 | args, | |
1849 | ) { | |
1850 | return true; | |
1851 | } | |
1852 | } | |
1853 | if let Some(param_to_point_at) = param_to_point_at | |
1854 | && self.point_at_generic_if_possible(error, def_id, param_to_point_at, segment) | |
1855 | { | |
1856 | return true; | |
1857 | } | |
1858 | } | |
1859 | hir::ExprKind::Struct(qpath, fields, ..) => { | |
1860 | if let Res::Def(DefKind::Struct | DefKind::Variant, variant_def_id) = | |
1861 | self.typeck_results.borrow().qpath_res(qpath, hir_id) | |
1862 | { | |
1863 | for param in | |
1864 | [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] | |
1865 | { | |
1866 | if let Some(param) = param | |
1867 | && self.point_at_field_if_possible( | |
1868 | error, | |
1869 | def_id, | |
1870 | param, | |
1871 | variant_def_id, | |
1872 | fields, | |
1873 | ) | |
1874 | { | |
1875 | return true; | |
1876 | } | |
064997fb | 1877 | } |
f2b60f7d FG |
1878 | } |
1879 | if let Some(param_to_point_at) = param_to_point_at | |
1880 | && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath) | |
1881 | { | |
1882 | return true; | |
064997fb FG |
1883 | } |
1884 | } | |
f2b60f7d FG |
1885 | _ => {} |
1886 | } | |
3c0e092e | 1887 | |
f2b60f7d FG |
1888 | false |
1889 | } | |
1890 | ||
1891 | fn closure_span_overlaps_error( | |
1892 | &self, | |
1893 | error: &traits::FulfillmentError<'tcx>, | |
1894 | span: Span, | |
1895 | ) -> bool { | |
1896 | if let traits::FulfillmentErrorCode::CodeSelectionError( | |
1897 | traits::SelectionError::OutputTypeParameterMismatch(_, expected, _), | |
1898 | ) = error.code | |
1899 | && let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected.skip_binder().self_ty().kind() | |
1900 | && span.overlaps(self.tcx.def_span(*def_id)) | |
1901 | { | |
1902 | true | |
1903 | } else { | |
1904 | false | |
1905 | } | |
1906 | } | |
1907 | ||
1908 | fn point_at_arg_if_possible( | |
1909 | &self, | |
1910 | error: &mut traits::FulfillmentError<'tcx>, | |
1911 | def_id: DefId, | |
1912 | param_to_point_at: ty::GenericArg<'tcx>, | |
1913 | call_hir_id: hir::HirId, | |
1914 | callee_span: Span, | |
1915 | receiver: Option<&'tcx hir::Expr<'tcx>>, | |
1916 | args: &'tcx [hir::Expr<'tcx>], | |
1917 | ) -> bool { | |
487cf647 FG |
1918 | let ty = self.tcx.type_of(def_id); |
1919 | if !ty.is_fn() { | |
1920 | return false; | |
1921 | } | |
1922 | let sig = ty.fn_sig(self.tcx).skip_binder(); | |
f2b60f7d FG |
1923 | let args_referencing_param: Vec<_> = sig |
1924 | .inputs() | |
1925 | .iter() | |
1926 | .enumerate() | |
1927 | .filter(|(_, ty)| find_param_in_ty(**ty, param_to_point_at)) | |
1928 | .collect(); | |
1929 | // If there's one field that references the given generic, great! | |
1930 | if let [(idx, _)] = args_referencing_param.as_slice() | |
1931 | && let Some(arg) = receiver | |
1932 | .map_or(args.get(*idx), |rcvr| if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }) { | |
1933 | error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span); | |
1934 | error.obligation.cause.map_code(|parent_code| { | |
1935 | ObligationCauseCode::FunctionArgumentObligation { | |
1936 | arg_hir_id: arg.hir_id, | |
1937 | call_hir_id, | |
1938 | parent_code, | |
1939 | } | |
1940 | }); | |
1941 | return true; | |
1942 | } else if args_referencing_param.len() > 0 { | |
1943 | // If more than one argument applies, then point to the callee span at least... | |
1944 | // We have chance to fix this up further in `point_at_generics_if_possible` | |
1945 | error.obligation.cause.span = callee_span; | |
1946 | } | |
3c0e092e | 1947 | |
f2b60f7d FG |
1948 | false |
1949 | } | |
3c0e092e | 1950 | |
f2b60f7d FG |
1951 | fn point_at_field_if_possible( |
1952 | &self, | |
1953 | error: &mut traits::FulfillmentError<'tcx>, | |
1954 | def_id: DefId, | |
1955 | param_to_point_at: ty::GenericArg<'tcx>, | |
1956 | variant_def_id: DefId, | |
1957 | expr_fields: &[hir::ExprField<'tcx>], | |
1958 | ) -> bool { | |
1959 | let def = self.tcx.adt_def(def_id); | |
1960 | ||
1961 | let identity_substs = ty::InternalSubsts::identity_for_item(self.tcx, def_id); | |
1962 | let fields_referencing_param: Vec<_> = def | |
1963 | .variant_with_id(variant_def_id) | |
1964 | .fields | |
1965 | .iter() | |
1966 | .filter(|field| { | |
1967 | let field_ty = field.ty(self.tcx, identity_substs); | |
1968 | find_param_in_ty(field_ty, param_to_point_at) | |
1969 | }) | |
1970 | .collect(); | |
3c0e092e | 1971 | |
f2b60f7d FG |
1972 | if let [field] = fields_referencing_param.as_slice() { |
1973 | for expr_field in expr_fields { | |
1974 | // Look for the ExprField that matches the field, using the | |
1975 | // same rules that check_expr_struct uses for macro hygiene. | |
1976 | if self.tcx.adjust_ident(expr_field.ident, variant_def_id) == field.ident(self.tcx) | |
1977 | { | |
1978 | error.obligation.cause.span = expr_field | |
1979 | .expr | |
1980 | .span | |
1981 | .find_ancestor_in_same_ctxt(error.obligation.cause.span) | |
1982 | .unwrap_or(expr_field.span); | |
1983 | return true; | |
3c0e092e | 1984 | } |
f2b60f7d FG |
1985 | } |
1986 | } | |
1987 | ||
1988 | false | |
1989 | } | |
1990 | ||
1991 | fn point_at_path_if_possible( | |
1992 | &self, | |
1993 | error: &mut traits::FulfillmentError<'tcx>, | |
1994 | def_id: DefId, | |
1995 | param: ty::GenericArg<'tcx>, | |
1996 | qpath: &QPath<'tcx>, | |
1997 | ) -> bool { | |
1998 | match qpath { | |
1999 | hir::QPath::Resolved(_, path) => { | |
2000 | if let Some(segment) = path.segments.last() | |
2001 | && self.point_at_generic_if_possible(error, def_id, param, segment) | |
2002 | { | |
2003 | return true; | |
29967ef6 XL |
2004 | } |
2005 | } | |
f2b60f7d FG |
2006 | hir::QPath::TypeRelative(_, segment) => { |
2007 | if self.point_at_generic_if_possible(error, def_id, param, segment) { | |
2008 | return true; | |
2009 | } | |
2010 | } | |
2011 | _ => {} | |
29967ef6 | 2012 | } |
f2b60f7d FG |
2013 | |
2014 | false | |
29967ef6 XL |
2015 | } |
2016 | ||
f2b60f7d | 2017 | fn point_at_generic_if_possible( |
29967ef6 | 2018 | &self, |
f2b60f7d FG |
2019 | error: &mut traits::FulfillmentError<'tcx>, |
2020 | def_id: DefId, | |
2021 | param_to_point_at: ty::GenericArg<'tcx>, | |
2022 | segment: &hir::PathSegment<'tcx>, | |
2023 | ) -> bool { | |
2024 | let own_substs = self | |
2025 | .tcx | |
2026 | .generics_of(def_id) | |
2027 | .own_substs(ty::InternalSubsts::identity_for_item(self.tcx, def_id)); | |
2028 | let Some((index, _)) = own_substs | |
2029 | .iter() | |
2030 | .filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_))) | |
2031 | .enumerate() | |
2032 | .find(|(_, arg)| **arg == param_to_point_at) else { return false }; | |
2033 | let Some(arg) = segment | |
2034 | .args() | |
2035 | .args | |
2036 | .iter() | |
2037 | .filter(|arg| matches!(arg, hir::GenericArg::Type(_))) | |
2038 | .nth(index) else { return false; }; | |
2039 | error.obligation.cause.span = arg | |
2040 | .span() | |
2041 | .find_ancestor_in_same_ctxt(error.obligation.cause.span) | |
2042 | .unwrap_or(arg.span()); | |
2043 | true | |
2044 | } | |
2045 | ||
2046 | fn find_ambiguous_parameter_in<T: TypeVisitable<'tcx>>( | |
2047 | &self, | |
2048 | item_def_id: DefId, | |
2049 | t: T, | |
2050 | ) -> Option<ty::GenericArg<'tcx>> { | |
2051 | struct FindAmbiguousParameter<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, DefId); | |
2052 | impl<'tcx> TypeVisitor<'tcx> for FindAmbiguousParameter<'_, 'tcx> { | |
2053 | type BreakTy = ty::GenericArg<'tcx>; | |
2054 | fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> { | |
2055 | if let Some(origin) = self.0.type_var_origin(ty) | |
2056 | && let TypeVariableOriginKind::TypeParameterDefinition(_, Some(def_id)) = | |
2057 | origin.kind | |
2058 | && let generics = self.0.tcx.generics_of(self.1) | |
2059 | && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id) | |
2060 | && let Some(subst) = ty::InternalSubsts::identity_for_item(self.0.tcx, self.1) | |
2061 | .get(index as usize) | |
2062 | { | |
2063 | ControlFlow::Break(*subst) | |
2064 | } else { | |
2065 | ty.super_visit_with(self) | |
29967ef6 XL |
2066 | } |
2067 | } | |
2068 | } | |
f2b60f7d | 2069 | t.visit_with(&mut FindAmbiguousParameter(self, item_def_id)).break_value() |
29967ef6 | 2070 | } |
923072b8 | 2071 | |
064997fb FG |
2072 | fn label_fn_like( |
2073 | &self, | |
f2b60f7d | 2074 | err: &mut Diagnostic, |
064997fb FG |
2075 | callable_def_id: Option<DefId>, |
2076 | callee_ty: Option<Ty<'tcx>>, | |
f2b60f7d FG |
2077 | // A specific argument should be labeled, instead of all of them |
2078 | expected_idx: Option<usize>, | |
2079 | is_method: bool, | |
064997fb FG |
2080 | ) { |
2081 | let Some(mut def_id) = callable_def_id else { | |
2082 | return; | |
2083 | }; | |
2084 | ||
2085 | if let Some(assoc_item) = self.tcx.opt_associated_item(def_id) | |
2086 | // Possibly points at either impl or trait item, so try to get it | |
2087 | // to point to trait item, then get the parent. | |
2088 | // This parent might be an impl in the case of an inherent function, | |
2089 | // but the next check will fail. | |
2090 | && let maybe_trait_item_def_id = assoc_item.trait_item_def_id.unwrap_or(def_id) | |
2091 | && let maybe_trait_def_id = self.tcx.parent(maybe_trait_item_def_id) | |
2092 | // Just an easy way to check "trait_def_id == Fn/FnMut/FnOnce" | |
487cf647 | 2093 | && let Some(call_kind) = self.tcx.fn_trait_kind_from_def_id(maybe_trait_def_id) |
064997fb FG |
2094 | && let Some(callee_ty) = callee_ty |
2095 | { | |
2096 | let callee_ty = callee_ty.peel_refs(); | |
2097 | match *callee_ty.kind() { | |
2098 | ty::Param(param) => { | |
2099 | let param = | |
2100 | self.tcx.generics_of(self.body_id.owner).type_param(¶m, self.tcx); | |
2101 | if param.kind.is_synthetic() { | |
2102 | // if it's `impl Fn() -> ..` then just fall down to the def-id based logic | |
2103 | def_id = param.def_id; | |
2104 | } else { | |
2105 | // Otherwise, find the predicate that makes this generic callable, | |
2106 | // and point at that. | |
2107 | let instantiated = self | |
2108 | .tcx | |
2109 | .explicit_predicates_of(self.body_id.owner) | |
2110 | .instantiate_identity(self.tcx); | |
2111 | // FIXME(compiler-errors): This could be problematic if something has two | |
2112 | // fn-like predicates with different args, but callable types really never | |
2113 | // do that, so it's OK. | |
2114 | for (predicate, span) in | |
2115 | std::iter::zip(instantiated.predicates, instantiated.spans) | |
2116 | { | |
487cf647 | 2117 | if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = predicate.kind().skip_binder() |
064997fb | 2118 | && pred.self_ty().peel_refs() == callee_ty |
487cf647 | 2119 | && self.tcx.is_fn_trait(pred.def_id()) |
064997fb FG |
2120 | { |
2121 | err.span_note(span, "callable defined here"); | |
2122 | return; | |
2123 | } | |
2124 | } | |
2125 | } | |
2126 | } | |
2127 | ty::Opaque(new_def_id, _) | |
2128 | | ty::Closure(new_def_id, _) | |
2129 | | ty::FnDef(new_def_id, _) => { | |
2130 | def_id = new_def_id; | |
2131 | } | |
2132 | _ => { | |
2133 | // Look for a user-provided impl of a `Fn` trait, and point to it. | |
2134 | let new_def_id = self.probe(|_| { | |
2135 | let trait_ref = ty::TraitRef::new( | |
2136 | call_kind.to_def_id(self.tcx), | |
f2b60f7d FG |
2137 | self.tcx.mk_substs( |
2138 | [ | |
2139 | ty::GenericArg::from(callee_ty), | |
2140 | self.next_ty_var(TypeVariableOrigin { | |
2141 | kind: TypeVariableOriginKind::MiscVariable, | |
2142 | span: rustc_span::DUMMY_SP, | |
2143 | }) | |
2144 | .into(), | |
2145 | ] | |
2146 | .into_iter(), | |
2147 | ), | |
064997fb FG |
2148 | ); |
2149 | let obligation = traits::Obligation::new( | |
487cf647 | 2150 | self.tcx, |
064997fb FG |
2151 | traits::ObligationCause::dummy(), |
2152 | self.param_env, | |
487cf647 | 2153 | ty::Binder::dummy(trait_ref), |
064997fb FG |
2154 | ); |
2155 | match SelectionContext::new(&self).select(&obligation) { | |
2156 | Ok(Some(traits::ImplSource::UserDefined(impl_source))) => { | |
2157 | Some(impl_source.impl_def_id) | |
2158 | } | |
f2b60f7d | 2159 | _ => None, |
064997fb FG |
2160 | } |
2161 | }); | |
2162 | if let Some(new_def_id) = new_def_id { | |
2163 | def_id = new_def_id; | |
2164 | } else { | |
2165 | return; | |
2166 | } | |
2167 | } | |
2168 | } | |
923072b8 FG |
2169 | } |
2170 | ||
064997fb FG |
2171 | if let Some(def_span) = self.tcx.def_ident_span(def_id) && !def_span.is_dummy() { |
2172 | let mut spans: MultiSpan = def_span.into(); | |
923072b8 | 2173 | |
064997fb FG |
2174 | let params = self |
2175 | .tcx | |
2176 | .hir() | |
2177 | .get_if_local(def_id) | |
2178 | .and_then(|node| node.body_id()) | |
2179 | .into_iter() | |
f2b60f7d FG |
2180 | .flat_map(|id| self.tcx.hir().body(id).params) |
2181 | .skip(if is_method { 1 } else { 0 }); | |
923072b8 | 2182 | |
f2b60f7d FG |
2183 | for (_, param) in params |
2184 | .into_iter() | |
2185 | .enumerate() | |
2186 | .filter(|(idx, _)| expected_idx.map_or(true, |expected_idx| expected_idx == *idx)) | |
2187 | { | |
064997fb | 2188 | spans.push_span_label(param.span, ""); |
923072b8 | 2189 | } |
064997fb FG |
2190 | |
2191 | let def_kind = self.tcx.def_kind(def_id); | |
2192 | err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id))); | |
f2b60f7d FG |
2193 | } else if let Some(hir::Node::Expr(e)) = self.tcx.hir().get_if_local(def_id) |
2194 | && let hir::ExprKind::Closure(hir::Closure { body, .. }) = &e.kind | |
2195 | { | |
2196 | let param = expected_idx | |
2197 | .and_then(|expected_idx| self.tcx.hir().body(*body).params.get(expected_idx)); | |
2198 | let (kind, span) = if let Some(param) = param { | |
2199 | ("closure parameter", param.span) | |
2200 | } else { | |
2201 | ("closure", self.tcx.def_span(def_id)) | |
2202 | }; | |
2203 | err.span_note(span, &format!("{} defined here", kind)); | |
064997fb FG |
2204 | } else { |
2205 | let def_kind = self.tcx.def_kind(def_id); | |
2206 | err.span_note( | |
2207 | self.tcx.def_span(def_id), | |
2208 | &format!("{} defined here", def_kind.descr(def_id)), | |
2209 | ); | |
923072b8 FG |
2210 | } |
2211 | } | |
2212 | } | |
f2b60f7d FG |
2213 | |
2214 | fn find_param_in_ty<'tcx>(ty: Ty<'tcx>, param_to_point_at: ty::GenericArg<'tcx>) -> bool { | |
2215 | let mut walk = ty.walk(); | |
2216 | while let Some(arg) = walk.next() { | |
2217 | if arg == param_to_point_at { | |
2218 | return true; | |
2219 | } else if let ty::GenericArgKind::Type(ty) = arg.unpack() | |
2220 | && let ty::Projection(..) = ty.kind() | |
2221 | { | |
2222 | // This logic may seem a bit strange, but typically when | |
2223 | // we have a projection type in a function signature, the | |
2224 | // argument that's being passed into that signature is | |
2225 | // not actually constraining that projection's substs in | |
2226 | // a meaningful way. So we skip it, and see improvements | |
2227 | // in some UI tests. | |
2228 | walk.skip_current_subtree(); | |
2229 | } | |
2230 | } | |
2231 | false | |
2232 | } |