]>
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::{ | |
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; |
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; |
9c376795 | 31 | use rustc_span::symbol::{kw, 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 | ) | |
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 | |
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 | |
9c376795 | 476 | let (error_span, full_call_span, call_name, 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 | { | |
9c376795 FG |
484 | let name = match of { |
485 | CtorOf::Struct => "struct", | |
486 | CtorOf::Variant => "enum variant", | |
487 | }; | |
488 | (call_span, *span, name, false) | |
064997fb | 489 | } else { |
9c376795 | 490 | (call_span, *span, "function", false) |
064997fb FG |
491 | } |
492 | } | |
9c376795 | 493 | hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, "function", false), |
f2b60f7d | 494 | hir::ExprKind::MethodCall(path_segment, _, _, span) => { |
064997fb FG |
495 | let ident_span = path_segment.ident.span; |
496 | let ident_span = if let Some(args) = path_segment.args { | |
497 | ident_span.with_hi(args.span_ext.hi()) | |
498 | } else { | |
499 | ident_span | |
500 | }; | |
9c376795 | 501 | (*span, ident_span, "method", true) |
064997fb FG |
502 | } |
503 | k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k), | |
504 | }; | |
505 | let args_span = error_span.trim_start(full_call_span).unwrap_or(error_span); | |
923072b8 | 506 | |
064997fb FG |
507 | // Don't print if it has error types or is just plain `_` |
508 | fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool { | |
509 | tys.into_iter().any(|ty| ty.references_error() || ty.is_ty_var()) | |
510 | } | |
511 | ||
064997fb | 512 | let tcx = self.tcx; |
487cf647 FG |
513 | // FIXME: taint after emitting errors and pass through an `ErrorGuaranteed` |
514 | self.set_tainted_by_errors( | |
515 | tcx.sess.delay_span_bug(call_span, "no errors reported for args"), | |
516 | ); | |
064997fb FG |
517 | |
518 | // Get the argument span in the context of the call span so that | |
519 | // suggestions and labels are (more) correct when an arg is a | |
520 | // macro invocation. | |
521 | let normalize_span = |span: Span| -> Span { | |
522 | let normalized_span = span.find_ancestor_inside(error_span).unwrap_or(span); | |
523 | // Sometimes macros mess up the spans, so do not normalize the | |
524 | // arg span to equal the error span, because that's less useful | |
525 | // than pointing out the arg expr in the wrong context. | |
526 | if normalized_span.source_equal(error_span) { span } else { normalized_span } | |
527 | }; | |
528 | ||
529 | // Precompute the provided types and spans, since that's all we typically need for below | |
530 | let provided_arg_tys: IndexVec<ProvidedIdx, (Ty<'tcx>, Span)> = provided_args | |
531 | .iter() | |
532 | .map(|expr| { | |
533 | let ty = self | |
534 | .typeck_results | |
535 | .borrow() | |
536 | .expr_ty_adjusted_opt(*expr) | |
537 | .unwrap_or_else(|| tcx.ty_error()); | |
538 | (self.resolve_vars_if_possible(ty), normalize_span(expr.span)) | |
539 | }) | |
540 | .collect(); | |
541 | let callee_expr = match &call_expr.peel_blocks().kind { | |
542 | hir::ExprKind::Call(callee, _) => Some(*callee), | |
f2b60f7d | 543 | hir::ExprKind::MethodCall(_, receiver, ..) => { |
064997fb FG |
544 | if let Some((DefKind::AssocFn, def_id)) = |
545 | self.typeck_results.borrow().type_dependent_def(call_expr.hir_id) | |
546 | && let Some(assoc) = tcx.opt_associated_item(def_id) | |
547 | && assoc.fn_has_self_parameter | |
548 | { | |
f2b60f7d | 549 | Some(*receiver) |
064997fb FG |
550 | } else { |
551 | None | |
923072b8 | 552 | } |
064997fb FG |
553 | } |
554 | _ => None, | |
555 | }; | |
556 | let callee_ty = callee_expr | |
557 | .and_then(|callee_expr| self.typeck_results.borrow().expr_ty_adjusted_opt(callee_expr)); | |
558 | ||
559 | // A "softer" version of the `demand_compatible`, which checks types without persisting them, | |
560 | // and treats error types differently | |
561 | // This will allow us to "probe" for other argument orders that would likely have been correct | |
562 | let check_compatible = |provided_idx: ProvidedIdx, expected_idx: ExpectedIdx| { | |
563 | if provided_idx.as_usize() == expected_idx.as_usize() { | |
564 | return compatibility_diagonal[provided_idx].clone(); | |
565 | } | |
566 | ||
567 | let (formal_input_ty, expected_input_ty) = formal_and_expected_inputs[expected_idx]; | |
568 | // If either is an error type, we defy the usual convention and consider them to *not* be | |
569 | // coercible. This prevents our error message heuristic from trying to pass errors into | |
570 | // every argument. | |
571 | if (formal_input_ty, expected_input_ty).references_error() { | |
572 | return Compatibility::Incompatible(None); | |
573 | } | |
574 | ||
575 | let (arg_ty, arg_span) = provided_arg_tys[provided_idx]; | |
576 | ||
577 | let expectation = Expectation::rvalue_hint(self, expected_input_ty); | |
578 | let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty); | |
579 | let can_coerce = self.can_coerce(arg_ty, coerced_ty); | |
580 | if !can_coerce { | |
f2b60f7d FG |
581 | return Compatibility::Incompatible(Some(ty::error::TypeError::Sorts( |
582 | ty::error::ExpectedFound::new(true, coerced_ty, arg_ty), | |
583 | ))); | |
064997fb FG |
584 | } |
585 | ||
586 | // Using probe here, since we don't want this subtyping to affect inference. | |
587 | let subtyping_error = self.probe(|_| { | |
588 | self.at(&self.misc(arg_span), self.param_env).sup(formal_input_ty, coerced_ty).err() | |
923072b8 FG |
589 | }); |
590 | ||
064997fb FG |
591 | // Same as above: if either the coerce type or the checked type is an error type, |
592 | // consider them *not* compatible. | |
593 | let references_error = (coerced_ty, arg_ty).references_error(); | |
594 | match (references_error, subtyping_error) { | |
595 | (false, None) => Compatibility::Compatible, | |
596 | (_, subtyping_error) => Compatibility::Incompatible(subtyping_error), | |
923072b8 | 597 | } |
064997fb | 598 | }; |
923072b8 | 599 | |
487cf647 FG |
600 | let mk_trace = |span, (formal_ty, expected_ty), provided_ty| { |
601 | let mismatched_ty = if expected_ty == provided_ty { | |
602 | // If expected == provided, then we must have failed to sup | |
603 | // the formal type. Avoid printing out "expected Ty, found Ty" | |
604 | // in that case. | |
605 | formal_ty | |
606 | } else { | |
607 | expected_ty | |
608 | }; | |
609 | TypeTrace::types(&self.misc(span), true, mismatched_ty, provided_ty) | |
610 | }; | |
611 | ||
064997fb FG |
612 | // The algorithm here is inspired by levenshtein distance and longest common subsequence. |
613 | // We'll try to detect 4 different types of mistakes: | |
614 | // - An extra parameter has been provided that doesn't satisfy *any* of the other inputs | |
615 | // - An input is missing, which isn't satisfied by *any* of the other arguments | |
616 | // - Some number of arguments have been provided in the wrong order | |
617 | // - A type is straight up invalid | |
618 | ||
619 | // First, let's find the errors | |
620 | let (mut errors, matched_inputs) = | |
621 | ArgMatrix::new(provided_args.len(), formal_and_expected_inputs.len(), check_compatible) | |
622 | .find_errors(); | |
623 | ||
624 | // First, check if we just need to wrap some arguments in a tuple. | |
625 | if let Some((mismatch_idx, terr)) = | |
626 | compatibility_diagonal.iter().enumerate().find_map(|(i, c)| { | |
f2b60f7d FG |
627 | if let Compatibility::Incompatible(Some(terr)) = c { |
628 | Some((i, *terr)) | |
629 | } else { | |
630 | None | |
631 | } | |
064997fb FG |
632 | }) |
633 | { | |
634 | // Is the first bad expected argument a tuple? | |
635 | // Do we have as many extra provided arguments as the tuple's length? | |
636 | // If so, we might have just forgotten to wrap some args in a tuple. | |
637 | if let Some(ty::Tuple(tys)) = | |
638 | formal_and_expected_inputs.get(mismatch_idx.into()).map(|tys| tys.1.kind()) | |
639 | // If the tuple is unit, we're not actually wrapping any arguments. | |
640 | && !tys.is_empty() | |
641 | && provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len() | |
642 | { | |
643 | // Wrap up the N provided arguments starting at this position in a tuple. | |
644 | let provided_as_tuple = tcx.mk_tup( | |
645 | provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx).take(tys.len()), | |
646 | ); | |
647 | ||
648 | let mut satisfied = true; | |
649 | // Check if the newly wrapped tuple + rest of the arguments are compatible. | |
650 | for ((_, expected_ty), provided_ty) in std::iter::zip( | |
651 | formal_and_expected_inputs.iter().skip(mismatch_idx), | |
652 | [provided_as_tuple].into_iter().chain( | |
653 | provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx + tys.len()), | |
654 | ), | |
655 | ) { | |
656 | if !self.can_coerce(provided_ty, *expected_ty) { | |
657 | satisfied = false; | |
658 | break; | |
659 | } | |
5099ac24 | 660 | } |
5e7ed085 | 661 | |
064997fb FG |
662 | // If they're compatible, suggest wrapping in an arg, and we're done! |
663 | // Take some care with spans, so we don't suggest wrapping a macro's | |
664 | // innards in parenthesis, for example. | |
665 | if satisfied | |
666 | && let Some((_, lo)) = | |
667 | provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx)) | |
668 | && let Some((_, hi)) = | |
669 | provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx + tys.len() - 1)) | |
670 | { | |
671 | let mut err; | |
672 | if tys.len() == 1 { | |
673 | // A tuple wrap suggestion actually occurs within, | |
674 | // so don't do anything special here. | |
2b03887a | 675 | err = self.err_ctxt().report_and_explain_type_error( |
487cf647 FG |
676 | mk_trace( |
677 | *lo, | |
678 | formal_and_expected_inputs[mismatch_idx.into()], | |
064997fb FG |
679 | provided_arg_tys[mismatch_idx.into()].0, |
680 | ), | |
681 | terr, | |
682 | ); | |
683 | err.span_label( | |
684 | full_call_span, | |
685 | format!("arguments to this {} are incorrect", call_name), | |
686 | ); | |
687 | } else { | |
688 | err = tcx.sess.struct_span_err_with_code( | |
689 | full_call_span, | |
690 | &format!( | |
9c376795 | 691 | "{call_name} takes {}{} but {} {} supplied", |
064997fb FG |
692 | if c_variadic { "at least " } else { "" }, |
693 | potentially_plural_count( | |
694 | formal_and_expected_inputs.len(), | |
695 | "argument" | |
696 | ), | |
697 | potentially_plural_count(provided_args.len(), "argument"), | |
698 | pluralize!("was", provided_args.len()) | |
699 | ), | |
700 | DiagnosticId::Error(err_code.to_owned()), | |
701 | ); | |
702 | err.multipart_suggestion_verbose( | |
703 | "wrap these arguments in parentheses to construct a tuple", | |
704 | vec![ | |
705 | (lo.shrink_to_lo(), "(".to_string()), | |
706 | (hi.shrink_to_hi(), ")".to_string()), | |
707 | ], | |
708 | Applicability::MachineApplicable, | |
709 | ); | |
923072b8 | 710 | }; |
f2b60f7d FG |
711 | self.label_fn_like( |
712 | &mut err, | |
713 | fn_def_id, | |
714 | callee_ty, | |
715 | Some(mismatch_idx), | |
716 | is_method, | |
717 | ); | |
923072b8 | 718 | err.emit(); |
064997fb | 719 | return; |
04454e1e | 720 | } |
923072b8 | 721 | } |
064997fb FG |
722 | } |
723 | ||
724 | // Okay, so here's where it gets complicated in regards to what errors | |
725 | // we emit and how. | |
726 | // There are 3 different "types" of errors we might encounter. | |
727 | // 1) Missing/extra/swapped arguments | |
728 | // 2) Valid but incorrect arguments | |
729 | // 3) Invalid arguments | |
730 | // - Currently I think this only comes up with `CyclicTy` | |
731 | // | |
732 | // We first need to go through, remove those from (3) and emit those | |
733 | // as their own error, particularly since they're error code and | |
734 | // message is special. From what I can tell, we *must* emit these | |
735 | // here (vs somewhere prior to this function) since the arguments | |
736 | // become invalid *because* of how they get used in the function. | |
737 | // It is what it is. | |
738 | ||
739 | if errors.is_empty() { | |
740 | if cfg!(debug_assertions) { | |
741 | span_bug!(error_span, "expected errors from argument matrix"); | |
742 | } else { | |
743 | tcx.sess | |
744 | .struct_span_err( | |
745 | error_span, | |
746 | "argument type mismatch was detected, \ | |
747 | but rustc had trouble determining where", | |
748 | ) | |
749 | .note( | |
750 | "we would appreciate a bug report: \ | |
751 | https://github.com/rust-lang/rust/issues/new", | |
752 | ) | |
753 | .emit(); | |
754 | } | |
755 | return; | |
756 | } | |
757 | ||
758 | errors.drain_filter(|error| { | |
f2b60f7d | 759 | let Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(e))) = error else { return false }; |
064997fb | 760 | let (provided_ty, provided_span) = provided_arg_tys[*provided_idx]; |
487cf647 | 761 | let trace = mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty); |
f2b60f7d | 762 | if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308(_)) { |
2b03887a | 763 | self.err_ctxt().report_and_explain_type_error(trace, *e).emit(); |
f2b60f7d | 764 | return true; |
064997fb FG |
765 | } |
766 | false | |
767 | }); | |
768 | ||
769 | // We're done if we found errors, but we already emitted them. | |
770 | if errors.is_empty() { | |
771 | return; | |
772 | } | |
773 | ||
774 | // Okay, now that we've emitted the special errors separately, we | |
775 | // are only left missing/extra/swapped and mismatched arguments, both | |
776 | // can be collated pretty easily if needed. | |
777 | ||
778 | // Next special case: if there is only one "Incompatible" error, just emit that | |
779 | if let [ | |
780 | Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(err))), | |
781 | ] = &errors[..] | |
782 | { | |
783 | let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx]; | |
784 | let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx]; | |
487cf647 | 785 | let trace = mk_trace(provided_arg_span, (formal_ty, expected_ty), provided_ty); |
2b03887a | 786 | let mut err = self.err_ctxt().report_and_explain_type_error(trace, *err); |
064997fb FG |
787 | self.emit_coerce_suggestions( |
788 | &mut err, | |
789 | &provided_args[*provided_idx], | |
790 | provided_ty, | |
791 | Expectation::rvalue_hint(self, expected_ty) | |
792 | .only_has_type(self) | |
793 | .unwrap_or(formal_ty), | |
794 | None, | |
795 | None, | |
796 | ); | |
797 | err.span_label( | |
798 | full_call_span, | |
799 | format!("arguments to this {} are incorrect", call_name), | |
800 | ); | |
801 | // Call out where the function is defined | |
f2b60f7d FG |
802 | self.label_fn_like( |
803 | &mut err, | |
804 | fn_def_id, | |
805 | callee_ty, | |
806 | Some(expected_idx.as_usize()), | |
807 | is_method, | |
808 | ); | |
064997fb FG |
809 | err.emit(); |
810 | return; | |
811 | } | |
812 | ||
813 | let mut err = if formal_and_expected_inputs.len() == provided_args.len() { | |
814 | struct_span_err!( | |
815 | tcx.sess, | |
816 | full_call_span, | |
817 | E0308, | |
818 | "arguments to this {} are incorrect", | |
819 | call_name, | |
820 | ) | |
821 | } else { | |
822 | tcx.sess.struct_span_err_with_code( | |
823 | full_call_span, | |
824 | &format!( | |
825 | "this {} takes {}{} but {} {} supplied", | |
826 | call_name, | |
827 | if c_variadic { "at least " } else { "" }, | |
828 | potentially_plural_count(formal_and_expected_inputs.len(), "argument"), | |
829 | potentially_plural_count(provided_args.len(), "argument"), | |
830 | pluralize!("was", provided_args.len()) | |
831 | ), | |
832 | DiagnosticId::Error(err_code.to_owned()), | |
833 | ) | |
834 | }; | |
835 | ||
836 | // As we encounter issues, keep track of what we want to provide for the suggestion | |
837 | let mut labels = vec![]; | |
838 | // If there is a single error, we give a specific suggestion; otherwise, we change to | |
839 | // "did you mean" with the suggested function call | |
840 | enum SuggestionText { | |
841 | None, | |
842 | Provide(bool), | |
843 | Remove(bool), | |
844 | Swap, | |
845 | Reorder, | |
846 | DidYouMean, | |
847 | } | |
848 | let mut suggestion_text = SuggestionText::None; | |
849 | ||
850 | let mut errors = errors.into_iter().peekable(); | |
851 | while let Some(error) = errors.next() { | |
852 | match error { | |
853 | Error::Invalid(provided_idx, expected_idx, compatibility) => { | |
854 | let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx]; | |
855 | let (provided_ty, provided_span) = provided_arg_tys[provided_idx]; | |
f2b60f7d | 856 | if let Compatibility::Incompatible(error) = compatibility { |
487cf647 | 857 | let trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty); |
064997fb | 858 | if let Some(e) = error { |
2b03887a | 859 | self.err_ctxt().note_type_err( |
064997fb FG |
860 | &mut err, |
861 | &trace.cause, | |
862 | None, | |
863 | Some(trace.values), | |
864 | e, | |
865 | false, | |
866 | true, | |
867 | ); | |
868 | } | |
869 | } | |
923072b8 | 870 | |
923072b8 FG |
871 | self.emit_coerce_suggestions( |
872 | &mut err, | |
064997fb | 873 | &provided_args[provided_idx], |
923072b8 | 874 | provided_ty, |
064997fb FG |
875 | Expectation::rvalue_hint(self, expected_ty) |
876 | .only_has_type(self) | |
877 | .unwrap_or(formal_ty), | |
923072b8 FG |
878 | None, |
879 | None, | |
880 | ); | |
923072b8 | 881 | } |
064997fb FG |
882 | Error::Extra(arg_idx) => { |
883 | let (provided_ty, provided_span) = provided_arg_tys[arg_idx]; | |
884 | let provided_ty_name = if !has_error_or_infer([provided_ty]) { | |
885 | // FIXME: not suggestable, use something else | |
886 | format!(" of type `{}`", provided_ty) | |
887 | } else { | |
888 | "".to_string() | |
889 | }; | |
890 | labels | |
891 | .push((provided_span, format!("argument{} unexpected", provided_ty_name))); | |
892 | suggestion_text = match suggestion_text { | |
893 | SuggestionText::None => SuggestionText::Remove(false), | |
894 | SuggestionText::Remove(_) => SuggestionText::Remove(true), | |
895 | _ => SuggestionText::DidYouMean, | |
896 | }; | |
897 | } | |
898 | Error::Missing(expected_idx) => { | |
899 | // If there are multiple missing arguments adjacent to each other, | |
900 | // then we can provide a single error. | |
901 | ||
902 | let mut missing_idxs = vec![expected_idx]; | |
903 | while let Some(e) = errors.next_if(|e| { | |
904 | matches!(e, Error::Missing(next_expected_idx) | |
905 | if *next_expected_idx == *missing_idxs.last().unwrap() + 1) | |
906 | }) { | |
907 | match e { | |
908 | Error::Missing(expected_idx) => missing_idxs.push(expected_idx), | |
909 | _ => unreachable!(), | |
923072b8 | 910 | } |
923072b8 | 911 | } |
064997fb FG |
912 | |
913 | // NOTE: Because we might be re-arranging arguments, might have extra | |
914 | // arguments, etc. it's hard to *really* know where we should provide | |
915 | // this error label, so as a heuristic, we point to the provided arg, or | |
916 | // to the call if the missing inputs pass the provided args. | |
917 | match &missing_idxs[..] { | |
918 | &[expected_idx] => { | |
919 | let (_, input_ty) = formal_and_expected_inputs[expected_idx]; | |
920 | let span = if let Some((_, arg_span)) = | |
921 | provided_arg_tys.get(expected_idx.to_provided_idx()) | |
922 | { | |
923 | *arg_span | |
923072b8 | 924 | } else { |
064997fb FG |
925 | args_span |
926 | }; | |
927 | let rendered = if !has_error_or_infer([input_ty]) { | |
928 | format!(" of type `{}`", input_ty) | |
929 | } else { | |
930 | "".to_string() | |
931 | }; | |
932 | labels.push((span, format!("an argument{} is missing", rendered))); | |
933 | suggestion_text = match suggestion_text { | |
934 | SuggestionText::None => SuggestionText::Provide(false), | |
935 | SuggestionText::Provide(_) => SuggestionText::Provide(true), | |
936 | _ => SuggestionText::DidYouMean, | |
937 | }; | |
923072b8 | 938 | } |
064997fb FG |
939 | &[first_idx, second_idx] => { |
940 | let (_, first_expected_ty) = formal_and_expected_inputs[first_idx]; | |
941 | let (_, second_expected_ty) = formal_and_expected_inputs[second_idx]; | |
942 | let span = if let (Some((_, first_span)), Some((_, second_span))) = ( | |
943 | provided_arg_tys.get(first_idx.to_provided_idx()), | |
944 | provided_arg_tys.get(second_idx.to_provided_idx()), | |
945 | ) { | |
946 | first_span.to(*second_span) | |
947 | } else { | |
948 | args_span | |
949 | }; | |
950 | let rendered = | |
951 | if !has_error_or_infer([first_expected_ty, second_expected_ty]) { | |
923072b8 FG |
952 | format!( |
953 | " of type `{}` and `{}`", | |
064997fb | 954 | first_expected_ty, second_expected_ty |
923072b8 FG |
955 | ) |
956 | } else { | |
064997fb | 957 | "".to_string() |
923072b8 | 958 | }; |
064997fb FG |
959 | labels.push((span, format!("two arguments{} are missing", rendered))); |
960 | suggestion_text = match suggestion_text { | |
961 | SuggestionText::None | SuggestionText::Provide(_) => { | |
962 | SuggestionText::Provide(true) | |
963 | } | |
964 | _ => SuggestionText::DidYouMean, | |
965 | }; | |
923072b8 | 966 | } |
064997fb FG |
967 | &[first_idx, second_idx, third_idx] => { |
968 | let (_, first_expected_ty) = formal_and_expected_inputs[first_idx]; | |
969 | let (_, second_expected_ty) = formal_and_expected_inputs[second_idx]; | |
970 | let (_, third_expected_ty) = formal_and_expected_inputs[third_idx]; | |
971 | let span = if let (Some((_, first_span)), Some((_, third_span))) = ( | |
972 | provided_arg_tys.get(first_idx.to_provided_idx()), | |
973 | provided_arg_tys.get(third_idx.to_provided_idx()), | |
974 | ) { | |
975 | first_span.to(*third_span) | |
923072b8 | 976 | } else { |
064997fb | 977 | args_span |
923072b8 | 978 | }; |
064997fb FG |
979 | let rendered = if !has_error_or_infer([ |
980 | first_expected_ty, | |
981 | second_expected_ty, | |
982 | third_expected_ty, | |
983 | ]) { | |
984 | format!( | |
985 | " of type `{}`, `{}`, and `{}`", | |
986 | first_expected_ty, second_expected_ty, third_expected_ty | |
987 | ) | |
923072b8 | 988 | } else { |
064997fb FG |
989 | "".to_string() |
990 | }; | |
991 | labels.push((span, format!("three arguments{} are missing", rendered))); | |
992 | suggestion_text = match suggestion_text { | |
993 | SuggestionText::None | SuggestionText::Provide(_) => { | |
994 | SuggestionText::Provide(true) | |
995 | } | |
996 | _ => SuggestionText::DidYouMean, | |
997 | }; | |
998 | } | |
999 | missing_idxs => { | |
1000 | let first_idx = *missing_idxs.first().unwrap(); | |
1001 | let last_idx = *missing_idxs.last().unwrap(); | |
1002 | // NOTE: Because we might be re-arranging arguments, might have extra arguments, etc. | |
1003 | // It's hard to *really* know where we should provide this error label, so this is a | |
1004 | // decent heuristic | |
1005 | let span = if let (Some((_, first_span)), Some((_, last_span))) = ( | |
1006 | provided_arg_tys.get(first_idx.to_provided_idx()), | |
1007 | provided_arg_tys.get(last_idx.to_provided_idx()), | |
1008 | ) { | |
1009 | first_span.to(*last_span) | |
1010 | } else { | |
1011 | args_span | |
1012 | }; | |
9c376795 | 1013 | labels.push((span, "multiple arguments are missing".to_string())); |
064997fb FG |
1014 | suggestion_text = match suggestion_text { |
1015 | SuggestionText::None | SuggestionText::Provide(_) => { | |
1016 | SuggestionText::Provide(true) | |
1017 | } | |
1018 | _ => SuggestionText::DidYouMean, | |
923072b8 | 1019 | }; |
923072b8 | 1020 | } |
923072b8 FG |
1021 | } |
1022 | } | |
064997fb FG |
1023 | Error::Swap( |
1024 | first_provided_idx, | |
1025 | second_provided_idx, | |
1026 | first_expected_idx, | |
1027 | second_expected_idx, | |
1028 | ) => { | |
1029 | let (first_provided_ty, first_span) = provided_arg_tys[first_provided_idx]; | |
1030 | let (_, first_expected_ty) = formal_and_expected_inputs[first_expected_idx]; | |
1031 | let first_provided_ty_name = if !has_error_or_infer([first_provided_ty]) { | |
1032 | format!(", found `{}`", first_provided_ty) | |
923072b8 | 1033 | } else { |
064997fb FG |
1034 | String::new() |
1035 | }; | |
1036 | labels.push(( | |
1037 | first_span, | |
1038 | format!("expected `{}`{}", first_expected_ty, first_provided_ty_name), | |
1039 | )); | |
1040 | ||
1041 | let (second_provided_ty, second_span) = provided_arg_tys[second_provided_idx]; | |
1042 | let (_, second_expected_ty) = formal_and_expected_inputs[second_expected_idx]; | |
1043 | let second_provided_ty_name = if !has_error_or_infer([second_provided_ty]) { | |
1044 | format!(", found `{}`", second_provided_ty) | |
1045 | } else { | |
1046 | String::new() | |
923072b8 | 1047 | }; |
064997fb FG |
1048 | labels.push(( |
1049 | second_span, | |
1050 | format!("expected `{}`{}", second_expected_ty, second_provided_ty_name), | |
1051 | )); | |
1052 | ||
1053 | suggestion_text = match suggestion_text { | |
1054 | SuggestionText::None => SuggestionText::Swap, | |
1055 | _ => SuggestionText::DidYouMean, | |
1056 | }; | |
1057 | } | |
1058 | Error::Permutation(args) => { | |
1059 | for (dst_arg, dest_input) in args { | |
1060 | let (_, expected_ty) = formal_and_expected_inputs[dst_arg]; | |
1061 | let (provided_ty, provided_span) = provided_arg_tys[dest_input]; | |
1062 | let provided_ty_name = if !has_error_or_infer([provided_ty]) { | |
1063 | format!(", found `{}`", provided_ty) | |
1064 | } else { | |
1065 | String::new() | |
1066 | }; | |
1067 | labels.push(( | |
1068 | provided_span, | |
1069 | format!("expected `{}`{}", expected_ty, provided_ty_name), | |
1070 | )); | |
923072b8 | 1071 | } |
064997fb FG |
1072 | |
1073 | suggestion_text = match suggestion_text { | |
1074 | SuggestionText::None => SuggestionText::Reorder, | |
1075 | _ => SuggestionText::DidYouMean, | |
1076 | }; | |
04454e1e | 1077 | } |
5099ac24 | 1078 | } |
5099ac24 FG |
1079 | } |
1080 | ||
064997fb FG |
1081 | // If we have less than 5 things to say, it would be useful to call out exactly what's wrong |
1082 | if labels.len() <= 5 { | |
1083 | for (span, label) in labels { | |
1084 | err.span_label(span, label); | |
1085 | } | |
1086 | } | |
5869c6ff | 1087 | |
064997fb | 1088 | // Call out where the function is defined |
f2b60f7d | 1089 | self.label_fn_like(&mut err, fn_def_id, callee_ty, None, is_method); |
29967ef6 | 1090 | |
064997fb FG |
1091 | // And add a suggestion block for all of the parameters |
1092 | let suggestion_text = match suggestion_text { | |
1093 | SuggestionText::None => None, | |
1094 | SuggestionText::Provide(plural) => { | |
1095 | Some(format!("provide the argument{}", if plural { "s" } else { "" })) | |
1096 | } | |
1097 | SuggestionText::Remove(plural) => { | |
1098 | Some(format!("remove the extra argument{}", if plural { "s" } else { "" })) | |
1099 | } | |
1100 | SuggestionText::Swap => Some("swap these arguments".to_string()), | |
1101 | SuggestionText::Reorder => Some("reorder these arguments".to_string()), | |
1102 | SuggestionText::DidYouMean => Some("did you mean".to_string()), | |
1103 | }; | |
1104 | if let Some(suggestion_text) = suggestion_text { | |
1105 | let source_map = self.sess().source_map(); | |
f2b60f7d FG |
1106 | let (mut suggestion, suggestion_span) = |
1107 | if let Some(call_span) = full_call_span.find_ancestor_inside(error_span) { | |
1108 | ("(".to_string(), call_span.shrink_to_hi().to(error_span.shrink_to_hi())) | |
1109 | } else { | |
1110 | ( | |
1111 | format!( | |
1112 | "{}(", | |
1113 | source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| { | |
1114 | fn_def_id.map_or("".to_string(), |fn_def_id| { | |
1115 | tcx.item_name(fn_def_id).to_string() | |
1116 | }) | |
1117 | }) | |
1118 | ), | |
1119 | error_span, | |
1120 | ) | |
1121 | }; | |
064997fb FG |
1122 | let mut needs_comma = false; |
1123 | for (expected_idx, provided_idx) in matched_inputs.iter_enumerated() { | |
1124 | if needs_comma { | |
1125 | suggestion += ", "; | |
1126 | } else { | |
1127 | needs_comma = true; | |
5e7ed085 | 1128 | } |
064997fb FG |
1129 | let suggestion_text = if let Some(provided_idx) = provided_idx |
1130 | && let (_, provided_span) = provided_arg_tys[*provided_idx] | |
f2b60f7d | 1131 | && let Ok(arg_text) = source_map.span_to_snippet(provided_span) |
064997fb FG |
1132 | { |
1133 | arg_text | |
1134 | } else { | |
1135 | // Propose a placeholder of the correct type | |
1136 | let (_, expected_ty) = formal_and_expected_inputs[expected_idx]; | |
1137 | if expected_ty.is_unit() { | |
1138 | "()".to_string() | |
1139 | } else if expected_ty.is_suggestable(tcx, false) { | |
1140 | format!("/* {} */", expected_ty) | |
9c376795 FG |
1141 | } else if let Some(fn_def_id) = fn_def_id |
1142 | && self.tcx.def_kind(fn_def_id).is_fn_like() | |
1143 | && let self_implicit = matches!(call_expr.kind, hir::ExprKind::MethodCall(..)) as usize | |
1144 | && let Some(arg) = self.tcx.fn_arg_names(fn_def_id).get(expected_idx.as_usize() + self_implicit) | |
1145 | && arg.name != kw::SelfLower | |
1146 | { | |
1147 | format!("/* {} */", arg.name) | |
064997fb FG |
1148 | } else { |
1149 | "/* value */".to_string() | |
29967ef6 | 1150 | } |
064997fb FG |
1151 | }; |
1152 | suggestion += &suggestion_text; | |
29967ef6 | 1153 | } |
064997fb FG |
1154 | suggestion += ")"; |
1155 | err.span_suggestion_verbose( | |
f2b60f7d | 1156 | suggestion_span, |
064997fb FG |
1157 | &suggestion_text, |
1158 | suggestion, | |
1159 | Applicability::HasPlaceholders, | |
1160 | ); | |
29967ef6 | 1161 | } |
5099ac24 | 1162 | |
064997fb | 1163 | err.emit(); |
5099ac24 FG |
1164 | } |
1165 | ||
29967ef6 XL |
1166 | // AST fragment checking |
1167 | pub(in super::super) fn check_lit( | |
1168 | &self, | |
1169 | lit: &hir::Lit, | |
1170 | expected: Expectation<'tcx>, | |
1171 | ) -> Ty<'tcx> { | |
1172 | let tcx = self.tcx; | |
1173 | ||
1174 | match lit.node { | |
1175 | ast::LitKind::Str(..) => tcx.mk_static_str(), | |
9c376795 | 1176 | ast::LitKind::ByteStr(ref v, _) => { |
29967ef6 XL |
1177 | tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.u8, v.len() as u64)) |
1178 | } | |
1179 | ast::LitKind::Byte(_) => tcx.types.u8, | |
1180 | ast::LitKind::Char(_) => tcx.types.char, | |
5869c6ff XL |
1181 | ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(ty::int_ty(t)), |
1182 | ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(ty::uint_ty(t)), | |
29967ef6 XL |
1183 | ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => { |
1184 | let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { | |
1185 | ty::Int(_) | ty::Uint(_) => Some(ty), | |
1186 | ty::Char => Some(tcx.types.u8), | |
1187 | ty::RawPtr(..) => Some(tcx.types.usize), | |
1188 | ty::FnDef(..) | ty::FnPtr(_) => Some(tcx.types.usize), | |
1189 | _ => None, | |
1190 | }); | |
1191 | opt_ty.unwrap_or_else(|| self.next_int_var()) | |
1192 | } | |
5869c6ff XL |
1193 | ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => { |
1194 | tcx.mk_mach_float(ty::float_ty(t)) | |
1195 | } | |
29967ef6 XL |
1196 | ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => { |
1197 | let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { | |
1198 | ty::Float(_) => Some(ty), | |
1199 | _ => None, | |
1200 | }); | |
1201 | opt_ty.unwrap_or_else(|| self.next_float_var()) | |
1202 | } | |
1203 | ast::LitKind::Bool(_) => tcx.types.bool, | |
f2b60f7d | 1204 | ast::LitKind::Err => tcx.ty_error(), |
29967ef6 XL |
1205 | } |
1206 | } | |
1207 | ||
1208 | pub fn check_struct_path( | |
1209 | &self, | |
1210 | qpath: &QPath<'_>, | |
1211 | hir_id: hir::HirId, | |
1212 | ) -> Option<(&'tcx ty::VariantDef, Ty<'tcx>)> { | |
6a06907d | 1213 | let path_span = qpath.span(); |
29967ef6 XL |
1214 | let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id); |
1215 | let variant = match def { | |
1216 | Res::Err => { | |
487cf647 FG |
1217 | self.set_tainted_by_errors( |
1218 | self.tcx.sess.delay_span_bug(path_span, "`Res::Err` but no error emitted"), | |
1219 | ); | |
29967ef6 XL |
1220 | return None; |
1221 | } | |
9c376795 FG |
1222 | Res::Def(DefKind::Variant, _) => match ty.normalized.ty_adt_def() { |
1223 | Some(adt) => { | |
1224 | Some((adt.variant_of_res(def), adt.did(), Self::user_substs_for_adt(ty))) | |
1225 | } | |
1226 | _ => bug!("unexpected type: {:?}", ty.normalized), | |
29967ef6 XL |
1227 | }, |
1228 | Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) | |
2b03887a | 1229 | | Res::SelfTyParam { .. } |
9c376795 FG |
1230 | | Res::SelfTyAlias { .. } => match ty.normalized.ty_adt_def() { |
1231 | Some(adt) if !adt.is_enum() => { | |
1232 | Some((adt.non_enum_variant(), adt.did(), Self::user_substs_for_adt(ty))) | |
29967ef6 XL |
1233 | } |
1234 | _ => None, | |
1235 | }, | |
1236 | _ => bug!("unexpected definition: {:?}", def), | |
1237 | }; | |
1238 | ||
9c376795 | 1239 | if let Some((variant, did, ty::UserSubsts { substs, user_self_ty })) = variant { |
29967ef6 | 1240 | debug!("check_struct_path: did={:?} substs={:?}", did, substs); |
9c376795 FG |
1241 | |
1242 | // Register type annotation. | |
1243 | self.write_user_type_annotation_from_substs(hir_id, did, substs, user_self_ty); | |
29967ef6 XL |
1244 | |
1245 | // Check bounds on type arguments used in the path. | |
f2b60f7d | 1246 | self.add_required_obligations_for_hir(path_span, did, substs, hir_id); |
29967ef6 | 1247 | |
9c376795 | 1248 | Some((variant, ty.normalized)) |
29967ef6 | 1249 | } else { |
9c376795 | 1250 | match ty.normalized.kind() { |
c295e0f8 XL |
1251 | ty::Error(_) => { |
1252 | // E0071 might be caused by a spelling error, which will have | |
1253 | // already caused an error message and probably a suggestion | |
1254 | // elsewhere. Refrain from emitting more unhelpful errors here | |
1255 | // (issue #88844). | |
1256 | } | |
1257 | _ => { | |
1258 | struct_span_err!( | |
1259 | self.tcx.sess, | |
1260 | path_span, | |
1261 | E0071, | |
1262 | "expected struct, variant or union type, found {}", | |
9c376795 | 1263 | ty.normalized.sort_string(self.tcx) |
c295e0f8 XL |
1264 | ) |
1265 | .span_label(path_span, "not a struct") | |
1266 | .emit(); | |
1267 | } | |
1268 | } | |
29967ef6 XL |
1269 | None |
1270 | } | |
1271 | } | |
1272 | ||
1273 | pub fn check_decl_initializer( | |
1274 | &self, | |
a2a8927a XL |
1275 | hir_id: hir::HirId, |
1276 | pat: &'tcx hir::Pat<'tcx>, | |
29967ef6 XL |
1277 | init: &'tcx hir::Expr<'tcx>, |
1278 | ) -> Ty<'tcx> { | |
1279 | // FIXME(tschottdorf): `contains_explicit_ref_binding()` must be removed | |
1280 | // for #42640 (default match binding modes). | |
1281 | // | |
1282 | // See #44848. | |
a2a8927a | 1283 | let ref_bindings = pat.contains_explicit_ref_binding(); |
29967ef6 | 1284 | |
a2a8927a | 1285 | let local_ty = self.local_ty(init.span, hir_id).revealed_ty; |
29967ef6 XL |
1286 | if let Some(m) = ref_bindings { |
1287 | // Somewhat subtle: if we have a `ref` binding in the pattern, | |
1288 | // we want to avoid introducing coercions for the RHS. This is | |
1289 | // both because it helps preserve sanity and, in the case of | |
1290 | // ref mut, for soundness (issue #23116). In particular, in | |
1291 | // the latter case, we need to be clear that the type of the | |
1292 | // referent for the reference that results is *equal to* the | |
1293 | // type of the place it is referencing, and not some | |
1294 | // supertype thereof. | |
1295 | let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m)); | |
1296 | self.demand_eqtype(init.span, local_ty, init_ty); | |
1297 | init_ty | |
1298 | } else { | |
1299 | self.check_expr_coercable_to_type(init, local_ty, None) | |
1300 | } | |
1301 | } | |
1302 | ||
a2a8927a | 1303 | pub(in super::super) fn check_decl(&self, decl: Declaration<'tcx>) { |
29967ef6 | 1304 | // Determine and write the type which we'll check the pattern against. |
a2a8927a XL |
1305 | let decl_ty = self.local_ty(decl.span, decl.hir_id).decl_ty; |
1306 | self.write_ty(decl.hir_id, decl_ty); | |
29967ef6 XL |
1307 | |
1308 | // Type check the initializer. | |
a2a8927a XL |
1309 | if let Some(ref init) = decl.init { |
1310 | let init_ty = self.check_decl_initializer(decl.hir_id, decl.pat, &init); | |
9c376795 | 1311 | self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, init_ty); |
29967ef6 XL |
1312 | } |
1313 | ||
1314 | // Does the expected pattern type originate from an expression and what is the span? | |
a2a8927a | 1315 | let (origin_expr, ty_span) = match (decl.ty, decl.init) { |
29967ef6 | 1316 | (Some(ty), _) => (false, Some(ty.span)), // Bias towards the explicit user type. |
064997fb FG |
1317 | (_, Some(init)) => { |
1318 | (true, Some(init.span.find_ancestor_inside(decl.span).unwrap_or(init.span))) | |
1319 | } // No explicit type; so use the scrutinee. | |
29967ef6 XL |
1320 | _ => (false, None), // We have `let $pat;`, so the expected type is unconstrained. |
1321 | }; | |
1322 | ||
1323 | // Type check the pattern. Override if necessary to avoid knock-on errors. | |
a2a8927a XL |
1324 | self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr); |
1325 | let pat_ty = self.node_ty(decl.pat.hir_id); | |
9c376795 | 1326 | self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, pat_ty); |
064997fb FG |
1327 | |
1328 | if let Some(blk) = decl.els { | |
1329 | let previous_diverges = self.diverges.get(); | |
1330 | let else_ty = self.check_block_with_expected(blk, NoExpectation); | |
1331 | let cause = self.cause(blk.span, ObligationCauseCode::LetElse); | |
1332 | if let Some(mut err) = | |
1333 | self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty) | |
1334 | { | |
1335 | err.emit(); | |
1336 | } | |
1337 | self.diverges.set(previous_diverges); | |
1338 | } | |
a2a8927a XL |
1339 | } |
1340 | ||
1341 | /// Type check a `let` statement. | |
1342 | pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) { | |
1343 | self.check_decl(local.into()); | |
29967ef6 XL |
1344 | } |
1345 | ||
6a06907d | 1346 | pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>, is_last: bool) { |
29967ef6 XL |
1347 | // Don't do all the complex logic below for `DeclItem`. |
1348 | match stmt.kind { | |
1349 | hir::StmtKind::Item(..) => return, | |
1350 | hir::StmtKind::Local(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {} | |
1351 | } | |
1352 | ||
1353 | self.warn_if_unreachable(stmt.hir_id, stmt.span, "statement"); | |
1354 | ||
1355 | // Hide the outer diverging and `has_errors` flags. | |
1356 | let old_diverges = self.diverges.replace(Diverges::Maybe); | |
29967ef6 XL |
1357 | |
1358 | match stmt.kind { | |
064997fb FG |
1359 | hir::StmtKind::Local(l) => { |
1360 | self.check_decl_local(l); | |
29967ef6 XL |
1361 | } |
1362 | // Ignore for now. | |
1363 | hir::StmtKind::Item(_) => {} | |
1364 | hir::StmtKind::Expr(ref expr) => { | |
1365 | // Check with expected type of `()`. | |
1366 | self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| { | |
6a06907d XL |
1367 | if expr.can_have_side_effects() { |
1368 | self.suggest_semicolon_at_end(expr.span, err); | |
1369 | } | |
29967ef6 XL |
1370 | }); |
1371 | } | |
1372 | hir::StmtKind::Semi(ref expr) => { | |
6a06907d XL |
1373 | // All of this is equivalent to calling `check_expr`, but it is inlined out here |
1374 | // in order to capture the fact that this `match` is the last statement in its | |
1375 | // function. This is done for better suggestions to remove the `;`. | |
1376 | let expectation = match expr.kind { | |
1377 | hir::ExprKind::Match(..) if is_last => IsLast(stmt.span), | |
1378 | _ => NoExpectation, | |
1379 | }; | |
1380 | self.check_expr_with_expectation(expr, expectation); | |
29967ef6 XL |
1381 | } |
1382 | } | |
1383 | ||
1384 | // Combine the diverging and `has_error` flags. | |
1385 | self.diverges.set(self.diverges.get() | old_diverges); | |
29967ef6 XL |
1386 | } |
1387 | ||
1388 | pub fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) { | |
1389 | let unit = self.tcx.mk_unit(); | |
1390 | let ty = self.check_block_with_expected(blk, ExpectHasType(unit)); | |
1391 | ||
1392 | // if the block produces a `!` value, that can always be | |
1393 | // (effectively) coerced to unit. | |
1394 | if !ty.is_never() { | |
1395 | self.demand_suptype(blk.span, unit, ty); | |
1396 | } | |
1397 | } | |
1398 | ||
1399 | pub(in super::super) fn check_block_with_expected( | |
1400 | &self, | |
1401 | blk: &'tcx hir::Block<'tcx>, | |
1402 | expected: Expectation<'tcx>, | |
1403 | ) -> Ty<'tcx> { | |
29967ef6 XL |
1404 | // In some cases, blocks have just one exit, but other blocks |
1405 | // can be targeted by multiple breaks. This can happen both | |
1406 | // with labeled blocks as well as when we desugar | |
1407 | // a `try { ... }` expression. | |
1408 | // | |
1409 | // Example 1: | |
1410 | // | |
1411 | // 'a: { if true { break 'a Err(()); } Ok(()) } | |
1412 | // | |
1413 | // Here we would wind up with two coercions, one from | |
1414 | // `Err(())` and the other from the tail expression | |
1415 | // `Ok(())`. If the tail expression is omitted, that's a | |
1416 | // "forced unit" -- unless the block diverges, in which | |
1417 | // case we can ignore the tail expression (e.g., `'a: { | |
1418 | // break 'a 22; }` would not force the type of the block | |
1419 | // to be `()`). | |
1420 | let tail_expr = blk.expr.as_ref(); | |
1421 | let coerce_to_ty = expected.coercion_target_type(self, blk.span); | |
1422 | let coerce = if blk.targeted_by_break { | |
1423 | CoerceMany::new(coerce_to_ty) | |
1424 | } else { | |
1425 | let tail_expr: &[&hir::Expr<'_>] = match tail_expr { | |
1426 | Some(e) => slice::from_ref(e), | |
1427 | None => &[], | |
1428 | }; | |
1429 | CoerceMany::with_coercion_sites(coerce_to_ty, tail_expr) | |
1430 | }; | |
1431 | ||
1432 | let prev_diverges = self.diverges.get(); | |
1433 | let ctxt = BreakableCtxt { coerce: Some(coerce), may_break: false }; | |
1434 | ||
1435 | let (ctxt, ()) = self.with_breakable_ctxt(blk.hir_id, ctxt, || { | |
6a06907d XL |
1436 | for (pos, s) in blk.stmts.iter().enumerate() { |
1437 | self.check_stmt(s, blk.stmts.len() - 1 == pos); | |
29967ef6 XL |
1438 | } |
1439 | ||
1440 | // check the tail expression **without** holding the | |
1441 | // `enclosing_breakables` lock below. | |
1442 | let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected)); | |
1443 | ||
1444 | let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); | |
1445 | let ctxt = enclosing_breakables.find_breakable(blk.hir_id); | |
1446 | let coerce = ctxt.coerce.as_mut().unwrap(); | |
1447 | if let Some(tail_expr_ty) = tail_expr_ty { | |
1448 | let tail_expr = tail_expr.unwrap(); | |
1449 | let span = self.get_expr_coercion_span(tail_expr); | |
1450 | let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id)); | |
5e7ed085 FG |
1451 | let ty_for_diagnostic = coerce.merged_ty(); |
1452 | // We use coerce_inner here because we want to augment the error | |
1453 | // suggesting to wrap the block in square brackets if it might've | |
1454 | // been mistaken array syntax | |
1455 | coerce.coerce_inner( | |
1456 | self, | |
1457 | &cause, | |
1458 | Some(tail_expr), | |
1459 | tail_expr_ty, | |
1460 | Some(&mut |diag: &mut Diagnostic| { | |
1461 | self.suggest_block_to_brackets(diag, blk, tail_expr_ty, ty_for_diagnostic); | |
1462 | }), | |
1463 | false, | |
1464 | ); | |
29967ef6 XL |
1465 | } else { |
1466 | // Subtle: if there is no explicit tail expression, | |
1467 | // that is typically equivalent to a tail expression | |
1468 | // of `()` -- except if the block diverges. In that | |
1469 | // case, there is no value supplied from the tail | |
1470 | // expression (assuming there are no other breaks, | |
1471 | // this implies that the type of the block will be | |
1472 | // `!`). | |
1473 | // | |
1474 | // #41425 -- label the implicit `()` as being the | |
1475 | // "found type" here, rather than the "expected type". | |
1476 | if !self.diverges.get().is_always() { | |
1477 | // #50009 -- Do not point at the entire fn block span, point at the return type | |
1478 | // span, as it is the cause of the requirement, and | |
1479 | // `consider_hint_about_removing_semicolon` will point at the last expression | |
1480 | // if it were a relevant part of the error. This improves usability in editors | |
1481 | // that highlight errors inline. | |
1482 | let mut sp = blk.span; | |
1483 | let mut fn_span = None; | |
1484 | if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) { | |
1485 | let ret_sp = decl.output.span(); | |
1486 | if let Some(block_sp) = self.parent_item_span(blk.hir_id) { | |
1487 | // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the | |
1488 | // output would otherwise be incorrect and even misleading. Make sure | |
1489 | // the span we're aiming at correspond to a `fn` body. | |
1490 | if block_sp == blk.span { | |
1491 | sp = ret_sp; | |
1492 | fn_span = Some(ident.span); | |
1493 | } | |
1494 | } | |
1495 | } | |
1496 | coerce.coerce_forced_unit( | |
1497 | self, | |
1498 | &self.misc(sp), | |
1499 | &mut |err| { | |
1500 | if let Some(expected_ty) = expected.only_has_type(self) { | |
064997fb | 1501 | if !self.consider_removing_semicolon(blk, expected_ty, err) { |
2b03887a FG |
1502 | self.err_ctxt().consider_returning_binding( |
1503 | blk, | |
1504 | expected_ty, | |
1505 | err, | |
1506 | ); | |
064997fb | 1507 | } |
3c0e092e XL |
1508 | if expected_ty == self.tcx.types.bool { |
1509 | // If this is caused by a missing `let` in a `while let`, | |
1510 | // silence this redundant error, as we already emit E0070. | |
5e7ed085 FG |
1511 | |
1512 | // Our block must be a `assign desugar local; assignment` | |
1513 | if let Some(hir::Node::Block(hir::Block { | |
1514 | stmts: | |
1515 | [ | |
1516 | hir::Stmt { | |
1517 | kind: | |
1518 | hir::StmtKind::Local(hir::Local { | |
1519 | source: | |
1520 | hir::LocalSource::AssignDesugar(_), | |
1521 | .. | |
1522 | }), | |
1523 | .. | |
1524 | }, | |
1525 | hir::Stmt { | |
1526 | kind: | |
1527 | hir::StmtKind::Expr(hir::Expr { | |
1528 | kind: hir::ExprKind::Assign(..), | |
1529 | .. | |
1530 | }), | |
1531 | .. | |
1532 | }, | |
1533 | ], | |
1534 | .. | |
1535 | })) = self.tcx.hir().find(blk.hir_id) | |
1536 | { | |
1537 | self.comes_from_while_condition(blk.hir_id, |_| { | |
1538 | err.downgrade_to_delayed_bug(); | |
1539 | }) | |
3c0e092e XL |
1540 | } |
1541 | } | |
29967ef6 XL |
1542 | } |
1543 | if let Some(fn_span) = fn_span { | |
1544 | err.span_label( | |
1545 | fn_span, | |
1546 | "implicitly returns `()` as its body has no tail or `return` \ | |
1547 | expression", | |
1548 | ); | |
1549 | } | |
1550 | }, | |
1551 | false, | |
1552 | ); | |
1553 | } | |
1554 | } | |
1555 | }); | |
1556 | ||
1557 | if ctxt.may_break { | |
1558 | // If we can break from the block, then the block's exit is always reachable | |
1559 | // (... as long as the entry is reachable) - regardless of the tail of the block. | |
1560 | self.diverges.set(prev_diverges); | |
1561 | } | |
1562 | ||
487cf647 | 1563 | let ty = ctxt.coerce.unwrap().complete(self); |
29967ef6 XL |
1564 | |
1565 | self.write_ty(blk.hir_id, ty); | |
1566 | ||
29967ef6 XL |
1567 | ty |
1568 | } | |
1569 | ||
29967ef6 | 1570 | fn parent_item_span(&self, id: hir::HirId) -> Option<Span> { |
2b03887a | 1571 | let node = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(id).def_id); |
29967ef6 XL |
1572 | match node { |
1573 | Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. }) | |
1574 | | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => { | |
1575 | let body = self.tcx.hir().body(body_id); | |
1576 | if let ExprKind::Block(block, _) = &body.value.kind { | |
1577 | return Some(block.span); | |
1578 | } | |
1579 | } | |
1580 | _ => {} | |
1581 | } | |
1582 | None | |
1583 | } | |
1584 | ||
1585 | /// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise. | |
1586 | fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> { | |
2b03887a | 1587 | let parent = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(blk_id).def_id); |
29967ef6 XL |
1588 | self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident)) |
1589 | } | |
1590 | ||
1591 | /// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail | |
1592 | /// expression's `Span`, otherwise return `expr.span`. This is done to give better errors | |
1593 | /// when given code like the following: | |
1594 | /// ```text | |
1595 | /// if false { return 0i32; } else { 1u32 } | |
1596 | /// // ^^^^ point at this instead of the whole `if` expression | |
1597 | /// ``` | |
1598 | fn get_expr_coercion_span(&self, expr: &hir::Expr<'_>) -> rustc_span::Span { | |
5869c6ff | 1599 | let check_in_progress = |elem: &hir::Expr<'_>| { |
064997fb FG |
1600 | self.typeck_results.borrow().node_type_opt(elem.hir_id).filter(|ty| !ty.is_never()).map( |
1601 | |_| match elem.kind { | |
1602 | // Point at the tail expression when possible. | |
1603 | hir::ExprKind::Block(block, _) => block.expr.map_or(block.span, |e| e.span), | |
1604 | _ => elem.span, | |
1605 | }, | |
1606 | ) | |
5869c6ff XL |
1607 | }; |
1608 | ||
1609 | if let hir::ExprKind::If(_, _, Some(el)) = expr.kind { | |
1610 | if let Some(rslt) = check_in_progress(el) { | |
1611 | return rslt; | |
29967ef6 XL |
1612 | } |
1613 | } | |
5869c6ff XL |
1614 | |
1615 | if let hir::ExprKind::Match(_, arms, _) = expr.kind { | |
1616 | let mut iter = arms.iter().filter_map(|arm| check_in_progress(arm.body)); | |
1617 | if let Some(span) = iter.next() { | |
1618 | if iter.next().is_none() { | |
1619 | return span; | |
1620 | } | |
1621 | } | |
1622 | } | |
1623 | ||
29967ef6 XL |
1624 | expr.span |
1625 | } | |
1626 | ||
1627 | fn overwrite_local_ty_if_err( | |
1628 | &self, | |
a2a8927a XL |
1629 | hir_id: hir::HirId, |
1630 | pat: &'tcx hir::Pat<'tcx>, | |
29967ef6 XL |
1631 | ty: Ty<'tcx>, |
1632 | ) { | |
1633 | if ty.references_error() { | |
1634 | // Override the types everywhere with `err()` to avoid knock on errors. | |
9c376795 FG |
1635 | let err = self.tcx.ty_error(); |
1636 | self.write_ty(hir_id, err); | |
1637 | self.write_ty(pat.hir_id, err); | |
1638 | let local_ty = LocalTy { decl_ty: err, revealed_ty: err }; | |
a2a8927a XL |
1639 | self.locals.borrow_mut().insert(hir_id, local_ty); |
1640 | self.locals.borrow_mut().insert(pat.hir_id, local_ty); | |
29967ef6 XL |
1641 | } |
1642 | } | |
1643 | ||
1644 | // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary. | |
1645 | // The newly resolved definition is written into `type_dependent_defs`. | |
1646 | fn finish_resolving_struct_path( | |
1647 | &self, | |
1648 | qpath: &QPath<'_>, | |
1649 | path_span: Span, | |
1650 | hir_id: hir::HirId, | |
9c376795 | 1651 | ) -> (Res, RawTy<'tcx>) { |
29967ef6 XL |
1652 | match *qpath { |
1653 | QPath::Resolved(ref maybe_qself, ref path) => { | |
9c376795 FG |
1654 | let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself).raw); |
1655 | let ty = self.astconv().res_to_ty(self_ty, path, true); | |
1656 | (path.res, self.handle_raw_ty(path_span, ty)) | |
29967ef6 XL |
1657 | } |
1658 | QPath::TypeRelative(ref qself, ref segment) => { | |
1659 | let ty = self.to_ty(qself); | |
1660 | ||
9c376795 FG |
1661 | let result = self |
1662 | .astconv() | |
1663 | .associated_path_to_ty(hir_id, path_span, ty.raw, qself, segment, true); | |
29967ef6 | 1664 | let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error()); |
9c376795 | 1665 | let ty = self.handle_raw_ty(path_span, ty); |
29967ef6 XL |
1666 | let result = result.map(|(_, kind, def_id)| (kind, def_id)); |
1667 | ||
1668 | // Write back the new resolution. | |
1669 | self.write_resolution(hir_id, result); | |
1670 | ||
5869c6ff | 1671 | (result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), ty) |
29967ef6 | 1672 | } |
a2a8927a | 1673 | QPath::LangItem(lang_item, span, id) => { |
9c376795 FG |
1674 | let (res, ty) = self.resolve_lang_item_path(lang_item, span, hir_id, id); |
1675 | (res, self.handle_raw_ty(path_span, ty)) | |
29967ef6 XL |
1676 | } |
1677 | } | |
1678 | } | |
1679 | ||
f2b60f7d FG |
1680 | /// Given a vector of fulfillment errors, try to adjust the spans of the |
1681 | /// errors to more accurately point at the cause of the failure. | |
1682 | /// | |
1683 | /// This applies to calls, methods, and struct expressions. This will also | |
1684 | /// try to deduplicate errors that are due to the same cause but might | |
1685 | /// have been created with different [`ObligationCause`][traits::ObligationCause]s. | |
1686 | pub(super) fn adjust_fulfillment_errors_for_expr_obligation( | |
29967ef6 XL |
1687 | &self, |
1688 | errors: &mut Vec<traits::FulfillmentError<'tcx>>, | |
29967ef6 | 1689 | ) { |
f2b60f7d FG |
1690 | // Store a mapping from `(Span, Predicate) -> ObligationCause`, so that |
1691 | // other errors that have the same span and predicate can also get fixed, | |
1692 | // even if their `ObligationCauseCode` isn't an `Expr*Obligation` kind. | |
1693 | // This is important since if we adjust one span but not the other, then | |
1694 | // we will have "duplicated" the error on the UI side. | |
9c376795 | 1695 | let mut remap_cause = FxIndexSet::default(); |
f2b60f7d FG |
1696 | let mut not_adjusted = vec![]; |
1697 | ||
1698 | for error in errors { | |
1699 | let before_span = error.obligation.cause.span; | |
1700 | if self.adjust_fulfillment_error_for_expr_obligation(error) | |
1701 | || before_span != error.obligation.cause.span | |
1702 | { | |
1703 | // Store both the predicate and the predicate *without constness* | |
1704 | // since sometimes we instantiate and check both of these in a | |
1705 | // method call, for example. | |
1706 | remap_cause.insert(( | |
1707 | before_span, | |
1708 | error.obligation.predicate, | |
1709 | error.obligation.cause.clone(), | |
1710 | )); | |
1711 | remap_cause.insert(( | |
1712 | before_span, | |
1713 | error.obligation.predicate.without_const(self.tcx), | |
1714 | error.obligation.cause.clone(), | |
1715 | )); | |
1716 | } else { | |
1717 | // If it failed to be adjusted once around, it may be adjusted | |
1718 | // via the "remap cause" mapping the second time... | |
1719 | not_adjusted.push(error); | |
29967ef6 | 1720 | } |
f2b60f7d | 1721 | } |
29967ef6 | 1722 | |
9c376795 FG |
1723 | // Adjust any other errors that come from other cause codes, when these |
1724 | // errors are of the same predicate as one we successfully adjusted, and | |
1725 | // when their spans overlap (suggesting they're due to the same root cause). | |
1726 | // | |
1727 | // This is because due to normalization, we often register duplicate | |
1728 | // obligations with misc obligations that are basically impossible to | |
1729 | // line back up with a useful ExprBindingObligation. | |
f2b60f7d FG |
1730 | for error in not_adjusted { |
1731 | for (span, predicate, cause) in &remap_cause { | |
1732 | if *predicate == error.obligation.predicate | |
1733 | && span.contains(error.obligation.cause.span) | |
1734 | { | |
1735 | error.obligation.cause = cause.clone(); | |
1736 | continue; | |
3c0e092e | 1737 | } |
3c0e092e | 1738 | } |
f2b60f7d FG |
1739 | } |
1740 | } | |
1741 | ||
1742 | fn adjust_fulfillment_error_for_expr_obligation( | |
1743 | &self, | |
1744 | error: &mut traits::FulfillmentError<'tcx>, | |
1745 | ) -> bool { | |
1746 | let (traits::ExprItemObligation(def_id, hir_id, idx) | traits::ExprBindingObligation(def_id, _, hir_id, idx)) | |
1747 | = *error.obligation.cause.code().peel_derives() else { return false; }; | |
1748 | let hir = self.tcx.hir(); | |
1749 | let hir::Node::Expr(expr) = hir.get(hir_id) else { return false; }; | |
1750 | ||
f2b60f7d FG |
1751 | let Some(unsubstituted_pred) = |
1752 | self.tcx.predicates_of(def_id).instantiate_identity(self.tcx).predicates.into_iter().nth(idx) | |
1753 | else { return false; }; | |
1754 | ||
1755 | let generics = self.tcx.generics_of(def_id); | |
1756 | let predicate_substs = match unsubstituted_pred.kind().skip_binder() { | |
487cf647 FG |
1757 | ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs, |
1758 | ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => pred.projection_ty.substs, | |
f2b60f7d FG |
1759 | _ => ty::List::empty(), |
1760 | }; | |
1761 | ||
1762 | let find_param_matching = |matches: &dyn Fn(&ty::ParamTy) -> bool| { | |
1763 | predicate_substs.types().find_map(|ty| { | |
1764 | ty.walk().find_map(|arg| { | |
1765 | if let ty::GenericArgKind::Type(ty) = arg.unpack() | |
1766 | && let ty::Param(param_ty) = ty.kind() | |
1767 | && matches(param_ty) | |
1768 | { | |
1769 | Some(arg) | |
1770 | } else { | |
1771 | None | |
064997fb | 1772 | } |
f2b60f7d FG |
1773 | }) |
1774 | }) | |
1775 | }; | |
1776 | ||
1777 | // Prefer generics that are local to the fn item, since these are likely | |
1778 | // to be the cause of the unsatisfied predicate. | |
1779 | let mut param_to_point_at = find_param_matching(&|param_ty| { | |
1780 | self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) == def_id | |
1781 | }); | |
1782 | // Fall back to generic that isn't local to the fn item. This will come | |
1783 | // from a trait or impl, for example. | |
1784 | let mut fallback_param_to_point_at = find_param_matching(&|param_ty| { | |
1785 | self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) != def_id | |
1786 | && param_ty.name != rustc_span::symbol::kw::SelfUpper | |
1787 | }); | |
1788 | // Finally, the `Self` parameter is possibly the reason that the predicate | |
1789 | // is unsatisfied. This is less likely to be true for methods, because | |
1790 | // method probe means that we already kinda check that the predicates due | |
1791 | // to the `Self` type are true. | |
1792 | let mut self_param_to_point_at = | |
1793 | find_param_matching(&|param_ty| param_ty.name == rustc_span::symbol::kw::SelfUpper); | |
1794 | ||
1795 | // Finally, for ambiguity-related errors, we actually want to look | |
1796 | // for a parameter that is the source of the inference type left | |
1797 | // over in this predicate. | |
1798 | if let traits::FulfillmentErrorCode::CodeAmbiguity = error.code { | |
1799 | fallback_param_to_point_at = None; | |
1800 | self_param_to_point_at = None; | |
1801 | param_to_point_at = | |
1802 | self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate); | |
1803 | } | |
1804 | ||
1805 | if self.closure_span_overlaps_error(error, expr.span) { | |
1806 | return false; | |
1807 | } | |
1808 | ||
1809 | match &expr.kind { | |
1810 | hir::ExprKind::Path(qpath) => { | |
1811 | if let hir::Node::Expr(hir::Expr { | |
1812 | kind: hir::ExprKind::Call(callee, args), | |
1813 | hir_id: call_hir_id, | |
1814 | span: call_span, | |
1815 | .. | |
9c376795 | 1816 | }) = hir.get_parent(expr.hir_id) |
f2b60f7d FG |
1817 | && callee.hir_id == expr.hir_id |
1818 | { | |
1819 | if self.closure_span_overlaps_error(error, *call_span) { | |
1820 | return false; | |
064997fb | 1821 | } |
f2b60f7d FG |
1822 | |
1823 | for param in | |
1824 | [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] | |
1825 | .into_iter() | |
1826 | .flatten() | |
064997fb | 1827 | { |
f2b60f7d FG |
1828 | if self.point_at_arg_if_possible( |
1829 | error, | |
1830 | def_id, | |
1831 | param, | |
1832 | *call_hir_id, | |
1833 | callee.span, | |
1834 | None, | |
1835 | args, | |
1836 | ) | |
1837 | { | |
1838 | return true; | |
1839 | } | |
3c0e092e | 1840 | } |
f2b60f7d FG |
1841 | } |
1842 | // Notably, we only point to params that are local to the | |
1843 | // item we're checking, since those are the ones we are able | |
1844 | // to look in the final `hir::PathSegment` for. Everything else | |
1845 | // would require a deeper search into the `qpath` than I think | |
1846 | // is worthwhile. | |
1847 | if let Some(param_to_point_at) = param_to_point_at | |
1848 | && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath) | |
1849 | { | |
1850 | return true; | |
1851 | } | |
1852 | } | |
1853 | hir::ExprKind::MethodCall(segment, receiver, args, ..) => { | |
1854 | for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] | |
1855 | .into_iter() | |
1856 | .flatten() | |
1857 | { | |
1858 | if self.point_at_arg_if_possible( | |
1859 | error, | |
1860 | def_id, | |
1861 | param, | |
1862 | hir_id, | |
1863 | segment.ident.span, | |
1864 | Some(receiver), | |
1865 | args, | |
1866 | ) { | |
1867 | return true; | |
1868 | } | |
1869 | } | |
1870 | if let Some(param_to_point_at) = param_to_point_at | |
1871 | && self.point_at_generic_if_possible(error, def_id, param_to_point_at, segment) | |
1872 | { | |
1873 | return true; | |
1874 | } | |
1875 | } | |
1876 | hir::ExprKind::Struct(qpath, fields, ..) => { | |
1877 | if let Res::Def(DefKind::Struct | DefKind::Variant, variant_def_id) = | |
1878 | self.typeck_results.borrow().qpath_res(qpath, hir_id) | |
1879 | { | |
1880 | for param in | |
1881 | [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] | |
1882 | { | |
1883 | if let Some(param) = param | |
1884 | && self.point_at_field_if_possible( | |
1885 | error, | |
1886 | def_id, | |
1887 | param, | |
1888 | variant_def_id, | |
1889 | fields, | |
1890 | ) | |
1891 | { | |
1892 | return true; | |
1893 | } | |
064997fb | 1894 | } |
f2b60f7d FG |
1895 | } |
1896 | if let Some(param_to_point_at) = param_to_point_at | |
1897 | && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath) | |
1898 | { | |
1899 | return true; | |
064997fb FG |
1900 | } |
1901 | } | |
f2b60f7d FG |
1902 | _ => {} |
1903 | } | |
3c0e092e | 1904 | |
f2b60f7d FG |
1905 | false |
1906 | } | |
1907 | ||
1908 | fn closure_span_overlaps_error( | |
1909 | &self, | |
1910 | error: &traits::FulfillmentError<'tcx>, | |
1911 | span: Span, | |
1912 | ) -> bool { | |
1913 | if let traits::FulfillmentErrorCode::CodeSelectionError( | |
1914 | traits::SelectionError::OutputTypeParameterMismatch(_, expected, _), | |
1915 | ) = error.code | |
1916 | && let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected.skip_binder().self_ty().kind() | |
1917 | && span.overlaps(self.tcx.def_span(*def_id)) | |
1918 | { | |
1919 | true | |
1920 | } else { | |
1921 | false | |
1922 | } | |
1923 | } | |
1924 | ||
1925 | fn point_at_arg_if_possible( | |
1926 | &self, | |
1927 | error: &mut traits::FulfillmentError<'tcx>, | |
1928 | def_id: DefId, | |
1929 | param_to_point_at: ty::GenericArg<'tcx>, | |
1930 | call_hir_id: hir::HirId, | |
1931 | callee_span: Span, | |
1932 | receiver: Option<&'tcx hir::Expr<'tcx>>, | |
1933 | args: &'tcx [hir::Expr<'tcx>], | |
1934 | ) -> bool { | |
487cf647 FG |
1935 | let ty = self.tcx.type_of(def_id); |
1936 | if !ty.is_fn() { | |
1937 | return false; | |
1938 | } | |
1939 | let sig = ty.fn_sig(self.tcx).skip_binder(); | |
f2b60f7d FG |
1940 | let args_referencing_param: Vec<_> = sig |
1941 | .inputs() | |
1942 | .iter() | |
1943 | .enumerate() | |
1944 | .filter(|(_, ty)| find_param_in_ty(**ty, param_to_point_at)) | |
1945 | .collect(); | |
1946 | // If there's one field that references the given generic, great! | |
1947 | if let [(idx, _)] = args_referencing_param.as_slice() | |
1948 | && let Some(arg) = receiver | |
1949 | .map_or(args.get(*idx), |rcvr| if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }) { | |
1950 | error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span); | |
1951 | error.obligation.cause.map_code(|parent_code| { | |
1952 | ObligationCauseCode::FunctionArgumentObligation { | |
1953 | arg_hir_id: arg.hir_id, | |
1954 | call_hir_id, | |
1955 | parent_code, | |
1956 | } | |
1957 | }); | |
1958 | return true; | |
1959 | } else if args_referencing_param.len() > 0 { | |
1960 | // If more than one argument applies, then point to the callee span at least... | |
1961 | // We have chance to fix this up further in `point_at_generics_if_possible` | |
1962 | error.obligation.cause.span = callee_span; | |
1963 | } | |
3c0e092e | 1964 | |
f2b60f7d FG |
1965 | false |
1966 | } | |
3c0e092e | 1967 | |
f2b60f7d FG |
1968 | fn point_at_field_if_possible( |
1969 | &self, | |
1970 | error: &mut traits::FulfillmentError<'tcx>, | |
1971 | def_id: DefId, | |
1972 | param_to_point_at: ty::GenericArg<'tcx>, | |
1973 | variant_def_id: DefId, | |
1974 | expr_fields: &[hir::ExprField<'tcx>], | |
1975 | ) -> bool { | |
1976 | let def = self.tcx.adt_def(def_id); | |
1977 | ||
1978 | let identity_substs = ty::InternalSubsts::identity_for_item(self.tcx, def_id); | |
1979 | let fields_referencing_param: Vec<_> = def | |
1980 | .variant_with_id(variant_def_id) | |
1981 | .fields | |
1982 | .iter() | |
1983 | .filter(|field| { | |
1984 | let field_ty = field.ty(self.tcx, identity_substs); | |
1985 | find_param_in_ty(field_ty, param_to_point_at) | |
1986 | }) | |
1987 | .collect(); | |
3c0e092e | 1988 | |
f2b60f7d FG |
1989 | if let [field] = fields_referencing_param.as_slice() { |
1990 | for expr_field in expr_fields { | |
1991 | // Look for the ExprField that matches the field, using the | |
1992 | // same rules that check_expr_struct uses for macro hygiene. | |
1993 | if self.tcx.adjust_ident(expr_field.ident, variant_def_id) == field.ident(self.tcx) | |
1994 | { | |
1995 | error.obligation.cause.span = expr_field | |
1996 | .expr | |
1997 | .span | |
1998 | .find_ancestor_in_same_ctxt(error.obligation.cause.span) | |
1999 | .unwrap_or(expr_field.span); | |
2000 | return true; | |
3c0e092e | 2001 | } |
f2b60f7d FG |
2002 | } |
2003 | } | |
2004 | ||
2005 | false | |
2006 | } | |
2007 | ||
2008 | fn point_at_path_if_possible( | |
2009 | &self, | |
2010 | error: &mut traits::FulfillmentError<'tcx>, | |
2011 | def_id: DefId, | |
2012 | param: ty::GenericArg<'tcx>, | |
2013 | qpath: &QPath<'tcx>, | |
2014 | ) -> bool { | |
2015 | match qpath { | |
2016 | hir::QPath::Resolved(_, path) => { | |
2017 | if let Some(segment) = path.segments.last() | |
2018 | && self.point_at_generic_if_possible(error, def_id, param, segment) | |
2019 | { | |
2020 | return true; | |
29967ef6 XL |
2021 | } |
2022 | } | |
f2b60f7d FG |
2023 | hir::QPath::TypeRelative(_, segment) => { |
2024 | if self.point_at_generic_if_possible(error, def_id, param, segment) { | |
2025 | return true; | |
2026 | } | |
2027 | } | |
2028 | _ => {} | |
29967ef6 | 2029 | } |
f2b60f7d FG |
2030 | |
2031 | false | |
29967ef6 XL |
2032 | } |
2033 | ||
f2b60f7d | 2034 | fn point_at_generic_if_possible( |
29967ef6 | 2035 | &self, |
f2b60f7d FG |
2036 | error: &mut traits::FulfillmentError<'tcx>, |
2037 | def_id: DefId, | |
2038 | param_to_point_at: ty::GenericArg<'tcx>, | |
2039 | segment: &hir::PathSegment<'tcx>, | |
2040 | ) -> bool { | |
2041 | let own_substs = self | |
2042 | .tcx | |
2043 | .generics_of(def_id) | |
2044 | .own_substs(ty::InternalSubsts::identity_for_item(self.tcx, def_id)); | |
2045 | let Some((index, _)) = own_substs | |
2046 | .iter() | |
2047 | .filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_))) | |
2048 | .enumerate() | |
2049 | .find(|(_, arg)| **arg == param_to_point_at) else { return false }; | |
2050 | let Some(arg) = segment | |
2051 | .args() | |
2052 | .args | |
2053 | .iter() | |
2054 | .filter(|arg| matches!(arg, hir::GenericArg::Type(_))) | |
2055 | .nth(index) else { return false; }; | |
2056 | error.obligation.cause.span = arg | |
2057 | .span() | |
2058 | .find_ancestor_in_same_ctxt(error.obligation.cause.span) | |
2059 | .unwrap_or(arg.span()); | |
2060 | true | |
2061 | } | |
2062 | ||
2063 | fn find_ambiguous_parameter_in<T: TypeVisitable<'tcx>>( | |
2064 | &self, | |
2065 | item_def_id: DefId, | |
2066 | t: T, | |
2067 | ) -> Option<ty::GenericArg<'tcx>> { | |
2068 | struct FindAmbiguousParameter<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, DefId); | |
2069 | impl<'tcx> TypeVisitor<'tcx> for FindAmbiguousParameter<'_, 'tcx> { | |
2070 | type BreakTy = ty::GenericArg<'tcx>; | |
2071 | fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> { | |
2072 | if let Some(origin) = self.0.type_var_origin(ty) | |
2073 | && let TypeVariableOriginKind::TypeParameterDefinition(_, Some(def_id)) = | |
2074 | origin.kind | |
2075 | && let generics = self.0.tcx.generics_of(self.1) | |
2076 | && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id) | |
2077 | && let Some(subst) = ty::InternalSubsts::identity_for_item(self.0.tcx, self.1) | |
2078 | .get(index as usize) | |
2079 | { | |
2080 | ControlFlow::Break(*subst) | |
2081 | } else { | |
2082 | ty.super_visit_with(self) | |
29967ef6 XL |
2083 | } |
2084 | } | |
2085 | } | |
f2b60f7d | 2086 | t.visit_with(&mut FindAmbiguousParameter(self, item_def_id)).break_value() |
29967ef6 | 2087 | } |
923072b8 | 2088 | |
064997fb FG |
2089 | fn label_fn_like( |
2090 | &self, | |
f2b60f7d | 2091 | err: &mut Diagnostic, |
064997fb FG |
2092 | callable_def_id: Option<DefId>, |
2093 | callee_ty: Option<Ty<'tcx>>, | |
f2b60f7d FG |
2094 | // A specific argument should be labeled, instead of all of them |
2095 | expected_idx: Option<usize>, | |
2096 | is_method: bool, | |
064997fb FG |
2097 | ) { |
2098 | let Some(mut def_id) = callable_def_id else { | |
2099 | return; | |
2100 | }; | |
2101 | ||
2102 | if let Some(assoc_item) = self.tcx.opt_associated_item(def_id) | |
2103 | // Possibly points at either impl or trait item, so try to get it | |
2104 | // to point to trait item, then get the parent. | |
2105 | // This parent might be an impl in the case of an inherent function, | |
2106 | // but the next check will fail. | |
2107 | && let maybe_trait_item_def_id = assoc_item.trait_item_def_id.unwrap_or(def_id) | |
2108 | && let maybe_trait_def_id = self.tcx.parent(maybe_trait_item_def_id) | |
2109 | // Just an easy way to check "trait_def_id == Fn/FnMut/FnOnce" | |
487cf647 | 2110 | && let Some(call_kind) = self.tcx.fn_trait_kind_from_def_id(maybe_trait_def_id) |
064997fb FG |
2111 | && let Some(callee_ty) = callee_ty |
2112 | { | |
2113 | let callee_ty = callee_ty.peel_refs(); | |
2114 | match *callee_ty.kind() { | |
2115 | ty::Param(param) => { | |
2116 | let param = | |
2117 | self.tcx.generics_of(self.body_id.owner).type_param(¶m, self.tcx); | |
2118 | if param.kind.is_synthetic() { | |
2119 | // if it's `impl Fn() -> ..` then just fall down to the def-id based logic | |
2120 | def_id = param.def_id; | |
2121 | } else { | |
2122 | // Otherwise, find the predicate that makes this generic callable, | |
2123 | // and point at that. | |
2124 | let instantiated = self | |
2125 | .tcx | |
2126 | .explicit_predicates_of(self.body_id.owner) | |
2127 | .instantiate_identity(self.tcx); | |
2128 | // FIXME(compiler-errors): This could be problematic if something has two | |
2129 | // fn-like predicates with different args, but callable types really never | |
2130 | // do that, so it's OK. | |
9c376795 | 2131 | for (predicate, span) in instantiated |
064997fb | 2132 | { |
487cf647 | 2133 | if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = predicate.kind().skip_binder() |
064997fb | 2134 | && pred.self_ty().peel_refs() == callee_ty |
487cf647 | 2135 | && self.tcx.is_fn_trait(pred.def_id()) |
064997fb FG |
2136 | { |
2137 | err.span_note(span, "callable defined here"); | |
2138 | return; | |
2139 | } | |
2140 | } | |
2141 | } | |
2142 | } | |
9c376795 | 2143 | ty::Alias(ty::Opaque, ty::AliasTy { def_id: new_def_id, .. }) |
064997fb FG |
2144 | | ty::Closure(new_def_id, _) |
2145 | | ty::FnDef(new_def_id, _) => { | |
2146 | def_id = new_def_id; | |
2147 | } | |
2148 | _ => { | |
2149 | // Look for a user-provided impl of a `Fn` trait, and point to it. | |
2150 | let new_def_id = self.probe(|_| { | |
9c376795 | 2151 | let trait_ref = self.tcx.mk_trait_ref( |
064997fb | 2152 | call_kind.to_def_id(self.tcx), |
9c376795 FG |
2153 | [ |
2154 | callee_ty, | |
2155 | self.next_ty_var(TypeVariableOrigin { | |
2156 | kind: TypeVariableOriginKind::MiscVariable, | |
2157 | span: rustc_span::DUMMY_SP, | |
2158 | }), | |
2159 | ], | |
064997fb FG |
2160 | ); |
2161 | let obligation = traits::Obligation::new( | |
487cf647 | 2162 | self.tcx, |
064997fb FG |
2163 | traits::ObligationCause::dummy(), |
2164 | self.param_env, | |
487cf647 | 2165 | ty::Binder::dummy(trait_ref), |
064997fb FG |
2166 | ); |
2167 | match SelectionContext::new(&self).select(&obligation) { | |
2168 | Ok(Some(traits::ImplSource::UserDefined(impl_source))) => { | |
2169 | Some(impl_source.impl_def_id) | |
2170 | } | |
f2b60f7d | 2171 | _ => None, |
064997fb FG |
2172 | } |
2173 | }); | |
2174 | if let Some(new_def_id) = new_def_id { | |
2175 | def_id = new_def_id; | |
2176 | } else { | |
2177 | return; | |
2178 | } | |
2179 | } | |
2180 | } | |
923072b8 FG |
2181 | } |
2182 | ||
064997fb FG |
2183 | if let Some(def_span) = self.tcx.def_ident_span(def_id) && !def_span.is_dummy() { |
2184 | let mut spans: MultiSpan = def_span.into(); | |
923072b8 | 2185 | |
064997fb FG |
2186 | let params = self |
2187 | .tcx | |
2188 | .hir() | |
2189 | .get_if_local(def_id) | |
2190 | .and_then(|node| node.body_id()) | |
2191 | .into_iter() | |
f2b60f7d FG |
2192 | .flat_map(|id| self.tcx.hir().body(id).params) |
2193 | .skip(if is_method { 1 } else { 0 }); | |
923072b8 | 2194 | |
f2b60f7d FG |
2195 | for (_, param) in params |
2196 | .into_iter() | |
2197 | .enumerate() | |
2198 | .filter(|(idx, _)| expected_idx.map_or(true, |expected_idx| expected_idx == *idx)) | |
2199 | { | |
064997fb | 2200 | spans.push_span_label(param.span, ""); |
923072b8 | 2201 | } |
064997fb FG |
2202 | |
2203 | let def_kind = self.tcx.def_kind(def_id); | |
2204 | err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id))); | |
f2b60f7d FG |
2205 | } else if let Some(hir::Node::Expr(e)) = self.tcx.hir().get_if_local(def_id) |
2206 | && let hir::ExprKind::Closure(hir::Closure { body, .. }) = &e.kind | |
2207 | { | |
2208 | let param = expected_idx | |
2209 | .and_then(|expected_idx| self.tcx.hir().body(*body).params.get(expected_idx)); | |
2210 | let (kind, span) = if let Some(param) = param { | |
2211 | ("closure parameter", param.span) | |
2212 | } else { | |
2213 | ("closure", self.tcx.def_span(def_id)) | |
2214 | }; | |
2215 | err.span_note(span, &format!("{} defined here", kind)); | |
064997fb FG |
2216 | } else { |
2217 | let def_kind = self.tcx.def_kind(def_id); | |
2218 | err.span_note( | |
2219 | self.tcx.def_span(def_id), | |
2220 | &format!("{} defined here", def_kind.descr(def_id)), | |
2221 | ); | |
923072b8 FG |
2222 | } |
2223 | } | |
2224 | } | |
f2b60f7d FG |
2225 | |
2226 | fn find_param_in_ty<'tcx>(ty: Ty<'tcx>, param_to_point_at: ty::GenericArg<'tcx>) -> bool { | |
2227 | let mut walk = ty.walk(); | |
2228 | while let Some(arg) = walk.next() { | |
2229 | if arg == param_to_point_at { | |
2230 | return true; | |
2231 | } else if let ty::GenericArgKind::Type(ty) = arg.unpack() | |
9c376795 | 2232 | && let ty::Alias(ty::Projection, ..) = ty.kind() |
f2b60f7d FG |
2233 | { |
2234 | // This logic may seem a bit strange, but typically when | |
2235 | // we have a projection type in a function signature, the | |
2236 | // argument that's being passed into that signature is | |
2237 | // not actually constraining that projection's substs in | |
2238 | // a meaningful way. So we skip it, and see improvements | |
2239 | // in some UI tests. | |
2240 | walk.skip_current_subtree(); | |
2241 | } | |
2242 | } | |
2243 | false | |
2244 | } |