]>
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; | |
2b03887a | 5 | use crate::TupleArgumentsFlag::*; |
49aad941 | 6 | use crate::{errors, Expectation::*}; |
2b03887a | 7 | use crate::{ |
9c376795 | 8 | struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, Needs, RawTy, |
2b03887a | 9 | TupleArgumentsFlag, |
064997fb | 10 | }; |
29967ef6 | 11 | use rustc_ast as ast; |
9c376795 | 12 | use rustc_data_structures::fx::FxIndexSet; |
9ffffee4 FG |
13 | use rustc_errors::{ |
14 | pluralize, Applicability, Diagnostic, DiagnosticId, ErrorGuaranteed, MultiSpan, | |
15 | }; | |
29967ef6 | 16 | use rustc_hir as hir; |
136023e0 | 17 | use rustc_hir::def::{CtorOf, DefKind, Res}; |
29967ef6 XL |
18 | use rustc_hir::def_id::DefId; |
19 | use rustc_hir::{ExprKind, Node, QPath}; | |
2b03887a FG |
20 | use rustc_hir_analysis::astconv::AstConv; |
21 | use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt; | |
22 | use rustc_hir_analysis::check::potentially_plural_count; | |
23 | use rustc_hir_analysis::structured_errors::StructuredDiagnostic; | |
49aad941 | 24 | use rustc_index::IndexVec; |
923072b8 | 25 | use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt}; |
064997fb | 26 | use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; |
923072b8 | 27 | use rustc_infer::infer::TypeTrace; |
353b0b11 | 28 | use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; |
29967ef6 | 29 | use rustc_middle::ty::adjustment::AllowTwoPhase; |
9ffffee4 | 30 | use rustc_middle::ty::visit::TypeVisitableExt; |
353b0b11 | 31 | use rustc_middle::ty::{self, IsSuggestable, Ty}; |
29967ef6 | 32 | use rustc_session::Session; |
9c376795 | 33 | use rustc_span::symbol::{kw, Ident}; |
353b0b11 | 34 | use rustc_span::{self, sym, BytePos, Span}; |
064997fb | 35 | use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}; |
29967ef6 | 36 | |
cdc7bbd5 | 37 | use std::iter; |
2b03887a | 38 | use std::mem; |
29967ef6 XL |
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() { |
9ffffee4 | 76 | self.tcx.ty_error_misc() |
f2b60f7d FG |
77 | } else { |
78 | self.tcx.erase_regions(ty) | |
79 | } | |
80 | }; | |
81 | InlineAsmCtxt::new_in_fn(self.tcx, self.param_env, get_operand_ty) | |
9ffffee4 | 82 | .check_asm(asm, 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, | |
9ffffee4 | 104 | TupleArguments => vec![self.tcx.mk_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 | 116 | ); |
9ffffee4 | 117 | return self.tcx.ty_error_misc(); |
29967ef6 XL |
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 | ) | |
9c376795 | 217 | .emit(); |
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 | |
49aad941 | 286 | .emit_err(errors::ConstSelectMustBeConst { span: provided_arg.span }); |
f2b60f7d FG |
287 | } |
288 | } else { | |
49aad941 FG |
289 | self.tcx.sess.emit_err(errors::ConstSelectMustBeFn { |
290 | span: provided_arg.span, | |
291 | ty: checked_ty, | |
292 | }); | |
f2b60f7d FG |
293 | } |
294 | } | |
295 | ||
923072b8 FG |
296 | // 3. Check if the formal type is a supertype of the checked one |
297 | // and register any such obligations for future type checks | |
353b0b11 FG |
298 | let supertype_error = self.at(&self.misc(provided_arg.span), self.param_env).sup( |
299 | DefineOpaqueTypes::No, | |
300 | formal_input_ty, | |
301 | coerced_ty, | |
302 | ); | |
923072b8 FG |
303 | let subtyping_error = match supertype_error { |
304 | Ok(InferOk { obligations, value: () }) => { | |
305 | self.register_predicates(obligations); | |
306 | None | |
307 | } | |
308 | Err(err) => Some(err), | |
309 | }; | |
310 | ||
311 | // If neither check failed, the types are compatible | |
312 | match subtyping_error { | |
313 | None => Compatibility::Compatible, | |
314 | Some(_) => Compatibility::Incompatible(subtyping_error), | |
315 | } | |
316 | }; | |
317 | ||
923072b8 FG |
318 | // To start, we only care "along the diagonal", where we expect every |
319 | // provided arg to be in the right spot | |
064997fb FG |
320 | let mut compatibility_diagonal = |
321 | vec![Compatibility::Incompatible(None); provided_args.len()]; | |
923072b8 FG |
322 | |
323 | // Keep track of whether we *could possibly* be satisfied, i.e. whether we're on the happy path | |
324 | // if the wrong number of arguments were supplied, we CAN'T be satisfied, | |
325 | // and if we're c_variadic, the supplied arguments must be >= the minimum count from the function | |
326 | // otherwise, they need to be identical, because rust doesn't currently support variadic functions | |
327 | let mut call_appears_satisfied = if c_variadic { | |
328 | provided_arg_count >= minimum_input_count | |
329 | } else { | |
330 | provided_arg_count == minimum_input_count | |
331 | }; | |
5e7ed085 | 332 | |
29967ef6 XL |
333 | // Check the arguments. |
334 | // We do this in a pretty awful way: first we type-check any arguments | |
335 | // that are not closures, then we type-check the closures. This is so | |
336 | // that we have more information about the types of arguments when we | |
337 | // type-check the functions. This isn't really the right way to do this. | |
136023e0 | 338 | for check_closures in [false, true] { |
29967ef6 XL |
339 | // More awful hacks: before we check argument types, try to do |
340 | // an "opportunistic" trait resolution of any trait bounds on | |
341 | // the call. This helps coercions. | |
342 | if check_closures { | |
487cf647 | 343 | self.select_obligations_where_possible(|_| {}) |
29967ef6 XL |
344 | } |
345 | ||
923072b8 FG |
346 | // Check each argument, to satisfy the input it was provided for |
347 | // Visually, we're traveling down the diagonal of the compatibility matrix | |
a2a8927a | 348 | for (idx, arg) in provided_args.iter().enumerate() { |
29967ef6 XL |
349 | // Warn only for the first loop (the "no closures" one). |
350 | // Closure arguments themselves can't be diverging, but | |
351 | // a previous argument can, e.g., `foo(panic!(), || {})`. | |
352 | if !check_closures { | |
353 | self.warn_if_unreachable(arg.hir_id, arg.span, "expression"); | |
354 | } | |
355 | ||
a2a8927a XL |
356 | // For C-variadic functions, we don't have a declared type for all of |
357 | // the arguments hence we only do our usual type checking with | |
358 | // the arguments who's types we do know. However, we *can* check | |
359 | // for unreachable expressions (see above). | |
360 | // FIXME: unreachable warning current isn't emitted | |
361 | if idx >= minimum_input_count { | |
362 | continue; | |
363 | } | |
29967ef6 | 364 | |
49aad941 FG |
365 | // For this check, we do *not* want to treat async generator closures (async blocks) |
366 | // as proper closures. Doing so would regress type inference when feeding | |
367 | // the return value of an argument-position async block to an argument-position | |
368 | // closure wrapped in a block. | |
369 | // See <https://github.com/rust-lang/rust/issues/112225>. | |
370 | let is_closure = if let ExprKind::Closure(closure) = arg.kind { | |
371 | !tcx.generator_is_async(closure.def_id.to_def_id()) | |
372 | } else { | |
373 | false | |
374 | }; | |
29967ef6 XL |
375 | if is_closure != check_closures { |
376 | continue; | |
377 | } | |
378 | ||
064997fb | 379 | let compatible = demand_compatible(idx); |
923072b8 | 380 | let is_compatible = matches!(compatible, Compatibility::Compatible); |
064997fb | 381 | compatibility_diagonal[idx] = compatible; |
923072b8 FG |
382 | |
383 | if !is_compatible { | |
384 | call_appears_satisfied = false; | |
385 | } | |
29967ef6 XL |
386 | } |
387 | } | |
388 | ||
064997fb FG |
389 | if c_variadic && provided_arg_count < minimum_input_count { |
390 | err_code = "E0060"; | |
391 | } | |
392 | ||
393 | for arg in provided_args.iter().skip(minimum_input_count) { | |
394 | // Make sure we've checked this expr at least once. | |
395 | let arg_ty = self.check_expr(&arg); | |
396 | ||
397 | // If the function is c-style variadic, we skipped a bunch of arguments | |
398 | // so we need to check those, and write out the types | |
399 | // Ideally this would be folded into the above, for uniform style | |
400 | // but c-variadic is already a corner case | |
401 | if c_variadic { | |
402 | fn variadic_error<'tcx>( | |
403 | sess: &'tcx Session, | |
404 | span: Span, | |
405 | ty: Ty<'tcx>, | |
406 | cast_ty: &str, | |
407 | ) { | |
2b03887a | 408 | use rustc_hir_analysis::structured_errors::MissingCastForVariadicArg; |
064997fb FG |
409 | |
410 | MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit(); | |
411 | } | |
412 | ||
413 | // There are a few types which get autopromoted when passed via varargs | |
414 | // in C but we just error out instead and require explicit casts. | |
415 | let arg_ty = self.structurally_resolved_type(arg.span, arg_ty); | |
416 | match arg_ty.kind() { | |
417 | ty::Float(ty::FloatTy::F32) => { | |
418 | variadic_error(tcx.sess, arg.span, arg_ty, "c_double"); | |
419 | } | |
420 | ty::Int(ty::IntTy::I8 | ty::IntTy::I16) | ty::Bool => { | |
421 | variadic_error(tcx.sess, arg.span, arg_ty, "c_int"); | |
422 | } | |
423 | ty::Uint(ty::UintTy::U8 | ty::UintTy::U16) => { | |
424 | variadic_error(tcx.sess, arg.span, arg_ty, "c_uint"); | |
425 | } | |
426 | ty::FnDef(..) => { | |
427 | let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx)); | |
428 | let ptr_ty = self.resolve_vars_if_possible(ptr_ty); | |
429 | variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string()); | |
430 | } | |
431 | _ => {} | |
432 | } | |
923072b8 | 433 | } |
064997fb | 434 | } |
923072b8 | 435 | |
064997fb FG |
436 | if !call_appears_satisfied { |
437 | let compatibility_diagonal = IndexVec::from_raw(compatibility_diagonal); | |
438 | let provided_args = IndexVec::from_iter(provided_args.iter().take(if c_variadic { | |
439 | minimum_input_count | |
440 | } else { | |
441 | provided_arg_count | |
442 | })); | |
443 | debug_assert_eq!( | |
444 | formal_input_tys.len(), | |
445 | expected_input_tys.len(), | |
446 | "expected formal_input_tys to be the same size as expected_input_tys" | |
447 | ); | |
448 | let formal_and_expected_inputs = IndexVec::from_iter( | |
449 | formal_input_tys | |
450 | .iter() | |
451 | .copied() | |
452 | .zip(expected_input_tys.iter().copied()) | |
453 | .map(|vars| self.resolve_vars_if_possible(vars)), | |
454 | ); | |
923072b8 | 455 | |
064997fb FG |
456 | self.report_arg_errors( |
457 | compatibility_diagonal, | |
458 | formal_and_expected_inputs, | |
459 | provided_args, | |
460 | c_variadic, | |
461 | err_code, | |
462 | fn_def_id, | |
463 | call_span, | |
464 | call_expr, | |
465 | ); | |
466 | } | |
467 | } | |
923072b8 | 468 | |
064997fb FG |
469 | fn report_arg_errors( |
470 | &self, | |
471 | compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>, | |
472 | formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>, | |
473 | provided_args: IndexVec<ProvidedIdx, &'tcx hir::Expr<'tcx>>, | |
474 | c_variadic: bool, | |
475 | err_code: &str, | |
476 | fn_def_id: Option<DefId>, | |
477 | call_span: Span, | |
353b0b11 | 478 | call_expr: &'tcx hir::Expr<'tcx>, |
064997fb FG |
479 | ) { |
480 | // Next, let's construct the error | |
9c376795 | 481 | let (error_span, full_call_span, call_name, is_method) = match &call_expr.kind { |
064997fb FG |
482 | hir::ExprKind::Call( |
483 | hir::Expr { hir_id, span, kind: hir::ExprKind::Path(qpath), .. }, | |
484 | _, | |
485 | ) => { | |
486 | if let Res::Def(DefKind::Ctor(of, _), _) = | |
487 | self.typeck_results.borrow().qpath_res(qpath, *hir_id) | |
488 | { | |
9c376795 FG |
489 | let name = match of { |
490 | CtorOf::Struct => "struct", | |
491 | CtorOf::Variant => "enum variant", | |
492 | }; | |
493 | (call_span, *span, name, false) | |
064997fb | 494 | } else { |
9c376795 | 495 | (call_span, *span, "function", false) |
064997fb FG |
496 | } |
497 | } | |
9c376795 | 498 | hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, "function", false), |
f2b60f7d | 499 | hir::ExprKind::MethodCall(path_segment, _, _, span) => { |
064997fb FG |
500 | let ident_span = path_segment.ident.span; |
501 | let ident_span = if let Some(args) = path_segment.args { | |
502 | ident_span.with_hi(args.span_ext.hi()) | |
503 | } else { | |
504 | ident_span | |
505 | }; | |
9c376795 | 506 | (*span, ident_span, "method", true) |
064997fb FG |
507 | } |
508 | k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k), | |
509 | }; | |
510 | let args_span = error_span.trim_start(full_call_span).unwrap_or(error_span); | |
923072b8 | 511 | |
064997fb FG |
512 | // Don't print if it has error types or is just plain `_` |
513 | fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool { | |
514 | tys.into_iter().any(|ty| ty.references_error() || ty.is_ty_var()) | |
515 | } | |
516 | ||
064997fb | 517 | let tcx = self.tcx; |
487cf647 FG |
518 | // FIXME: taint after emitting errors and pass through an `ErrorGuaranteed` |
519 | self.set_tainted_by_errors( | |
520 | tcx.sess.delay_span_bug(call_span, "no errors reported for args"), | |
521 | ); | |
064997fb FG |
522 | |
523 | // Get the argument span in the context of the call span so that | |
524 | // suggestions and labels are (more) correct when an arg is a | |
525 | // macro invocation. | |
526 | let normalize_span = |span: Span| -> Span { | |
527 | let normalized_span = span.find_ancestor_inside(error_span).unwrap_or(span); | |
528 | // Sometimes macros mess up the spans, so do not normalize the | |
529 | // arg span to equal the error span, because that's less useful | |
530 | // than pointing out the arg expr in the wrong context. | |
531 | if normalized_span.source_equal(error_span) { span } else { normalized_span } | |
532 | }; | |
533 | ||
534 | // Precompute the provided types and spans, since that's all we typically need for below | |
535 | let provided_arg_tys: IndexVec<ProvidedIdx, (Ty<'tcx>, Span)> = provided_args | |
536 | .iter() | |
537 | .map(|expr| { | |
538 | let ty = self | |
539 | .typeck_results | |
540 | .borrow() | |
541 | .expr_ty_adjusted_opt(*expr) | |
9ffffee4 | 542 | .unwrap_or_else(|| tcx.ty_error_misc()); |
064997fb FG |
543 | (self.resolve_vars_if_possible(ty), normalize_span(expr.span)) |
544 | }) | |
545 | .collect(); | |
546 | let callee_expr = match &call_expr.peel_blocks().kind { | |
547 | hir::ExprKind::Call(callee, _) => Some(*callee), | |
f2b60f7d | 548 | hir::ExprKind::MethodCall(_, receiver, ..) => { |
064997fb FG |
549 | if let Some((DefKind::AssocFn, def_id)) = |
550 | self.typeck_results.borrow().type_dependent_def(call_expr.hir_id) | |
551 | && let Some(assoc) = tcx.opt_associated_item(def_id) | |
552 | && assoc.fn_has_self_parameter | |
553 | { | |
f2b60f7d | 554 | Some(*receiver) |
064997fb FG |
555 | } else { |
556 | None | |
923072b8 | 557 | } |
064997fb FG |
558 | } |
559 | _ => None, | |
560 | }; | |
561 | let callee_ty = callee_expr | |
562 | .and_then(|callee_expr| self.typeck_results.borrow().expr_ty_adjusted_opt(callee_expr)); | |
563 | ||
564 | // A "softer" version of the `demand_compatible`, which checks types without persisting them, | |
565 | // and treats error types differently | |
566 | // This will allow us to "probe" for other argument orders that would likely have been correct | |
567 | let check_compatible = |provided_idx: ProvidedIdx, expected_idx: ExpectedIdx| { | |
568 | if provided_idx.as_usize() == expected_idx.as_usize() { | |
569 | return compatibility_diagonal[provided_idx].clone(); | |
570 | } | |
571 | ||
572 | let (formal_input_ty, expected_input_ty) = formal_and_expected_inputs[expected_idx]; | |
573 | // If either is an error type, we defy the usual convention and consider them to *not* be | |
574 | // coercible. This prevents our error message heuristic from trying to pass errors into | |
575 | // every argument. | |
576 | if (formal_input_ty, expected_input_ty).references_error() { | |
577 | return Compatibility::Incompatible(None); | |
578 | } | |
579 | ||
580 | let (arg_ty, arg_span) = provided_arg_tys[provided_idx]; | |
581 | ||
582 | let expectation = Expectation::rvalue_hint(self, expected_input_ty); | |
583 | let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty); | |
584 | let can_coerce = self.can_coerce(arg_ty, coerced_ty); | |
585 | if !can_coerce { | |
f2b60f7d FG |
586 | return Compatibility::Incompatible(Some(ty::error::TypeError::Sorts( |
587 | ty::error::ExpectedFound::new(true, coerced_ty, arg_ty), | |
588 | ))); | |
064997fb FG |
589 | } |
590 | ||
591 | // Using probe here, since we don't want this subtyping to affect inference. | |
592 | let subtyping_error = self.probe(|_| { | |
353b0b11 FG |
593 | self.at(&self.misc(arg_span), self.param_env) |
594 | .sup(DefineOpaqueTypes::No, formal_input_ty, coerced_ty) | |
595 | .err() | |
923072b8 FG |
596 | }); |
597 | ||
064997fb FG |
598 | // Same as above: if either the coerce type or the checked type is an error type, |
599 | // consider them *not* compatible. | |
600 | let references_error = (coerced_ty, arg_ty).references_error(); | |
601 | match (references_error, subtyping_error) { | |
602 | (false, None) => Compatibility::Compatible, | |
603 | (_, subtyping_error) => Compatibility::Incompatible(subtyping_error), | |
923072b8 | 604 | } |
064997fb | 605 | }; |
923072b8 | 606 | |
487cf647 FG |
607 | let mk_trace = |span, (formal_ty, expected_ty), provided_ty| { |
608 | let mismatched_ty = if expected_ty == provided_ty { | |
609 | // If expected == provided, then we must have failed to sup | |
610 | // the formal type. Avoid printing out "expected Ty, found Ty" | |
611 | // in that case. | |
612 | formal_ty | |
613 | } else { | |
614 | expected_ty | |
615 | }; | |
616 | TypeTrace::types(&self.misc(span), true, mismatched_ty, provided_ty) | |
617 | }; | |
618 | ||
064997fb FG |
619 | // The algorithm here is inspired by levenshtein distance and longest common subsequence. |
620 | // We'll try to detect 4 different types of mistakes: | |
621 | // - An extra parameter has been provided that doesn't satisfy *any* of the other inputs | |
622 | // - An input is missing, which isn't satisfied by *any* of the other arguments | |
623 | // - Some number of arguments have been provided in the wrong order | |
624 | // - A type is straight up invalid | |
625 | ||
626 | // First, let's find the errors | |
627 | let (mut errors, matched_inputs) = | |
628 | ArgMatrix::new(provided_args.len(), formal_and_expected_inputs.len(), check_compatible) | |
629 | .find_errors(); | |
630 | ||
631 | // First, check if we just need to wrap some arguments in a tuple. | |
632 | if let Some((mismatch_idx, terr)) = | |
633 | compatibility_diagonal.iter().enumerate().find_map(|(i, c)| { | |
f2b60f7d FG |
634 | if let Compatibility::Incompatible(Some(terr)) = c { |
635 | Some((i, *terr)) | |
636 | } else { | |
637 | None | |
638 | } | |
064997fb FG |
639 | }) |
640 | { | |
641 | // Is the first bad expected argument a tuple? | |
642 | // Do we have as many extra provided arguments as the tuple's length? | |
643 | // If so, we might have just forgotten to wrap some args in a tuple. | |
644 | if let Some(ty::Tuple(tys)) = | |
645 | formal_and_expected_inputs.get(mismatch_idx.into()).map(|tys| tys.1.kind()) | |
646 | // If the tuple is unit, we're not actually wrapping any arguments. | |
647 | && !tys.is_empty() | |
648 | && provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len() | |
649 | { | |
650 | // Wrap up the N provided arguments starting at this position in a tuple. | |
9ffffee4 | 651 | let provided_as_tuple = tcx.mk_tup_from_iter( |
064997fb FG |
652 | provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx).take(tys.len()), |
653 | ); | |
654 | ||
655 | let mut satisfied = true; | |
656 | // Check if the newly wrapped tuple + rest of the arguments are compatible. | |
657 | for ((_, expected_ty), provided_ty) in std::iter::zip( | |
658 | formal_and_expected_inputs.iter().skip(mismatch_idx), | |
659 | [provided_as_tuple].into_iter().chain( | |
660 | provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx + tys.len()), | |
661 | ), | |
662 | ) { | |
663 | if !self.can_coerce(provided_ty, *expected_ty) { | |
664 | satisfied = false; | |
665 | break; | |
666 | } | |
5099ac24 | 667 | } |
5e7ed085 | 668 | |
064997fb FG |
669 | // If they're compatible, suggest wrapping in an arg, and we're done! |
670 | // Take some care with spans, so we don't suggest wrapping a macro's | |
671 | // innards in parenthesis, for example. | |
672 | if satisfied | |
673 | && let Some((_, lo)) = | |
674 | provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx)) | |
675 | && let Some((_, hi)) = | |
676 | provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx + tys.len() - 1)) | |
677 | { | |
678 | let mut err; | |
679 | if tys.len() == 1 { | |
680 | // A tuple wrap suggestion actually occurs within, | |
681 | // so don't do anything special here. | |
2b03887a | 682 | err = self.err_ctxt().report_and_explain_type_error( |
487cf647 FG |
683 | mk_trace( |
684 | *lo, | |
685 | formal_and_expected_inputs[mismatch_idx.into()], | |
064997fb FG |
686 | provided_arg_tys[mismatch_idx.into()].0, |
687 | ), | |
688 | terr, | |
689 | ); | |
690 | err.span_label( | |
691 | full_call_span, | |
692 | format!("arguments to this {} are incorrect", call_name), | |
693 | ); | |
694 | } else { | |
695 | err = tcx.sess.struct_span_err_with_code( | |
696 | full_call_span, | |
49aad941 | 697 | format!( |
9c376795 | 698 | "{call_name} takes {}{} but {} {} supplied", |
064997fb FG |
699 | if c_variadic { "at least " } else { "" }, |
700 | potentially_plural_count( | |
701 | formal_and_expected_inputs.len(), | |
702 | "argument" | |
703 | ), | |
704 | potentially_plural_count(provided_args.len(), "argument"), | |
705 | pluralize!("was", provided_args.len()) | |
706 | ), | |
707 | DiagnosticId::Error(err_code.to_owned()), | |
708 | ); | |
709 | err.multipart_suggestion_verbose( | |
710 | "wrap these arguments in parentheses to construct a tuple", | |
711 | vec![ | |
712 | (lo.shrink_to_lo(), "(".to_string()), | |
713 | (hi.shrink_to_hi(), ")".to_string()), | |
714 | ], | |
715 | Applicability::MachineApplicable, | |
716 | ); | |
923072b8 | 717 | }; |
f2b60f7d FG |
718 | self.label_fn_like( |
719 | &mut err, | |
720 | fn_def_id, | |
721 | callee_ty, | |
722 | Some(mismatch_idx), | |
723 | is_method, | |
724 | ); | |
923072b8 | 725 | err.emit(); |
064997fb | 726 | return; |
04454e1e | 727 | } |
923072b8 | 728 | } |
064997fb FG |
729 | } |
730 | ||
731 | // Okay, so here's where it gets complicated in regards to what errors | |
732 | // we emit and how. | |
733 | // There are 3 different "types" of errors we might encounter. | |
734 | // 1) Missing/extra/swapped arguments | |
735 | // 2) Valid but incorrect arguments | |
736 | // 3) Invalid arguments | |
737 | // - Currently I think this only comes up with `CyclicTy` | |
738 | // | |
739 | // We first need to go through, remove those from (3) and emit those | |
740 | // as their own error, particularly since they're error code and | |
741 | // message is special. From what I can tell, we *must* emit these | |
742 | // here (vs somewhere prior to this function) since the arguments | |
743 | // become invalid *because* of how they get used in the function. | |
744 | // It is what it is. | |
745 | ||
746 | if errors.is_empty() { | |
747 | if cfg!(debug_assertions) { | |
748 | span_bug!(error_span, "expected errors from argument matrix"); | |
749 | } else { | |
49aad941 | 750 | tcx.sess.emit_err(errors::ArgMismatchIndeterminate { span: error_span }); |
064997fb FG |
751 | } |
752 | return; | |
753 | } | |
754 | ||
755 | errors.drain_filter(|error| { | |
9ffffee4 FG |
756 | let Error::Invalid( |
757 | provided_idx, | |
758 | expected_idx, | |
759 | Compatibility::Incompatible(Some(e)), | |
760 | ) = error else { return false }; | |
761 | let (provided_ty, provided_span) = provided_arg_tys[*provided_idx]; | |
762 | let trace = | |
763 | mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty); | |
353b0b11 | 764 | if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) { |
9ffffee4 FG |
765 | self.err_ctxt().report_and_explain_type_error(trace, *e).emit(); |
766 | return true; | |
767 | } | |
768 | false | |
769 | }); | |
064997fb FG |
770 | |
771 | // We're done if we found errors, but we already emitted them. | |
772 | if errors.is_empty() { | |
773 | return; | |
774 | } | |
775 | ||
776 | // Okay, now that we've emitted the special errors separately, we | |
777 | // are only left missing/extra/swapped and mismatched arguments, both | |
778 | // can be collated pretty easily if needed. | |
779 | ||
780 | // Next special case: if there is only one "Incompatible" error, just emit that | |
781 | if let [ | |
782 | Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(err))), | |
783 | ] = &errors[..] | |
784 | { | |
785 | let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx]; | |
786 | let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx]; | |
487cf647 | 787 | let trace = mk_trace(provided_arg_span, (formal_ty, expected_ty), provided_ty); |
2b03887a | 788 | let mut err = self.err_ctxt().report_and_explain_type_error(trace, *err); |
064997fb FG |
789 | self.emit_coerce_suggestions( |
790 | &mut err, | |
791 | &provided_args[*provided_idx], | |
792 | provided_ty, | |
793 | Expectation::rvalue_hint(self, expected_ty) | |
794 | .only_has_type(self) | |
795 | .unwrap_or(formal_ty), | |
796 | None, | |
797 | None, | |
798 | ); | |
799 | err.span_label( | |
800 | full_call_span, | |
801 | format!("arguments to this {} are incorrect", call_name), | |
802 | ); | |
353b0b11 FG |
803 | |
804 | if let hir::ExprKind::MethodCall(_, rcvr, _, _) = call_expr.kind | |
805 | && provided_idx.as_usize() == expected_idx.as_usize() | |
9ffffee4 | 806 | { |
353b0b11 | 807 | self.note_source_of_type_mismatch_constraint( |
9ffffee4 FG |
808 | &mut err, |
809 | rcvr, | |
353b0b11 FG |
810 | crate::demand::TypeMismatchSource::Arg { |
811 | call_expr, | |
812 | incompatible_arg: provided_idx.as_usize(), | |
813 | }, | |
9ffffee4 FG |
814 | ); |
815 | } | |
353b0b11 | 816 | |
064997fb | 817 | // Call out where the function is defined |
f2b60f7d FG |
818 | self.label_fn_like( |
819 | &mut err, | |
820 | fn_def_id, | |
821 | callee_ty, | |
822 | Some(expected_idx.as_usize()), | |
823 | is_method, | |
824 | ); | |
064997fb FG |
825 | err.emit(); |
826 | return; | |
827 | } | |
828 | ||
829 | let mut err = if formal_and_expected_inputs.len() == provided_args.len() { | |
830 | struct_span_err!( | |
831 | tcx.sess, | |
832 | full_call_span, | |
833 | E0308, | |
834 | "arguments to this {} are incorrect", | |
835 | call_name, | |
836 | ) | |
837 | } else { | |
838 | tcx.sess.struct_span_err_with_code( | |
839 | full_call_span, | |
49aad941 | 840 | format!( |
064997fb FG |
841 | "this {} takes {}{} but {} {} supplied", |
842 | call_name, | |
843 | if c_variadic { "at least " } else { "" }, | |
844 | potentially_plural_count(formal_and_expected_inputs.len(), "argument"), | |
845 | potentially_plural_count(provided_args.len(), "argument"), | |
846 | pluralize!("was", provided_args.len()) | |
847 | ), | |
848 | DiagnosticId::Error(err_code.to_owned()), | |
849 | ) | |
850 | }; | |
851 | ||
852 | // As we encounter issues, keep track of what we want to provide for the suggestion | |
853 | let mut labels = vec![]; | |
854 | // If there is a single error, we give a specific suggestion; otherwise, we change to | |
855 | // "did you mean" with the suggested function call | |
856 | enum SuggestionText { | |
857 | None, | |
858 | Provide(bool), | |
859 | Remove(bool), | |
860 | Swap, | |
861 | Reorder, | |
862 | DidYouMean, | |
863 | } | |
864 | let mut suggestion_text = SuggestionText::None; | |
865 | ||
9ffffee4 FG |
866 | let ty_to_snippet = |ty: Ty<'tcx>, expected_idx: ExpectedIdx| { |
867 | if ty.is_unit() { | |
868 | "()".to_string() | |
869 | } else if ty.is_suggestable(tcx, false) { | |
870 | format!("/* {} */", ty) | |
871 | } else if let Some(fn_def_id) = fn_def_id | |
872 | && self.tcx.def_kind(fn_def_id).is_fn_like() | |
873 | && let self_implicit = | |
874 | matches!(call_expr.kind, hir::ExprKind::MethodCall(..)) as usize | |
875 | && let Some(arg) = self.tcx.fn_arg_names(fn_def_id) | |
876 | .get(expected_idx.as_usize() + self_implicit) | |
877 | && arg.name != kw::SelfLower | |
878 | { | |
879 | format!("/* {} */", arg.name) | |
880 | } else { | |
881 | "/* value */".to_string() | |
882 | } | |
883 | }; | |
884 | ||
064997fb | 885 | let mut errors = errors.into_iter().peekable(); |
353b0b11 FG |
886 | let mut only_extras_so_far = errors |
887 | .peek() | |
49aad941 | 888 | .is_some_and(|first| matches!(first, Error::Extra(arg_idx) if arg_idx.index() == 0)); |
9ffffee4 | 889 | let mut suggestions = vec![]; |
064997fb | 890 | while let Some(error) = errors.next() { |
353b0b11 FG |
891 | only_extras_so_far &= matches!(error, Error::Extra(_)); |
892 | ||
064997fb FG |
893 | match error { |
894 | Error::Invalid(provided_idx, expected_idx, compatibility) => { | |
895 | let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx]; | |
896 | let (provided_ty, provided_span) = provided_arg_tys[provided_idx]; | |
f2b60f7d | 897 | if let Compatibility::Incompatible(error) = compatibility { |
487cf647 | 898 | let trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty); |
064997fb | 899 | if let Some(e) = error { |
2b03887a | 900 | self.err_ctxt().note_type_err( |
064997fb FG |
901 | &mut err, |
902 | &trace.cause, | |
903 | None, | |
904 | Some(trace.values), | |
905 | e, | |
906 | false, | |
907 | true, | |
908 | ); | |
909 | } | |
910 | } | |
923072b8 | 911 | |
923072b8 FG |
912 | self.emit_coerce_suggestions( |
913 | &mut err, | |
064997fb | 914 | &provided_args[provided_idx], |
923072b8 | 915 | provided_ty, |
064997fb FG |
916 | Expectation::rvalue_hint(self, expected_ty) |
917 | .only_has_type(self) | |
918 | .unwrap_or(formal_ty), | |
923072b8 FG |
919 | None, |
920 | None, | |
921 | ); | |
923072b8 | 922 | } |
064997fb FG |
923 | Error::Extra(arg_idx) => { |
924 | let (provided_ty, provided_span) = provided_arg_tys[arg_idx]; | |
925 | let provided_ty_name = if !has_error_or_infer([provided_ty]) { | |
926 | // FIXME: not suggestable, use something else | |
927 | format!(" of type `{}`", provided_ty) | |
928 | } else { | |
929 | "".to_string() | |
930 | }; | |
931 | labels | |
9ffffee4 FG |
932 | .push((provided_span, format!("unexpected argument{}", provided_ty_name))); |
933 | let mut span = provided_span; | |
934 | if span.can_be_used_for_suggestions() { | |
935 | if arg_idx.index() > 0 | |
936 | && let Some((_, prev)) = provided_arg_tys | |
937 | .get(ProvidedIdx::from_usize(arg_idx.index() - 1) | |
353b0b11 FG |
938 | ) { |
939 | // Include previous comma | |
940 | span = prev.shrink_to_hi().to(span); | |
941 | } | |
942 | ||
943 | // Is last argument for deletion in a row starting from the 0-th argument? | |
944 | // Then delete the next comma, so we are not left with `f(, ...)` | |
945 | // | |
946 | // fn f() {} | |
947 | // - f(0, 1,) | |
948 | // + f() | |
949 | if only_extras_so_far | |
950 | && errors | |
951 | .peek() | |
952 | .map_or(true, |next_error| !matches!(next_error, Error::Extra(_))) | |
953 | { | |
954 | let next = provided_arg_tys | |
955 | .get(arg_idx + 1) | |
956 | .map(|&(_, sp)| sp) | |
957 | .unwrap_or_else(|| { | |
958 | // Subtract one to move before `)` | |
959 | call_expr.span.with_lo(call_expr.span.hi() - BytePos(1)) | |
960 | }); | |
961 | ||
962 | // Include next comma | |
963 | span = span.until(next); | |
964 | } | |
965 | ||
9ffffee4 FG |
966 | suggestions.push((span, String::new())); |
967 | ||
968 | suggestion_text = match suggestion_text { | |
969 | SuggestionText::None => SuggestionText::Remove(false), | |
970 | SuggestionText::Remove(_) => SuggestionText::Remove(true), | |
971 | _ => SuggestionText::DidYouMean, | |
972 | }; | |
973 | } | |
064997fb FG |
974 | } |
975 | Error::Missing(expected_idx) => { | |
976 | // If there are multiple missing arguments adjacent to each other, | |
977 | // then we can provide a single error. | |
978 | ||
979 | let mut missing_idxs = vec![expected_idx]; | |
980 | while let Some(e) = errors.next_if(|e| { | |
981 | matches!(e, Error::Missing(next_expected_idx) | |
982 | if *next_expected_idx == *missing_idxs.last().unwrap() + 1) | |
983 | }) { | |
984 | match e { | |
985 | Error::Missing(expected_idx) => missing_idxs.push(expected_idx), | |
986 | _ => unreachable!(), | |
923072b8 | 987 | } |
923072b8 | 988 | } |
064997fb FG |
989 | |
990 | // NOTE: Because we might be re-arranging arguments, might have extra | |
991 | // arguments, etc. it's hard to *really* know where we should provide | |
992 | // this error label, so as a heuristic, we point to the provided arg, or | |
993 | // to the call if the missing inputs pass the provided args. | |
994 | match &missing_idxs[..] { | |
995 | &[expected_idx] => { | |
996 | let (_, input_ty) = formal_and_expected_inputs[expected_idx]; | |
997 | let span = if let Some((_, arg_span)) = | |
998 | provided_arg_tys.get(expected_idx.to_provided_idx()) | |
999 | { | |
1000 | *arg_span | |
923072b8 | 1001 | } else { |
064997fb FG |
1002 | args_span |
1003 | }; | |
1004 | let rendered = if !has_error_or_infer([input_ty]) { | |
1005 | format!(" of type `{}`", input_ty) | |
1006 | } else { | |
1007 | "".to_string() | |
1008 | }; | |
1009 | labels.push((span, format!("an argument{} is missing", rendered))); | |
1010 | suggestion_text = match suggestion_text { | |
1011 | SuggestionText::None => SuggestionText::Provide(false), | |
1012 | SuggestionText::Provide(_) => SuggestionText::Provide(true), | |
1013 | _ => SuggestionText::DidYouMean, | |
1014 | }; | |
923072b8 | 1015 | } |
064997fb FG |
1016 | &[first_idx, second_idx] => { |
1017 | let (_, first_expected_ty) = formal_and_expected_inputs[first_idx]; | |
1018 | let (_, second_expected_ty) = formal_and_expected_inputs[second_idx]; | |
1019 | let span = if let (Some((_, first_span)), Some((_, second_span))) = ( | |
1020 | provided_arg_tys.get(first_idx.to_provided_idx()), | |
1021 | provided_arg_tys.get(second_idx.to_provided_idx()), | |
1022 | ) { | |
1023 | first_span.to(*second_span) | |
1024 | } else { | |
1025 | args_span | |
1026 | }; | |
1027 | let rendered = | |
1028 | if !has_error_or_infer([first_expected_ty, second_expected_ty]) { | |
923072b8 FG |
1029 | format!( |
1030 | " of type `{}` and `{}`", | |
064997fb | 1031 | first_expected_ty, second_expected_ty |
923072b8 FG |
1032 | ) |
1033 | } else { | |
064997fb | 1034 | "".to_string() |
923072b8 | 1035 | }; |
064997fb FG |
1036 | labels.push((span, format!("two arguments{} are missing", rendered))); |
1037 | suggestion_text = match suggestion_text { | |
1038 | SuggestionText::None | SuggestionText::Provide(_) => { | |
1039 | SuggestionText::Provide(true) | |
1040 | } | |
1041 | _ => SuggestionText::DidYouMean, | |
1042 | }; | |
923072b8 | 1043 | } |
064997fb FG |
1044 | &[first_idx, second_idx, third_idx] => { |
1045 | let (_, first_expected_ty) = formal_and_expected_inputs[first_idx]; | |
1046 | let (_, second_expected_ty) = formal_and_expected_inputs[second_idx]; | |
1047 | let (_, third_expected_ty) = formal_and_expected_inputs[third_idx]; | |
1048 | let span = if let (Some((_, first_span)), Some((_, third_span))) = ( | |
1049 | provided_arg_tys.get(first_idx.to_provided_idx()), | |
1050 | provided_arg_tys.get(third_idx.to_provided_idx()), | |
1051 | ) { | |
1052 | first_span.to(*third_span) | |
923072b8 | 1053 | } else { |
064997fb | 1054 | args_span |
923072b8 | 1055 | }; |
064997fb FG |
1056 | let rendered = if !has_error_or_infer([ |
1057 | first_expected_ty, | |
1058 | second_expected_ty, | |
1059 | third_expected_ty, | |
1060 | ]) { | |
1061 | format!( | |
1062 | " of type `{}`, `{}`, and `{}`", | |
1063 | first_expected_ty, second_expected_ty, third_expected_ty | |
1064 | ) | |
923072b8 | 1065 | } else { |
064997fb FG |
1066 | "".to_string() |
1067 | }; | |
1068 | labels.push((span, format!("three arguments{} are missing", rendered))); | |
1069 | suggestion_text = match suggestion_text { | |
1070 | SuggestionText::None | SuggestionText::Provide(_) => { | |
1071 | SuggestionText::Provide(true) | |
1072 | } | |
1073 | _ => SuggestionText::DidYouMean, | |
1074 | }; | |
1075 | } | |
1076 | missing_idxs => { | |
1077 | let first_idx = *missing_idxs.first().unwrap(); | |
1078 | let last_idx = *missing_idxs.last().unwrap(); | |
1079 | // NOTE: Because we might be re-arranging arguments, might have extra arguments, etc. | |
1080 | // It's hard to *really* know where we should provide this error label, so this is a | |
1081 | // decent heuristic | |
1082 | let span = if let (Some((_, first_span)), Some((_, last_span))) = ( | |
1083 | provided_arg_tys.get(first_idx.to_provided_idx()), | |
1084 | provided_arg_tys.get(last_idx.to_provided_idx()), | |
1085 | ) { | |
1086 | first_span.to(*last_span) | |
1087 | } else { | |
1088 | args_span | |
1089 | }; | |
9c376795 | 1090 | labels.push((span, "multiple arguments are missing".to_string())); |
064997fb FG |
1091 | suggestion_text = match suggestion_text { |
1092 | SuggestionText::None | SuggestionText::Provide(_) => { | |
1093 | SuggestionText::Provide(true) | |
1094 | } | |
1095 | _ => SuggestionText::DidYouMean, | |
923072b8 | 1096 | }; |
923072b8 | 1097 | } |
923072b8 FG |
1098 | } |
1099 | } | |
064997fb FG |
1100 | Error::Swap( |
1101 | first_provided_idx, | |
1102 | second_provided_idx, | |
1103 | first_expected_idx, | |
1104 | second_expected_idx, | |
1105 | ) => { | |
1106 | let (first_provided_ty, first_span) = provided_arg_tys[first_provided_idx]; | |
1107 | let (_, first_expected_ty) = formal_and_expected_inputs[first_expected_idx]; | |
1108 | let first_provided_ty_name = if !has_error_or_infer([first_provided_ty]) { | |
1109 | format!(", found `{}`", first_provided_ty) | |
923072b8 | 1110 | } else { |
064997fb FG |
1111 | String::new() |
1112 | }; | |
1113 | labels.push(( | |
1114 | first_span, | |
1115 | format!("expected `{}`{}", first_expected_ty, first_provided_ty_name), | |
1116 | )); | |
1117 | ||
1118 | let (second_provided_ty, second_span) = provided_arg_tys[second_provided_idx]; | |
1119 | let (_, second_expected_ty) = formal_and_expected_inputs[second_expected_idx]; | |
1120 | let second_provided_ty_name = if !has_error_or_infer([second_provided_ty]) { | |
1121 | format!(", found `{}`", second_provided_ty) | |
1122 | } else { | |
1123 | String::new() | |
923072b8 | 1124 | }; |
064997fb FG |
1125 | labels.push(( |
1126 | second_span, | |
1127 | format!("expected `{}`{}", second_expected_ty, second_provided_ty_name), | |
1128 | )); | |
1129 | ||
1130 | suggestion_text = match suggestion_text { | |
1131 | SuggestionText::None => SuggestionText::Swap, | |
1132 | _ => SuggestionText::DidYouMean, | |
1133 | }; | |
1134 | } | |
1135 | Error::Permutation(args) => { | |
1136 | for (dst_arg, dest_input) in args { | |
1137 | let (_, expected_ty) = formal_and_expected_inputs[dst_arg]; | |
1138 | let (provided_ty, provided_span) = provided_arg_tys[dest_input]; | |
1139 | let provided_ty_name = if !has_error_or_infer([provided_ty]) { | |
1140 | format!(", found `{}`", provided_ty) | |
1141 | } else { | |
1142 | String::new() | |
1143 | }; | |
1144 | labels.push(( | |
1145 | provided_span, | |
1146 | format!("expected `{}`{}", expected_ty, provided_ty_name), | |
1147 | )); | |
923072b8 | 1148 | } |
064997fb FG |
1149 | |
1150 | suggestion_text = match suggestion_text { | |
1151 | SuggestionText::None => SuggestionText::Reorder, | |
1152 | _ => SuggestionText::DidYouMean, | |
1153 | }; | |
04454e1e | 1154 | } |
5099ac24 | 1155 | } |
5099ac24 FG |
1156 | } |
1157 | ||
9ffffee4 FG |
1158 | // Incorporate the argument changes in the removal suggestion. |
1159 | // When a type is *missing*, and the rest are additional, we want to suggest these with a | |
1160 | // multipart suggestion, but in order to do so we need to figure out *where* the arg that | |
1161 | // was provided but had the wrong type should go, because when looking at `expected_idx` | |
1162 | // that is the position in the argument list in the definition, while `provided_idx` will | |
1163 | // not be present. So we have to look at what the *last* provided position was, and point | |
1164 | // one after to suggest the replacement. FIXME(estebank): This is hacky, and there's | |
1165 | // probably a better more involved change we can make to make this work. | |
1166 | // For example, if we have | |
1167 | // ``` | |
1168 | // fn foo(i32, &'static str) {} | |
1169 | // foo((), (), ()); | |
1170 | // ``` | |
1171 | // what should be suggested is | |
1172 | // ``` | |
1173 | // foo(/* i32 */, /* &str */); | |
1174 | // ``` | |
1175 | // which includes the replacement of the first two `()` for the correct type, and the | |
1176 | // removal of the last `()`. | |
1177 | let mut prev = -1; | |
1178 | for (expected_idx, provided_idx) in matched_inputs.iter_enumerated() { | |
1179 | // We want to point not at the *current* argument expression index, but rather at the | |
1180 | // index position where it *should have been*, which is *after* the previous one. | |
1181 | if let Some(provided_idx) = provided_idx { | |
1182 | prev = provided_idx.index() as i64; | |
353b0b11 | 1183 | continue; |
9ffffee4 FG |
1184 | } |
1185 | let idx = ProvidedIdx::from_usize((prev + 1) as usize); | |
353b0b11 FG |
1186 | if let Some((_, arg_span)) = provided_arg_tys.get(idx) { |
1187 | prev += 1; | |
9ffffee4 FG |
1188 | // There is a type that was *not* found anywhere, so it isn't a move, but a |
1189 | // replacement and we look at what type it should have been. This will allow us | |
1190 | // To suggest a multipart suggestion when encountering `foo(1, "")` where the def | |
1191 | // was `fn foo(())`. | |
1192 | let (_, expected_ty) = formal_and_expected_inputs[expected_idx]; | |
1193 | suggestions.push((*arg_span, ty_to_snippet(expected_ty, expected_idx))); | |
1194 | } | |
1195 | } | |
1196 | ||
064997fb FG |
1197 | // If we have less than 5 things to say, it would be useful to call out exactly what's wrong |
1198 | if labels.len() <= 5 { | |
1199 | for (span, label) in labels { | |
1200 | err.span_label(span, label); | |
1201 | } | |
1202 | } | |
5869c6ff | 1203 | |
064997fb | 1204 | // Call out where the function is defined |
f2b60f7d | 1205 | self.label_fn_like(&mut err, fn_def_id, callee_ty, None, is_method); |
29967ef6 | 1206 | |
064997fb FG |
1207 | // And add a suggestion block for all of the parameters |
1208 | let suggestion_text = match suggestion_text { | |
1209 | SuggestionText::None => None, | |
1210 | SuggestionText::Provide(plural) => { | |
1211 | Some(format!("provide the argument{}", if plural { "s" } else { "" })) | |
1212 | } | |
1213 | SuggestionText::Remove(plural) => { | |
9ffffee4 | 1214 | err.multipart_suggestion( |
49aad941 | 1215 | format!("remove the extra argument{}", if plural { "s" } else { "" }), |
9ffffee4 FG |
1216 | suggestions, |
1217 | Applicability::HasPlaceholders, | |
1218 | ); | |
1219 | None | |
064997fb FG |
1220 | } |
1221 | SuggestionText::Swap => Some("swap these arguments".to_string()), | |
1222 | SuggestionText::Reorder => Some("reorder these arguments".to_string()), | |
1223 | SuggestionText::DidYouMean => Some("did you mean".to_string()), | |
1224 | }; | |
1225 | if let Some(suggestion_text) = suggestion_text { | |
1226 | let source_map = self.sess().source_map(); | |
f2b60f7d FG |
1227 | let (mut suggestion, suggestion_span) = |
1228 | if let Some(call_span) = full_call_span.find_ancestor_inside(error_span) { | |
1229 | ("(".to_string(), call_span.shrink_to_hi().to(error_span.shrink_to_hi())) | |
1230 | } else { | |
1231 | ( | |
1232 | format!( | |
1233 | "{}(", | |
1234 | source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| { | |
1235 | fn_def_id.map_or("".to_string(), |fn_def_id| { | |
1236 | tcx.item_name(fn_def_id).to_string() | |
1237 | }) | |
1238 | }) | |
1239 | ), | |
1240 | error_span, | |
1241 | ) | |
1242 | }; | |
064997fb FG |
1243 | let mut needs_comma = false; |
1244 | for (expected_idx, provided_idx) in matched_inputs.iter_enumerated() { | |
1245 | if needs_comma { | |
1246 | suggestion += ", "; | |
1247 | } else { | |
1248 | needs_comma = true; | |
5e7ed085 | 1249 | } |
064997fb FG |
1250 | let suggestion_text = if let Some(provided_idx) = provided_idx |
1251 | && let (_, provided_span) = provided_arg_tys[*provided_idx] | |
f2b60f7d | 1252 | && let Ok(arg_text) = source_map.span_to_snippet(provided_span) |
064997fb FG |
1253 | { |
1254 | arg_text | |
1255 | } else { | |
1256 | // Propose a placeholder of the correct type | |
1257 | let (_, expected_ty) = formal_and_expected_inputs[expected_idx]; | |
9ffffee4 | 1258 | ty_to_snippet(expected_ty, expected_idx) |
064997fb FG |
1259 | }; |
1260 | suggestion += &suggestion_text; | |
29967ef6 | 1261 | } |
064997fb FG |
1262 | suggestion += ")"; |
1263 | err.span_suggestion_verbose( | |
f2b60f7d | 1264 | suggestion_span, |
49aad941 | 1265 | suggestion_text, |
064997fb FG |
1266 | suggestion, |
1267 | Applicability::HasPlaceholders, | |
1268 | ); | |
29967ef6 | 1269 | } |
5099ac24 | 1270 | |
064997fb | 1271 | err.emit(); |
5099ac24 FG |
1272 | } |
1273 | ||
29967ef6 XL |
1274 | // AST fragment checking |
1275 | pub(in super::super) fn check_lit( | |
1276 | &self, | |
1277 | lit: &hir::Lit, | |
1278 | expected: Expectation<'tcx>, | |
1279 | ) -> Ty<'tcx> { | |
1280 | let tcx = self.tcx; | |
1281 | ||
1282 | match lit.node { | |
1283 | ast::LitKind::Str(..) => tcx.mk_static_str(), | |
9c376795 | 1284 | ast::LitKind::ByteStr(ref v, _) => { |
29967ef6 XL |
1285 | tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.u8, v.len() as u64)) |
1286 | } | |
1287 | ast::LitKind::Byte(_) => tcx.types.u8, | |
1288 | ast::LitKind::Char(_) => tcx.types.char, | |
5869c6ff XL |
1289 | ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(ty::int_ty(t)), |
1290 | ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(ty::uint_ty(t)), | |
29967ef6 XL |
1291 | ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => { |
1292 | let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { | |
1293 | ty::Int(_) | ty::Uint(_) => Some(ty), | |
1294 | ty::Char => Some(tcx.types.u8), | |
1295 | ty::RawPtr(..) => Some(tcx.types.usize), | |
1296 | ty::FnDef(..) | ty::FnPtr(_) => Some(tcx.types.usize), | |
1297 | _ => None, | |
1298 | }); | |
1299 | opt_ty.unwrap_or_else(|| self.next_int_var()) | |
1300 | } | |
5869c6ff XL |
1301 | ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => { |
1302 | tcx.mk_mach_float(ty::float_ty(t)) | |
1303 | } | |
29967ef6 XL |
1304 | ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => { |
1305 | let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { | |
1306 | ty::Float(_) => Some(ty), | |
1307 | _ => None, | |
1308 | }); | |
1309 | opt_ty.unwrap_or_else(|| self.next_float_var()) | |
1310 | } | |
1311 | ast::LitKind::Bool(_) => tcx.types.bool, | |
49aad941 FG |
1312 | ast::LitKind::CStr(_, _) => tcx.mk_imm_ref( |
1313 | tcx.lifetimes.re_static, | |
1314 | tcx.type_of(tcx.require_lang_item(hir::LangItem::CStr, Some(lit.span))) | |
1315 | .skip_binder(), | |
1316 | ), | |
9ffffee4 | 1317 | ast::LitKind::Err => tcx.ty_error_misc(), |
29967ef6 XL |
1318 | } |
1319 | } | |
1320 | ||
1321 | pub fn check_struct_path( | |
1322 | &self, | |
1323 | qpath: &QPath<'_>, | |
1324 | hir_id: hir::HirId, | |
9ffffee4 | 1325 | ) -> Result<(&'tcx ty::VariantDef, Ty<'tcx>), ErrorGuaranteed> { |
6a06907d | 1326 | let path_span = qpath.span(); |
29967ef6 XL |
1327 | let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id); |
1328 | let variant = match def { | |
1329 | Res::Err => { | |
9ffffee4 FG |
1330 | let guar = |
1331 | self.tcx.sess.delay_span_bug(path_span, "`Res::Err` but no error emitted"); | |
1332 | self.set_tainted_by_errors(guar); | |
1333 | return Err(guar); | |
29967ef6 | 1334 | } |
9c376795 FG |
1335 | Res::Def(DefKind::Variant, _) => match ty.normalized.ty_adt_def() { |
1336 | Some(adt) => { | |
1337 | Some((adt.variant_of_res(def), adt.did(), Self::user_substs_for_adt(ty))) | |
1338 | } | |
1339 | _ => bug!("unexpected type: {:?}", ty.normalized), | |
29967ef6 XL |
1340 | }, |
1341 | Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) | |
2b03887a | 1342 | | Res::SelfTyParam { .. } |
9c376795 FG |
1343 | | Res::SelfTyAlias { .. } => match ty.normalized.ty_adt_def() { |
1344 | Some(adt) if !adt.is_enum() => { | |
1345 | Some((adt.non_enum_variant(), adt.did(), Self::user_substs_for_adt(ty))) | |
29967ef6 XL |
1346 | } |
1347 | _ => None, | |
1348 | }, | |
1349 | _ => bug!("unexpected definition: {:?}", def), | |
1350 | }; | |
1351 | ||
9c376795 | 1352 | if let Some((variant, did, ty::UserSubsts { substs, user_self_ty })) = variant { |
29967ef6 | 1353 | debug!("check_struct_path: did={:?} substs={:?}", did, substs); |
9c376795 FG |
1354 | |
1355 | // Register type annotation. | |
1356 | self.write_user_type_annotation_from_substs(hir_id, did, substs, user_self_ty); | |
29967ef6 XL |
1357 | |
1358 | // Check bounds on type arguments used in the path. | |
f2b60f7d | 1359 | self.add_required_obligations_for_hir(path_span, did, substs, hir_id); |
29967ef6 | 1360 | |
9ffffee4 | 1361 | Ok((variant, ty.normalized)) |
29967ef6 | 1362 | } else { |
9ffffee4 FG |
1363 | Err(match *ty.normalized.kind() { |
1364 | ty::Error(guar) => { | |
c295e0f8 XL |
1365 | // E0071 might be caused by a spelling error, which will have |
1366 | // already caused an error message and probably a suggestion | |
1367 | // elsewhere. Refrain from emitting more unhelpful errors here | |
1368 | // (issue #88844). | |
9ffffee4 | 1369 | guar |
c295e0f8 | 1370 | } |
9ffffee4 FG |
1371 | _ => struct_span_err!( |
1372 | self.tcx.sess, | |
1373 | path_span, | |
1374 | E0071, | |
1375 | "expected struct, variant or union type, found {}", | |
1376 | ty.normalized.sort_string(self.tcx) | |
1377 | ) | |
1378 | .span_label(path_span, "not a struct") | |
1379 | .emit(), | |
1380 | }) | |
29967ef6 XL |
1381 | } |
1382 | } | |
1383 | ||
1384 | pub fn check_decl_initializer( | |
1385 | &self, | |
a2a8927a XL |
1386 | hir_id: hir::HirId, |
1387 | pat: &'tcx hir::Pat<'tcx>, | |
29967ef6 XL |
1388 | init: &'tcx hir::Expr<'tcx>, |
1389 | ) -> Ty<'tcx> { | |
1390 | // FIXME(tschottdorf): `contains_explicit_ref_binding()` must be removed | |
1391 | // for #42640 (default match binding modes). | |
1392 | // | |
1393 | // See #44848. | |
a2a8927a | 1394 | let ref_bindings = pat.contains_explicit_ref_binding(); |
29967ef6 | 1395 | |
a2a8927a | 1396 | let local_ty = self.local_ty(init.span, hir_id).revealed_ty; |
29967ef6 XL |
1397 | if let Some(m) = ref_bindings { |
1398 | // Somewhat subtle: if we have a `ref` binding in the pattern, | |
1399 | // we want to avoid introducing coercions for the RHS. This is | |
1400 | // both because it helps preserve sanity and, in the case of | |
1401 | // ref mut, for soundness (issue #23116). In particular, in | |
1402 | // the latter case, we need to be clear that the type of the | |
1403 | // referent for the reference that results is *equal to* the | |
1404 | // type of the place it is referencing, and not some | |
1405 | // supertype thereof. | |
1406 | let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m)); | |
1407 | self.demand_eqtype(init.span, local_ty, init_ty); | |
1408 | init_ty | |
1409 | } else { | |
353b0b11 | 1410 | self.check_expr_coercible_to_type(init, local_ty, None) |
29967ef6 XL |
1411 | } |
1412 | } | |
1413 | ||
a2a8927a | 1414 | pub(in super::super) fn check_decl(&self, decl: Declaration<'tcx>) { |
29967ef6 | 1415 | // Determine and write the type which we'll check the pattern against. |
a2a8927a XL |
1416 | let decl_ty = self.local_ty(decl.span, decl.hir_id).decl_ty; |
1417 | self.write_ty(decl.hir_id, decl_ty); | |
29967ef6 XL |
1418 | |
1419 | // Type check the initializer. | |
a2a8927a XL |
1420 | if let Some(ref init) = decl.init { |
1421 | let init_ty = self.check_decl_initializer(decl.hir_id, decl.pat, &init); | |
9c376795 | 1422 | self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, init_ty); |
29967ef6 XL |
1423 | } |
1424 | ||
1425 | // Does the expected pattern type originate from an expression and what is the span? | |
a2a8927a | 1426 | let (origin_expr, ty_span) = match (decl.ty, decl.init) { |
9ffffee4 | 1427 | (Some(ty), _) => (None, Some(ty.span)), // Bias towards the explicit user type. |
064997fb | 1428 | (_, Some(init)) => { |
9ffffee4 | 1429 | (Some(init), Some(init.span.find_ancestor_inside(decl.span).unwrap_or(init.span))) |
064997fb | 1430 | } // No explicit type; so use the scrutinee. |
9ffffee4 | 1431 | _ => (None, None), // We have `let $pat;`, so the expected type is unconstrained. |
29967ef6 XL |
1432 | }; |
1433 | ||
1434 | // Type check the pattern. Override if necessary to avoid knock-on errors. | |
a2a8927a XL |
1435 | self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr); |
1436 | let pat_ty = self.node_ty(decl.pat.hir_id); | |
9c376795 | 1437 | self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, pat_ty); |
064997fb FG |
1438 | |
1439 | if let Some(blk) = decl.els { | |
1440 | let previous_diverges = self.diverges.get(); | |
1441 | let else_ty = self.check_block_with_expected(blk, NoExpectation); | |
1442 | let cause = self.cause(blk.span, ObligationCauseCode::LetElse); | |
1443 | if let Some(mut err) = | |
1444 | self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty) | |
1445 | { | |
1446 | err.emit(); | |
1447 | } | |
1448 | self.diverges.set(previous_diverges); | |
1449 | } | |
a2a8927a XL |
1450 | } |
1451 | ||
1452 | /// Type check a `let` statement. | |
1453 | pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) { | |
1454 | self.check_decl(local.into()); | |
29967ef6 XL |
1455 | } |
1456 | ||
6a06907d | 1457 | pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>, is_last: bool) { |
29967ef6 XL |
1458 | // Don't do all the complex logic below for `DeclItem`. |
1459 | match stmt.kind { | |
1460 | hir::StmtKind::Item(..) => return, | |
1461 | hir::StmtKind::Local(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {} | |
1462 | } | |
1463 | ||
1464 | self.warn_if_unreachable(stmt.hir_id, stmt.span, "statement"); | |
1465 | ||
1466 | // Hide the outer diverging and `has_errors` flags. | |
1467 | let old_diverges = self.diverges.replace(Diverges::Maybe); | |
29967ef6 XL |
1468 | |
1469 | match stmt.kind { | |
064997fb FG |
1470 | hir::StmtKind::Local(l) => { |
1471 | self.check_decl_local(l); | |
29967ef6 XL |
1472 | } |
1473 | // Ignore for now. | |
1474 | hir::StmtKind::Item(_) => {} | |
1475 | hir::StmtKind::Expr(ref expr) => { | |
1476 | // Check with expected type of `()`. | |
1477 | self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| { | |
6a06907d XL |
1478 | if expr.can_have_side_effects() { |
1479 | self.suggest_semicolon_at_end(expr.span, err); | |
1480 | } | |
29967ef6 XL |
1481 | }); |
1482 | } | |
1483 | hir::StmtKind::Semi(ref expr) => { | |
6a06907d XL |
1484 | // All of this is equivalent to calling `check_expr`, but it is inlined out here |
1485 | // in order to capture the fact that this `match` is the last statement in its | |
1486 | // function. This is done for better suggestions to remove the `;`. | |
1487 | let expectation = match expr.kind { | |
1488 | hir::ExprKind::Match(..) if is_last => IsLast(stmt.span), | |
1489 | _ => NoExpectation, | |
1490 | }; | |
1491 | self.check_expr_with_expectation(expr, expectation); | |
29967ef6 XL |
1492 | } |
1493 | } | |
1494 | ||
1495 | // Combine the diverging and `has_error` flags. | |
1496 | self.diverges.set(self.diverges.get() | old_diverges); | |
29967ef6 XL |
1497 | } |
1498 | ||
1499 | pub fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) { | |
1500 | let unit = self.tcx.mk_unit(); | |
1501 | let ty = self.check_block_with_expected(blk, ExpectHasType(unit)); | |
1502 | ||
1503 | // if the block produces a `!` value, that can always be | |
1504 | // (effectively) coerced to unit. | |
1505 | if !ty.is_never() { | |
1506 | self.demand_suptype(blk.span, unit, ty); | |
1507 | } | |
1508 | } | |
1509 | ||
1510 | pub(in super::super) fn check_block_with_expected( | |
1511 | &self, | |
1512 | blk: &'tcx hir::Block<'tcx>, | |
1513 | expected: Expectation<'tcx>, | |
1514 | ) -> Ty<'tcx> { | |
29967ef6 XL |
1515 | // In some cases, blocks have just one exit, but other blocks |
1516 | // can be targeted by multiple breaks. This can happen both | |
1517 | // with labeled blocks as well as when we desugar | |
1518 | // a `try { ... }` expression. | |
1519 | // | |
1520 | // Example 1: | |
1521 | // | |
1522 | // 'a: { if true { break 'a Err(()); } Ok(()) } | |
1523 | // | |
1524 | // Here we would wind up with two coercions, one from | |
1525 | // `Err(())` and the other from the tail expression | |
1526 | // `Ok(())`. If the tail expression is omitted, that's a | |
1527 | // "forced unit" -- unless the block diverges, in which | |
1528 | // case we can ignore the tail expression (e.g., `'a: { | |
1529 | // break 'a 22; }` would not force the type of the block | |
1530 | // to be `()`). | |
29967ef6 XL |
1531 | let coerce_to_ty = expected.coercion_target_type(self, blk.span); |
1532 | let coerce = if blk.targeted_by_break { | |
1533 | CoerceMany::new(coerce_to_ty) | |
1534 | } else { | |
9ffffee4 | 1535 | CoerceMany::with_coercion_sites(coerce_to_ty, blk.expr.as_slice()) |
29967ef6 XL |
1536 | }; |
1537 | ||
1538 | let prev_diverges = self.diverges.get(); | |
1539 | let ctxt = BreakableCtxt { coerce: Some(coerce), may_break: false }; | |
1540 | ||
1541 | let (ctxt, ()) = self.with_breakable_ctxt(blk.hir_id, ctxt, || { | |
6a06907d XL |
1542 | for (pos, s) in blk.stmts.iter().enumerate() { |
1543 | self.check_stmt(s, blk.stmts.len() - 1 == pos); | |
29967ef6 XL |
1544 | } |
1545 | ||
1546 | // check the tail expression **without** holding the | |
1547 | // `enclosing_breakables` lock below. | |
49aad941 FG |
1548 | let tail_expr_ty = |
1549 | blk.expr.map(|expr| (expr, self.check_expr_with_expectation(expr, expected))); | |
29967ef6 XL |
1550 | |
1551 | let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); | |
1552 | let ctxt = enclosing_breakables.find_breakable(blk.hir_id); | |
1553 | let coerce = ctxt.coerce.as_mut().unwrap(); | |
49aad941 | 1554 | if let Some((tail_expr, tail_expr_ty)) = tail_expr_ty { |
29967ef6 XL |
1555 | let span = self.get_expr_coercion_span(tail_expr); |
1556 | let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id)); | |
5e7ed085 FG |
1557 | let ty_for_diagnostic = coerce.merged_ty(); |
1558 | // We use coerce_inner here because we want to augment the error | |
1559 | // suggesting to wrap the block in square brackets if it might've | |
1560 | // been mistaken array syntax | |
1561 | coerce.coerce_inner( | |
1562 | self, | |
1563 | &cause, | |
1564 | Some(tail_expr), | |
1565 | tail_expr_ty, | |
1566 | Some(&mut |diag: &mut Diagnostic| { | |
1567 | self.suggest_block_to_brackets(diag, blk, tail_expr_ty, ty_for_diagnostic); | |
1568 | }), | |
1569 | false, | |
1570 | ); | |
29967ef6 XL |
1571 | } else { |
1572 | // Subtle: if there is no explicit tail expression, | |
1573 | // that is typically equivalent to a tail expression | |
1574 | // of `()` -- except if the block diverges. In that | |
1575 | // case, there is no value supplied from the tail | |
1576 | // expression (assuming there are no other breaks, | |
1577 | // this implies that the type of the block will be | |
1578 | // `!`). | |
1579 | // | |
1580 | // #41425 -- label the implicit `()` as being the | |
1581 | // "found type" here, rather than the "expected type". | |
1582 | if !self.diverges.get().is_always() { | |
1583 | // #50009 -- Do not point at the entire fn block span, point at the return type | |
1584 | // span, as it is the cause of the requirement, and | |
1585 | // `consider_hint_about_removing_semicolon` will point at the last expression | |
1586 | // if it were a relevant part of the error. This improves usability in editors | |
1587 | // that highlight errors inline. | |
1588 | let mut sp = blk.span; | |
1589 | let mut fn_span = None; | |
1590 | if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) { | |
1591 | let ret_sp = decl.output.span(); | |
1592 | if let Some(block_sp) = self.parent_item_span(blk.hir_id) { | |
1593 | // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the | |
1594 | // output would otherwise be incorrect and even misleading. Make sure | |
1595 | // the span we're aiming at correspond to a `fn` body. | |
1596 | if block_sp == blk.span { | |
1597 | sp = ret_sp; | |
1598 | fn_span = Some(ident.span); | |
1599 | } | |
1600 | } | |
1601 | } | |
1602 | coerce.coerce_forced_unit( | |
1603 | self, | |
1604 | &self.misc(sp), | |
1605 | &mut |err| { | |
1606 | if let Some(expected_ty) = expected.only_has_type(self) { | |
49aad941 FG |
1607 | if blk.stmts.is_empty() && blk.expr.is_none() { |
1608 | self.suggest_boxing_when_appropriate( | |
1609 | err, | |
1610 | blk.span, | |
1611 | blk.hir_id, | |
1612 | expected_ty, | |
1613 | self.tcx.mk_unit(), | |
1614 | ); | |
1615 | } | |
064997fb | 1616 | if !self.consider_removing_semicolon(blk, expected_ty, err) { |
2b03887a FG |
1617 | self.err_ctxt().consider_returning_binding( |
1618 | blk, | |
1619 | expected_ty, | |
1620 | err, | |
1621 | ); | |
064997fb | 1622 | } |
3c0e092e XL |
1623 | if expected_ty == self.tcx.types.bool { |
1624 | // If this is caused by a missing `let` in a `while let`, | |
1625 | // silence this redundant error, as we already emit E0070. | |
5e7ed085 FG |
1626 | |
1627 | // Our block must be a `assign desugar local; assignment` | |
49aad941 | 1628 | if let hir::Block { |
5e7ed085 FG |
1629 | stmts: |
1630 | [ | |
1631 | hir::Stmt { | |
1632 | kind: | |
1633 | hir::StmtKind::Local(hir::Local { | |
1634 | source: | |
1635 | hir::LocalSource::AssignDesugar(_), | |
1636 | .. | |
1637 | }), | |
1638 | .. | |
1639 | }, | |
1640 | hir::Stmt { | |
1641 | kind: | |
1642 | hir::StmtKind::Expr(hir::Expr { | |
1643 | kind: hir::ExprKind::Assign(..), | |
1644 | .. | |
1645 | }), | |
1646 | .. | |
1647 | }, | |
1648 | ], | |
1649 | .. | |
49aad941 | 1650 | } = blk |
5e7ed085 FG |
1651 | { |
1652 | self.comes_from_while_condition(blk.hir_id, |_| { | |
1653 | err.downgrade_to_delayed_bug(); | |
1654 | }) | |
3c0e092e XL |
1655 | } |
1656 | } | |
29967ef6 XL |
1657 | } |
1658 | if let Some(fn_span) = fn_span { | |
1659 | err.span_label( | |
1660 | fn_span, | |
1661 | "implicitly returns `()` as its body has no tail or `return` \ | |
1662 | expression", | |
1663 | ); | |
1664 | } | |
1665 | }, | |
1666 | false, | |
1667 | ); | |
1668 | } | |
1669 | } | |
1670 | }); | |
1671 | ||
1672 | if ctxt.may_break { | |
1673 | // If we can break from the block, then the block's exit is always reachable | |
1674 | // (... as long as the entry is reachable) - regardless of the tail of the block. | |
1675 | self.diverges.set(prev_diverges); | |
1676 | } | |
1677 | ||
487cf647 | 1678 | let ty = ctxt.coerce.unwrap().complete(self); |
29967ef6 XL |
1679 | |
1680 | self.write_ty(blk.hir_id, ty); | |
1681 | ||
29967ef6 XL |
1682 | ty |
1683 | } | |
1684 | ||
29967ef6 | 1685 | fn parent_item_span(&self, id: hir::HirId) -> Option<Span> { |
2b03887a | 1686 | let node = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(id).def_id); |
29967ef6 XL |
1687 | match node { |
1688 | Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. }) | |
1689 | | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => { | |
1690 | let body = self.tcx.hir().body(body_id); | |
1691 | if let ExprKind::Block(block, _) = &body.value.kind { | |
1692 | return Some(block.span); | |
1693 | } | |
1694 | } | |
1695 | _ => {} | |
1696 | } | |
1697 | None | |
1698 | } | |
1699 | ||
1700 | /// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise. | |
1701 | fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> { | |
2b03887a | 1702 | let parent = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(blk_id).def_id); |
353b0b11 | 1703 | self.get_node_fn_decl(parent).map(|(_, fn_decl, ident, _)| (fn_decl, ident)) |
29967ef6 XL |
1704 | } |
1705 | ||
1706 | /// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail | |
1707 | /// expression's `Span`, otherwise return `expr.span`. This is done to give better errors | |
1708 | /// when given code like the following: | |
1709 | /// ```text | |
1710 | /// if false { return 0i32; } else { 1u32 } | |
1711 | /// // ^^^^ point at this instead of the whole `if` expression | |
1712 | /// ``` | |
1713 | fn get_expr_coercion_span(&self, expr: &hir::Expr<'_>) -> rustc_span::Span { | |
5869c6ff | 1714 | let check_in_progress = |elem: &hir::Expr<'_>| { |
064997fb FG |
1715 | self.typeck_results.borrow().node_type_opt(elem.hir_id).filter(|ty| !ty.is_never()).map( |
1716 | |_| match elem.kind { | |
1717 | // Point at the tail expression when possible. | |
1718 | hir::ExprKind::Block(block, _) => block.expr.map_or(block.span, |e| e.span), | |
1719 | _ => elem.span, | |
1720 | }, | |
1721 | ) | |
5869c6ff XL |
1722 | }; |
1723 | ||
1724 | if let hir::ExprKind::If(_, _, Some(el)) = expr.kind { | |
1725 | if let Some(rslt) = check_in_progress(el) { | |
1726 | return rslt; | |
29967ef6 XL |
1727 | } |
1728 | } | |
5869c6ff XL |
1729 | |
1730 | if let hir::ExprKind::Match(_, arms, _) = expr.kind { | |
1731 | let mut iter = arms.iter().filter_map(|arm| check_in_progress(arm.body)); | |
1732 | if let Some(span) = iter.next() { | |
1733 | if iter.next().is_none() { | |
1734 | return span; | |
1735 | } | |
1736 | } | |
1737 | } | |
1738 | ||
29967ef6 XL |
1739 | expr.span |
1740 | } | |
1741 | ||
1742 | fn overwrite_local_ty_if_err( | |
1743 | &self, | |
a2a8927a XL |
1744 | hir_id: hir::HirId, |
1745 | pat: &'tcx hir::Pat<'tcx>, | |
29967ef6 XL |
1746 | ty: Ty<'tcx>, |
1747 | ) { | |
9ffffee4 | 1748 | if let Err(guar) = ty.error_reported() { |
29967ef6 | 1749 | // Override the types everywhere with `err()` to avoid knock on errors. |
9ffffee4 | 1750 | let err = self.tcx.ty_error(guar); |
9c376795 FG |
1751 | self.write_ty(hir_id, err); |
1752 | self.write_ty(pat.hir_id, err); | |
1753 | let local_ty = LocalTy { decl_ty: err, revealed_ty: err }; | |
a2a8927a XL |
1754 | self.locals.borrow_mut().insert(hir_id, local_ty); |
1755 | self.locals.borrow_mut().insert(pat.hir_id, local_ty); | |
29967ef6 XL |
1756 | } |
1757 | } | |
1758 | ||
1759 | // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary. | |
1760 | // The newly resolved definition is written into `type_dependent_defs`. | |
1761 | fn finish_resolving_struct_path( | |
1762 | &self, | |
1763 | qpath: &QPath<'_>, | |
1764 | path_span: Span, | |
1765 | hir_id: hir::HirId, | |
9c376795 | 1766 | ) -> (Res, RawTy<'tcx>) { |
29967ef6 XL |
1767 | match *qpath { |
1768 | QPath::Resolved(ref maybe_qself, ref path) => { | |
9c376795 | 1769 | let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself).raw); |
9ffffee4 | 1770 | let ty = self.astconv().res_to_ty(self_ty, path, hir_id, true); |
9c376795 | 1771 | (path.res, self.handle_raw_ty(path_span, ty)) |
29967ef6 XL |
1772 | } |
1773 | QPath::TypeRelative(ref qself, ref segment) => { | |
1774 | let ty = self.to_ty(qself); | |
1775 | ||
9c376795 FG |
1776 | let result = self |
1777 | .astconv() | |
1778 | .associated_path_to_ty(hir_id, path_span, ty.raw, qself, segment, true); | |
9ffffee4 FG |
1779 | let ty = |
1780 | result.map(|(ty, _, _)| ty).unwrap_or_else(|guar| self.tcx().ty_error(guar)); | |
9c376795 | 1781 | let ty = self.handle_raw_ty(path_span, ty); |
29967ef6 XL |
1782 | let result = result.map(|(_, kind, def_id)| (kind, def_id)); |
1783 | ||
1784 | // Write back the new resolution. | |
1785 | self.write_resolution(hir_id, result); | |
1786 | ||
5869c6ff | 1787 | (result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), ty) |
29967ef6 | 1788 | } |
a2a8927a | 1789 | QPath::LangItem(lang_item, span, id) => { |
9c376795 FG |
1790 | let (res, ty) = self.resolve_lang_item_path(lang_item, span, hir_id, id); |
1791 | (res, self.handle_raw_ty(path_span, ty)) | |
29967ef6 XL |
1792 | } |
1793 | } | |
1794 | } | |
1795 | ||
f2b60f7d FG |
1796 | /// Given a vector of fulfillment errors, try to adjust the spans of the |
1797 | /// errors to more accurately point at the cause of the failure. | |
1798 | /// | |
1799 | /// This applies to calls, methods, and struct expressions. This will also | |
1800 | /// try to deduplicate errors that are due to the same cause but might | |
1801 | /// have been created with different [`ObligationCause`][traits::ObligationCause]s. | |
1802 | pub(super) fn adjust_fulfillment_errors_for_expr_obligation( | |
29967ef6 XL |
1803 | &self, |
1804 | errors: &mut Vec<traits::FulfillmentError<'tcx>>, | |
29967ef6 | 1805 | ) { |
f2b60f7d FG |
1806 | // Store a mapping from `(Span, Predicate) -> ObligationCause`, so that |
1807 | // other errors that have the same span and predicate can also get fixed, | |
1808 | // even if their `ObligationCauseCode` isn't an `Expr*Obligation` kind. | |
1809 | // This is important since if we adjust one span but not the other, then | |
1810 | // we will have "duplicated" the error on the UI side. | |
9c376795 | 1811 | let mut remap_cause = FxIndexSet::default(); |
f2b60f7d FG |
1812 | let mut not_adjusted = vec![]; |
1813 | ||
1814 | for error in errors { | |
1815 | let before_span = error.obligation.cause.span; | |
1816 | if self.adjust_fulfillment_error_for_expr_obligation(error) | |
1817 | || before_span != error.obligation.cause.span | |
1818 | { | |
1819 | // Store both the predicate and the predicate *without constness* | |
1820 | // since sometimes we instantiate and check both of these in a | |
1821 | // method call, for example. | |
1822 | remap_cause.insert(( | |
1823 | before_span, | |
1824 | error.obligation.predicate, | |
1825 | error.obligation.cause.clone(), | |
1826 | )); | |
1827 | remap_cause.insert(( | |
1828 | before_span, | |
1829 | error.obligation.predicate.without_const(self.tcx), | |
1830 | error.obligation.cause.clone(), | |
1831 | )); | |
1832 | } else { | |
1833 | // If it failed to be adjusted once around, it may be adjusted | |
1834 | // via the "remap cause" mapping the second time... | |
1835 | not_adjusted.push(error); | |
29967ef6 | 1836 | } |
f2b60f7d | 1837 | } |
29967ef6 | 1838 | |
9c376795 FG |
1839 | // Adjust any other errors that come from other cause codes, when these |
1840 | // errors are of the same predicate as one we successfully adjusted, and | |
1841 | // when their spans overlap (suggesting they're due to the same root cause). | |
1842 | // | |
1843 | // This is because due to normalization, we often register duplicate | |
1844 | // obligations with misc obligations that are basically impossible to | |
1845 | // line back up with a useful ExprBindingObligation. | |
f2b60f7d FG |
1846 | for error in not_adjusted { |
1847 | for (span, predicate, cause) in &remap_cause { | |
1848 | if *predicate == error.obligation.predicate | |
1849 | && span.contains(error.obligation.cause.span) | |
1850 | { | |
1851 | error.obligation.cause = cause.clone(); | |
1852 | continue; | |
3c0e092e | 1853 | } |
3c0e092e | 1854 | } |
f2b60f7d FG |
1855 | } |
1856 | } | |
1857 | ||
064997fb FG |
1858 | fn label_fn_like( |
1859 | &self, | |
f2b60f7d | 1860 | err: &mut Diagnostic, |
064997fb FG |
1861 | callable_def_id: Option<DefId>, |
1862 | callee_ty: Option<Ty<'tcx>>, | |
f2b60f7d FG |
1863 | // A specific argument should be labeled, instead of all of them |
1864 | expected_idx: Option<usize>, | |
1865 | is_method: bool, | |
064997fb FG |
1866 | ) { |
1867 | let Some(mut def_id) = callable_def_id else { | |
1868 | return; | |
1869 | }; | |
1870 | ||
1871 | if let Some(assoc_item) = self.tcx.opt_associated_item(def_id) | |
1872 | // Possibly points at either impl or trait item, so try to get it | |
1873 | // to point to trait item, then get the parent. | |
1874 | // This parent might be an impl in the case of an inherent function, | |
1875 | // but the next check will fail. | |
1876 | && let maybe_trait_item_def_id = assoc_item.trait_item_def_id.unwrap_or(def_id) | |
1877 | && let maybe_trait_def_id = self.tcx.parent(maybe_trait_item_def_id) | |
1878 | // Just an easy way to check "trait_def_id == Fn/FnMut/FnOnce" | |
487cf647 | 1879 | && let Some(call_kind) = self.tcx.fn_trait_kind_from_def_id(maybe_trait_def_id) |
064997fb FG |
1880 | && let Some(callee_ty) = callee_ty |
1881 | { | |
1882 | let callee_ty = callee_ty.peel_refs(); | |
1883 | match *callee_ty.kind() { | |
1884 | ty::Param(param) => { | |
1885 | let param = | |
9ffffee4 | 1886 | self.tcx.generics_of(self.body_id).type_param(¶m, self.tcx); |
064997fb FG |
1887 | if param.kind.is_synthetic() { |
1888 | // if it's `impl Fn() -> ..` then just fall down to the def-id based logic | |
1889 | def_id = param.def_id; | |
1890 | } else { | |
1891 | // Otherwise, find the predicate that makes this generic callable, | |
1892 | // and point at that. | |
1893 | let instantiated = self | |
1894 | .tcx | |
9ffffee4 | 1895 | .explicit_predicates_of(self.body_id) |
064997fb FG |
1896 | .instantiate_identity(self.tcx); |
1897 | // FIXME(compiler-errors): This could be problematic if something has two | |
1898 | // fn-like predicates with different args, but callable types really never | |
1899 | // do that, so it's OK. | |
9c376795 | 1900 | for (predicate, span) in instantiated |
064997fb | 1901 | { |
487cf647 | 1902 | if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = predicate.kind().skip_binder() |
064997fb | 1903 | && pred.self_ty().peel_refs() == callee_ty |
487cf647 | 1904 | && self.tcx.is_fn_trait(pred.def_id()) |
064997fb FG |
1905 | { |
1906 | err.span_note(span, "callable defined here"); | |
1907 | return; | |
1908 | } | |
1909 | } | |
1910 | } | |
1911 | } | |
9c376795 | 1912 | ty::Alias(ty::Opaque, ty::AliasTy { def_id: new_def_id, .. }) |
064997fb FG |
1913 | | ty::Closure(new_def_id, _) |
1914 | | ty::FnDef(new_def_id, _) => { | |
1915 | def_id = new_def_id; | |
1916 | } | |
1917 | _ => { | |
1918 | // Look for a user-provided impl of a `Fn` trait, and point to it. | |
1919 | let new_def_id = self.probe(|_| { | |
49aad941 | 1920 | let trait_ref = ty::TraitRef::new(self.tcx, |
064997fb | 1921 | call_kind.to_def_id(self.tcx), |
9c376795 FG |
1922 | [ |
1923 | callee_ty, | |
1924 | self.next_ty_var(TypeVariableOrigin { | |
1925 | kind: TypeVariableOriginKind::MiscVariable, | |
1926 | span: rustc_span::DUMMY_SP, | |
1927 | }), | |
1928 | ], | |
064997fb FG |
1929 | ); |
1930 | let obligation = traits::Obligation::new( | |
487cf647 | 1931 | self.tcx, |
064997fb FG |
1932 | traits::ObligationCause::dummy(), |
1933 | self.param_env, | |
487cf647 | 1934 | ty::Binder::dummy(trait_ref), |
064997fb FG |
1935 | ); |
1936 | match SelectionContext::new(&self).select(&obligation) { | |
1937 | Ok(Some(traits::ImplSource::UserDefined(impl_source))) => { | |
1938 | Some(impl_source.impl_def_id) | |
1939 | } | |
f2b60f7d | 1940 | _ => None, |
064997fb FG |
1941 | } |
1942 | }); | |
1943 | if let Some(new_def_id) = new_def_id { | |
1944 | def_id = new_def_id; | |
1945 | } else { | |
1946 | return; | |
1947 | } | |
1948 | } | |
1949 | } | |
923072b8 FG |
1950 | } |
1951 | ||
064997fb FG |
1952 | if let Some(def_span) = self.tcx.def_ident_span(def_id) && !def_span.is_dummy() { |
1953 | let mut spans: MultiSpan = def_span.into(); | |
923072b8 | 1954 | |
064997fb FG |
1955 | let params = self |
1956 | .tcx | |
1957 | .hir() | |
1958 | .get_if_local(def_id) | |
1959 | .and_then(|node| node.body_id()) | |
1960 | .into_iter() | |
f2b60f7d FG |
1961 | .flat_map(|id| self.tcx.hir().body(id).params) |
1962 | .skip(if is_method { 1 } else { 0 }); | |
923072b8 | 1963 | |
f2b60f7d FG |
1964 | for (_, param) in params |
1965 | .into_iter() | |
1966 | .enumerate() | |
1967 | .filter(|(idx, _)| expected_idx.map_or(true, |expected_idx| expected_idx == *idx)) | |
1968 | { | |
064997fb | 1969 | spans.push_span_label(param.span, ""); |
923072b8 | 1970 | } |
064997fb | 1971 | |
49aad941 | 1972 | err.span_note(spans, format!("{} defined here", self.tcx.def_descr(def_id))); |
f2b60f7d FG |
1973 | } else if let Some(hir::Node::Expr(e)) = self.tcx.hir().get_if_local(def_id) |
1974 | && let hir::ExprKind::Closure(hir::Closure { body, .. }) = &e.kind | |
1975 | { | |
1976 | let param = expected_idx | |
1977 | .and_then(|expected_idx| self.tcx.hir().body(*body).params.get(expected_idx)); | |
1978 | let (kind, span) = if let Some(param) = param { | |
1979 | ("closure parameter", param.span) | |
1980 | } else { | |
1981 | ("closure", self.tcx.def_span(def_id)) | |
1982 | }; | |
49aad941 | 1983 | err.span_note(span, format!("{} defined here", kind)); |
064997fb | 1984 | } else { |
064997fb FG |
1985 | err.span_note( |
1986 | self.tcx.def_span(def_id), | |
49aad941 | 1987 | format!("{} defined here", self.tcx.def_descr(def_id)), |
064997fb | 1988 | ); |
923072b8 FG |
1989 | } |
1990 | } | |
1991 | } |