]>
Commit | Line | Data |
---|---|---|
9c376795 FG |
1 | // ignore-tidy-filelength |
2 | ||
3 | use super::{ | |
4 | DefIdOrName, FindExprBySpan, Obligation, ObligationCause, ObligationCauseCode, | |
5 | PredicateObligation, | |
6 | }; | |
dfeec247 XL |
7 | |
8 | use crate::infer::InferCtxt; | |
9c376795 | 9 | use crate::traits::{NormalizeExt, ObligationCtxt}; |
dfeec247 | 10 | |
2b03887a | 11 | use hir::def::CtorOf; |
fc512014 | 12 | use rustc_data_structures::fx::FxHashSet; |
3dfed10e | 13 | use rustc_data_structures::stack::ensure_sufficient_stack; |
c295e0f8 | 14 | use rustc_errors::{ |
5e7ed085 | 15 | error_code, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, |
04454e1e | 16 | ErrorGuaranteed, MultiSpan, Style, |
c295e0f8 | 17 | }; |
dfeec247 XL |
18 | use rustc_hir as hir; |
19 | use rustc_hir::def::DefKind; | |
20 | use rustc_hir::def_id::DefId; | |
21 | use rustc_hir::intravisit::Visitor; | |
9ffffee4 | 22 | use rustc_hir::is_range_literal; |
3dfed10e | 23 | use rustc_hir::lang_items::LangItem; |
ba9703b0 | 24 | use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node}; |
9ffffee4 | 25 | use rustc_hir::{Expr, HirId}; |
2b03887a | 26 | use rustc_infer::infer::error_reporting::TypeErrCtxt; |
f2b60f7d | 27 | use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; |
487cf647 | 28 | use rustc_infer::infer::{InferOk, LateBoundRegionConversionTime}; |
04454e1e | 29 | use rustc_middle::hir::map; |
9c376795 FG |
30 | use rustc_middle::ty::error::TypeError::{self, Sorts}; |
31 | use rustc_middle::ty::relate::TypeRelation; | |
ba9703b0 | 32 | use rustc_middle::ty::{ |
6a06907d | 33 | self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree, |
9c376795 FG |
34 | GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, InternalSubsts, |
35 | IsSuggestable, ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder, | |
9ffffee4 | 36 | TypeSuperFoldable, TypeVisitableExt, TypeckResults, |
ba9703b0 | 37 | }; |
9ffffee4 | 38 | use rustc_span::def_id::LocalDefId; |
2b03887a | 39 | use rustc_span::symbol::{sym, Ident, Symbol}; |
9c376795 | 40 | use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span, DUMMY_SP}; |
29967ef6 | 41 | use rustc_target::spec::abi; |
9c376795 | 42 | use std::ops::Deref; |
dfeec247 | 43 | |
9c376795 | 44 | use super::method_chain::CollectAllMismatches; |
ba9703b0 | 45 | use super::InferCtxtPrivExt; |
136023e0 | 46 | use crate::infer::InferCtxtExt as _; |
ba9703b0 | 47 | use crate::traits::query::evaluate_obligation::InferCtxtExt as _; |
9c376795 | 48 | use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths}; |
ba9703b0 | 49 | |
f9f354fc XL |
50 | #[derive(Debug)] |
51 | pub enum GeneratorInteriorOrUpvar { | |
52 | // span of interior type | |
487cf647 | 53 | Interior(Span, Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>), |
f9f354fc XL |
54 | // span of upvar |
55 | Upvar(Span), | |
56 | } | |
57 | ||
04454e1e FG |
58 | // This type provides a uniform interface to retrieve data on generators, whether it originated from |
59 | // the local crate being compiled or from a foreign crate. | |
60 | #[derive(Debug)] | |
61 | pub enum GeneratorData<'tcx, 'a> { | |
62 | Local(&'a TypeckResults<'tcx>), | |
63 | Foreign(&'tcx GeneratorDiagnosticData<'tcx>), | |
64 | } | |
65 | ||
66 | impl<'tcx, 'a> GeneratorData<'tcx, 'a> { | |
67 | // Try to get information about variables captured by the generator that matches a type we are | |
68 | // looking for with `ty_matches` function. We uses it to find upvar which causes a failure to | |
69 | // meet an obligation | |
70 | fn try_get_upvar_span<F>( | |
71 | &self, | |
2b03887a | 72 | infer_context: &InferCtxt<'tcx>, |
04454e1e FG |
73 | generator_did: DefId, |
74 | ty_matches: F, | |
75 | ) -> Option<GeneratorInteriorOrUpvar> | |
76 | where | |
77 | F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool, | |
78 | { | |
79 | match self { | |
80 | GeneratorData::Local(typeck_results) => { | |
81 | infer_context.tcx.upvars_mentioned(generator_did).and_then(|upvars| { | |
82 | upvars.iter().find_map(|(upvar_id, upvar)| { | |
83 | let upvar_ty = typeck_results.node_type(*upvar_id); | |
84 | let upvar_ty = infer_context.resolve_vars_if_possible(upvar_ty); | |
9ffffee4 FG |
85 | ty_matches(ty::Binder::dummy(upvar_ty)) |
86 | .then(|| GeneratorInteriorOrUpvar::Upvar(upvar.span)) | |
04454e1e FG |
87 | }) |
88 | }) | |
89 | } | |
90 | GeneratorData::Foreign(_) => None, | |
91 | } | |
92 | } | |
93 | ||
94 | // Try to get the span of a type being awaited on that matches the type we are looking with the | |
95 | // `ty_matches` function. We uses it to find awaited type which causes a failure to meet an | |
96 | // obligation | |
97 | fn get_from_await_ty<F>( | |
98 | &self, | |
9ffffee4 | 99 | tcx: TyCtxt<'tcx>, |
04454e1e FG |
100 | visitor: AwaitsVisitor, |
101 | hir: map::Map<'tcx>, | |
102 | ty_matches: F, | |
103 | ) -> Option<Span> | |
104 | where | |
105 | F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool, | |
106 | { | |
107 | match self { | |
108 | GeneratorData::Local(typeck_results) => visitor | |
109 | .awaits | |
110 | .into_iter() | |
111 | .map(|id| hir.expect_expr(id)) | |
112 | .find(|await_expr| { | |
113 | ty_matches(ty::Binder::dummy(typeck_results.expr_ty_adjusted(&await_expr))) | |
114 | }) | |
115 | .map(|expr| expr.span), | |
116 | GeneratorData::Foreign(generator_diagnostic_data) => visitor | |
117 | .awaits | |
118 | .into_iter() | |
119 | .map(|id| hir.expect_expr(id)) | |
120 | .find(|await_expr| { | |
121 | ty_matches(ty::Binder::dummy( | |
122 | generator_diagnostic_data | |
123 | .adjustments | |
124 | .get(&await_expr.hir_id.local_id) | |
125 | .map_or::<&[ty::adjustment::Adjustment<'tcx>], _>(&[], |a| &a[..]) | |
126 | .last() | |
127 | .map_or_else::<Ty<'tcx>, _, _>( | |
128 | || { | |
129 | generator_diagnostic_data | |
130 | .nodes_types | |
131 | .get(&await_expr.hir_id.local_id) | |
132 | .cloned() | |
133 | .unwrap_or_else(|| { | |
134 | bug!( | |
9ffffee4 FG |
135 | "node_type: no type for node {}", |
136 | tcx.hir().node_to_string(await_expr.hir_id) | |
04454e1e FG |
137 | ) |
138 | }) | |
139 | }, | |
140 | |adj| adj.target, | |
141 | ), | |
142 | )) | |
143 | }) | |
144 | .map(|expr| expr.span), | |
145 | } | |
146 | } | |
147 | ||
148 | /// Get the type, expression, span and optional scope span of all types | |
149 | /// that are live across the yield of this generator | |
150 | fn get_generator_interior_types( | |
151 | &self, | |
923072b8 | 152 | ) -> ty::Binder<'tcx, &[GeneratorInteriorTypeCause<'tcx>]> { |
04454e1e | 153 | match self { |
923072b8 FG |
154 | GeneratorData::Local(typeck_result) => { |
155 | typeck_result.generator_interior_types.as_deref() | |
156 | } | |
04454e1e | 157 | GeneratorData::Foreign(generator_diagnostic_data) => { |
923072b8 | 158 | generator_diagnostic_data.generator_interior_types.as_deref() |
04454e1e FG |
159 | } |
160 | } | |
161 | } | |
162 | ||
163 | // Used to get the source of the data, note we don't have as much information for generators | |
164 | // originated from foreign crates | |
165 | fn is_foreign(&self) -> bool { | |
166 | match self { | |
167 | GeneratorData::Local(_) => false, | |
168 | GeneratorData::Foreign(_) => true, | |
169 | } | |
170 | } | |
171 | } | |
172 | ||
ba9703b0 | 173 | // This trait is public to expose the diagnostics methods to clippy. |
2b03887a | 174 | pub trait TypeErrCtxtExt<'tcx> { |
ba9703b0 XL |
175 | fn suggest_restricting_param_bound( |
176 | &self, | |
5e7ed085 | 177 | err: &mut Diagnostic, |
5099ac24 | 178 | trait_pred: ty::PolyTraitPredicate<'tcx>, |
f2b60f7d | 179 | associated_item: Option<(&'static str, Ty<'tcx>)>, |
9ffffee4 | 180 | body_id: LocalDefId, |
ba9703b0 XL |
181 | ); |
182 | ||
f035d41b XL |
183 | fn suggest_dereferences( |
184 | &self, | |
185 | obligation: &PredicateObligation<'tcx>, | |
5e7ed085 | 186 | err: &mut Diagnostic, |
5099ac24 | 187 | trait_pred: ty::PolyTraitPredicate<'tcx>, |
04454e1e | 188 | ) -> bool; |
f035d41b | 189 | |
064997fb | 190 | fn get_closure_name(&self, def_id: DefId, err: &mut Diagnostic, msg: &str) -> Option<Symbol>; |
ba9703b0 XL |
191 | |
192 | fn suggest_fn_call( | |
193 | &self, | |
194 | obligation: &PredicateObligation<'tcx>, | |
5e7ed085 | 195 | err: &mut Diagnostic, |
5099ac24 | 196 | trait_pred: ty::PolyTraitPredicate<'tcx>, |
04454e1e | 197 | ) -> bool; |
ba9703b0 | 198 | |
9c376795 FG |
199 | fn check_for_binding_assigned_block_without_tail_expression( |
200 | &self, | |
201 | obligation: &PredicateObligation<'tcx>, | |
202 | err: &mut Diagnostic, | |
203 | trait_pred: ty::PolyTraitPredicate<'tcx>, | |
204 | ); | |
205 | ||
206 | fn suggest_add_clone_to_arg( | |
207 | &self, | |
208 | obligation: &PredicateObligation<'tcx>, | |
209 | err: &mut Diagnostic, | |
210 | trait_pred: ty::PolyTraitPredicate<'tcx>, | |
211 | ) -> bool; | |
212 | ||
213 | fn extract_callable_info( | |
214 | &self, | |
215 | hir_id: HirId, | |
216 | param_env: ty::ParamEnv<'tcx>, | |
217 | found: Ty<'tcx>, | |
218 | ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)>; | |
219 | ||
ba9703b0 XL |
220 | fn suggest_add_reference_to_arg( |
221 | &self, | |
222 | obligation: &PredicateObligation<'tcx>, | |
5e7ed085 | 223 | err: &mut Diagnostic, |
5099ac24 | 224 | trait_pred: ty::PolyTraitPredicate<'tcx>, |
ba9703b0 XL |
225 | has_custom_message: bool, |
226 | ) -> bool; | |
227 | ||
04454e1e FG |
228 | fn suggest_borrowing_for_object_cast( |
229 | &self, | |
230 | err: &mut Diagnostic, | |
231 | obligation: &PredicateObligation<'tcx>, | |
232 | self_ty: Ty<'tcx>, | |
233 | object_ty: Ty<'tcx>, | |
234 | ); | |
235 | ||
ba9703b0 XL |
236 | fn suggest_remove_reference( |
237 | &self, | |
238 | obligation: &PredicateObligation<'tcx>, | |
5e7ed085 | 239 | err: &mut Diagnostic, |
5099ac24 | 240 | trait_pred: ty::PolyTraitPredicate<'tcx>, |
04454e1e | 241 | ) -> bool; |
ba9703b0 | 242 | |
5e7ed085 | 243 | fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic); |
a2a8927a | 244 | |
ba9703b0 XL |
245 | fn suggest_change_mut( |
246 | &self, | |
247 | obligation: &PredicateObligation<'tcx>, | |
5e7ed085 | 248 | err: &mut Diagnostic, |
5099ac24 | 249 | trait_pred: ty::PolyTraitPredicate<'tcx>, |
ba9703b0 XL |
250 | ); |
251 | ||
252 | fn suggest_semicolon_removal( | |
253 | &self, | |
254 | obligation: &PredicateObligation<'tcx>, | |
5e7ed085 | 255 | err: &mut Diagnostic, |
ba9703b0 | 256 | span: Span, |
5099ac24 | 257 | trait_pred: ty::PolyTraitPredicate<'tcx>, |
04454e1e | 258 | ) -> bool; |
ba9703b0 | 259 | |
f9f354fc XL |
260 | fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span>; |
261 | ||
ba9703b0 XL |
262 | fn suggest_impl_trait( |
263 | &self, | |
5e7ed085 | 264 | err: &mut Diagnostic, |
ba9703b0 XL |
265 | span: Span, |
266 | obligation: &PredicateObligation<'tcx>, | |
5099ac24 | 267 | trait_pred: ty::PolyTraitPredicate<'tcx>, |
ba9703b0 XL |
268 | ) -> bool; |
269 | ||
270 | fn point_at_returns_when_relevant( | |
271 | &self, | |
9c376795 | 272 | err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, |
ba9703b0 XL |
273 | obligation: &PredicateObligation<'tcx>, |
274 | ); | |
275 | ||
276 | fn report_closure_arg_mismatch( | |
277 | &self, | |
278 | span: Span, | |
279 | found_span: Option<Span>, | |
ba9703b0 | 280 | found: ty::PolyTraitRef<'tcx>, |
064997fb | 281 | expected: ty::PolyTraitRef<'tcx>, |
2b03887a | 282 | cause: &ObligationCauseCode<'tcx>, |
9c376795 FG |
283 | found_node: Option<Node<'_>>, |
284 | param_env: ty::ParamEnv<'tcx>, | |
5e7ed085 | 285 | ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; |
ba9703b0 | 286 | |
2b03887a FG |
287 | fn note_conflicting_closure_bounds( |
288 | &self, | |
289 | cause: &ObligationCauseCode<'tcx>, | |
290 | err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, | |
291 | ); | |
292 | ||
ba9703b0 XL |
293 | fn suggest_fully_qualified_path( |
294 | &self, | |
5e7ed085 FG |
295 | err: &mut Diagnostic, |
296 | item_def_id: DefId, | |
ba9703b0 XL |
297 | span: Span, |
298 | trait_ref: DefId, | |
299 | ); | |
300 | ||
301 | fn maybe_note_obligation_cause_for_async_await( | |
302 | &self, | |
5e7ed085 | 303 | err: &mut Diagnostic, |
ba9703b0 XL |
304 | obligation: &PredicateObligation<'tcx>, |
305 | ) -> bool; | |
306 | ||
307 | fn note_obligation_cause_for_async_await( | |
308 | &self, | |
5e7ed085 | 309 | err: &mut Diagnostic, |
f9f354fc | 310 | interior_or_upvar_span: GeneratorInteriorOrUpvar, |
04454e1e | 311 | is_async: bool, |
ba9703b0 | 312 | outer_generator: Option<DefId>, |
5099ac24 | 313 | trait_pred: ty::TraitPredicate<'tcx>, |
ba9703b0 | 314 | target_ty: Ty<'tcx>, |
3c0e092e | 315 | typeck_results: Option<&ty::TypeckResults<'tcx>>, |
ba9703b0 XL |
316 | obligation: &PredicateObligation<'tcx>, |
317 | next_code: Option<&ObligationCauseCode<'tcx>>, | |
ba9703b0 XL |
318 | ); |
319 | ||
320 | fn note_obligation_cause_code<T>( | |
321 | &self, | |
5e7ed085 | 322 | err: &mut Diagnostic, |
9c376795 | 323 | predicate: T, |
5099ac24 | 324 | param_env: ty::ParamEnv<'tcx>, |
ba9703b0 | 325 | cause_code: &ObligationCauseCode<'tcx>, |
5099ac24 | 326 | obligated_types: &mut Vec<Ty<'tcx>>, |
fc512014 | 327 | seen_requirements: &mut FxHashSet<DefId>, |
ba9703b0 | 328 | ) where |
9c376795 | 329 | T: ToPredicate<'tcx>; |
ba9703b0 | 330 | |
f9f354fc XL |
331 | /// Suggest to await before try: future? => future.await? |
332 | fn suggest_await_before_try( | |
333 | &self, | |
5e7ed085 | 334 | err: &mut Diagnostic, |
f9f354fc | 335 | obligation: &PredicateObligation<'tcx>, |
5099ac24 | 336 | trait_pred: ty::PolyTraitPredicate<'tcx>, |
f9f354fc XL |
337 | span: Span, |
338 | ); | |
5e7ed085 FG |
339 | |
340 | fn suggest_floating_point_literal( | |
341 | &self, | |
342 | obligation: &PredicateObligation<'tcx>, | |
343 | err: &mut Diagnostic, | |
344 | trait_ref: &ty::PolyTraitRef<'tcx>, | |
345 | ); | |
04454e1e FG |
346 | |
347 | fn suggest_derive( | |
348 | &self, | |
349 | obligation: &PredicateObligation<'tcx>, | |
350 | err: &mut Diagnostic, | |
351 | trait_pred: ty::PolyTraitPredicate<'tcx>, | |
352 | ); | |
064997fb FG |
353 | |
354 | fn suggest_dereferencing_index( | |
355 | &self, | |
356 | obligation: &PredicateObligation<'tcx>, | |
357 | err: &mut Diagnostic, | |
358 | trait_pred: ty::PolyTraitPredicate<'tcx>, | |
359 | ); | |
9c376795 FG |
360 | fn note_function_argument_obligation( |
361 | &self, | |
362 | arg_hir_id: HirId, | |
363 | err: &mut Diagnostic, | |
364 | parent_code: &ObligationCauseCode<'tcx>, | |
365 | param_env: ty::ParamEnv<'tcx>, | |
366 | predicate: ty::Predicate<'tcx>, | |
367 | call_hir_id: HirId, | |
368 | ); | |
369 | fn point_at_chain( | |
370 | &self, | |
371 | expr: &hir::Expr<'_>, | |
372 | typeck_results: &TypeckResults<'tcx>, | |
373 | type_diffs: Vec<TypeError<'tcx>>, | |
374 | param_env: ty::ParamEnv<'tcx>, | |
375 | err: &mut Diagnostic, | |
376 | ); | |
377 | fn probe_assoc_types_at_expr( | |
378 | &self, | |
379 | type_diffs: &[TypeError<'tcx>], | |
380 | span: Span, | |
381 | prev_ty: Ty<'tcx>, | |
382 | body_id: hir::HirId, | |
383 | param_env: ty::ParamEnv<'tcx>, | |
384 | ) -> Vec<Option<(Span, (DefId, Ty<'tcx>))>>; | |
ba9703b0 XL |
385 | } |
386 | ||
487cf647 | 387 | fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -> (Span, String) { |
ba9703b0 | 388 | ( |
04454e1e | 389 | generics.tail_span_for_predicate_suggestion(), |
923072b8 | 390 | format!("{} {}", generics.add_where_or_trailing_comma(), pred), |
ba9703b0 XL |
391 | ) |
392 | } | |
393 | ||
394 | /// Type parameter needs more bounds. The trivial case is `T` `where T: Bound`, but | |
395 | /// it can also be an `impl Trait` param that needs to be decomposed to a type | |
396 | /// param for cleaner code. | |
a2a8927a | 397 | fn suggest_restriction<'tcx>( |
f9f354fc | 398 | tcx: TyCtxt<'tcx>, |
9ffffee4 | 399 | item_id: LocalDefId, |
923072b8 | 400 | hir_generics: &hir::Generics<'tcx>, |
ba9703b0 | 401 | msg: &str, |
5e7ed085 | 402 | err: &mut Diagnostic, |
ba9703b0 | 403 | fn_sig: Option<&hir::FnSig<'_>>, |
9c376795 | 404 | projection: Option<&ty::AliasTy<'_>>, |
5099ac24 | 405 | trait_pred: ty::PolyTraitPredicate<'tcx>, |
f9f354fc XL |
406 | // When we are dealing with a trait, `super_traits` will be `Some`: |
407 | // Given `trait T: A + B + C {}` | |
408 | // - ^^^^^^^^^ GenericBounds | |
409 | // | | |
410 | // &Ident | |
923072b8 FG |
411 | super_traits: Option<(&Ident, &hir::GenericBounds<'_>)>, |
412 | ) { | |
413 | if hir_generics.where_clause_span.from_expansion() | |
414 | || hir_generics.where_clause_span.desugaring_kind().is_some() | |
415 | { | |
ba9703b0 XL |
416 | return; |
417 | } | |
923072b8 | 418 | let generics = tcx.generics_of(item_id); |
ba9703b0 | 419 | // Given `fn foo(t: impl Trait)` where `Trait` requires assoc type `A`... |
923072b8 | 420 | if let Some((param, bound_str, fn_sig)) = |
1b1a35ee | 421 | fn_sig.zip(projection).and_then(|(sig, p)| match p.self_ty().kind() { |
ba9703b0 XL |
422 | // Shenanigans to get the `Trait` from the `impl Trait`. |
423 | ty::Param(param) => { | |
923072b8 FG |
424 | let param_def = generics.type_param(param, tcx); |
425 | if param_def.kind.is_synthetic() { | |
426 | let bound_str = | |
427 | param_def.name.as_str().strip_prefix("impl ")?.trim_start().to_string(); | |
428 | return Some((param_def, bound_str, sig)); | |
429 | } | |
430 | None | |
ba9703b0 XL |
431 | } |
432 | _ => None, | |
433 | }) | |
434 | { | |
923072b8 FG |
435 | let type_param_name = hir_generics.params.next_type_param_name(Some(&bound_str)); |
436 | let trait_pred = trait_pred.fold_with(&mut ReplaceImplTraitFolder { | |
437 | tcx, | |
438 | param, | |
439 | replace_ty: ty::ParamTy::new(generics.count() as u32, Symbol::intern(&type_param_name)) | |
440 | .to_ty(tcx), | |
441 | }); | |
064997fb | 442 | if !trait_pred.is_suggestable(tcx, false) { |
923072b8 FG |
443 | return; |
444 | } | |
ba9703b0 XL |
445 | // We know we have an `impl Trait` that doesn't satisfy a required projection. |
446 | ||
5e7ed085 | 447 | // Find all of the occurrences of `impl Trait` for `Trait` in the function arguments' |
ba9703b0 XL |
448 | // types. There should be at least one, but there might be *more* than one. In that |
449 | // case we could just ignore it and try to identify which one needs the restriction, | |
450 | // but instead we choose to suggest replacing all instances of `impl Trait` with `T` | |
451 | // where `T: Trait`. | |
452 | let mut ty_spans = vec![]; | |
ba9703b0 | 453 | for input in fn_sig.decl.inputs { |
923072b8 FG |
454 | ReplaceImplTraitVisitor { ty_spans: &mut ty_spans, param_did: param.def_id } |
455 | .visit_ty(input); | |
ba9703b0 | 456 | } |
ba9703b0 XL |
457 | // The type param `T: Trait` we will suggest to introduce. |
458 | let type_param = format!("{}: {}", type_param_name, bound_str); | |
459 | ||
ba9703b0 | 460 | let mut sugg = vec![ |
923072b8 | 461 | if let Some(span) = hir_generics.span_for_param_suggestion() { |
04454e1e FG |
462 | (span, format!(", {}", type_param)) |
463 | } else { | |
923072b8 | 464 | (hir_generics.span, format!("<{}>", type_param)) |
ba9703b0 XL |
465 | }, |
466 | // `fn foo(t: impl Trait)` | |
467 | // ^ suggest `where <T as Trait>::A: Bound` | |
487cf647 | 468 | predicate_constraint(hir_generics, trait_pred.to_predicate(tcx)), |
ba9703b0 XL |
469 | ]; |
470 | sugg.extend(ty_spans.into_iter().map(|s| (s, type_param_name.to_string()))); | |
471 | ||
472 | // Suggest `fn foo<T: Trait>(t: T) where <T as Trait>::A: Bound`. | |
473 | // FIXME: once `#![feature(associated_type_bounds)]` is stabilized, we should suggest | |
474 | // `fn foo(t: impl Trait<A: Bound>)` instead. | |
475 | err.multipart_suggestion( | |
476 | "introduce a type parameter with a trait bound instead of using `impl Trait`", | |
477 | sugg, | |
478 | Applicability::MaybeIncorrect, | |
479 | ); | |
480 | } else { | |
064997fb | 481 | if !trait_pred.is_suggestable(tcx, false) { |
923072b8 FG |
482 | return; |
483 | } | |
ba9703b0 | 484 | // Trivial case: `T` needs an extra bound: `T: Bound`. |
5869c6ff | 485 | let (sp, suggestion) = match ( |
923072b8 | 486 | hir_generics |
3c0e092e XL |
487 | .params |
488 | .iter() | |
489 | .find(|p| !matches!(p.kind, hir::GenericParamKind::Type { synthetic: true, .. })), | |
5869c6ff XL |
490 | super_traits, |
491 | ) { | |
487cf647 | 492 | (_, None) => predicate_constraint(hir_generics, trait_pred.to_predicate(tcx)), |
5099ac24 FG |
493 | (None, Some((ident, []))) => ( |
494 | ident.span.shrink_to_hi(), | |
495 | format!(": {}", trait_pred.print_modifiers_and_trait_path()), | |
496 | ), | |
497 | (_, Some((_, [.., bounds]))) => ( | |
498 | bounds.span().shrink_to_hi(), | |
499 | format!(" + {}", trait_pred.print_modifiers_and_trait_path()), | |
500 | ), | |
501 | (Some(_), Some((_, []))) => ( | |
923072b8 | 502 | hir_generics.span.shrink_to_hi(), |
5099ac24 | 503 | format!(": {}", trait_pred.print_modifiers_and_trait_path()), |
f9f354fc | 504 | ), |
f9f354fc XL |
505 | }; |
506 | ||
507 | err.span_suggestion_verbose( | |
508 | sp, | |
509 | &format!("consider further restricting {}", msg), | |
510 | suggestion, | |
511 | Applicability::MachineApplicable, | |
512 | ); | |
ba9703b0 XL |
513 | } |
514 | } | |
515 | ||
2b03887a | 516 | impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { |
ba9703b0 | 517 | fn suggest_restricting_param_bound( |
dfeec247 | 518 | &self, |
5e7ed085 | 519 | mut err: &mut Diagnostic, |
5099ac24 | 520 | trait_pred: ty::PolyTraitPredicate<'tcx>, |
f2b60f7d | 521 | associated_ty: Option<(&'static str, Ty<'tcx>)>, |
9ffffee4 | 522 | mut body_id: LocalDefId, |
dfeec247 | 523 | ) { |
923072b8 FG |
524 | let trait_pred = self.resolve_numeric_literals_with_default(trait_pred); |
525 | ||
5099ac24 | 526 | let self_ty = trait_pred.skip_binder().self_ty(); |
1b1a35ee | 527 | let (param_ty, projection) = match self_ty.kind() { |
dfeec247 | 528 | ty::Param(_) => (true, None), |
9c376795 | 529 | ty::Alias(ty::Projection, projection) => (false, Some(projection)), |
6a06907d | 530 | _ => (false, None), |
dfeec247 XL |
531 | }; |
532 | ||
dfeec247 XL |
533 | // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we |
534 | // don't suggest `T: Sized + ?Sized`. | |
9ffffee4 | 535 | while let Some(node) = self.tcx.hir().find_by_def_id(body_id) { |
dfeec247 | 536 | match node { |
f9f354fc XL |
537 | hir::Node::Item(hir::Item { |
538 | ident, | |
539 | kind: hir::ItemKind::Trait(_, _, generics, bounds, _), | |
540 | .. | |
541 | }) if self_ty == self.tcx.types.self_param => { | |
542 | assert!(param_ty); | |
543 | // Restricting `Self` for a single method. | |
544 | suggest_restriction( | |
545 | self.tcx, | |
9ffffee4 | 546 | body_id, |
f9f354fc XL |
547 | &generics, |
548 | "`Self`", | |
549 | err, | |
550 | None, | |
551 | projection, | |
5099ac24 | 552 | trait_pred, |
f9f354fc XL |
553 | Some((ident, bounds)), |
554 | ); | |
555 | return; | |
556 | } | |
557 | ||
dfeec247 XL |
558 | hir::Node::TraitItem(hir::TraitItem { |
559 | generics, | |
ba9703b0 | 560 | kind: hir::TraitItemKind::Fn(..), |
dfeec247 | 561 | .. |
f9f354fc XL |
562 | }) if self_ty == self.tcx.types.self_param => { |
563 | assert!(param_ty); | |
dfeec247 | 564 | // Restricting `Self` for a single method. |
f9f354fc | 565 | suggest_restriction( |
9ffffee4 | 566 | self.tcx, body_id, &generics, "`Self`", err, None, projection, trait_pred, |
923072b8 | 567 | None, |
f9f354fc | 568 | ); |
dfeec247 XL |
569 | return; |
570 | } | |
571 | ||
ba9703b0 | 572 | hir::Node::TraitItem(hir::TraitItem { |
dfeec247 | 573 | generics, |
ba9703b0 | 574 | kind: hir::TraitItemKind::Fn(fn_sig, ..), |
dfeec247 XL |
575 | .. |
576 | }) | |
577 | | hir::Node::ImplItem(hir::ImplItem { | |
578 | generics, | |
ba9703b0 | 579 | kind: hir::ImplItemKind::Fn(fn_sig, ..), |
dfeec247 XL |
580 | .. |
581 | }) | |
582 | | hir::Node::Item(hir::Item { | |
ba9703b0 XL |
583 | kind: hir::ItemKind::Fn(fn_sig, generics, _), .. |
584 | }) if projection.is_some() => { | |
585 | // Missing restriction on associated type of type parameter (unmet projection). | |
586 | suggest_restriction( | |
f9f354fc | 587 | self.tcx, |
9ffffee4 | 588 | body_id, |
ba9703b0 XL |
589 | &generics, |
590 | "the associated type", | |
591 | err, | |
592 | Some(fn_sig), | |
593 | projection, | |
5099ac24 | 594 | trait_pred, |
f9f354fc | 595 | None, |
ba9703b0 XL |
596 | ); |
597 | return; | |
598 | } | |
599 | hir::Node::Item(hir::Item { | |
600 | kind: | |
5e7ed085 | 601 | hir::ItemKind::Trait(_, _, generics, ..) |
5869c6ff | 602 | | hir::ItemKind::Impl(hir::Impl { generics, .. }), |
dfeec247 | 603 | .. |
dfeec247 | 604 | }) if projection.is_some() => { |
ba9703b0 XL |
605 | // Missing restriction on associated type of type parameter (unmet projection). |
606 | suggest_restriction( | |
f9f354fc | 607 | self.tcx, |
9ffffee4 | 608 | body_id, |
ba9703b0 XL |
609 | &generics, |
610 | "the associated type", | |
611 | err, | |
612 | None, | |
613 | projection, | |
5099ac24 | 614 | trait_pred, |
f9f354fc | 615 | None, |
ba9703b0 | 616 | ); |
dfeec247 XL |
617 | return; |
618 | } | |
619 | ||
620 | hir::Node::Item(hir::Item { | |
ba9703b0 XL |
621 | kind: |
622 | hir::ItemKind::Struct(_, generics) | |
623 | | hir::ItemKind::Enum(_, generics) | |
624 | | hir::ItemKind::Union(_, generics) | |
625 | | hir::ItemKind::Trait(_, _, generics, ..) | |
5869c6ff | 626 | | hir::ItemKind::Impl(hir::Impl { generics, .. }) |
ba9703b0 XL |
627 | | hir::ItemKind::Fn(_, generics, _) |
628 | | hir::ItemKind::TyAlias(_, generics) | |
629 | | hir::ItemKind::TraitAlias(generics, _) | |
630 | | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), | |
dfeec247 XL |
631 | .. |
632 | }) | |
ba9703b0 XL |
633 | | hir::Node::TraitItem(hir::TraitItem { generics, .. }) |
634 | | hir::Node::ImplItem(hir::ImplItem { generics, .. }) | |
dfeec247 XL |
635 | if param_ty => |
636 | { | |
923072b8 FG |
637 | // We skip the 0'th subst (self) because we do not want |
638 | // to consider the predicate as not suggestible if the | |
639 | // self type is an arg position `impl Trait` -- instead, | |
640 | // we handle that by adding ` + Bound` below. | |
641 | // FIXME(compiler-errors): It would be nice to do the same | |
642 | // this that we do in `suggest_restriction` and pull the | |
643 | // `impl Trait` into a new generic if it shows up somewhere | |
644 | // else in the predicate. | |
645 | if !trait_pred.skip_binder().trait_ref.substs[1..] | |
646 | .iter() | |
064997fb | 647 | .all(|g| g.is_suggestable(self.tcx, false)) |
923072b8 FG |
648 | { |
649 | return; | |
650 | } | |
dfeec247 XL |
651 | // Missing generic type parameter bound. |
652 | let param_name = self_ty.to_string(); | |
064997fb | 653 | let mut constraint = with_no_trimmed_paths!( |
5099ac24 | 654 | trait_pred.print_modifiers_and_trait_path().to_string() |
5e7ed085 | 655 | ); |
064997fb | 656 | |
f2b60f7d | 657 | if let Some((name, term)) = associated_ty { |
064997fb FG |
658 | // FIXME: this case overlaps with code in TyCtxt::note_and_explain_type_err. |
659 | // That should be extracted into a helper function. | |
660 | if constraint.ends_with('>') { | |
661 | constraint = format!( | |
f2b60f7d | 662 | "{}, {} = {}>", |
064997fb | 663 | &constraint[..constraint.len() - 1], |
f2b60f7d | 664 | name, |
064997fb FG |
665 | term |
666 | ); | |
667 | } else { | |
f2b60f7d | 668 | constraint.push_str(&format!("<{} = {}>", name, term)); |
064997fb FG |
669 | } |
670 | } | |
671 | ||
dfeec247 | 672 | if suggest_constraining_type_param( |
74b04a01 | 673 | self.tcx, |
dfeec247 XL |
674 | generics, |
675 | &mut err, | |
676 | ¶m_name, | |
677 | &constraint, | |
5099ac24 | 678 | Some(trait_pred.def_id()), |
9ffffee4 | 679 | None, |
dfeec247 XL |
680 | ) { |
681 | return; | |
682 | } | |
683 | } | |
684 | ||
6a06907d XL |
685 | hir::Node::Item(hir::Item { |
686 | kind: | |
687 | hir::ItemKind::Struct(_, generics) | |
688 | | hir::ItemKind::Enum(_, generics) | |
689 | | hir::ItemKind::Union(_, generics) | |
690 | | hir::ItemKind::Trait(_, _, generics, ..) | |
691 | | hir::ItemKind::Impl(hir::Impl { generics, .. }) | |
692 | | hir::ItemKind::Fn(_, generics, _) | |
693 | | hir::ItemKind::TyAlias(_, generics) | |
694 | | hir::ItemKind::TraitAlias(generics, _) | |
695 | | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), | |
696 | .. | |
697 | }) if !param_ty => { | |
698 | // Missing generic type parameter bound. | |
f2b60f7d FG |
699 | if suggest_arbitrary_trait_bound( |
700 | self.tcx, | |
701 | generics, | |
702 | &mut err, | |
703 | trait_pred, | |
704 | associated_ty, | |
705 | ) { | |
6a06907d XL |
706 | return; |
707 | } | |
708 | } | |
ba9703b0 | 709 | hir::Node::Crate(..) => return, |
dfeec247 XL |
710 | |
711 | _ => {} | |
712 | } | |
9ffffee4 | 713 | body_id = self.tcx.local_parent(body_id); |
dfeec247 XL |
714 | } |
715 | } | |
716 | ||
f035d41b XL |
717 | /// When after several dereferencing, the reference satisfies the trait |
718 | /// binding. This function provides dereference suggestion for this | |
719 | /// specific situation. | |
720 | fn suggest_dereferences( | |
721 | &self, | |
722 | obligation: &PredicateObligation<'tcx>, | |
5e7ed085 | 723 | err: &mut Diagnostic, |
5099ac24 | 724 | trait_pred: ty::PolyTraitPredicate<'tcx>, |
04454e1e | 725 | ) -> bool { |
f035d41b | 726 | // It only make sense when suggesting dereferences for arguments |
9c376795 | 727 | let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, call_hir_id, .. } = obligation.cause.code() |
f2b60f7d | 728 | else { return false; }; |
2b03887a | 729 | let Some(typeck_results) = &self.typeck_results |
f2b60f7d | 730 | else { return false; }; |
f2b60f7d FG |
731 | let hir::Node::Expr(expr) = self.tcx.hir().get(*arg_hir_id) |
732 | else { return false; }; | |
733 | let Some(arg_ty) = typeck_results.expr_ty_adjusted_opt(expr) | |
734 | else { return false; }; | |
735 | ||
f035d41b | 736 | let span = obligation.cause.span; |
04454e1e FG |
737 | let mut real_trait_pred = trait_pred; |
738 | let mut code = obligation.cause.code(); | |
923072b8 FG |
739 | while let Some((parent_code, parent_trait_pred)) = code.parent() { |
740 | code = parent_code; | |
741 | if let Some(parent_trait_pred) = parent_trait_pred { | |
742 | real_trait_pred = parent_trait_pred; | |
743 | } | |
744 | ||
f2b60f7d FG |
745 | let real_ty = real_trait_pred.self_ty(); |
746 | // We `erase_late_bound_regions` here because `make_subregion` does not handle | |
747 | // `ReLateBound`, and we don't particularly care about the regions. | |
9ffffee4 FG |
748 | if !self.can_eq( |
749 | obligation.param_env, | |
750 | self.tcx.erase_late_bound_regions(real_ty), | |
751 | arg_ty, | |
752 | ) { | |
f2b60f7d FG |
753 | continue; |
754 | } | |
f035d41b | 755 | |
f2b60f7d | 756 | if let ty::Ref(region, base_ty, mutbl) = *real_ty.skip_binder().kind() { |
9c376795 FG |
757 | let autoderef = (self.autoderef_steps)(base_ty); |
758 | if let Some(steps) = | |
759 | autoderef.into_iter().enumerate().find_map(|(steps, (ty, obligations))| { | |
760 | // Re-add the `&` | |
761 | let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl }); | |
762 | ||
763 | // Remapping bound vars here | |
764 | let real_trait_pred_and_ty = | |
765 | real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, ty)); | |
766 | let obligation = self.mk_trait_obligation_with_new_self_ty( | |
767 | obligation.param_env, | |
768 | real_trait_pred_and_ty, | |
769 | ); | |
9ffffee4 | 770 | let may_hold = obligations |
9c376795 FG |
771 | .iter() |
772 | .chain([&obligation]) | |
773 | .all(|obligation| self.predicate_may_hold(obligation)) | |
9ffffee4 FG |
774 | .then_some(steps); |
775 | ||
776 | may_hold | |
9c376795 FG |
777 | }) |
778 | { | |
04454e1e | 779 | if steps > 0 { |
f2b60f7d FG |
780 | // Don't care about `&mut` because `DerefMut` is used less |
781 | // often and user will not expect autoderef happens. | |
782 | if let Some(hir::Node::Expr(hir::Expr { | |
783 | kind: | |
784 | hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, expr), | |
785 | .. | |
786 | })) = self.tcx.hir().find(*arg_hir_id) | |
787 | { | |
788 | let derefs = "*".repeat(steps); | |
789 | err.span_suggestion_verbose( | |
790 | expr.span.shrink_to_lo(), | |
791 | "consider dereferencing here", | |
792 | derefs, | |
793 | Applicability::MachineApplicable, | |
794 | ); | |
795 | return true; | |
f035d41b XL |
796 | } |
797 | } | |
04454e1e FG |
798 | } else if real_trait_pred != trait_pred { |
799 | // This branch addresses #87437. | |
923072b8 FG |
800 | |
801 | // Remapping bound vars here | |
802 | let real_trait_pred_and_base_ty = | |
803 | real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, base_ty)); | |
04454e1e | 804 | let obligation = self.mk_trait_obligation_with_new_self_ty( |
f2b60f7d | 805 | obligation.param_env, |
923072b8 | 806 | real_trait_pred_and_base_ty, |
04454e1e FG |
807 | ); |
808 | if self.predicate_may_hold(&obligation) { | |
9c376795 FG |
809 | let call_node = self.tcx.hir().get(*call_hir_id); |
810 | let msg = "consider dereferencing here"; | |
811 | let is_receiver = matches!( | |
812 | call_node, | |
813 | Node::Expr(hir::Expr { | |
814 | kind: hir::ExprKind::MethodCall(_, receiver_expr, ..), | |
815 | .. | |
816 | }) | |
817 | if receiver_expr.hir_id == *arg_hir_id | |
04454e1e | 818 | ); |
9c376795 FG |
819 | if is_receiver { |
820 | err.multipart_suggestion_verbose( | |
821 | msg, | |
822 | vec![ | |
823 | (span.shrink_to_lo(), "(*".to_string()), | |
824 | (span.shrink_to_hi(), ")".to_string()), | |
825 | ], | |
826 | Applicability::MachineApplicable, | |
827 | ) | |
828 | } else { | |
829 | err.span_suggestion_verbose( | |
830 | span.shrink_to_lo(), | |
831 | msg, | |
832 | '*', | |
833 | Applicability::MachineApplicable, | |
834 | ) | |
835 | }; | |
04454e1e FG |
836 | return true; |
837 | } | |
f035d41b XL |
838 | } |
839 | } | |
840 | } | |
04454e1e | 841 | false |
f035d41b XL |
842 | } |
843 | ||
dfeec247 XL |
844 | /// Given a closure's `DefId`, return the given name of the closure. |
845 | /// | |
846 | /// This doesn't account for reassignments, but it's only used for suggestions. | |
064997fb FG |
847 | fn get_closure_name(&self, def_id: DefId, err: &mut Diagnostic, msg: &str) -> Option<Symbol> { |
848 | let get_name = |err: &mut Diagnostic, kind: &hir::PatKind<'_>| -> Option<Symbol> { | |
5e7ed085 FG |
849 | // Get the local name of this closure. This can be inaccurate because |
850 | // of the possibility of reassignment, but this should be good enough. | |
851 | match &kind { | |
f2b60f7d | 852 | hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, ident, None) => { |
064997fb | 853 | Some(ident.name) |
dfeec247 | 854 | } |
5e7ed085 | 855 | _ => { |
04454e1e | 856 | err.note(msg); |
5e7ed085 FG |
857 | None |
858 | } | |
859 | } | |
860 | }; | |
dfeec247 XL |
861 | |
862 | let hir = self.tcx.hir(); | |
3dfed10e | 863 | let hir_id = hir.local_def_id_to_hir_id(def_id.as_local()?); |
9c376795 | 864 | match hir.find_parent(hir_id) { |
dfeec247 XL |
865 | Some(hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(local), .. })) => { |
866 | get_name(err, &local.pat.kind) | |
867 | } | |
868 | // Different to previous arm because one is `&hir::Local` and the other | |
869 | // is `P<hir::Local>`. | |
870 | Some(hir::Node::Local(local)) => get_name(err, &local.pat.kind), | |
ba9703b0 | 871 | _ => None, |
dfeec247 XL |
872 | } |
873 | } | |
874 | ||
875 | /// We tried to apply the bound to an `fn` or closure. Check whether calling it would | |
876 | /// evaluate to a type that *would* satisfy the trait binding. If it would, suggest calling | |
877 | /// it: `bar(foo)` → `bar(foo())`. This case is *very* likely to be hit if `foo` is `async`. | |
ba9703b0 | 878 | fn suggest_fn_call( |
dfeec247 XL |
879 | &self, |
880 | obligation: &PredicateObligation<'tcx>, | |
5e7ed085 | 881 | err: &mut Diagnostic, |
5099ac24 | 882 | trait_pred: ty::PolyTraitPredicate<'tcx>, |
04454e1e | 883 | ) -> bool { |
9c376795 FG |
884 | // It doesn't make sense to make this suggestion outside of typeck... |
885 | // (also autoderef will ICE...) | |
886 | if self.typeck_results.is_none() { | |
887 | return false; | |
888 | } | |
889 | ||
487cf647 | 890 | if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = obligation.predicate.kind().skip_binder() |
2b03887a FG |
891 | && Some(trait_pred.def_id()) == self.tcx.lang_items().sized_trait() |
892 | { | |
893 | // Don't suggest calling to turn an unsized type into a sized type | |
894 | return false; | |
895 | } | |
dfeec247 | 896 | |
9ffffee4 | 897 | let self_ty = self.instantiate_binder_with_fresh_vars( |
9c376795 | 898 | DUMMY_SP, |
2b03887a | 899 | LateBoundRegionConversionTime::FnCall, |
9c376795 | 900 | trait_pred.self_ty(), |
2b03887a | 901 | ); |
9c376795 | 902 | |
9ffffee4 | 903 | let body_hir_id = self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id); |
9c376795 | 904 | let Some((def_id_or_name, output, inputs)) = self.extract_callable_info( |
9ffffee4 | 905 | body_hir_id, |
9c376795 FG |
906 | obligation.param_env, |
907 | self_ty, | |
908 | ) else { return false; }; | |
923072b8 FG |
909 | |
910 | // Remapping bound vars here | |
2b03887a | 911 | let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output)); |
f9f354fc XL |
912 | |
913 | let new_obligation = | |
923072b8 | 914 | self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self); |
2b03887a FG |
915 | if !self.predicate_must_hold_modulo_regions(&new_obligation) { |
916 | return false; | |
dfeec247 | 917 | } |
2b03887a | 918 | |
dfeec247 | 919 | // Get the name of the callable and the arguments to be used in the suggestion. |
2b03887a FG |
920 | let hir = self.tcx.hir(); |
921 | ||
922 | let msg = match def_id_or_name { | |
923 | DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) { | |
924 | DefKind::Ctor(CtorOf::Struct, _) => { | |
925 | "use parentheses to construct this tuple struct".to_string() | |
926 | } | |
927 | DefKind::Ctor(CtorOf::Variant, _) => { | |
928 | "use parentheses to construct this tuple variant".to_string() | |
929 | } | |
9ffffee4 FG |
930 | kind => format!( |
931 | "use parentheses to call this {}", | |
932 | self.tcx.def_kind_descr(kind, def_id) | |
933 | ), | |
2b03887a FG |
934 | }, |
935 | DefIdOrName::Name(name) => format!("use parentheses to call this {name}"), | |
dfeec247 | 936 | }; |
2b03887a FG |
937 | |
938 | let args = inputs | |
9c376795 | 939 | .into_iter() |
2b03887a FG |
940 | .map(|ty| { |
941 | if ty.is_suggestable(self.tcx, false) { | |
942 | format!("/* {ty} */") | |
943 | } else { | |
944 | "/* value */".to_string() | |
945 | } | |
946 | }) | |
947 | .collect::<Vec<_>>() | |
948 | .join(", "); | |
949 | ||
a2a8927a | 950 | if matches!(obligation.cause.code(), ObligationCauseCode::FunctionArgumentObligation { .. }) |
f2b60f7d | 951 | && obligation.cause.span.can_be_used_for_suggestions() |
a2a8927a | 952 | { |
dfeec247 XL |
953 | // When the obligation error has been ensured to have been caused by |
954 | // an argument, the `obligation.cause.span` points at the expression | |
c295e0f8 XL |
955 | // of the argument, so we can provide a suggestion. Otherwise, we give |
956 | // a more general note. | |
ba9703b0 XL |
957 | err.span_suggestion_verbose( |
958 | obligation.cause.span.shrink_to_hi(), | |
dfeec247 | 959 | &msg, |
2b03887a | 960 | format!("({args})"), |
dfeec247 XL |
961 | Applicability::HasPlaceholders, |
962 | ); | |
2b03887a FG |
963 | } else if let DefIdOrName::DefId(def_id) = def_id_or_name { |
964 | let name = match hir.get_if_local(def_id) { | |
965 | Some(hir::Node::Expr(hir::Expr { | |
966 | kind: hir::ExprKind::Closure(hir::Closure { fn_decl_span, .. }), | |
967 | .. | |
968 | })) => { | |
969 | err.span_label(*fn_decl_span, "consider calling this closure"); | |
970 | let Some(name) = self.get_closure_name(def_id, err, &msg) else { | |
971 | return false; | |
972 | }; | |
973 | name.to_string() | |
974 | } | |
975 | Some(hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Fn(..), .. })) => { | |
976 | err.span_label(ident.span, "consider calling this function"); | |
977 | ident.to_string() | |
978 | } | |
979 | Some(hir::Node::Ctor(..)) => { | |
980 | let name = self.tcx.def_path_str(def_id); | |
981 | err.span_label( | |
982 | self.tcx.def_span(def_id), | |
983 | format!("consider calling the constructor for `{}`", name), | |
984 | ); | |
985 | name | |
986 | } | |
987 | _ => return false, | |
988 | }; | |
989 | err.help(&format!("{msg}: `{name}({args})`")); | |
dfeec247 | 990 | } |
04454e1e | 991 | true |
dfeec247 XL |
992 | } |
993 | ||
9c376795 FG |
994 | fn check_for_binding_assigned_block_without_tail_expression( |
995 | &self, | |
996 | obligation: &PredicateObligation<'tcx>, | |
997 | err: &mut Diagnostic, | |
998 | trait_pred: ty::PolyTraitPredicate<'tcx>, | |
999 | ) { | |
1000 | let mut span = obligation.cause.span; | |
1001 | while span.from_expansion() { | |
1002 | // Remove all the desugaring and macro contexts. | |
1003 | span.remove_mark(); | |
1004 | } | |
1005 | let mut expr_finder = FindExprBySpan::new(span); | |
9ffffee4 FG |
1006 | let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { return; }; |
1007 | let body = self.tcx.hir().body(body_id); | |
1008 | expr_finder.visit_expr(body.value); | |
9c376795 FG |
1009 | let Some(expr) = expr_finder.result else { return; }; |
1010 | let Some(typeck) = &self.typeck_results else { return; }; | |
1011 | let Some(ty) = typeck.expr_ty_adjusted_opt(expr) else { return; }; | |
1012 | if !ty.is_unit() { | |
1013 | return; | |
1014 | }; | |
1015 | let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else { return; }; | |
1016 | let hir::def::Res::Local(hir_id) = path.res else { return; }; | |
1017 | let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(hir_id) else { | |
1018 | return; | |
1019 | }; | |
1020 | let Some(hir::Node::Local(hir::Local { | |
1021 | ty: None, | |
1022 | init: Some(init), | |
1023 | .. | |
1024 | })) = self.tcx.hir().find_parent(pat.hir_id) else { return; }; | |
1025 | let hir::ExprKind::Block(block, None) = init.kind else { return; }; | |
1026 | if block.expr.is_some() { | |
1027 | return; | |
1028 | } | |
1029 | let [.., stmt] = block.stmts else { | |
1030 | err.span_label(block.span, "this empty block is missing a tail expression"); | |
1031 | return; | |
1032 | }; | |
1033 | let hir::StmtKind::Semi(tail_expr) = stmt.kind else { return; }; | |
1034 | let Some(ty) = typeck.expr_ty_opt(tail_expr) else { | |
1035 | err.span_label(block.span, "this block is missing a tail expression"); | |
1036 | return; | |
1037 | }; | |
1038 | let ty = self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(ty)); | |
1039 | let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, ty)); | |
1040 | ||
1041 | let new_obligation = | |
1042 | self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self); | |
1043 | if self.predicate_must_hold_modulo_regions(&new_obligation) { | |
1044 | err.span_suggestion_short( | |
1045 | stmt.span.with_lo(tail_expr.span.hi()), | |
1046 | "remove this semicolon", | |
1047 | "", | |
1048 | Applicability::MachineApplicable, | |
1049 | ); | |
1050 | } else { | |
1051 | err.span_label(block.span, "this block is missing a tail expression"); | |
1052 | } | |
1053 | } | |
1054 | ||
1055 | fn suggest_add_clone_to_arg( | |
1056 | &self, | |
1057 | obligation: &PredicateObligation<'tcx>, | |
1058 | err: &mut Diagnostic, | |
1059 | trait_pred: ty::PolyTraitPredicate<'tcx>, | |
1060 | ) -> bool { | |
1061 | let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); | |
9ffffee4 FG |
1062 | let ty = self.instantiate_binder_with_placeholders(self_ty); |
1063 | let Some(generics) = self.tcx.hir().get_generics(obligation.cause.body_id) else { return false }; | |
9c376795 FG |
1064 | let ty::Ref(_, inner_ty, hir::Mutability::Not) = ty.kind() else { return false }; |
1065 | let ty::Param(param) = inner_ty.kind() else { return false }; | |
1066 | let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = obligation.cause.code() else { return false }; | |
1067 | let arg_node = self.tcx.hir().get(*arg_hir_id); | |
1068 | let Node::Expr(Expr { kind: hir::ExprKind::Path(_), ..}) = arg_node else { return false }; | |
1069 | ||
1070 | let clone_trait = self.tcx.require_lang_item(LangItem::Clone, None); | |
1071 | let has_clone = |ty| { | |
1072 | self.type_implements_trait(clone_trait, [ty], obligation.param_env) | |
1073 | .must_apply_modulo_regions() | |
1074 | }; | |
1075 | ||
1076 | let new_obligation = self.mk_trait_obligation_with_new_self_ty( | |
1077 | obligation.param_env, | |
1078 | trait_pred.map_bound(|trait_pred| (trait_pred, *inner_ty)), | |
1079 | ); | |
1080 | ||
1081 | if self.predicate_may_hold(&new_obligation) && has_clone(ty) { | |
1082 | if !has_clone(param.to_ty(self.tcx)) { | |
1083 | suggest_constraining_type_param( | |
1084 | self.tcx, | |
1085 | generics, | |
1086 | err, | |
1087 | param.name.as_str(), | |
1088 | "Clone", | |
1089 | Some(clone_trait), | |
9ffffee4 | 1090 | None, |
9c376795 FG |
1091 | ); |
1092 | } | |
1093 | err.span_suggestion_verbose( | |
1094 | obligation.cause.span.shrink_to_hi(), | |
1095 | "consider using clone here", | |
1096 | ".clone()".to_string(), | |
1097 | Applicability::MaybeIncorrect, | |
1098 | ); | |
1099 | return true; | |
1100 | } | |
1101 | false | |
1102 | } | |
1103 | ||
1104 | /// Extracts information about a callable type for diagnostics. This is a | |
1105 | /// heuristic -- it doesn't necessarily mean that a type is always callable, | |
1106 | /// because the callable type must also be well-formed to be called. | |
9ffffee4 | 1107 | // FIXME(vincenzopalazzo): move the HirId to a LocalDefId |
9c376795 FG |
1108 | fn extract_callable_info( |
1109 | &self, | |
1110 | hir_id: HirId, | |
1111 | param_env: ty::ParamEnv<'tcx>, | |
1112 | found: Ty<'tcx>, | |
1113 | ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> { | |
1114 | // Autoderef is useful here because sometimes we box callables, etc. | |
1115 | let Some((def_id_or_name, output, inputs)) = (self.autoderef_steps)(found).into_iter().find_map(|(found, _)| { | |
1116 | match *found.kind() { | |
1117 | ty::FnPtr(fn_sig) => | |
1118 | Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.inputs())), | |
1119 | ty::FnDef(def_id, _) => { | |
1120 | let fn_sig = found.fn_sig(self.tcx); | |
1121 | Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs())) | |
1122 | } | |
1123 | ty::Closure(def_id, substs) => { | |
1124 | let fn_sig = substs.as_closure().sig(); | |
1125 | Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs().map_bound(|inputs| &inputs[1..]))) | |
1126 | } | |
1127 | ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { | |
1128 | self.tcx.item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| { | |
1129 | if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder() | |
1130 | && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() | |
1131 | // args tuple will always be substs[1] | |
1132 | && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind() | |
1133 | { | |
1134 | Some(( | |
1135 | DefIdOrName::DefId(def_id), | |
1136 | pred.kind().rebind(proj.term.ty().unwrap()), | |
1137 | pred.kind().rebind(args.as_slice()), | |
1138 | )) | |
1139 | } else { | |
1140 | None | |
1141 | } | |
1142 | }) | |
1143 | } | |
1144 | ty::Dynamic(data, _, ty::Dyn) => { | |
1145 | data.iter().find_map(|pred| { | |
1146 | if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder() | |
1147 | && Some(proj.def_id) == self.tcx.lang_items().fn_once_output() | |
1148 | // for existential projection, substs are shifted over by 1 | |
1149 | && let ty::Tuple(args) = proj.substs.type_at(0).kind() | |
1150 | { | |
1151 | Some(( | |
1152 | DefIdOrName::Name("trait object"), | |
1153 | pred.rebind(proj.term.ty().unwrap()), | |
1154 | pred.rebind(args.as_slice()), | |
1155 | )) | |
1156 | } else { | |
1157 | None | |
1158 | } | |
1159 | }) | |
1160 | } | |
1161 | ty::Param(param) => { | |
1162 | let generics = self.tcx.generics_of(hir_id.owner.to_def_id()); | |
1163 | let name = if generics.count() > param.index as usize | |
1164 | && let def = generics.param_at(param.index as usize, self.tcx) | |
1165 | && matches!(def.kind, ty::GenericParamDefKind::Type { .. }) | |
1166 | && def.name == param.name | |
1167 | { | |
1168 | DefIdOrName::DefId(def.def_id) | |
1169 | } else { | |
1170 | DefIdOrName::Name("type parameter") | |
1171 | }; | |
1172 | param_env.caller_bounds().iter().find_map(|pred| { | |
1173 | if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder() | |
1174 | && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() | |
1175 | && proj.projection_ty.self_ty() == found | |
1176 | // args tuple will always be substs[1] | |
1177 | && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind() | |
1178 | { | |
1179 | Some(( | |
1180 | name, | |
1181 | pred.kind().rebind(proj.term.ty().unwrap()), | |
1182 | pred.kind().rebind(args.as_slice()), | |
1183 | )) | |
1184 | } else { | |
1185 | None | |
1186 | } | |
1187 | }) | |
1188 | } | |
1189 | _ => None, | |
1190 | } | |
1191 | }) else { return None; }; | |
1192 | ||
9ffffee4 | 1193 | let output = self.instantiate_binder_with_fresh_vars( |
9c376795 FG |
1194 | DUMMY_SP, |
1195 | LateBoundRegionConversionTime::FnCall, | |
1196 | output, | |
1197 | ); | |
1198 | let inputs = inputs | |
1199 | .skip_binder() | |
1200 | .iter() | |
1201 | .map(|ty| { | |
9ffffee4 | 1202 | self.instantiate_binder_with_fresh_vars( |
9c376795 FG |
1203 | DUMMY_SP, |
1204 | LateBoundRegionConversionTime::FnCall, | |
1205 | inputs.rebind(*ty), | |
1206 | ) | |
1207 | }) | |
1208 | .collect(); | |
1209 | ||
1210 | // We don't want to register any extra obligations, which should be | |
1211 | // implied by wf, but also because that would possibly result in | |
1212 | // erroneous errors later on. | |
1213 | let InferOk { value: output, obligations: _ } = | |
1214 | self.at(&ObligationCause::dummy(), param_env).normalize(output); | |
1215 | ||
1216 | if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) } | |
1217 | } | |
1218 | ||
ba9703b0 | 1219 | fn suggest_add_reference_to_arg( |
dfeec247 XL |
1220 | &self, |
1221 | obligation: &PredicateObligation<'tcx>, | |
5e7ed085 | 1222 | err: &mut Diagnostic, |
5099ac24 | 1223 | poly_trait_pred: ty::PolyTraitPredicate<'tcx>, |
dfeec247 XL |
1224 | has_custom_message: bool, |
1225 | ) -> bool { | |
c295e0f8 XL |
1226 | let span = obligation.cause.span; |
1227 | ||
1228 | let code = if let ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } = | |
a2a8927a | 1229 | obligation.cause.code() |
c295e0f8 | 1230 | { |
a2a8927a | 1231 | &parent_code |
f2b60f7d FG |
1232 | } else if let ObligationCauseCode::ItemObligation(_) |
1233 | | ObligationCauseCode::ExprItemObligation(..) = obligation.cause.code() | |
1234 | { | |
1235 | obligation.cause.code() | |
3c0e092e | 1236 | } else if let ExpnKind::Desugaring(DesugaringKind::ForLoop) = |
c295e0f8 XL |
1237 | span.ctxt().outer_expn_data().kind |
1238 | { | |
a2a8927a | 1239 | obligation.cause.code() |
c295e0f8 | 1240 | } else { |
dfeec247 | 1241 | return false; |
c295e0f8 | 1242 | }; |
dfeec247 | 1243 | |
136023e0 | 1244 | // List of traits for which it would be nonsensical to suggest borrowing. |
17df50a5 XL |
1245 | // For instance, immutable references are always Copy, so suggesting to |
1246 | // borrow would always succeed, but it's probably not what the user wanted. | |
136023e0 XL |
1247 | let mut never_suggest_borrow: Vec<_> = |
1248 | [LangItem::Copy, LangItem::Clone, LangItem::Unpin, LangItem::Sized] | |
17df50a5 | 1249 | .iter() |
487cf647 | 1250 | .filter_map(|lang_item| self.tcx.lang_items().get(*lang_item)) |
17df50a5 XL |
1251 | .collect(); |
1252 | ||
c295e0f8 XL |
1253 | if let Some(def_id) = self.tcx.get_diagnostic_item(sym::Send) { |
1254 | never_suggest_borrow.push(def_id); | |
1255 | } | |
136023e0 | 1256 | |
dfeec247 | 1257 | let param_env = obligation.param_env; |
17df50a5 XL |
1258 | |
1259 | // Try to apply the original trait binding obligation by borrowing. | |
f2b60f7d FG |
1260 | let mut try_borrowing = |old_pred: ty::PolyTraitPredicate<'tcx>, |
1261 | blacklist: &[DefId]| | |
1262 | -> bool { | |
1263 | if blacklist.contains(&old_pred.def_id()) { | |
1264 | return false; | |
1265 | } | |
1266 | // We map bounds to `&T` and `&mut T` | |
1267 | let trait_pred_and_imm_ref = old_pred.map_bound(|trait_pred| { | |
1268 | ( | |
1269 | trait_pred, | |
1270 | self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()), | |
1271 | ) | |
1272 | }); | |
1273 | let trait_pred_and_mut_ref = old_pred.map_bound(|trait_pred| { | |
1274 | ( | |
1275 | trait_pred, | |
1276 | self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()), | |
1277 | ) | |
1278 | }); | |
1279 | ||
1280 | let mk_result = |trait_pred_and_new_ty| { | |
1281 | let obligation = | |
1282 | self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty); | |
1283 | self.predicate_must_hold_modulo_regions(&obligation) | |
1284 | }; | |
1285 | let imm_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_imm_ref); | |
1286 | let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref); | |
1287 | ||
1288 | let (ref_inner_ty_satisfies_pred, ref_inner_ty_mut) = | |
1289 | if let ObligationCauseCode::ItemObligation(_) | ObligationCauseCode::ExprItemObligation(..) = obligation.cause.code() | |
1290 | && let ty::Ref(_, ty, mutability) = old_pred.self_ty().skip_binder().kind() | |
1291 | { | |
923072b8 | 1292 | ( |
f2b60f7d | 1293 | mk_result(old_pred.map_bound(|trait_pred| (trait_pred, *ty))), |
487cf647 | 1294 | mutability.is_mut(), |
923072b8 | 1295 | ) |
f2b60f7d FG |
1296 | } else { |
1297 | (false, false) | |
923072b8 | 1298 | }; |
f2b60f7d FG |
1299 | |
1300 | if imm_ref_self_ty_satisfies_pred | |
1301 | || mut_ref_self_ty_satisfies_pred | |
1302 | || ref_inner_ty_satisfies_pred | |
1303 | { | |
1304 | if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { | |
1305 | // We don't want a borrowing suggestion on the fields in structs, | |
1306 | // ``` | |
1307 | // struct Foo { | |
1308 | // the_foos: Vec<Foo> | |
1309 | // } | |
1310 | // ``` | |
1311 | if !matches!( | |
1312 | span.ctxt().outer_expn_data().kind, | |
1313 | ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) | |
1314 | ) { | |
1315 | return false; | |
1316 | } | |
1317 | if snippet.starts_with('&') { | |
1318 | // This is already a literal borrow and the obligation is failing | |
1319 | // somewhere else in the obligation chain. Do not suggest non-sense. | |
1320 | return false; | |
1321 | } | |
1322 | // We have a very specific type of error, where just borrowing this argument | |
1323 | // might solve the problem. In cases like this, the important part is the | |
1324 | // original type obligation, not the last one that failed, which is arbitrary. | |
1325 | // Because of this, we modify the error to refer to the original obligation and | |
1326 | // return early in the caller. | |
1327 | ||
1328 | let msg = format!("the trait bound `{}` is not satisfied", old_pred); | |
1329 | if has_custom_message { | |
1330 | err.note(&msg); | |
1331 | } else { | |
1332 | err.message = | |
1333 | vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)]; | |
1334 | } | |
1335 | err.span_label( | |
1336 | span, | |
1337 | format!( | |
1338 | "the trait `{}` is not implemented for `{}`", | |
1339 | old_pred.print_modifiers_and_trait_path(), | |
1340 | old_pred.self_ty().skip_binder(), | |
1341 | ), | |
1342 | ); | |
1343 | ||
1344 | if imm_ref_self_ty_satisfies_pred && mut_ref_self_ty_satisfies_pred { | |
1345 | err.span_suggestions( | |
1346 | span.shrink_to_lo(), | |
1347 | "consider borrowing here", | |
487cf647 | 1348 | ["&".to_string(), "&mut ".to_string()], |
f2b60f7d FG |
1349 | Applicability::MaybeIncorrect, |
1350 | ); | |
1351 | } else { | |
9ffffee4 FG |
1352 | // Issue #104961, we need to add parentheses properly for compond expressions |
1353 | // for example, `x.starts_with("hi".to_string() + "you")` | |
1354 | // should be `x.starts_with(&("hi".to_string() + "you"))` | |
1355 | let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { return false; }; | |
1356 | let body = self.tcx.hir().body(body_id); | |
1357 | let mut expr_finder = FindExprBySpan::new(span); | |
1358 | expr_finder.visit_expr(body.value); | |
1359 | let Some(expr) = expr_finder.result else { return false; }; | |
1360 | let needs_parens = match expr.kind { | |
1361 | // parenthesize if needed (Issue #46756) | |
1362 | hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true, | |
1363 | // parenthesize borrows of range literals (Issue #54505) | |
1364 | _ if is_range_literal(expr) => true, | |
1365 | _ => false, | |
1366 | }; | |
1367 | ||
f2b60f7d | 1368 | let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut; |
9ffffee4 FG |
1369 | let span = if needs_parens { span } else { span.shrink_to_lo() }; |
1370 | let sugg_prefix = format!("&{}", if is_mut { "mut " } else { "" }); | |
1371 | let sugg_msg = &format!( | |
1372 | "consider{} borrowing here", | |
1373 | if is_mut { " mutably" } else { "" } | |
1374 | ); | |
1375 | ||
1376 | let suggestions = if !needs_parens { | |
1377 | vec![(span.shrink_to_lo(), format!("{}", sugg_prefix))] | |
1378 | } else { | |
1379 | vec![ | |
1380 | (span.shrink_to_lo(), format!("{}(", sugg_prefix)), | |
1381 | (span.shrink_to_hi(), ")".to_string()), | |
1382 | ] | |
1383 | }; | |
1384 | err.multipart_suggestion_verbose( | |
1385 | sugg_msg, | |
1386 | suggestions, | |
f2b60f7d | 1387 | Applicability::MaybeIncorrect, |
923072b8 | 1388 | ); |
f9f354fc | 1389 | } |
f2b60f7d | 1390 | return true; |
dfeec247 | 1391 | } |
f2b60f7d FG |
1392 | } |
1393 | return false; | |
1394 | }; | |
17df50a5 | 1395 | |
5e7ed085 FG |
1396 | if let ObligationCauseCode::ImplDerivedObligation(cause) = &*code { |
1397 | try_borrowing(cause.derived.parent_trait_pred, &[]) | |
17df50a5 | 1398 | } else if let ObligationCauseCode::BindingObligation(_, _) |
f2b60f7d FG |
1399 | | ObligationCauseCode::ItemObligation(_) |
1400 | | ObligationCauseCode::ExprItemObligation(..) | |
1401 | | ObligationCauseCode::ExprBindingObligation(..) = code | |
17df50a5 | 1402 | { |
5099ac24 | 1403 | try_borrowing(poly_trait_pred, &never_suggest_borrow) |
17df50a5 XL |
1404 | } else { |
1405 | false | |
dfeec247 | 1406 | } |
dfeec247 XL |
1407 | } |
1408 | ||
04454e1e FG |
1409 | // Suggest borrowing the type |
1410 | fn suggest_borrowing_for_object_cast( | |
1411 | &self, | |
1412 | err: &mut Diagnostic, | |
1413 | obligation: &PredicateObligation<'tcx>, | |
1414 | self_ty: Ty<'tcx>, | |
1415 | object_ty: Ty<'tcx>, | |
1416 | ) { | |
f2b60f7d | 1417 | let ty::Dynamic(predicates, _, ty::Dyn) = object_ty.kind() else { return; }; |
04454e1e FG |
1418 | let self_ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, self_ty); |
1419 | ||
1420 | for predicate in predicates.iter() { | |
1421 | if !self.predicate_must_hold_modulo_regions( | |
487cf647 | 1422 | &obligation.with(self.tcx, predicate.with_self_ty(self.tcx, self_ref_ty)), |
04454e1e FG |
1423 | ) { |
1424 | return; | |
1425 | } | |
1426 | } | |
1427 | ||
1428 | err.span_suggestion( | |
1429 | obligation.cause.span.shrink_to_lo(), | |
1430 | &format!( | |
1431 | "consider borrowing the value, since `&{self_ty}` can be coerced into `{object_ty}`" | |
1432 | ), | |
923072b8 | 1433 | "&", |
04454e1e FG |
1434 | Applicability::MaybeIncorrect, |
1435 | ); | |
1436 | } | |
1437 | ||
dfeec247 XL |
1438 | /// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`, |
1439 | /// suggest removing these references until we reach a type that implements the trait. | |
ba9703b0 | 1440 | fn suggest_remove_reference( |
dfeec247 XL |
1441 | &self, |
1442 | obligation: &PredicateObligation<'tcx>, | |
5e7ed085 | 1443 | err: &mut Diagnostic, |
5099ac24 | 1444 | trait_pred: ty::PolyTraitPredicate<'tcx>, |
04454e1e | 1445 | ) -> bool { |
9c376795 FG |
1446 | let mut span = obligation.cause.span; |
1447 | let mut trait_pred = trait_pred; | |
1448 | let mut code = obligation.cause.code(); | |
1449 | while let Some((c, Some(parent_trait_pred))) = code.parent() { | |
1450 | // We want the root obligation, in order to detect properly handle | |
1451 | // `for _ in &mut &mut vec![] {}`. | |
1452 | code = c; | |
1453 | trait_pred = parent_trait_pred; | |
1454 | } | |
1455 | while span.desugaring_kind().is_some() { | |
1456 | // Remove all the hir desugaring contexts while maintaining the macro contexts. | |
1457 | span.remove_mark(); | |
1458 | } | |
1459 | let mut expr_finder = super::FindExprBySpan::new(span); | |
9ffffee4 | 1460 | let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { |
9c376795 FG |
1461 | return false; |
1462 | }; | |
9ffffee4 FG |
1463 | let body = self.tcx.hir().body(body_id); |
1464 | expr_finder.visit_expr(body.value); | |
9c376795 FG |
1465 | let mut maybe_suggest = |suggested_ty, count, suggestions| { |
1466 | // Remapping bound vars here | |
1467 | let trait_pred_and_suggested_ty = | |
1468 | trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty)); | |
1469 | ||
1470 | let new_obligation = self.mk_trait_obligation_with_new_self_ty( | |
1471 | obligation.param_env, | |
1472 | trait_pred_and_suggested_ty, | |
1473 | ); | |
dfeec247 | 1474 | |
9c376795 FG |
1475 | if self.predicate_may_hold(&new_obligation) { |
1476 | let msg = if count == 1 { | |
1477 | "consider removing the leading `&`-reference".to_string() | |
1478 | } else { | |
1479 | format!("consider removing {count} leading `&`-references") | |
1480 | }; | |
1481 | ||
1482 | err.multipart_suggestion_verbose( | |
1483 | &msg, | |
1484 | suggestions, | |
1485 | Applicability::MachineApplicable, | |
1486 | ); | |
1487 | true | |
1488 | } else { | |
1489 | false | |
dfeec247 | 1490 | } |
9c376795 | 1491 | }; |
dfeec247 | 1492 | |
9c376795 FG |
1493 | // Maybe suggest removal of borrows from types in type parameters, like in |
1494 | // `src/test/ui/not-panic/not-panic-safe.rs`. | |
1495 | let mut count = 0; | |
1496 | let mut suggestions = vec![]; | |
1497 | // Skipping binder here, remapping below | |
1498 | let mut suggested_ty = trait_pred.self_ty().skip_binder(); | |
1499 | if let Some(mut hir_ty) = expr_finder.ty_result { | |
1500 | while let hir::TyKind::Ref(_, mut_ty) = &hir_ty.kind { | |
1501 | count += 1; | |
1502 | let span = hir_ty.span.until(mut_ty.ty.span); | |
1503 | suggestions.push((span, String::new())); | |
dfeec247 | 1504 | |
5099ac24 FG |
1505 | let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else { |
1506 | break; | |
1507 | }; | |
1508 | suggested_ty = *inner_ty; | |
dfeec247 | 1509 | |
9c376795 | 1510 | hir_ty = mut_ty.ty; |
923072b8 | 1511 | |
9c376795 FG |
1512 | if maybe_suggest(suggested_ty, count, suggestions.clone()) { |
1513 | return true; | |
1514 | } | |
1515 | } | |
1516 | } | |
dfeec247 | 1517 | |
9c376795 FG |
1518 | // Maybe suggest removal of borrows from expressions, like in `for i in &&&foo {}`. |
1519 | let Some(mut expr) = expr_finder.result else { return false; }; | |
1520 | let mut count = 0; | |
1521 | let mut suggestions = vec![]; | |
1522 | // Skipping binder here, remapping below | |
1523 | let mut suggested_ty = trait_pred.self_ty().skip_binder(); | |
1524 | 'outer: loop { | |
1525 | while let hir::ExprKind::AddrOf(_, _, borrowed) = expr.kind { | |
1526 | count += 1; | |
1527 | let span = if expr.span.eq_ctxt(borrowed.span) { | |
1528 | expr.span.until(borrowed.span) | |
1529 | } else { | |
1530 | expr.span.with_hi(expr.span.lo() + BytePos(1)) | |
1531 | }; | |
1532 | suggestions.push((span, String::new())); | |
dfeec247 | 1533 | |
9c376795 FG |
1534 | let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else { |
1535 | break 'outer; | |
1536 | }; | |
1537 | suggested_ty = *inner_ty; | |
74b04a01 | 1538 | |
9c376795 | 1539 | expr = borrowed; |
dfeec247 | 1540 | |
9c376795 FG |
1541 | if maybe_suggest(suggested_ty, count, suggestions.clone()) { |
1542 | return true; | |
dfeec247 XL |
1543 | } |
1544 | } | |
9c376795 FG |
1545 | if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind |
1546 | && let hir::def::Res::Local(hir_id) = path.res | |
1547 | && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(hir_id) | |
1548 | && let Some(hir::Node::Local(local)) = self.tcx.hir().find_parent(binding.hir_id) | |
1549 | && let None = local.ty | |
1550 | && let Some(binding_expr) = local.init | |
1551 | { | |
1552 | expr = binding_expr; | |
1553 | } else { | |
1554 | break 'outer; | |
1555 | } | |
dfeec247 | 1556 | } |
9c376795 | 1557 | false |
dfeec247 XL |
1558 | } |
1559 | ||
5e7ed085 | 1560 | fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic) { |
a2a8927a XL |
1561 | let span = obligation.cause.span; |
1562 | ||
1563 | if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code().peel_derives() { | |
1564 | let hir = self.tcx.hir(); | |
9c376795 FG |
1565 | if let Some(hir::Node::Expr(expr)) = hir_id.and_then(|hir_id| hir.find(hir_id)) { |
1566 | // FIXME: use `obligation.predicate.kind()...trait_ref.self_ty()` to see if we have `()` | |
1567 | // and if not maybe suggest doing something else? If we kept the expression around we | |
1568 | // could also check if it is an fn call (very likely) and suggest changing *that*, if | |
1569 | // it is from the local crate. | |
1570 | err.span_suggestion( | |
1571 | span, | |
1572 | "remove the `.await`", | |
1573 | "", | |
1574 | Applicability::MachineApplicable, | |
1575 | ); | |
1576 | // FIXME: account for associated `async fn`s. | |
1577 | if let hir::Expr { span, kind: hir::ExprKind::Call(base, _), .. } = expr { | |
1578 | if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = | |
1579 | obligation.predicate.kind().skip_binder() | |
1580 | { | |
1581 | err.span_label(*span, &format!("this call returns `{}`", pred.self_ty())); | |
1582 | } | |
1583 | if let Some(typeck_results) = &self.typeck_results | |
5e7ed085 FG |
1584 | && let ty = typeck_results.expr_ty_adjusted(base) |
1585 | && let ty::FnDef(def_id, _substs) = ty.kind() | |
04454e1e | 1586 | && let Some(hir::Node::Item(hir::Item { ident, span, vis_span, .. })) = |
5e7ed085 | 1587 | hir.get_if_local(*def_id) |
a2a8927a | 1588 | { |
04454e1e FG |
1589 | let msg = format!( |
1590 | "alternatively, consider making `fn {}` asynchronous", | |
1591 | ident | |
5e7ed085 | 1592 | ); |
04454e1e FG |
1593 | if vis_span.is_empty() { |
1594 | err.span_suggestion_verbose( | |
1595 | span.shrink_to_lo(), | |
1596 | &msg, | |
923072b8 | 1597 | "async ", |
04454e1e FG |
1598 | Applicability::MaybeIncorrect, |
1599 | ); | |
1600 | } else { | |
1601 | err.span_suggestion_verbose( | |
1602 | vis_span.shrink_to_hi(), | |
1603 | &msg, | |
923072b8 | 1604 | " async", |
04454e1e FG |
1605 | Applicability::MaybeIncorrect, |
1606 | ); | |
1607 | } | |
a2a8927a | 1608 | } |
a2a8927a XL |
1609 | } |
1610 | } | |
1611 | } | |
1612 | } | |
1613 | ||
dfeec247 XL |
1614 | /// Check if the trait bound is implemented for a different mutability and note it in the |
1615 | /// final error. | |
ba9703b0 | 1616 | fn suggest_change_mut( |
dfeec247 XL |
1617 | &self, |
1618 | obligation: &PredicateObligation<'tcx>, | |
5e7ed085 | 1619 | err: &mut Diagnostic, |
5099ac24 | 1620 | trait_pred: ty::PolyTraitPredicate<'tcx>, |
dfeec247 | 1621 | ) { |
c295e0f8 | 1622 | let points_at_arg = matches!( |
a2a8927a | 1623 | obligation.cause.code(), |
c295e0f8 XL |
1624 | ObligationCauseCode::FunctionArgumentObligation { .. }, |
1625 | ); | |
1626 | ||
dfeec247 XL |
1627 | let span = obligation.cause.span; |
1628 | if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { | |
1629 | let refs_number = | |
1630 | snippet.chars().filter(|c| !c.is_whitespace()).take_while(|c| *c == '&').count(); | |
74b04a01 | 1631 | if let Some('\'') = snippet.chars().filter(|c| !c.is_whitespace()).nth(refs_number) { |
dfeec247 XL |
1632 | // Do not suggest removal of borrow from type arguments. |
1633 | return; | |
1634 | } | |
5099ac24 | 1635 | let trait_pred = self.resolve_vars_if_possible(trait_pred); |
2b03887a | 1636 | if trait_pred.has_non_region_infer() { |
dfeec247 XL |
1637 | // Do not ICE while trying to find if a reborrow would succeed on a trait with |
1638 | // unresolved bindings. | |
1639 | return; | |
1640 | } | |
1641 | ||
923072b8 | 1642 | // Skipping binder here, remapping below |
5099ac24 FG |
1643 | if let ty::Ref(region, t_type, mutability) = *trait_pred.skip_binder().self_ty().kind() |
1644 | { | |
f9f354fc | 1645 | let suggested_ty = match mutability { |
dfeec247 XL |
1646 | hir::Mutability::Mut => self.tcx.mk_imm_ref(region, t_type), |
1647 | hir::Mutability::Not => self.tcx.mk_mut_ref(region, t_type), | |
1648 | }; | |
1649 | ||
923072b8 FG |
1650 | // Remapping bound vars here |
1651 | let trait_pred_and_suggested_ty = | |
1652 | trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty)); | |
1653 | ||
f9f354fc | 1654 | let new_obligation = self.mk_trait_obligation_with_new_self_ty( |
dfeec247 | 1655 | obligation.param_env, |
923072b8 | 1656 | trait_pred_and_suggested_ty, |
dfeec247 | 1657 | ); |
f9f354fc XL |
1658 | let suggested_ty_would_satisfy_obligation = self |
1659 | .evaluate_obligation_no_overflow(&new_obligation) | |
1660 | .must_apply_modulo_regions(); | |
1661 | if suggested_ty_would_satisfy_obligation { | |
dfeec247 XL |
1662 | let sp = self |
1663 | .tcx | |
1664 | .sess | |
1665 | .source_map() | |
1666 | .span_take_while(span, |c| c.is_whitespace() || *c == '&'); | |
487cf647 | 1667 | if points_at_arg && mutability.is_not() && refs_number > 0 { |
9c376795 FG |
1668 | // If we have a call like foo(&mut buf), then don't suggest foo(&mut mut buf) |
1669 | if snippet | |
1670 | .trim_start_matches(|c: char| c.is_whitespace() || c == '&') | |
1671 | .starts_with("mut") | |
1672 | { | |
1673 | return; | |
1674 | } | |
ba9703b0 | 1675 | err.span_suggestion_verbose( |
dfeec247 XL |
1676 | sp, |
1677 | "consider changing this borrow's mutability", | |
923072b8 | 1678 | "&mut ", |
dfeec247 XL |
1679 | Applicability::MachineApplicable, |
1680 | ); | |
1681 | } else { | |
1682 | err.note(&format!( | |
1683 | "`{}` is implemented for `{:?}`, but not for `{:?}`", | |
5099ac24 | 1684 | trait_pred.print_modifiers_and_trait_path(), |
f9f354fc | 1685 | suggested_ty, |
5099ac24 | 1686 | trait_pred.skip_binder().self_ty(), |
dfeec247 XL |
1687 | )); |
1688 | } | |
1689 | } | |
1690 | } | |
1691 | } | |
1692 | } | |
1693 | ||
ba9703b0 | 1694 | fn suggest_semicolon_removal( |
dfeec247 XL |
1695 | &self, |
1696 | obligation: &PredicateObligation<'tcx>, | |
5e7ed085 | 1697 | err: &mut Diagnostic, |
dfeec247 | 1698 | span: Span, |
5099ac24 | 1699 | trait_pred: ty::PolyTraitPredicate<'tcx>, |
04454e1e | 1700 | ) -> bool { |
dfeec247 | 1701 | let hir = self.tcx.hir(); |
9ffffee4 | 1702 | let node = hir.find_by_def_id(obligation.cause.body_id); |
5e7ed085 | 1703 | if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. })) = node |
04454e1e | 1704 | && let hir::ExprKind::Block(blk, _) = &hir.body(*body_id).value.kind |
5e7ed085 FG |
1705 | && sig.decl.output.span().overlaps(span) |
1706 | && blk.expr.is_none() | |
04454e1e | 1707 | && trait_pred.self_ty().skip_binder().is_unit() |
5e7ed085 | 1708 | && let Some(stmt) = blk.stmts.last() |
04454e1e FG |
1709 | && let hir::StmtKind::Semi(expr) = stmt.kind |
1710 | // Only suggest this if the expression behind the semicolon implements the predicate | |
2b03887a FG |
1711 | && let Some(typeck_results) = &self.typeck_results |
1712 | && let Some(ty) = typeck_results.expr_ty_opt(expr) | |
923072b8 FG |
1713 | && self.predicate_may_hold(&self.mk_trait_obligation_with_new_self_ty( |
1714 | obligation.param_env, trait_pred.map_bound(|trait_pred| (trait_pred, ty)) | |
1715 | )) | |
dfeec247 | 1716 | { |
04454e1e FG |
1717 | err.span_label( |
1718 | expr.span, | |
1719 | &format!( | |
1720 | "this expression has type `{}`, which implements `{}`", | |
1721 | ty, | |
1722 | trait_pred.print_modifiers_and_trait_path() | |
1723 | ) | |
1724 | ); | |
1725 | err.span_suggestion( | |
1726 | self.tcx.sess.source_map().end_point(stmt.span), | |
1727 | "remove this semicolon", | |
923072b8 | 1728 | "", |
04454e1e FG |
1729 | Applicability::MachineApplicable |
1730 | ); | |
1731 | return true; | |
dfeec247 | 1732 | } |
04454e1e | 1733 | false |
dfeec247 XL |
1734 | } |
1735 | ||
f9f354fc XL |
1736 | fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span> { |
1737 | let hir = self.tcx.hir(); | |
9ffffee4 | 1738 | let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. })) = hir.find_by_def_id(obligation.cause.body_id) else { |
5e7ed085 | 1739 | return None; |
f9f354fc XL |
1740 | }; |
1741 | ||
1742 | if let hir::FnRetTy::Return(ret_ty) = sig.decl.output { Some(ret_ty.span) } else { None } | |
1743 | } | |
1744 | ||
dfeec247 XL |
1745 | /// If all conditions are met to identify a returned `dyn Trait`, suggest using `impl Trait` if |
1746 | /// applicable and signal that the error has been expanded appropriately and needs to be | |
1747 | /// emitted. | |
ba9703b0 | 1748 | fn suggest_impl_trait( |
dfeec247 | 1749 | &self, |
5e7ed085 | 1750 | err: &mut Diagnostic, |
dfeec247 XL |
1751 | span: Span, |
1752 | obligation: &PredicateObligation<'tcx>, | |
5099ac24 | 1753 | trait_pred: ty::PolyTraitPredicate<'tcx>, |
dfeec247 | 1754 | ) -> bool { |
a2a8927a | 1755 | match obligation.cause.code().peel_derives() { |
dfeec247 XL |
1756 | // Only suggest `impl Trait` if the return type is unsized because it is `dyn Trait`. |
1757 | ObligationCauseCode::SizedReturnType => {} | |
1758 | _ => return false, | |
1759 | } | |
1760 | ||
1761 | let hir = self.tcx.hir(); | |
9ffffee4 FG |
1762 | let fn_hir_id = hir.local_def_id_to_hir_id(obligation.cause.body_id); |
1763 | let node = hir.find_by_def_id(obligation.cause.body_id); | |
3c0e092e | 1764 | let Some(hir::Node::Item(hir::Item { |
dfeec247 XL |
1765 | kind: hir::ItemKind::Fn(sig, _, body_id), |
1766 | .. | |
1767 | })) = node | |
3c0e092e | 1768 | else { |
dfeec247 XL |
1769 | return false; |
1770 | }; | |
1771 | let body = hir.body(*body_id); | |
5099ac24 FG |
1772 | let trait_pred = self.resolve_vars_if_possible(trait_pred); |
1773 | let ty = trait_pred.skip_binder().self_ty(); | |
1b1a35ee | 1774 | let is_object_safe = match ty.kind() { |
f2b60f7d | 1775 | ty::Dynamic(predicates, _, ty::Dyn) => { |
dfeec247 XL |
1776 | // If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`. |
1777 | predicates | |
1778 | .principal_def_id() | |
9ffffee4 | 1779 | .map_or(true, |def_id| self.tcx.check_is_object_safe(def_id)) |
dfeec247 XL |
1780 | } |
1781 | // We only want to suggest `impl Trait` to `dyn Trait`s. | |
1782 | // For example, `fn foo() -> str` needs to be filtered out. | |
1783 | _ => return false, | |
1784 | }; | |
1785 | ||
5099ac24 | 1786 | let hir::FnRetTy::Return(ret_ty) = sig.decl.output else { |
dfeec247 XL |
1787 | return false; |
1788 | }; | |
1789 | ||
1790 | // Use `TypeVisitor` instead of the output type directly to find the span of `ty` for | |
1791 | // cases like `fn foo() -> (dyn Trait, i32) {}`. | |
1792 | // Recursively look for `TraitObject` types and if there's only one, use that span to | |
1793 | // suggest `impl Trait`. | |
1794 | ||
1795 | // Visit to make sure there's a single `return` type to suggest `impl Trait`, | |
1796 | // otherwise suggest using `Box<dyn Trait>` or an enum. | |
1797 | let mut visitor = ReturnsVisitor::default(); | |
1798 | visitor.visit_body(&body); | |
1799 | ||
2b03887a | 1800 | let typeck_results = self.typeck_results.as_ref().unwrap(); |
064997fb | 1801 | let Some(liberated_sig) = typeck_results.liberated_fn_sigs().get(fn_hir_id).copied() else { return false; }; |
dfeec247 | 1802 | |
04454e1e | 1803 | let ret_types = visitor |
dfeec247 XL |
1804 | .returns |
1805 | .iter() | |
04454e1e FG |
1806 | .filter_map(|expr| Some((expr.span, typeck_results.node_type_opt(expr.hir_id)?))) |
1807 | .map(|(expr_span, ty)| (expr_span, self.resolve_vars_if_possible(ty))); | |
f9f354fc XL |
1808 | let (last_ty, all_returns_have_same_type, only_never_return) = ret_types.clone().fold( |
1809 | (None, true, true), | |
1810 | |(last_ty, mut same, only_never_return): (std::option::Option<Ty<'_>>, bool, bool), | |
04454e1e | 1811 | (_, ty)| { |
fc512014 | 1812 | let ty = self.resolve_vars_if_possible(ty); |
f9f354fc | 1813 | same &= |
1b1a35ee | 1814 | !matches!(ty.kind(), ty::Error(_)) |
f9f354fc XL |
1815 | && last_ty.map_or(true, |last_ty| { |
1816 | // FIXME: ideally we would use `can_coerce` here instead, but `typeck` comes | |
1817 | // *after* in the dependency graph. | |
1b1a35ee | 1818 | match (ty.kind(), last_ty.kind()) { |
f9f354fc XL |
1819 | (Infer(InferTy::IntVar(_)), Infer(InferTy::IntVar(_))) |
1820 | | (Infer(InferTy::FloatVar(_)), Infer(InferTy::FloatVar(_))) | |
1821 | | (Infer(InferTy::FreshIntTy(_)), Infer(InferTy::FreshIntTy(_))) | |
1822 | | ( | |
1823 | Infer(InferTy::FreshFloatTy(_)), | |
1824 | Infer(InferTy::FreshFloatTy(_)), | |
1825 | ) => true, | |
1826 | _ => ty == last_ty, | |
1827 | } | |
1828 | }); | |
1b1a35ee | 1829 | (Some(ty), same, only_never_return && matches!(ty.kind(), ty::Never)) |
dfeec247 XL |
1830 | }, |
1831 | ); | |
04454e1e FG |
1832 | let mut spans_and_needs_box = vec![]; |
1833 | ||
1834 | match liberated_sig.output().kind() { | |
2b03887a | 1835 | ty::Dynamic(predicates, _, ty::Dyn) => { |
9ffffee4 | 1836 | let cause = ObligationCause::misc(ret_ty.span, obligation.cause.body_id); |
04454e1e FG |
1837 | let param_env = ty::ParamEnv::empty(); |
1838 | ||
1839 | if !only_never_return { | |
1840 | for (expr_span, return_ty) in ret_types { | |
1841 | let self_ty_satisfies_dyn_predicates = |self_ty| { | |
1842 | predicates.iter().all(|predicate| { | |
1843 | let pred = predicate.with_self_ty(self.tcx, self_ty); | |
487cf647 | 1844 | let obl = Obligation::new(self.tcx, cause.clone(), param_env, pred); |
04454e1e | 1845 | self.predicate_may_hold(&obl) |
dfeec247 | 1846 | }) |
04454e1e FG |
1847 | }; |
1848 | ||
1849 | if let ty::Adt(def, substs) = return_ty.kind() | |
1850 | && def.is_box() | |
1851 | && self_ty_satisfies_dyn_predicates(substs.type_at(0)) | |
1852 | { | |
1853 | spans_and_needs_box.push((expr_span, false)); | |
1854 | } else if self_ty_satisfies_dyn_predicates(return_ty) { | |
1855 | spans_and_needs_box.push((expr_span, true)); | |
1856 | } else { | |
1857 | return false; | |
1858 | } | |
dfeec247 | 1859 | } |
dfeec247 | 1860 | } |
04454e1e FG |
1861 | } |
1862 | _ => return false, | |
1863 | }; | |
dfeec247 | 1864 | |
ba9703b0 | 1865 | let sm = self.tcx.sess.source_map(); |
04454e1e | 1866 | if !ret_ty.span.overlaps(span) { |
f9f354fc | 1867 | return false; |
04454e1e FG |
1868 | } |
1869 | let snippet = if let hir::TyKind::TraitObject(..) = ret_ty.kind { | |
1870 | if let Ok(snippet) = sm.span_to_snippet(ret_ty.span) { | |
1871 | snippet | |
1872 | } else { | |
1873 | return false; | |
1874 | } | |
1875 | } else { | |
1876 | // Substitute the type, so we can print a fixup given `type Alias = dyn Trait` | |
1877 | let name = liberated_sig.output().to_string(); | |
1878 | let name = | |
1879 | name.strip_prefix('(').and_then(|name| name.strip_suffix(')')).unwrap_or(&name); | |
1880 | if !name.starts_with("dyn ") { | |
1881 | return false; | |
1882 | } | |
1883 | name.to_owned() | |
f9f354fc | 1884 | }; |
04454e1e | 1885 | |
dfeec247 XL |
1886 | err.code(error_code!(E0746)); |
1887 | err.set_primary_message("return type cannot have an unboxed trait object"); | |
1888 | err.children.clear(); | |
1889 | let impl_trait_msg = "for information on `impl Trait`, see \ | |
1890 | <https://doc.rust-lang.org/book/ch10-02-traits.html\ | |
1891 | #returning-types-that-implement-traits>"; | |
1892 | let trait_obj_msg = "for information on trait objects, see \ | |
1893 | <https://doc.rust-lang.org/book/ch17-02-trait-objects.html\ | |
1894 | #using-trait-objects-that-allow-for-values-of-different-types>"; | |
04454e1e | 1895 | |
dfeec247 | 1896 | let has_dyn = snippet.split_whitespace().next().map_or(false, |s| s == "dyn"); |
a2a8927a | 1897 | let trait_obj = if has_dyn { &snippet[4..] } else { &snippet }; |
f9f354fc XL |
1898 | if only_never_return { |
1899 | // No return paths, probably using `panic!()` or similar. | |
9c376795 | 1900 | // Suggest `-> impl Trait`, and if `Trait` is object safe, `-> Box<dyn Trait>`. |
f9f354fc XL |
1901 | suggest_trait_object_return_type_alternatives( |
1902 | err, | |
1903 | ret_ty.span, | |
1904 | trait_obj, | |
1905 | is_object_safe, | |
1906 | ); | |
1907 | } else if let (Some(last_ty), true) = (last_ty, all_returns_have_same_type) { | |
dfeec247 XL |
1908 | // Suggest `-> impl Trait`. |
1909 | err.span_suggestion( | |
1910 | ret_ty.span, | |
1911 | &format!( | |
f9f354fc XL |
1912 | "use `impl {1}` as the return type, as all return paths are of type `{}`, \ |
1913 | which implements `{1}`", | |
dfeec247 XL |
1914 | last_ty, trait_obj, |
1915 | ), | |
1916 | format!("impl {}", trait_obj), | |
1917 | Applicability::MachineApplicable, | |
1918 | ); | |
1919 | err.note(impl_trait_msg); | |
1920 | } else { | |
1921 | if is_object_safe { | |
1922 | // Suggest `-> Box<dyn Trait>` and `Box::new(returned_value)`. | |
04454e1e FG |
1923 | err.multipart_suggestion( |
1924 | "return a boxed trait object instead", | |
1925 | vec![ | |
1926 | (ret_ty.span.shrink_to_lo(), "Box<".to_string()), | |
1927 | (span.shrink_to_hi(), ">".to_string()), | |
1928 | ], | |
1929 | Applicability::MaybeIncorrect, | |
1930 | ); | |
1931 | for (span, needs_box) in spans_and_needs_box { | |
1932 | if needs_box { | |
1933 | err.multipart_suggestion( | |
1934 | "... and box this value", | |
1935 | vec![ | |
1936 | (span.shrink_to_lo(), "Box::new(".to_string()), | |
1937 | (span.shrink_to_hi(), ")".to_string()), | |
1938 | ], | |
1939 | Applicability::MaybeIncorrect, | |
1940 | ); | |
1941 | } | |
ba9703b0 | 1942 | } |
dfeec247 XL |
1943 | } else { |
1944 | // This is currently not possible to trigger because E0038 takes precedence, but | |
1945 | // leave it in for completeness in case anything changes in an earlier stage. | |
1946 | err.note(&format!( | |
6a06907d | 1947 | "if trait `{}` were object-safe, you could return a trait object", |
dfeec247 XL |
1948 | trait_obj, |
1949 | )); | |
1950 | } | |
1951 | err.note(trait_obj_msg); | |
1952 | err.note(&format!( | |
f9f354fc XL |
1953 | "if all the returned values were of the same type you could use `impl {}` as the \ |
1954 | return type", | |
dfeec247 XL |
1955 | trait_obj, |
1956 | )); | |
1957 | err.note(impl_trait_msg); | |
1958 | err.note("you can create a new `enum` with a variant for each returned type"); | |
1959 | } | |
1960 | true | |
1961 | } | |
1962 | ||
ba9703b0 | 1963 | fn point_at_returns_when_relevant( |
dfeec247 | 1964 | &self, |
9c376795 | 1965 | err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, |
dfeec247 XL |
1966 | obligation: &PredicateObligation<'tcx>, |
1967 | ) { | |
a2a8927a | 1968 | match obligation.cause.code().peel_derives() { |
dfeec247 XL |
1969 | ObligationCauseCode::SizedReturnType => {} |
1970 | _ => return, | |
1971 | } | |
1972 | ||
1973 | let hir = self.tcx.hir(); | |
9ffffee4 | 1974 | let node = hir.find_by_def_id(obligation.cause.body_id); |
dfeec247 XL |
1975 | if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) = |
1976 | node | |
1977 | { | |
1978 | let body = hir.body(*body_id); | |
1979 | // Point at all the `return`s in the function as they have failed trait bounds. | |
1980 | let mut visitor = ReturnsVisitor::default(); | |
1981 | visitor.visit_body(&body); | |
2b03887a | 1982 | let typeck_results = self.typeck_results.as_ref().unwrap(); |
dfeec247 | 1983 | for expr in &visitor.returns { |
3dfed10e | 1984 | if let Some(returned_ty) = typeck_results.node_type_opt(expr.hir_id) { |
fc512014 | 1985 | let ty = self.resolve_vars_if_possible(returned_ty); |
9c376795 FG |
1986 | if ty.references_error() { |
1987 | // don't print out the [type error] here | |
1988 | err.delay_as_bug(); | |
1989 | } else { | |
1990 | err.span_label( | |
1991 | expr.span, | |
1992 | &format!("this returned value is of type `{}`", ty), | |
1993 | ); | |
1994 | } | |
dfeec247 XL |
1995 | } |
1996 | } | |
1997 | } | |
1998 | } | |
1999 | ||
ba9703b0 | 2000 | fn report_closure_arg_mismatch( |
dfeec247 XL |
2001 | &self, |
2002 | span: Span, | |
2003 | found_span: Option<Span>, | |
dfeec247 | 2004 | found: ty::PolyTraitRef<'tcx>, |
064997fb | 2005 | expected: ty::PolyTraitRef<'tcx>, |
2b03887a | 2006 | cause: &ObligationCauseCode<'tcx>, |
9c376795 FG |
2007 | found_node: Option<Node<'_>>, |
2008 | param_env: ty::ParamEnv<'tcx>, | |
5e7ed085 | 2009 | ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { |
064997fb | 2010 | pub(crate) fn build_fn_sig_ty<'tcx>( |
2b03887a | 2011 | infcx: &InferCtxt<'tcx>, |
fc512014 | 2012 | trait_ref: ty::PolyTraitRef<'tcx>, |
064997fb | 2013 | ) -> Ty<'tcx> { |
fc512014 | 2014 | let inputs = trait_ref.skip_binder().substs.type_at(1); |
c295e0f8 | 2015 | let sig = match inputs.kind() { |
487cf647 | 2016 | ty::Tuple(inputs) if infcx.tcx.is_fn_trait(trait_ref.def_id()) => { |
f2b60f7d | 2017 | infcx.tcx.mk_fn_sig( |
9ffffee4 | 2018 | *inputs, |
f2b60f7d FG |
2019 | infcx.next_ty_var(TypeVariableOrigin { |
2020 | span: DUMMY_SP, | |
2021 | kind: TypeVariableOriginKind::MiscVariable, | |
2022 | }), | |
c295e0f8 XL |
2023 | false, |
2024 | hir::Unsafety::Normal, | |
2025 | abi::Abi::Rust, | |
2026 | ) | |
2027 | } | |
f2b60f7d | 2028 | _ => infcx.tcx.mk_fn_sig( |
9ffffee4 | 2029 | [inputs], |
f2b60f7d FG |
2030 | infcx.next_ty_var(TypeVariableOrigin { |
2031 | span: DUMMY_SP, | |
2032 | kind: TypeVariableOriginKind::MiscVariable, | |
2033 | }), | |
dfeec247 XL |
2034 | false, |
2035 | hir::Unsafety::Normal, | |
29967ef6 | 2036 | abi::Abi::Rust, |
c295e0f8 | 2037 | ), |
dfeec247 | 2038 | }; |
064997fb | 2039 | |
f2b60f7d | 2040 | infcx.tcx.mk_fn_ptr(trait_ref.rebind(sig)) |
dfeec247 XL |
2041 | } |
2042 | ||
064997fb | 2043 | let argument_kind = match expected.skip_binder().self_ty().kind() { |
5099ac24 FG |
2044 | ty::Closure(..) => "closure", |
2045 | ty::Generator(..) => "generator", | |
c295e0f8 XL |
2046 | _ => "function", |
2047 | }; | |
dfeec247 XL |
2048 | let mut err = struct_span_err!( |
2049 | self.tcx.sess, | |
2050 | span, | |
2051 | E0631, | |
064997fb | 2052 | "type mismatch in {argument_kind} arguments", |
dfeec247 XL |
2053 | ); |
2054 | ||
064997fb | 2055 | err.span_label(span, "expected due to this"); |
dfeec247 XL |
2056 | |
2057 | let found_span = found_span.unwrap_or(span); | |
064997fb FG |
2058 | err.span_label(found_span, "found signature defined here"); |
2059 | ||
f2b60f7d FG |
2060 | let expected = build_fn_sig_ty(self, expected); |
2061 | let found = build_fn_sig_ty(self, found); | |
064997fb | 2062 | |
f2b60f7d | 2063 | let (expected_str, found_str) = self.cmp(expected, found); |
064997fb FG |
2064 | |
2065 | let signature_kind = format!("{argument_kind} signature"); | |
2066 | err.note_expected_found(&signature_kind, expected_str, &signature_kind, found_str); | |
dfeec247 | 2067 | |
2b03887a FG |
2068 | self.note_conflicting_closure_bounds(cause, &mut err); |
2069 | ||
9c376795 FG |
2070 | if let Some(found_node) = found_node { |
2071 | hint_missing_borrow(self, param_env, span, found, expected, found_node, &mut err); | |
2072 | } | |
2073 | ||
dfeec247 XL |
2074 | err |
2075 | } | |
dfeec247 | 2076 | |
2b03887a FG |
2077 | // Add a note if there are two `Fn`-family bounds that have conflicting argument |
2078 | // requirements, which will always cause a closure to have a type error. | |
2079 | fn note_conflicting_closure_bounds( | |
2080 | &self, | |
2081 | cause: &ObligationCauseCode<'tcx>, | |
2082 | err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, | |
2083 | ) { | |
2084 | // First, look for an `ExprBindingObligation`, which means we can get | |
2085 | // the unsubstituted predicate list of the called function. And check | |
2086 | // that the predicate that we failed to satisfy is a `Fn`-like trait. | |
2087 | if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = cause | |
2088 | && let predicates = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx) | |
2089 | && let Some(pred) = predicates.predicates.get(*idx) | |
487cf647 FG |
2090 | && let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = pred.kind().skip_binder() |
2091 | && self.tcx.is_fn_trait(trait_pred.def_id()) | |
2b03887a FG |
2092 | { |
2093 | let expected_self = | |
9c376795 | 2094 | self.tcx.anonymize_bound_vars(pred.kind().rebind(trait_pred.self_ty())); |
2b03887a FG |
2095 | let expected_substs = self |
2096 | .tcx | |
9c376795 | 2097 | .anonymize_bound_vars(pred.kind().rebind(trait_pred.trait_ref.substs)); |
2b03887a FG |
2098 | |
2099 | // Find another predicate whose self-type is equal to the expected self type, | |
2100 | // but whose substs don't match. | |
9c376795 | 2101 | let other_pred = predicates.into_iter() |
2b03887a FG |
2102 | .enumerate() |
2103 | .find(|(other_idx, (pred, _))| match pred.kind().skip_binder() { | |
487cf647 FG |
2104 | ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) |
2105 | if self.tcx.is_fn_trait(trait_pred.def_id()) | |
2b03887a FG |
2106 | && other_idx != idx |
2107 | // Make sure that the self type matches | |
2108 | // (i.e. constraining this closure) | |
2109 | && expected_self | |
9c376795 | 2110 | == self.tcx.anonymize_bound_vars( |
2b03887a FG |
2111 | pred.kind().rebind(trait_pred.self_ty()), |
2112 | ) | |
2113 | // But the substs don't match (i.e. incompatible args) | |
2114 | && expected_substs | |
9c376795 | 2115 | != self.tcx.anonymize_bound_vars( |
2b03887a FG |
2116 | pred.kind().rebind(trait_pred.trait_ref.substs), |
2117 | ) => | |
2118 | { | |
2119 | true | |
2120 | } | |
2121 | _ => false, | |
2122 | }); | |
2123 | // If we found one, then it's very likely the cause of the error. | |
2124 | if let Some((_, (_, other_pred_span))) = other_pred { | |
2125 | err.span_note( | |
9c376795 | 2126 | other_pred_span, |
2b03887a FG |
2127 | "closure inferred to have a different signature due to this bound", |
2128 | ); | |
2129 | } | |
2130 | } | |
2131 | } | |
2132 | ||
ba9703b0 | 2133 | fn suggest_fully_qualified_path( |
dfeec247 | 2134 | &self, |
5e7ed085 FG |
2135 | err: &mut Diagnostic, |
2136 | item_def_id: DefId, | |
dfeec247 XL |
2137 | span: Span, |
2138 | trait_ref: DefId, | |
2139 | ) { | |
5e7ed085 | 2140 | if let Some(assoc_item) = self.tcx.opt_associated_item(item_def_id) { |
dfeec247 XL |
2141 | if let ty::AssocKind::Const | ty::AssocKind::Type = assoc_item.kind { |
2142 | err.note(&format!( | |
2143 | "{}s cannot be accessed directly on a `trait`, they can only be \ | |
2144 | accessed through a specific `impl`", | |
9ffffee4 | 2145 | self.tcx.def_kind_descr(assoc_item.kind.as_def_kind(), item_def_id) |
dfeec247 XL |
2146 | )); |
2147 | err.span_suggestion( | |
2148 | span, | |
2149 | "use the fully qualified path to an implementation", | |
5099ac24 | 2150 | format!("<Type as {}>::{}", self.tcx.def_path_str(trait_ref), assoc_item.name), |
dfeec247 XL |
2151 | Applicability::HasPlaceholders, |
2152 | ); | |
2153 | } | |
2154 | } | |
2155 | } | |
2156 | ||
2157 | /// Adds an async-await specific note to the diagnostic when the future does not implement | |
2158 | /// an auto trait because of a captured type. | |
2159 | /// | |
ba9703b0 | 2160 | /// ```text |
dfeec247 XL |
2161 | /// note: future does not implement `Qux` as this value is used across an await |
2162 | /// --> $DIR/issue-64130-3-other.rs:17:5 | |
2163 | /// | | |
2164 | /// LL | let x = Foo; | |
2165 | /// | - has type `Foo` | |
2166 | /// LL | baz().await; | |
2167 | /// | ^^^^^^^^^^^ await occurs here, with `x` maybe used later | |
2168 | /// LL | } | |
2169 | /// | - `x` is later dropped here | |
2170 | /// ``` | |
2171 | /// | |
2172 | /// When the diagnostic does not implement `Send` or `Sync` specifically, then the diagnostic | |
2173 | /// is "replaced" with a different message and a more specific error. | |
2174 | /// | |
ba9703b0 | 2175 | /// ```text |
dfeec247 XL |
2176 | /// error: future cannot be sent between threads safely |
2177 | /// --> $DIR/issue-64130-2-send.rs:21:5 | |
2178 | /// | | |
2179 | /// LL | fn is_send<T: Send>(t: T) { } | |
ba9703b0 | 2180 | /// | ---- required by this bound in `is_send` |
dfeec247 XL |
2181 | /// ... |
2182 | /// LL | is_send(bar()); | |
2183 | /// | ^^^^^^^ future returned by `bar` is not send | |
2184 | /// | | |
2185 | /// = help: within `impl std::future::Future`, the trait `std::marker::Send` is not | |
2186 | /// implemented for `Foo` | |
2187 | /// note: future is not send as this value is used across an await | |
2188 | /// --> $DIR/issue-64130-2-send.rs:15:5 | |
2189 | /// | | |
2190 | /// LL | let x = Foo; | |
2191 | /// | - has type `Foo` | |
2192 | /// LL | baz().await; | |
2193 | /// | ^^^^^^^^^^^ await occurs here, with `x` maybe used later | |
2194 | /// LL | } | |
2195 | /// | - `x` is later dropped here | |
2196 | /// ``` | |
2197 | /// | |
2198 | /// Returns `true` if an async-await specific note was added to the diagnostic. | |
923072b8 | 2199 | #[instrument(level = "debug", skip_all, fields(?obligation.predicate, ?obligation.cause.span))] |
ba9703b0 | 2200 | fn maybe_note_obligation_cause_for_async_await( |
dfeec247 | 2201 | &self, |
5e7ed085 | 2202 | err: &mut Diagnostic, |
dfeec247 XL |
2203 | obligation: &PredicateObligation<'tcx>, |
2204 | ) -> bool { | |
ba9703b0 | 2205 | let hir = self.tcx.hir(); |
dfeec247 XL |
2206 | |
2207 | // Attempt to detect an async-await error by looking at the obligation causes, looking | |
2208 | // for a generator to be present. | |
2209 | // | |
2210 | // When a future does not implement a trait because of a captured type in one of the | |
2211 | // generators somewhere in the call stack, then the result is a chain of obligations. | |
2212 | // | |
94222f64 | 2213 | // Given an `async fn` A that calls an `async fn` B which captures a non-send type and that |
dfeec247 XL |
2214 | // future is passed as an argument to a function C which requires a `Send` type, then the |
2215 | // chain looks something like this: | |
2216 | // | |
2217 | // - `BuiltinDerivedObligation` with a generator witness (B) | |
2218 | // - `BuiltinDerivedObligation` with a generator (B) | |
dfeec247 XL |
2219 | // - `BuiltinDerivedObligation` with `impl std::future::Future` (B) |
2220 | // - `BuiltinDerivedObligation` with a generator witness (A) | |
2221 | // - `BuiltinDerivedObligation` with a generator (A) | |
dfeec247 XL |
2222 | // - `BuiltinDerivedObligation` with `impl std::future::Future` (A) |
2223 | // - `BindingObligation` with `impl_send (Send requirement) | |
2224 | // | |
2225 | // The first obligation in the chain is the most useful and has the generator that captured | |
ba9703b0 XL |
2226 | // the type. The last generator (`outer_generator` below) has information about where the |
2227 | // bound was introduced. At least one generator should be present for this diagnostic to be | |
2228 | // modified. | |
5869c6ff | 2229 | let (mut trait_ref, mut target_ty) = match obligation.predicate.kind().skip_binder() { |
487cf647 | 2230 | ty::PredicateKind::Clause(ty::Clause::Trait(p)) => (Some(p), Some(p.self_ty())), |
dfeec247 XL |
2231 | _ => (None, None), |
2232 | }; | |
2233 | let mut generator = None; | |
ba9703b0 | 2234 | let mut outer_generator = None; |
a2a8927a | 2235 | let mut next_code = Some(obligation.cause.code()); |
29967ef6 XL |
2236 | |
2237 | let mut seen_upvar_tys_infer_tuple = false; | |
2238 | ||
dfeec247 | 2239 | while let Some(code) = next_code { |
923072b8 | 2240 | debug!(?code); |
dfeec247 | 2241 | match code { |
3c0e092e | 2242 | ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => { |
923072b8 | 2243 | next_code = Some(parent_code); |
3c0e092e | 2244 | } |
5e7ed085 FG |
2245 | ObligationCauseCode::ImplDerivedObligation(cause) => { |
2246 | let ty = cause.derived.parent_trait_pred.skip_binder().self_ty(); | |
2247 | debug!( | |
923072b8 FG |
2248 | parent_trait_ref = ?cause.derived.parent_trait_pred, |
2249 | self_ty.kind = ?ty.kind(), | |
2250 | "ImplDerived", | |
5e7ed085 FG |
2251 | ); |
2252 | ||
2253 | match *ty.kind() { | |
9ffffee4 | 2254 | ty::Generator(did, ..) | ty::GeneratorWitnessMIR(did, _) => { |
5e7ed085 FG |
2255 | generator = generator.or(Some(did)); |
2256 | outer_generator = Some(did); | |
2257 | } | |
2258 | ty::GeneratorWitness(..) => {} | |
2259 | ty::Tuple(_) if !seen_upvar_tys_infer_tuple => { | |
2260 | // By introducing a tuple of upvar types into the chain of obligations | |
2261 | // of a generator, the first non-generator item is now the tuple itself, | |
2262 | // we shall ignore this. | |
2263 | ||
2264 | seen_upvar_tys_infer_tuple = true; | |
2265 | } | |
2266 | _ if generator.is_none() => { | |
2267 | trait_ref = Some(cause.derived.parent_trait_pred.skip_binder()); | |
2268 | target_ty = Some(ty); | |
2269 | } | |
2270 | _ => {} | |
2271 | } | |
2272 | ||
923072b8 | 2273 | next_code = Some(&cause.derived.parent_code); |
5e7ed085 | 2274 | } |
ba9703b0 | 2275 | ObligationCauseCode::DerivedObligation(derived_obligation) |
5e7ed085 | 2276 | | ObligationCauseCode::BuiltinDerivedObligation(derived_obligation) => { |
5099ac24 | 2277 | let ty = derived_obligation.parent_trait_pred.skip_binder().self_ty(); |
dfeec247 | 2278 | debug!( |
923072b8 FG |
2279 | parent_trait_ref = ?derived_obligation.parent_trait_pred, |
2280 | self_ty.kind = ?ty.kind(), | |
dfeec247 XL |
2281 | ); |
2282 | ||
1b1a35ee | 2283 | match *ty.kind() { |
9ffffee4 | 2284 | ty::Generator(did, ..) | ty::GeneratorWitnessMIR(did, ..) => { |
dfeec247 | 2285 | generator = generator.or(Some(did)); |
ba9703b0 | 2286 | outer_generator = Some(did); |
dfeec247 XL |
2287 | } |
2288 | ty::GeneratorWitness(..) => {} | |
29967ef6 XL |
2289 | ty::Tuple(_) if !seen_upvar_tys_infer_tuple => { |
2290 | // By introducing a tuple of upvar types into the chain of obligations | |
2291 | // of a generator, the first non-generator item is now the tuple itself, | |
2292 | // we shall ignore this. | |
2293 | ||
2294 | seen_upvar_tys_infer_tuple = true; | |
2295 | } | |
dfeec247 | 2296 | _ if generator.is_none() => { |
5099ac24 | 2297 | trait_ref = Some(derived_obligation.parent_trait_pred.skip_binder()); |
dfeec247 XL |
2298 | target_ty = Some(ty); |
2299 | } | |
2300 | _ => {} | |
2301 | } | |
2302 | ||
923072b8 | 2303 | next_code = Some(&derived_obligation.parent_code); |
dfeec247 XL |
2304 | } |
2305 | _ => break, | |
2306 | } | |
2307 | } | |
2308 | ||
2309 | // Only continue if a generator was found. | |
923072b8 | 2310 | debug!(?generator, ?trait_ref, ?target_ty); |
5e7ed085 FG |
2311 | let (Some(generator_did), Some(trait_ref), Some(target_ty)) = (generator, trait_ref, target_ty) else { |
2312 | return false; | |
dfeec247 XL |
2313 | }; |
2314 | ||
2315 | let span = self.tcx.def_span(generator_did); | |
2316 | ||
3c0e092e | 2317 | let generator_did_root = self.tcx.typeck_root_def_id(generator_did); |
dfeec247 | 2318 | debug!( |
923072b8 FG |
2319 | ?generator_did, |
2320 | ?generator_did_root, | |
2b03887a | 2321 | typeck_results.hir_owner = ?self.typeck_results.as_ref().map(|t| t.hir_owner), |
923072b8 | 2322 | ?span, |
dfeec247 | 2323 | ); |
dfeec247 | 2324 | |
f9f354fc XL |
2325 | let generator_body = generator_did |
2326 | .as_local() | |
064997fb | 2327 | .and_then(|def_id| hir.maybe_body_owned_by(def_id)) |
ba9703b0 XL |
2328 | .map(|body_id| hir.body(body_id)); |
2329 | let mut visitor = AwaitsVisitor::default(); | |
2330 | if let Some(body) = generator_body { | |
2331 | visitor.visit_body(body); | |
2332 | } | |
923072b8 | 2333 | debug!(awaits = ?visitor.awaits); |
ba9703b0 | 2334 | |
dfeec247 XL |
2335 | // Look for a type inside the generator interior that matches the target type to get |
2336 | // a span. | |
fc512014 | 2337 | let target_ty_erased = self.tcx.erase_regions(target_ty); |
ba9703b0 XL |
2338 | let ty_matches = |ty| -> bool { |
2339 | // Careful: the regions for types that appear in the | |
2340 | // generator interior are not generally known, so we | |
2341 | // want to erase them when comparing (and anyway, | |
2342 | // `Send` and other bounds are generally unaffected by | |
9c376795 | 2343 | // the choice of region). When erasing regions, we |
ba9703b0 XL |
2344 | // also have to erase late-bound regions. This is |
2345 | // because the types that appear in the generator | |
2346 | // interior generally contain "bound regions" to | |
2347 | // represent regions that are part of the suspended | |
2348 | // generator frame. Bound regions are preserved by | |
2349 | // `erase_regions` and so we must also call | |
2350 | // `erase_late_bound_regions`. | |
fc512014 XL |
2351 | let ty_erased = self.tcx.erase_late_bound_regions(ty); |
2352 | let ty_erased = self.tcx.erase_regions(ty_erased); | |
5099ac24 | 2353 | let eq = ty_erased == target_ty_erased; |
923072b8 | 2354 | debug!(?ty_erased, ?target_ty_erased, ?eq); |
ba9703b0 XL |
2355 | eq |
2356 | }; | |
f9f354fc | 2357 | |
3c0e092e | 2358 | // Get the typeck results from the infcx if the generator is the function we are currently |
9c376795 | 2359 | // type-checking; otherwise, get them by performing a query. This is needed to avoid |
3c0e092e XL |
2360 | // cycles. If we can't use resolved types because the generator comes from another crate, |
2361 | // we still provide a targeted error but without all the relevant spans. | |
487cf647 FG |
2362 | let generator_data = match &self.typeck_results { |
2363 | Some(t) if t.hir_owner.to_def_id() == generator_did_root => GeneratorData::Local(&t), | |
3c0e092e | 2364 | _ if generator_did.is_local() => { |
487cf647 | 2365 | GeneratorData::Local(self.tcx.typeck(generator_did.expect_local())) |
3c0e092e | 2366 | } |
487cf647 FG |
2367 | _ if let Some(generator_diag_data) = self.tcx.generator_diagnostic_data(generator_did) => { |
2368 | GeneratorData::Foreign(generator_diag_data) | |
2369 | } | |
2370 | _ => return false, | |
f9f354fc | 2371 | }; |
04454e1e | 2372 | |
9ffffee4 FG |
2373 | let generator_within_in_progress_typeck = match &self.typeck_results { |
2374 | Some(t) => t.hir_owner.to_def_id() == generator_did_root, | |
2375 | _ => false, | |
2376 | }; | |
2377 | ||
487cf647 | 2378 | let mut interior_or_upvar_span = None; |
f9f354fc | 2379 | |
9ffffee4 | 2380 | let from_awaited_ty = generator_data.get_from_await_ty(self.tcx, visitor, hir, ty_matches); |
487cf647 | 2381 | debug!(?from_awaited_ty); |
f9f354fc | 2382 | |
487cf647 FG |
2383 | // The generator interior types share the same binders |
2384 | if let Some(cause) = | |
2385 | generator_data.get_generator_interior_types().skip_binder().iter().find( | |
2386 | |ty::GeneratorInteriorTypeCause { ty, .. }| { | |
2387 | ty_matches(generator_data.get_generator_interior_types().rebind(*ty)) | |
2388 | }, | |
2389 | ) | |
2390 | { | |
2391 | let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } = cause; | |
04454e1e | 2392 | |
487cf647 FG |
2393 | interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior( |
2394 | *span, | |
2395 | Some((*scope_span, *yield_span, *expr, from_awaited_ty)), | |
2396 | )); | |
9ffffee4 FG |
2397 | |
2398 | if interior_or_upvar_span.is_none() && generator_data.is_foreign() { | |
2399 | interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span, None)); | |
2400 | } | |
2401 | } else if self.tcx.sess.opts.unstable_opts.drop_tracking_mir | |
2402 | // Avoid disclosing internal information to downstream crates. | |
2403 | && generator_did.is_local() | |
2404 | // Try to avoid cycles. | |
2405 | && !generator_within_in_progress_typeck | |
2406 | { | |
2407 | let generator_info = &self.tcx.mir_generator_witnesses(generator_did); | |
2408 | debug!(?generator_info); | |
2409 | ||
2410 | 'find_source: for (variant, source_info) in | |
2411 | generator_info.variant_fields.iter().zip(&generator_info.variant_source_info) | |
2412 | { | |
2413 | debug!(?variant); | |
2414 | for &local in variant { | |
2415 | let decl = &generator_info.field_tys[local]; | |
2416 | debug!(?decl); | |
2417 | if ty_matches(ty::Binder::dummy(decl.ty)) && !decl.ignore_for_traits { | |
2418 | interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior( | |
2419 | decl.source_info.span, | |
2420 | Some((None, source_info.span, None, from_awaited_ty)), | |
2421 | )); | |
2422 | break 'find_source; | |
2423 | } | |
2424 | } | |
2425 | } | |
3c0e092e | 2426 | } |
dfeec247 | 2427 | |
487cf647 FG |
2428 | if interior_or_upvar_span.is_none() { |
2429 | interior_or_upvar_span = | |
2430 | generator_data.try_get_upvar_span(&self, generator_did, ty_matches); | |
2431 | } | |
2432 | ||
2433 | if interior_or_upvar_span.is_none() && generator_data.is_foreign() { | |
2434 | interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(span, None)); | |
2435 | } | |
2436 | ||
2437 | debug!(?interior_or_upvar_span); | |
f9f354fc | 2438 | if let Some(interior_or_upvar_span) = interior_or_upvar_span { |
487cf647 FG |
2439 | let is_async = self.tcx.generator_is_async(generator_did); |
2440 | let typeck_results = match generator_data { | |
04454e1e FG |
2441 | GeneratorData::Local(typeck_results) => Some(typeck_results), |
2442 | GeneratorData::Foreign(_) => None, | |
487cf647 | 2443 | }; |
dfeec247 XL |
2444 | self.note_obligation_cause_for_async_await( |
2445 | err, | |
f9f354fc | 2446 | interior_or_upvar_span, |
04454e1e | 2447 | is_async, |
ba9703b0 | 2448 | outer_generator, |
dfeec247 XL |
2449 | trait_ref, |
2450 | target_ty, | |
3dfed10e | 2451 | typeck_results, |
dfeec247 XL |
2452 | obligation, |
2453 | next_code, | |
2454 | ); | |
2455 | true | |
2456 | } else { | |
2457 | false | |
2458 | } | |
2459 | } | |
2460 | ||
2461 | /// Unconditionally adds the diagnostic note described in | |
2462 | /// `maybe_note_obligation_cause_for_async_await`'s documentation comment. | |
923072b8 | 2463 | #[instrument(level = "debug", skip_all)] |
ba9703b0 | 2464 | fn note_obligation_cause_for_async_await( |
dfeec247 | 2465 | &self, |
5e7ed085 | 2466 | err: &mut Diagnostic, |
f9f354fc | 2467 | interior_or_upvar_span: GeneratorInteriorOrUpvar, |
04454e1e | 2468 | is_async: bool, |
ba9703b0 | 2469 | outer_generator: Option<DefId>, |
5099ac24 | 2470 | trait_pred: ty::TraitPredicate<'tcx>, |
dfeec247 | 2471 | target_ty: Ty<'tcx>, |
3c0e092e | 2472 | typeck_results: Option<&ty::TypeckResults<'tcx>>, |
dfeec247 XL |
2473 | obligation: &PredicateObligation<'tcx>, |
2474 | next_code: Option<&ObligationCauseCode<'tcx>>, | |
2475 | ) { | |
2476 | let source_map = self.tcx.sess.source_map(); | |
2477 | ||
ba9703b0 XL |
2478 | let (await_or_yield, an_await_or_yield) = |
2479 | if is_async { ("await", "an await") } else { ("yield", "a yield") }; | |
2480 | let future_or_generator = if is_async { "future" } else { "generator" }; | |
dfeec247 XL |
2481 | |
2482 | // Special case the primary error message when send or sync is the trait that was | |
2483 | // not implemented. | |
dfeec247 | 2484 | let hir = self.tcx.hir(); |
c295e0f8 | 2485 | let trait_explanation = if let Some(name @ (sym::Send | sym::Sync)) = |
5099ac24 | 2486 | self.tcx.get_diagnostic_name(trait_pred.def_id()) |
c295e0f8 | 2487 | { |
dfeec247 | 2488 | let (trait_name, trait_verb) = |
c295e0f8 | 2489 | if name == sym::Send { ("`Send`", "sent") } else { ("`Sync`", "shared") }; |
dfeec247 XL |
2490 | |
2491 | err.clear_code(); | |
2492 | err.set_primary_message(format!( | |
ba9703b0 XL |
2493 | "{} cannot be {} between threads safely", |
2494 | future_or_generator, trait_verb | |
dfeec247 XL |
2495 | )); |
2496 | ||
2497 | let original_span = err.span.primary_span().unwrap(); | |
2498 | let mut span = MultiSpan::from_span(original_span); | |
2499 | ||
ba9703b0 XL |
2500 | let message = outer_generator |
2501 | .and_then(|generator_did| { | |
2502 | Some(match self.tcx.generator_kind(generator_did).unwrap() { | |
2503 | GeneratorKind::Gen => format!("generator is not {}", trait_name), | |
2504 | GeneratorKind::Async(AsyncGeneratorKind::Fn) => self | |
2505 | .tcx | |
2506 | .parent(generator_did) | |
04454e1e | 2507 | .as_local() |
3dfed10e | 2508 | .map(|parent_did| hir.local_def_id_to_hir_id(parent_did)) |
ba9703b0 XL |
2509 | .and_then(|parent_hir_id| hir.opt_name(parent_hir_id)) |
2510 | .map(|name| { | |
2511 | format!("future returned by `{}` is not {}", name, trait_name) | |
2512 | })?, | |
2513 | GeneratorKind::Async(AsyncGeneratorKind::Block) => { | |
2514 | format!("future created by async block is not {}", trait_name) | |
2515 | } | |
2516 | GeneratorKind::Async(AsyncGeneratorKind::Closure) => { | |
2517 | format!("future created by async closure is not {}", trait_name) | |
2518 | } | |
2519 | }) | |
2520 | }) | |
2521 | .unwrap_or_else(|| format!("{} is not {}", future_or_generator, trait_name)); | |
dfeec247 XL |
2522 | |
2523 | span.push_span_label(original_span, message); | |
2524 | err.set_span(span); | |
2525 | ||
2526 | format!("is not {}", trait_name) | |
2527 | } else { | |
5099ac24 | 2528 | format!("does not implement `{}`", trait_pred.print_modifiers_and_trait_path()) |
dfeec247 XL |
2529 | }; |
2530 | ||
9c376795 FG |
2531 | let mut explain_yield = |
2532 | |interior_span: Span, yield_span: Span, scope_span: Option<Span>| { | |
2533 | let mut span = MultiSpan::from_span(yield_span); | |
2534 | let snippet = match source_map.span_to_snippet(interior_span) { | |
2535 | // #70935: If snippet contains newlines, display "the value" instead | |
2536 | // so that we do not emit complex diagnostics. | |
2537 | Ok(snippet) if !snippet.contains('\n') => format!("`{}`", snippet), | |
2538 | _ => "the value".to_string(), | |
2539 | }; | |
a2a8927a XL |
2540 | // note: future is not `Send` as this value is used across an await |
2541 | // --> $DIR/issue-70935-complex-spans.rs:13:9 | |
2542 | // | | |
2543 | // LL | baz(|| async { | |
2544 | // | ______________- | |
2545 | // | | | |
2546 | // | | | |
2547 | // LL | | foo(tx.clone()); | |
2548 | // LL | | }).await; | |
2549 | // | | - ^^^^^^ await occurs here, with value maybe used later | |
2550 | // | |__________| | |
2551 | // | has type `closure` which is not `Send` | |
2552 | // note: value is later dropped here | |
2553 | // LL | | }).await; | |
2554 | // | | ^ | |
2555 | // | |
2556 | span.push_span_label( | |
2557 | yield_span, | |
2558 | format!("{} occurs here, with {} maybe used later", await_or_yield, snippet), | |
2559 | ); | |
2560 | span.push_span_label( | |
2561 | interior_span, | |
2562 | format!("has type `{}` which {}", target_ty, trait_explanation), | |
2563 | ); | |
a2a8927a XL |
2564 | if let Some(scope_span) = scope_span { |
2565 | let scope_span = source_map.end_point(scope_span); | |
2566 | ||
2567 | let msg = format!("{} is later dropped here", snippet); | |
9c376795 | 2568 | span.push_span_label(scope_span, msg); |
f9f354fc | 2569 | } |
a2a8927a XL |
2570 | err.span_note( |
2571 | span, | |
2572 | &format!( | |
2573 | "{} {} as this value is used across {}", | |
2574 | future_or_generator, trait_explanation, an_await_or_yield | |
2575 | ), | |
2576 | ); | |
9c376795 | 2577 | }; |
f9f354fc | 2578 | match interior_or_upvar_span { |
487cf647 | 2579 | GeneratorInteriorOrUpvar::Interior(interior_span, interior_extra_info) => { |
f9f354fc XL |
2580 | if let Some((scope_span, yield_span, expr, from_awaited_ty)) = interior_extra_info { |
2581 | if let Some(await_span) = from_awaited_ty { | |
2582 | // The type causing this obligation is one being awaited at await_span. | |
2583 | let mut span = MultiSpan::from_span(await_span); | |
2584 | span.push_span_label( | |
2585 | await_span, | |
2586 | format!( | |
2587 | "await occurs here on type `{}`, which {}", | |
2588 | target_ty, trait_explanation | |
2589 | ), | |
2590 | ); | |
2591 | err.span_note( | |
2592 | span, | |
2593 | &format!( | |
2594 | "future {not_trait} as it awaits another future which {not_trait}", | |
2595 | not_trait = trait_explanation | |
2596 | ), | |
2597 | ); | |
2598 | } else { | |
2599 | // Look at the last interior type to get a span for the `.await`. | |
2600 | debug!( | |
923072b8 FG |
2601 | generator_interior_types = ?format_args!( |
2602 | "{:#?}", typeck_results.as_ref().map(|t| &t.generator_interior_types) | |
2603 | ), | |
f9f354fc XL |
2604 | ); |
2605 | explain_yield(interior_span, yield_span, scope_span); | |
2606 | } | |
dfeec247 | 2607 | |
f9f354fc XL |
2608 | if let Some(expr_id) = expr { |
2609 | let expr = hir.expect_expr(expr_id); | |
2610 | debug!("target_ty evaluated from {:?}", expr); | |
2611 | ||
9c376795 | 2612 | let parent = hir.parent_id(expr_id); |
f9f354fc XL |
2613 | if let Some(hir::Node::Expr(e)) = hir.find(parent) { |
2614 | let parent_span = hir.span(parent); | |
2615 | let parent_did = parent.owner.to_def_id(); | |
2616 | // ```rust | |
2617 | // impl T { | |
2618 | // fn foo(&self) -> i32 {} | |
2619 | // } | |
2620 | // T.foo(); | |
2621 | // ^^^^^^^ a temporary `&T` created inside this method call due to `&self` | |
2622 | // ``` | |
2623 | // | |
3c0e092e XL |
2624 | let is_region_borrow = if let Some(typeck_results) = typeck_results { |
2625 | typeck_results | |
2626 | .expr_adjustments(expr) | |
2627 | .iter() | |
2628 | .any(|adj| adj.is_region_borrow()) | |
2629 | } else { | |
2630 | false | |
2631 | }; | |
f9f354fc XL |
2632 | |
2633 | // ```rust | |
2634 | // struct Foo(*const u8); | |
2635 | // bar(Foo(std::ptr::null())).await; | |
2636 | // ^^^^^^^^^^^^^^^^^^^^^ raw-ptr `*T` created inside this struct ctor. | |
2637 | // ``` | |
923072b8 | 2638 | debug!(parent_def_kind = ?self.tcx.def_kind(parent_did)); |
f9f354fc XL |
2639 | let is_raw_borrow_inside_fn_like_call = |
2640 | match self.tcx.def_kind(parent_did) { | |
2641 | DefKind::Fn | DefKind::Ctor(..) => target_ty.is_unsafe_ptr(), | |
2642 | _ => false, | |
2643 | }; | |
3c0e092e XL |
2644 | if let Some(typeck_results) = typeck_results { |
2645 | if (typeck_results.is_method_call(e) && is_region_borrow) | |
2646 | || is_raw_borrow_inside_fn_like_call | |
2647 | { | |
2648 | err.span_help( | |
2649 | parent_span, | |
2650 | "consider moving this into a `let` \ | |
dfeec247 | 2651 | binding to create a shorter lived borrow", |
3c0e092e XL |
2652 | ); |
2653 | } | |
f9f354fc XL |
2654 | } |
2655 | } | |
2656 | } | |
dfeec247 XL |
2657 | } |
2658 | } | |
f9f354fc | 2659 | GeneratorInteriorOrUpvar::Upvar(upvar_span) => { |
9c376795 FG |
2660 | // `Some((ref_ty, is_mut))` if `target_ty` is `&T` or `&mut T` and fails to impl `Send` |
2661 | let non_send = match target_ty.kind() { | |
2662 | ty::Ref(_, ref_ty, mutability) => match self.evaluate_obligation(&obligation) { | |
2663 | Ok(eval) if !eval.may_apply() => Some((ref_ty, mutability.is_mut())), | |
136023e0 XL |
2664 | _ => None, |
2665 | }, | |
2666 | _ => None, | |
2667 | }; | |
2668 | ||
9c376795 FG |
2669 | let (span_label, span_note) = match non_send { |
2670 | // if `target_ty` is `&T` or `&mut T` and fails to impl `Send`, | |
2671 | // include suggestions to make `T: Sync` so that `&T: Send`, | |
2672 | // or to make `T: Send` so that `&mut T: Send` | |
2673 | Some((ref_ty, is_mut)) => { | |
2674 | let ref_ty_trait = if is_mut { "Send" } else { "Sync" }; | |
2675 | let ref_kind = if is_mut { "&mut" } else { "&" }; | |
2676 | ( | |
2677 | format!( | |
2678 | "has type `{}` which {}, because `{}` is not `{}`", | |
2679 | target_ty, trait_explanation, ref_ty, ref_ty_trait | |
2680 | ), | |
2681 | format!( | |
2682 | "captured value {} because `{}` references cannot be sent unless their referent is `{}`", | |
2683 | trait_explanation, ref_kind, ref_ty_trait | |
2684 | ), | |
2685 | ) | |
2686 | } | |
136023e0 XL |
2687 | None => ( |
2688 | format!("has type `{}` which {}", target_ty, trait_explanation), | |
2689 | format!("captured value {}", trait_explanation), | |
2690 | ), | |
2691 | }; | |
2692 | ||
f9f354fc | 2693 | let mut span = MultiSpan::from_span(upvar_span); |
136023e0 XL |
2694 | span.push_span_label(upvar_span, span_label); |
2695 | err.span_note(span, &span_note); | |
f9f354fc | 2696 | } |
dfeec247 XL |
2697 | } |
2698 | ||
2699 | // Add a note for the item obligation that remains - normally a note pointing to the | |
2700 | // bound that introduced the obligation (e.g. `T: Send`). | |
923072b8 | 2701 | debug!(?next_code); |
dfeec247 XL |
2702 | self.note_obligation_cause_code( |
2703 | err, | |
9c376795 | 2704 | obligation.predicate, |
5099ac24 | 2705 | obligation.param_env, |
dfeec247 XL |
2706 | next_code.unwrap(), |
2707 | &mut Vec::new(), | |
fc512014 | 2708 | &mut Default::default(), |
dfeec247 XL |
2709 | ); |
2710 | } | |
2711 | ||
ba9703b0 | 2712 | fn note_obligation_cause_code<T>( |
dfeec247 | 2713 | &self, |
5e7ed085 | 2714 | err: &mut Diagnostic, |
9c376795 | 2715 | predicate: T, |
5099ac24 | 2716 | param_env: ty::ParamEnv<'tcx>, |
dfeec247 | 2717 | cause_code: &ObligationCauseCode<'tcx>, |
5099ac24 | 2718 | obligated_types: &mut Vec<Ty<'tcx>>, |
fc512014 | 2719 | seen_requirements: &mut FxHashSet<DefId>, |
dfeec247 | 2720 | ) where |
9c376795 | 2721 | T: ToPredicate<'tcx>, |
dfeec247 XL |
2722 | { |
2723 | let tcx = self.tcx; | |
9c376795 | 2724 | let predicate = predicate.to_predicate(tcx); |
dfeec247 XL |
2725 | match *cause_code { |
2726 | ObligationCauseCode::ExprAssignable | |
2727 | | ObligationCauseCode::MatchExpressionArm { .. } | |
2728 | | ObligationCauseCode::Pattern { .. } | |
2729 | | ObligationCauseCode::IfExpression { .. } | |
2730 | | ObligationCauseCode::IfExpressionWithNoElse | |
2731 | | ObligationCauseCode::MainFunctionType | |
2732 | | ObligationCauseCode::StartFunctionType | |
2733 | | ObligationCauseCode::IntrinsicType | |
2734 | | ObligationCauseCode::MethodReceiver | |
2735 | | ObligationCauseCode::ReturnNoExpression | |
3dfed10e | 2736 | | ObligationCauseCode::UnifyReceiver(..) |
cdc7bbd5 | 2737 | | ObligationCauseCode::OpaqueType |
136023e0 XL |
2738 | | ObligationCauseCode::MiscObligation |
2739 | | ObligationCauseCode::WellFormed(..) | |
94222f64 XL |
2740 | | ObligationCauseCode::MatchImpl(..) |
2741 | | ObligationCauseCode::ReturnType | |
2742 | | ObligationCauseCode::ReturnValue(_) | |
2743 | | ObligationCauseCode::BlockTailExpression(_) | |
a2a8927a XL |
2744 | | ObligationCauseCode::AwaitableExpr(_) |
2745 | | ObligationCauseCode::ForLoopIterator | |
2746 | | ObligationCauseCode::QuestionMark | |
5e7ed085 | 2747 | | ObligationCauseCode::CheckAssociatedTypeBounds { .. } |
5099ac24 | 2748 | | ObligationCauseCode::LetElse |
f2b60f7d | 2749 | | ObligationCauseCode::BinOp { .. } |
487cf647 FG |
2750 | | ObligationCauseCode::AscribeUserTypeProvePredicate(..) |
2751 | | ObligationCauseCode::RustCall => {} | |
dfeec247 XL |
2752 | ObligationCauseCode::SliceOrArrayElem => { |
2753 | err.note("slice and array elements must have `Sized` type"); | |
2754 | } | |
2755 | ObligationCauseCode::TupleElem => { | |
2756 | err.note("only the last element of a tuple may have a dynamically sized type"); | |
2757 | } | |
2758 | ObligationCauseCode::ProjectionWf(data) => { | |
9c376795 | 2759 | err.note(&format!("required so that the projection `{data}` is well-formed")); |
dfeec247 XL |
2760 | } |
2761 | ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => { | |
2762 | err.note(&format!( | |
9c376795 | 2763 | "required so that reference `{ref_ty}` does not outlive its referent" |
dfeec247 XL |
2764 | )); |
2765 | } | |
2766 | ObligationCauseCode::ObjectTypeBound(object_ty, region) => { | |
2767 | err.note(&format!( | |
2768 | "required so that the lifetime bound of `{}` for `{}` is satisfied", | |
2769 | region, object_ty, | |
2770 | )); | |
2771 | } | |
f2b60f7d FG |
2772 | ObligationCauseCode::ItemObligation(_) |
2773 | | ObligationCauseCode::ExprItemObligation(..) => { | |
3c0e092e XL |
2774 | // We hold the `DefId` of the item introducing the obligation, but displaying it |
2775 | // doesn't add user usable information. It always point at an associated item. | |
dfeec247 | 2776 | } |
f2b60f7d FG |
2777 | ObligationCauseCode::BindingObligation(item_def_id, span) |
2778 | | ObligationCauseCode::ExprBindingObligation(item_def_id, span, ..) => { | |
dfeec247 | 2779 | let item_name = tcx.def_path_str(item_def_id); |
9c376795 | 2780 | let short_item_name = with_forced_trimmed_paths!(tcx.def_path_str(item_def_id)); |
94222f64 | 2781 | let mut multispan = MultiSpan::from(span); |
9c376795 | 2782 | let sm = tcx.sess.source_map(); |
04454e1e | 2783 | if let Some(ident) = tcx.opt_item_ident(item_def_id) { |
ba9703b0 XL |
2784 | let same_line = |
2785 | match (sm.lookup_line(ident.span.hi()), sm.lookup_line(span.lo())) { | |
2786 | (Ok(l), Ok(r)) => l.line == r.line, | |
2787 | _ => true, | |
2788 | }; | |
9c376795 | 2789 | if ident.span.is_visible(sm) && !ident.span.overlaps(span) && !same_line { |
9ffffee4 FG |
2790 | multispan.push_span_label( |
2791 | ident.span, | |
2792 | format!( | |
2793 | "required by a bound in this {}", | |
2794 | tcx.def_kind(item_def_id).descr(item_def_id) | |
2795 | ), | |
2796 | ); | |
ba9703b0 | 2797 | } |
dfeec247 | 2798 | } |
9c376795 FG |
2799 | let descr = format!("required by a bound in `{item_name}`"); |
2800 | if span.is_visible(sm) { | |
2801 | let msg = format!("required by this bound in `{short_item_name}`"); | |
94222f64 XL |
2802 | multispan.push_span_label(span, msg); |
2803 | err.span_note(multispan, &descr); | |
dfeec247 | 2804 | } else { |
94222f64 | 2805 | err.span_note(tcx.def_span(item_def_id), &descr); |
dfeec247 XL |
2806 | } |
2807 | } | |
064997fb | 2808 | ObligationCauseCode::ObjectCastObligation(concrete_ty, object_ty) => { |
9c376795 FG |
2809 | let (concrete_ty, concrete_file) = |
2810 | self.tcx.short_ty_string(self.resolve_vars_if_possible(concrete_ty)); | |
2811 | let (object_ty, object_file) = | |
2812 | self.tcx.short_ty_string(self.resolve_vars_if_possible(object_ty)); | |
2813 | err.note(&with_forced_trimmed_paths!(format!( | |
2814 | "required for the cast from `{concrete_ty}` to the object type `{object_ty}`", | |
2815 | ))); | |
2816 | if let Some(file) = concrete_file { | |
2817 | err.note(&format!( | |
2818 | "the full name for the casted type has been written to '{}'", | |
2819 | file.display(), | |
2820 | )); | |
2821 | } | |
2822 | if let Some(file) = object_file { | |
2823 | err.note(&format!( | |
2824 | "the full name for the object type has been written to '{}'", | |
2825 | file.display(), | |
2826 | )); | |
2827 | } | |
dfeec247 XL |
2828 | } |
2829 | ObligationCauseCode::Coercion { source: _, target } => { | |
2830 | err.note(&format!("required by cast to type `{}`", self.ty_to_string(target))); | |
2831 | } | |
5e7ed085 | 2832 | ObligationCauseCode::RepeatElementCopy { is_const_fn } => { |
dfeec247 | 2833 | err.note( |
04454e1e | 2834 | "the `Copy` trait is required because this value will be copied for each element of the array", |
dfeec247 | 2835 | ); |
6a06907d XL |
2836 | |
2837 | if is_const_fn { | |
2838 | err.help( | |
2839 | "consider creating a new `const` item and initializing it with the result \ | |
2840 | of the function call to be used in the repeat position, like \ | |
2841 | `const VAL: Type = const_fn();` and `let x = [VAL; 42];`", | |
2842 | ); | |
2843 | } | |
2844 | ||
2845 | if self.tcx.sess.is_nightly_build() && is_const_fn { | |
2846 | err.help( | |
136023e0 XL |
2847 | "create an inline `const` block, see RFC #2920 \ |
2848 | <https://github.com/rust-lang/rfcs/pull/2920> for more information", | |
6a06907d XL |
2849 | ); |
2850 | } | |
dfeec247 | 2851 | } |
3dfed10e | 2852 | ObligationCauseCode::VariableType(hir_id) => { |
9c376795 | 2853 | let parent_node = self.tcx.hir().parent_id(hir_id); |
3dfed10e | 2854 | match self.tcx.hir().find(parent_node) { |
9c376795 FG |
2855 | Some(Node::Local(hir::Local { ty: Some(ty), .. })) => { |
2856 | err.span_suggestion_verbose( | |
2857 | ty.span.shrink_to_lo(), | |
2858 | "consider borrowing here", | |
2859 | "&", | |
2860 | Applicability::MachineApplicable, | |
2861 | ); | |
2862 | err.note("all local variables must have a statically known size"); | |
2863 | } | |
3dfed10e XL |
2864 | Some(Node::Local(hir::Local { |
2865 | init: Some(hir::Expr { kind: hir::ExprKind::Index(_, _), span, .. }), | |
2866 | .. | |
2867 | })) => { | |
2868 | // When encountering an assignment of an unsized trait, like | |
2869 | // `let x = ""[..];`, provide a suggestion to borrow the initializer in | |
2870 | // order to use have a slice instead. | |
2871 | err.span_suggestion_verbose( | |
2872 | span.shrink_to_lo(), | |
2873 | "consider borrowing here", | |
923072b8 | 2874 | "&", |
3dfed10e XL |
2875 | Applicability::MachineApplicable, |
2876 | ); | |
2877 | err.note("all local variables must have a statically known size"); | |
2878 | } | |
2879 | Some(Node::Param(param)) => { | |
2880 | err.span_suggestion_verbose( | |
2881 | param.ty_span.shrink_to_lo(), | |
2882 | "function arguments must have a statically known size, borrowed types \ | |
2883 | always have a known size", | |
923072b8 | 2884 | "&", |
3dfed10e XL |
2885 | Applicability::MachineApplicable, |
2886 | ); | |
2887 | } | |
2888 | _ => { | |
2889 | err.note("all local variables must have a statically known size"); | |
2890 | } | |
2891 | } | |
dfeec247 XL |
2892 | if !self.tcx.features().unsized_locals { |
2893 | err.help("unsized locals are gated as an unstable feature"); | |
2894 | } | |
2895 | } | |
3dfed10e XL |
2896 | ObligationCauseCode::SizedArgumentType(sp) => { |
2897 | if let Some(span) = sp { | |
9c376795 FG |
2898 | if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() |
2899 | && let ty::Clause::Trait(trait_pred) = clause | |
2900 | && let ty::Dynamic(..) = trait_pred.self_ty().kind() | |
2901 | { | |
2902 | let span = if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) | |
2903 | && snippet.starts_with("dyn ") | |
2904 | { | |
2905 | let pos = snippet.len() - snippet[3..].trim_start().len(); | |
2906 | span.with_hi(span.lo() + BytePos(pos as u32)) | |
2907 | } else { | |
2908 | span.shrink_to_lo() | |
2909 | }; | |
2910 | err.span_suggestion_verbose( | |
2911 | span, | |
2912 | "you can use `impl Trait` as the argument type", | |
2913 | "impl ".to_string(), | |
2914 | Applicability::MaybeIncorrect, | |
2915 | ); | |
2916 | } | |
3dfed10e XL |
2917 | err.span_suggestion_verbose( |
2918 | span.shrink_to_lo(), | |
2919 | "function arguments must have a statically known size, borrowed types \ | |
2920 | always have a known size", | |
923072b8 | 2921 | "&", |
3dfed10e XL |
2922 | Applicability::MachineApplicable, |
2923 | ); | |
2924 | } else { | |
2925 | err.note("all function arguments must have a statically known size"); | |
2926 | } | |
2927 | if tcx.sess.opts.unstable_features.is_nightly_build() | |
29967ef6 | 2928 | && !self.tcx.features().unsized_fn_params |
3dfed10e | 2929 | { |
29967ef6 | 2930 | err.help("unsized fn params are gated as an unstable feature"); |
dfeec247 XL |
2931 | } |
2932 | } | |
2933 | ObligationCauseCode::SizedReturnType => { | |
2934 | err.note("the return type of a function must have a statically known size"); | |
2935 | } | |
2936 | ObligationCauseCode::SizedYieldType => { | |
2937 | err.note("the yield type of a generator must have a statically known size"); | |
2938 | } | |
94222f64 XL |
2939 | ObligationCauseCode::SizedBoxType => { |
2940 | err.note("the type of a box expression must have a statically known size"); | |
2941 | } | |
dfeec247 XL |
2942 | ObligationCauseCode::AssignmentLhsSized => { |
2943 | err.note("the left-hand-side of an assignment must have a statically known size"); | |
2944 | } | |
2945 | ObligationCauseCode::TupleInitializerSized => { | |
2946 | err.note("tuples must have a statically known size to be initialized"); | |
2947 | } | |
2948 | ObligationCauseCode::StructInitializerSized => { | |
2949 | err.note("structs must have a statically known size to be initialized"); | |
2950 | } | |
3dfed10e XL |
2951 | ObligationCauseCode::FieldSized { adt_kind: ref item, last, span } => { |
2952 | match *item { | |
2953 | AdtKind::Struct => { | |
2954 | if last { | |
2955 | err.note( | |
2956 | "the last field of a packed struct may only have a \ | |
2957 | dynamically sized type if it does not need drop to be run", | |
2958 | ); | |
2959 | } else { | |
2960 | err.note( | |
2961 | "only the last field of a struct may have a dynamically sized type", | |
2962 | ); | |
2963 | } | |
2964 | } | |
2965 | AdtKind::Union => { | |
2966 | err.note("no field of a union may have a dynamically sized type"); | |
2967 | } | |
2968 | AdtKind::Enum => { | |
2969 | err.note("no field of an enum variant may have a dynamically sized type"); | |
dfeec247 XL |
2970 | } |
2971 | } | |
3dfed10e XL |
2972 | err.help("change the field's type to have a statically known size"); |
2973 | err.span_suggestion( | |
2974 | span.shrink_to_lo(), | |
2975 | "borrowed types always have a statically known size", | |
923072b8 | 2976 | "&", |
3dfed10e XL |
2977 | Applicability::MachineApplicable, |
2978 | ); | |
2979 | err.multipart_suggestion( | |
2980 | "the `Box` type always has a statically known size and allocates its contents \ | |
2981 | in the heap", | |
2982 | vec![ | |
2983 | (span.shrink_to_lo(), "Box<".to_string()), | |
2984 | (span.shrink_to_hi(), ">".to_string()), | |
2985 | ], | |
2986 | Applicability::MachineApplicable, | |
2987 | ); | |
2988 | } | |
dfeec247 XL |
2989 | ObligationCauseCode::ConstSized => { |
2990 | err.note("constant expressions must have a statically known size"); | |
2991 | } | |
f9f354fc XL |
2992 | ObligationCauseCode::InlineAsmSized => { |
2993 | err.note("all inline asm arguments must have a statically known size"); | |
2994 | } | |
dfeec247 XL |
2995 | ObligationCauseCode::ConstPatternStructural => { |
2996 | err.note("constants used for pattern-matching must derive `PartialEq` and `Eq`"); | |
2997 | } | |
2998 | ObligationCauseCode::SharedStatic => { | |
2999 | err.note("shared static variables must have a type that implements `Sync`"); | |
3000 | } | |
3001 | ObligationCauseCode::BuiltinDerivedObligation(ref data) => { | |
5099ac24 | 3002 | let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); |
dfeec247 | 3003 | let ty = parent_trait_ref.skip_binder().self_ty(); |
29967ef6 | 3004 | if parent_trait_ref.references_error() { |
5e7ed085 FG |
3005 | // NOTE(eddyb) this was `.cancel()`, but `err` |
3006 | // is borrowed, so we can't fully defuse it. | |
3007 | err.downgrade_to_delayed_bug(); | |
29967ef6 XL |
3008 | return; |
3009 | } | |
3010 | ||
3011 | // If the obligation for a tuple is set directly by a Generator or Closure, | |
3012 | // then the tuple must be the one containing capture types. | |
3013 | let is_upvar_tys_infer_tuple = if !matches!(ty.kind(), ty::Tuple(..)) { | |
3014 | false | |
3015 | } else { | |
923072b8 | 3016 | if let ObligationCauseCode::BuiltinDerivedObligation(data) = &*data.parent_code |
29967ef6 | 3017 | { |
5099ac24 FG |
3018 | let parent_trait_ref = |
3019 | self.resolve_vars_if_possible(data.parent_trait_pred); | |
923072b8 FG |
3020 | let nested_ty = parent_trait_ref.skip_binder().self_ty(); |
3021 | matches!(nested_ty.kind(), ty::Generator(..)) | |
3022 | || matches!(nested_ty.kind(), ty::Closure(..)) | |
29967ef6 XL |
3023 | } else { |
3024 | false | |
3025 | } | |
3026 | }; | |
3027 | ||
487cf647 | 3028 | let identity_future = tcx.require_lang_item(LangItem::IdentityFuture, None); |
923072b8 | 3029 | |
29967ef6 | 3030 | // Don't print the tuple of capture types |
923072b8 FG |
3031 | 'print: { |
3032 | if !is_upvar_tys_infer_tuple { | |
9c376795 FG |
3033 | let msg = with_forced_trimmed_paths!(format!( |
3034 | "required because it appears within the type `{ty}`", | |
3035 | )); | |
923072b8 | 3036 | match ty.kind() { |
487cf647 FG |
3037 | ty::Adt(def, _) => match self.tcx.opt_item_ident(def.did()) { |
3038 | Some(ident) => err.span_note(ident.span, &msg), | |
3039 | None => err.note(&msg), | |
3040 | }, | |
9c376795 | 3041 | ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { |
487cf647 FG |
3042 | // Avoid printing the future from `core::future::identity_future`, it's not helpful |
3043 | if tcx.parent(*def_id) == identity_future { | |
923072b8 FG |
3044 | break 'print; |
3045 | } | |
3046 | ||
487cf647 | 3047 | // If the previous type is `identity_future`, this is the future generated by the body of an async function. |
923072b8 FG |
3048 | // Avoid printing it twice (it was already printed in the `ty::Generator` arm below). |
3049 | let is_future = tcx.ty_is_opaque_future(ty); | |
3050 | debug!( | |
3051 | ?obligated_types, | |
3052 | ?is_future, | |
3053 | "note_obligation_cause_code: check for async fn" | |
3054 | ); | |
3055 | if is_future | |
3056 | && obligated_types.last().map_or(false, |ty| match ty.kind() { | |
487cf647 FG |
3057 | ty::Generator(last_def_id, ..) => { |
3058 | tcx.generator_is_async(*last_def_id) | |
923072b8 FG |
3059 | } |
3060 | _ => false, | |
3061 | }) | |
3062 | { | |
3063 | break 'print; | |
3064 | } | |
3065 | err.span_note(self.tcx.def_span(def_id), &msg) | |
3066 | } | |
3067 | ty::GeneratorWitness(bound_tys) => { | |
3068 | use std::fmt::Write; | |
3069 | ||
3070 | // FIXME: this is kind of an unusual format for rustc, can we make it more clear? | |
3071 | // Maybe we should just remove this note altogether? | |
3072 | // FIXME: only print types which don't meet the trait requirement | |
3073 | let mut msg = | |
3074 | "required because it captures the following types: ".to_owned(); | |
3075 | for ty in bound_tys.skip_binder() { | |
9c376795 | 3076 | with_forced_trimmed_paths!(write!(msg, "`{}`, ", ty).unwrap()); |
923072b8 FG |
3077 | } |
3078 | err.note(msg.trim_end_matches(", ")) | |
3079 | } | |
9ffffee4 FG |
3080 | ty::GeneratorWitnessMIR(def_id, substs) => { |
3081 | use std::fmt::Write; | |
3082 | ||
3083 | // FIXME: this is kind of an unusual format for rustc, can we make it more clear? | |
3084 | // Maybe we should just remove this note altogether? | |
3085 | // FIXME: only print types which don't meet the trait requirement | |
3086 | let mut msg = | |
3087 | "required because it captures the following types: ".to_owned(); | |
3088 | for bty in tcx.generator_hidden_types(*def_id) { | |
3089 | let ty = bty.subst(tcx, substs); | |
3090 | write!(msg, "`{}`, ", ty).unwrap(); | |
3091 | } | |
3092 | err.note(msg.trim_end_matches(", ")) | |
3093 | } | |
923072b8 FG |
3094 | ty::Generator(def_id, _, _) => { |
3095 | let sp = self.tcx.def_span(def_id); | |
3096 | ||
3097 | // Special-case this to say "async block" instead of `[static generator]`. | |
487cf647 | 3098 | let kind = tcx.generator_kind(def_id).unwrap().descr(); |
923072b8 FG |
3099 | err.span_note( |
3100 | sp, | |
9c376795 FG |
3101 | with_forced_trimmed_paths!(&format!( |
3102 | "required because it's used within this {kind}", | |
3103 | )), | |
923072b8 FG |
3104 | ) |
3105 | } | |
3106 | ty::Closure(def_id, _) => err.span_note( | |
3107 | self.tcx.def_span(def_id), | |
9c376795 | 3108 | "required because it's used within this closure", |
923072b8 | 3109 | ), |
9ffffee4 | 3110 | ty::Str => err.note("`str` is considered to contain a `[u8]` slice for auto trait purposes"), |
923072b8 FG |
3111 | _ => err.note(&msg), |
3112 | }; | |
3113 | } | |
29967ef6 XL |
3114 | } |
3115 | ||
dfeec247 XL |
3116 | obligated_types.push(ty); |
3117 | ||
487cf647 | 3118 | let parent_predicate = parent_trait_ref; |
dfeec247 | 3119 | if !self.is_recursive_obligation(obligated_types, &data.parent_code) { |
3dfed10e XL |
3120 | // #74711: avoid a stack overflow |
3121 | ensure_sufficient_stack(|| { | |
3122 | self.note_obligation_cause_code( | |
3123 | err, | |
9c376795 | 3124 | parent_predicate, |
5099ac24 | 3125 | param_env, |
3dfed10e XL |
3126 | &data.parent_code, |
3127 | obligated_types, | |
fc512014 | 3128 | seen_requirements, |
3dfed10e XL |
3129 | ) |
3130 | }); | |
a2a8927a XL |
3131 | } else { |
3132 | ensure_sufficient_stack(|| { | |
3133 | self.note_obligation_cause_code( | |
3134 | err, | |
9c376795 | 3135 | parent_predicate, |
5099ac24 | 3136 | param_env, |
923072b8 | 3137 | cause_code.peel_derives(), |
a2a8927a XL |
3138 | obligated_types, |
3139 | seen_requirements, | |
3140 | ) | |
3141 | }); | |
dfeec247 XL |
3142 | } |
3143 | } | |
3144 | ObligationCauseCode::ImplDerivedObligation(ref data) => { | |
5e7ed085 FG |
3145 | let mut parent_trait_pred = |
3146 | self.resolve_vars_if_possible(data.derived.parent_trait_pred); | |
5099ac24 FG |
3147 | parent_trait_pred.remap_constness_diag(param_env); |
3148 | let parent_def_id = parent_trait_pred.def_id(); | |
487cf647 FG |
3149 | let (self_ty, file) = |
3150 | self.tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty()); | |
cdc7bbd5 | 3151 | let msg = format!( |
487cf647 | 3152 | "required for `{self_ty}` to implement `{}`", |
f2b60f7d | 3153 | parent_trait_pred.print_modifiers_and_trait_path() |
cdc7bbd5 | 3154 | ); |
5e7ed085 | 3155 | let mut is_auto_trait = false; |
9ffffee4 | 3156 | match self.tcx.hir().get_if_local(data.impl_or_alias_def_id) { |
5e7ed085 FG |
3157 | Some(Node::Item(hir::Item { |
3158 | kind: hir::ItemKind::Trait(is_auto, ..), | |
3159 | ident, | |
3160 | .. | |
3161 | })) => { | |
3162 | // FIXME: we should do something else so that it works even on crate foreign | |
3163 | // auto traits. | |
3164 | is_auto_trait = matches!(is_auto, hir::IsAuto::Yes); | |
9c376795 | 3165 | err.span_note(ident.span, &msg); |
5e7ed085 FG |
3166 | } |
3167 | Some(Node::Item(hir::Item { | |
3168 | kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }), | |
3169 | .. | |
3170 | })) => { | |
3171 | let mut spans = Vec::with_capacity(2); | |
3172 | if let Some(trait_ref) = of_trait { | |
3173 | spans.push(trait_ref.path.span); | |
cdc7bbd5 | 3174 | } |
5e7ed085 | 3175 | spans.push(self_ty.span); |
9c376795 FG |
3176 | let mut spans: MultiSpan = spans.into(); |
3177 | if matches!( | |
3178 | self_ty.span.ctxt().outer_expn_data().kind, | |
3179 | ExpnKind::Macro(MacroKind::Derive, _) | |
3180 | ) || matches!( | |
3181 | of_trait.as_ref().map(|t| t.path.span.ctxt().outer_expn_data().kind), | |
3182 | Some(ExpnKind::Macro(MacroKind::Derive, _)) | |
3183 | ) { | |
3184 | spans.push_span_label( | |
3185 | data.span, | |
3186 | "unsatisfied trait bound introduced in this `derive` macro", | |
3187 | ); | |
3188 | } else if !data.span.is_dummy() && !data.span.overlaps(self_ty.span) { | |
3189 | spans.push_span_label( | |
3190 | data.span, | |
3191 | "unsatisfied trait bound introduced here", | |
3192 | ); | |
3193 | } | |
3194 | err.span_note(spans, &msg); | |
3195 | } | |
3196 | _ => { | |
3197 | err.note(&msg); | |
5e7ed085 | 3198 | } |
cdc7bbd5 | 3199 | }; |
fc512014 | 3200 | |
487cf647 FG |
3201 | if let Some(file) = file { |
3202 | err.note(&format!( | |
3203 | "the full type name has been written to '{}'", | |
3204 | file.display(), | |
3205 | )); | |
3206 | } | |
3207 | let mut parent_predicate = parent_trait_pred; | |
5e7ed085 | 3208 | let mut data = &data.derived; |
fc512014 XL |
3209 | let mut count = 0; |
3210 | seen_requirements.insert(parent_def_id); | |
5e7ed085 FG |
3211 | if is_auto_trait { |
3212 | // We don't want to point at the ADT saying "required because it appears within | |
3213 | // the type `X`", like we would otherwise do in test `supertrait-auto-trait.rs`. | |
3214 | while let ObligationCauseCode::BuiltinDerivedObligation(derived) = | |
3215 | &*data.parent_code | |
3216 | { | |
3217 | let child_trait_ref = | |
3218 | self.resolve_vars_if_possible(derived.parent_trait_pred); | |
3219 | let child_def_id = child_trait_ref.def_id(); | |
3220 | if seen_requirements.insert(child_def_id) { | |
3221 | break; | |
3222 | } | |
3223 | data = derived; | |
3224 | parent_predicate = child_trait_ref.to_predicate(tcx); | |
3225 | parent_trait_pred = child_trait_ref; | |
3226 | } | |
3227 | } | |
fc512014 XL |
3228 | while let ObligationCauseCode::ImplDerivedObligation(child) = &*data.parent_code { |
3229 | // Skip redundant recursive obligation notes. See `ui/issue-20413.rs`. | |
5e7ed085 FG |
3230 | let child_trait_pred = |
3231 | self.resolve_vars_if_possible(child.derived.parent_trait_pred); | |
5099ac24 | 3232 | let child_def_id = child_trait_pred.def_id(); |
fc512014 XL |
3233 | if seen_requirements.insert(child_def_id) { |
3234 | break; | |
3235 | } | |
3236 | count += 1; | |
5e7ed085 | 3237 | data = &child.derived; |
5099ac24 FG |
3238 | parent_predicate = child_trait_pred.to_predicate(tcx); |
3239 | parent_trait_pred = child_trait_pred; | |
fc512014 XL |
3240 | } |
3241 | if count > 0 { | |
c295e0f8 XL |
3242 | err.note(&format!( |
3243 | "{} redundant requirement{} hidden", | |
3244 | count, | |
3245 | pluralize!(count) | |
3246 | )); | |
487cf647 FG |
3247 | let (self_ty, file) = |
3248 | self.tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty()); | |
fc512014 | 3249 | err.note(&format!( |
487cf647 | 3250 | "required for `{self_ty}` to implement `{}`", |
f2b60f7d | 3251 | parent_trait_pred.print_modifiers_and_trait_path() |
fc512014 | 3252 | )); |
487cf647 FG |
3253 | if let Some(file) = file { |
3254 | err.note(&format!( | |
3255 | "the full type name has been written to '{}'", | |
3256 | file.display(), | |
3257 | )); | |
3258 | } | |
fc512014 | 3259 | } |
3dfed10e XL |
3260 | // #74711: avoid a stack overflow |
3261 | ensure_sufficient_stack(|| { | |
3262 | self.note_obligation_cause_code( | |
3263 | err, | |
9c376795 | 3264 | parent_predicate, |
5099ac24 | 3265 | param_env, |
3dfed10e XL |
3266 | &data.parent_code, |
3267 | obligated_types, | |
fc512014 | 3268 | seen_requirements, |
3dfed10e XL |
3269 | ) |
3270 | }); | |
dfeec247 | 3271 | } |
ba9703b0 | 3272 | ObligationCauseCode::DerivedObligation(ref data) => { |
5099ac24 | 3273 | let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); |
487cf647 | 3274 | let parent_predicate = parent_trait_ref; |
3dfed10e XL |
3275 | // #74711: avoid a stack overflow |
3276 | ensure_sufficient_stack(|| { | |
3277 | self.note_obligation_cause_code( | |
3278 | err, | |
9c376795 | 3279 | parent_predicate, |
5099ac24 | 3280 | param_env, |
3dfed10e XL |
3281 | &data.parent_code, |
3282 | obligated_types, | |
fc512014 | 3283 | seen_requirements, |
3dfed10e XL |
3284 | ) |
3285 | }); | |
ba9703b0 | 3286 | } |
c295e0f8 XL |
3287 | ObligationCauseCode::FunctionArgumentObligation { |
3288 | arg_hir_id, | |
3289 | call_hir_id, | |
3290 | ref parent_code, | |
9c376795 | 3291 | .. |
c295e0f8 | 3292 | } => { |
9c376795 FG |
3293 | self.note_function_argument_obligation( |
3294 | arg_hir_id, | |
3295 | err, | |
3296 | parent_code, | |
3297 | param_env, | |
3298 | predicate, | |
3299 | call_hir_id, | |
3300 | ); | |
c295e0f8 XL |
3301 | ensure_sufficient_stack(|| { |
3302 | self.note_obligation_cause_code( | |
3303 | err, | |
3304 | predicate, | |
5099ac24 | 3305 | param_env, |
c295e0f8 XL |
3306 | &parent_code, |
3307 | obligated_types, | |
3308 | seen_requirements, | |
3309 | ) | |
3310 | }); | |
3311 | } | |
064997fb | 3312 | ObligationCauseCode::CompareImplItemObligation { trait_item_def_id, kind, .. } => { |
3c0e092e | 3313 | let item_name = self.tcx.item_name(trait_item_def_id); |
cdc7bbd5 | 3314 | let msg = format!( |
9c376795 FG |
3315 | "the requirement `{predicate}` appears on the `impl`'s {kind} \ |
3316 | `{item_name}` but not on the corresponding trait's {kind}", | |
cdc7bbd5 XL |
3317 | ); |
3318 | let sp = self | |
3319 | .tcx | |
04454e1e | 3320 | .opt_item_ident(trait_item_def_id) |
cdc7bbd5 XL |
3321 | .map(|i| i.span) |
3322 | .unwrap_or_else(|| self.tcx.def_span(trait_item_def_id)); | |
3323 | let mut assoc_span: MultiSpan = sp.into(); | |
3324 | assoc_span.push_span_label( | |
3325 | sp, | |
9c376795 | 3326 | format!("this trait's {kind} doesn't have the requirement `{predicate}`"), |
cdc7bbd5 XL |
3327 | ); |
3328 | if let Some(ident) = self | |
3329 | .tcx | |
3330 | .opt_associated_item(trait_item_def_id) | |
064997fb | 3331 | .and_then(|i| self.tcx.opt_item_ident(i.container_id(self.tcx))) |
cdc7bbd5 | 3332 | { |
04454e1e | 3333 | assoc_span.push_span_label(ident.span, "in this trait"); |
cdc7bbd5 XL |
3334 | } |
3335 | err.span_note(assoc_span, &msg); | |
dfeec247 | 3336 | } |
dfeec247 XL |
3337 | ObligationCauseCode::TrivialBound => { |
3338 | err.help("see issue #48214"); | |
3339 | if tcx.sess.opts.unstable_features.is_nightly_build() { | |
3340 | err.help("add `#![feature(trivial_bounds)]` to the crate attributes to enable"); | |
3341 | } | |
3342 | } | |
923072b8 FG |
3343 | ObligationCauseCode::OpaqueReturnType(expr_info) => { |
3344 | if let Some((expr_ty, expr_span)) = expr_info { | |
9c376795 | 3345 | let expr_ty = with_forced_trimmed_paths!(self.ty_to_string(expr_ty)); |
923072b8 FG |
3346 | err.span_label( |
3347 | expr_span, | |
9c376795 FG |
3348 | with_forced_trimmed_paths!(format!( |
3349 | "return type was inferred to be `{expr_ty}` here", | |
3350 | )), | |
923072b8 FG |
3351 | ); |
3352 | } | |
3353 | } | |
dfeec247 XL |
3354 | } |
3355 | } | |
3356 | ||
923072b8 FG |
3357 | #[instrument( |
3358 | level = "debug", skip(self, err), fields(trait_pred.self_ty = ?trait_pred.self_ty()) | |
3359 | )] | |
f9f354fc XL |
3360 | fn suggest_await_before_try( |
3361 | &self, | |
5e7ed085 | 3362 | err: &mut Diagnostic, |
f9f354fc | 3363 | obligation: &PredicateObligation<'tcx>, |
5099ac24 | 3364 | trait_pred: ty::PolyTraitPredicate<'tcx>, |
f9f354fc XL |
3365 | span: Span, |
3366 | ) { | |
9ffffee4 | 3367 | if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) { |
f9f354fc XL |
3368 | let body = self.tcx.hir().body(body_id); |
3369 | if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind { | |
3dfed10e | 3370 | let future_trait = self.tcx.require_lang_item(LangItem::Future, None); |
f9f354fc | 3371 | |
5099ac24 | 3372 | let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); |
136023e0 | 3373 | let impls_future = self.type_implements_trait( |
f9f354fc | 3374 | future_trait, |
487cf647 | 3375 | [self.tcx.erase_late_bound_regions(self_ty)], |
f9f354fc | 3376 | obligation.param_env, |
136023e0 | 3377 | ); |
923072b8 FG |
3378 | if !impls_future.must_apply_modulo_regions() { |
3379 | return; | |
3380 | } | |
f9f354fc | 3381 | |
3c0e092e | 3382 | let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; |
f9f354fc | 3383 | // `<T as Future>::Output` |
923072b8 FG |
3384 | let projection_ty = trait_pred.map_bound(|trait_pred| { |
3385 | self.tcx.mk_projection( | |
3386 | item_def_id, | |
3387 | // Future::Output has no substs | |
9c376795 | 3388 | [trait_pred.self_ty()], |
923072b8 FG |
3389 | ) |
3390 | }); | |
487cf647 FG |
3391 | let InferOk { value: projection_ty, .. } = |
3392 | self.at(&obligation.cause, obligation.param_env).normalize(projection_ty); | |
f9f354fc XL |
3393 | |
3394 | debug!( | |
923072b8 | 3395 | normalized_projection_type = ?self.resolve_vars_if_possible(projection_ty) |
f9f354fc XL |
3396 | ); |
3397 | let try_obligation = self.mk_trait_obligation_with_new_self_ty( | |
3398 | obligation.param_env, | |
923072b8 | 3399 | trait_pred.map_bound(|trait_pred| (trait_pred, projection_ty.skip_binder())), |
f9f354fc | 3400 | ); |
923072b8 | 3401 | debug!(try_trait_obligation = ?try_obligation); |
136023e0 | 3402 | if self.predicate_may_hold(&try_obligation) |
5e7ed085 FG |
3403 | && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) |
3404 | && snippet.ends_with('?') | |
136023e0 | 3405 | { |
5e7ed085 FG |
3406 | err.span_suggestion_verbose( |
3407 | span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(), | |
3408 | "consider `await`ing on the `Future`", | |
923072b8 | 3409 | ".await", |
5e7ed085 FG |
3410 | Applicability::MaybeIncorrect, |
3411 | ); | |
f9f354fc XL |
3412 | } |
3413 | } | |
3414 | } | |
3415 | } | |
5e7ed085 FG |
3416 | |
3417 | fn suggest_floating_point_literal( | |
3418 | &self, | |
3419 | obligation: &PredicateObligation<'tcx>, | |
3420 | err: &mut Diagnostic, | |
3421 | trait_ref: &ty::PolyTraitRef<'tcx>, | |
3422 | ) { | |
3423 | let rhs_span = match obligation.cause.code() { | |
064997fb | 3424 | ObligationCauseCode::BinOp { rhs_span: Some(span), is_lit, .. } if *is_lit => span, |
5e7ed085 FG |
3425 | _ => return, |
3426 | }; | |
2b03887a FG |
3427 | if let ty::Float(_) = trait_ref.skip_binder().self_ty().kind() |
3428 | && let ty::Infer(InferTy::IntVar(_)) = trait_ref.skip_binder().substs.type_at(1).kind() | |
3429 | { | |
3430 | err.span_suggestion_verbose( | |
3431 | rhs_span.shrink_to_hi(), | |
3432 | "consider using a floating-point literal by writing it with `.0`", | |
3433 | ".0", | |
3434 | Applicability::MaybeIncorrect, | |
3435 | ); | |
5e7ed085 FG |
3436 | } |
3437 | } | |
04454e1e FG |
3438 | |
3439 | fn suggest_derive( | |
3440 | &self, | |
3441 | obligation: &PredicateObligation<'tcx>, | |
3442 | err: &mut Diagnostic, | |
3443 | trait_pred: ty::PolyTraitPredicate<'tcx>, | |
3444 | ) { | |
3445 | let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) else { | |
3446 | return; | |
3447 | }; | |
3448 | let (adt, substs) = match trait_pred.skip_binder().self_ty().kind() { | |
3449 | ty::Adt(adt, substs) if adt.did().is_local() => (adt, substs), | |
3450 | _ => return, | |
3451 | }; | |
3452 | let can_derive = { | |
3453 | let is_derivable_trait = match diagnostic_name { | |
3454 | sym::Default => !adt.is_enum(), | |
3455 | sym::PartialEq | sym::PartialOrd => { | |
3456 | let rhs_ty = trait_pred.skip_binder().trait_ref.substs.type_at(1); | |
3457 | trait_pred.skip_binder().self_ty() == rhs_ty | |
3458 | } | |
3459 | sym::Eq | sym::Ord | sym::Clone | sym::Copy | sym::Hash | sym::Debug => true, | |
3460 | _ => false, | |
3461 | }; | |
3462 | is_derivable_trait && | |
3463 | // Ensure all fields impl the trait. | |
3464 | adt.all_fields().all(|field| { | |
3465 | let field_ty = field.ty(self.tcx, substs); | |
3466 | let trait_substs = match diagnostic_name { | |
3467 | sym::PartialEq | sym::PartialOrd => { | |
487cf647 | 3468 | Some(field_ty) |
04454e1e | 3469 | } |
487cf647 | 3470 | _ => None, |
04454e1e FG |
3471 | }; |
3472 | let trait_pred = trait_pred.map_bound_ref(|tr| ty::TraitPredicate { | |
487cf647 FG |
3473 | trait_ref: self.tcx.mk_trait_ref( |
3474 | trait_pred.def_id(), | |
3475 | [field_ty].into_iter().chain(trait_substs), | |
3476 | ), | |
04454e1e FG |
3477 | ..*tr |
3478 | }); | |
3479 | let field_obl = Obligation::new( | |
487cf647 | 3480 | self.tcx, |
04454e1e FG |
3481 | obligation.cause.clone(), |
3482 | obligation.param_env, | |
487cf647 | 3483 | trait_pred, |
04454e1e FG |
3484 | ); |
3485 | self.predicate_must_hold_modulo_regions(&field_obl) | |
3486 | }) | |
3487 | }; | |
3488 | if can_derive { | |
3489 | err.span_suggestion_verbose( | |
3490 | self.tcx.def_span(adt.did()).shrink_to_lo(), | |
3491 | &format!( | |
3492 | "consider annotating `{}` with `#[derive({})]`", | |
3493 | trait_pred.skip_binder().self_ty(), | |
3494 | diagnostic_name, | |
3495 | ), | |
3496 | format!("#[derive({})]\n", diagnostic_name), | |
3497 | Applicability::MaybeIncorrect, | |
3498 | ); | |
3499 | } | |
3500 | } | |
064997fb FG |
3501 | |
3502 | fn suggest_dereferencing_index( | |
3503 | &self, | |
3504 | obligation: &PredicateObligation<'tcx>, | |
3505 | err: &mut Diagnostic, | |
3506 | trait_pred: ty::PolyTraitPredicate<'tcx>, | |
3507 | ) { | |
3508 | if let ObligationCauseCode::ImplDerivedObligation(_) = obligation.cause.code() | |
3509 | && self.tcx.is_diagnostic_item(sym::SliceIndex, trait_pred.skip_binder().trait_ref.def_id) | |
3510 | && let ty::Slice(_) = trait_pred.skip_binder().trait_ref.substs.type_at(1).kind() | |
3511 | && let ty::Ref(_, inner_ty, _) = trait_pred.skip_binder().self_ty().kind() | |
3512 | && let ty::Uint(ty::UintTy::Usize) = inner_ty.kind() | |
3513 | { | |
3514 | err.span_suggestion_verbose( | |
3515 | obligation.cause.span.shrink_to_lo(), | |
3516 | "dereference this index", | |
3517 | '*', | |
3518 | Applicability::MachineApplicable, | |
3519 | ); | |
3520 | } | |
3521 | } | |
9c376795 FG |
3522 | fn note_function_argument_obligation( |
3523 | &self, | |
3524 | arg_hir_id: HirId, | |
3525 | err: &mut Diagnostic, | |
3526 | parent_code: &ObligationCauseCode<'tcx>, | |
3527 | param_env: ty::ParamEnv<'tcx>, | |
3528 | failed_pred: ty::Predicate<'tcx>, | |
3529 | call_hir_id: HirId, | |
3530 | ) { | |
3531 | let tcx = self.tcx; | |
3532 | let hir = tcx.hir(); | |
3533 | if let Some(Node::Expr(expr)) = hir.find(arg_hir_id) | |
3534 | && let Some(typeck_results) = &self.typeck_results | |
3535 | { | |
3536 | if let hir::Expr { kind: hir::ExprKind::Block(..), .. } = expr { | |
3537 | let expr = expr.peel_blocks(); | |
9ffffee4 | 3538 | let ty = typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error_misc()); |
9c376795 FG |
3539 | let span = expr.span; |
3540 | if Some(span) != err.span.primary_span() { | |
3541 | err.span_label( | |
3542 | span, | |
3543 | if ty.references_error() { | |
3544 | String::new() | |
3545 | } else { | |
3546 | let ty = with_forced_trimmed_paths!(self.ty_to_string(ty)); | |
3547 | format!("this tail expression is of type `{ty}`") | |
3548 | }, | |
3549 | ); | |
3550 | } | |
3551 | } | |
3552 | ||
3553 | // FIXME: visit the ty to see if there's any closure involved, and if there is, | |
3554 | // check whether its evaluated return type is the same as the one corresponding | |
3555 | // to an associated type (as seen from `trait_pred`) in the predicate. Like in | |
3556 | // trait_pred `S: Sum<<Self as Iterator>::Item>` and predicate `i32: Sum<&()>` | |
3557 | let mut type_diffs = vec![]; | |
3558 | ||
3559 | if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = parent_code.deref() | |
3560 | && let Some(node_substs) = typeck_results.node_substs_opt(call_hir_id) | |
3561 | && let where_clauses = self.tcx.predicates_of(def_id).instantiate(self.tcx, node_substs) | |
3562 | && let Some(where_pred) = where_clauses.predicates.get(*idx) | |
3563 | { | |
3564 | if let Some(where_pred) = where_pred.to_opt_poly_trait_pred() | |
3565 | && let Some(failed_pred) = failed_pred.to_opt_poly_trait_pred() | |
3566 | { | |
3567 | let mut c = CollectAllMismatches { | |
3568 | infcx: self.infcx, | |
3569 | param_env, | |
3570 | errors: vec![], | |
3571 | }; | |
3572 | if let Ok(_) = c.relate(where_pred, failed_pred) { | |
3573 | type_diffs = c.errors; | |
3574 | } | |
3575 | } else if let Some(where_pred) = where_pred.to_opt_poly_projection_pred() | |
3576 | && let Some(failed_pred) = failed_pred.to_opt_poly_projection_pred() | |
3577 | && let Some(found) = failed_pred.skip_binder().term.ty() | |
3578 | { | |
3579 | type_diffs = vec![ | |
3580 | Sorts(ty::error::ExpectedFound { | |
9ffffee4 | 3581 | expected: self.tcx.mk_alias(ty::Projection, where_pred.skip_binder().projection_ty), |
9c376795 FG |
3582 | found, |
3583 | }), | |
3584 | ]; | |
3585 | } | |
3586 | } | |
3587 | if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind | |
3588 | && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path | |
3589 | && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id) | |
3590 | && let parent_hir_id = self.tcx.hir().parent_id(binding.hir_id) | |
3591 | && let Some(hir::Node::Local(local)) = self.tcx.hir().find(parent_hir_id) | |
3592 | && let Some(binding_expr) = local.init | |
3593 | { | |
3594 | // If the expression we're calling on is a binding, we want to point at the | |
3595 | // `let` when talking about the type. Otherwise we'll point at every part | |
3596 | // of the method chain with the type. | |
3597 | self.point_at_chain(binding_expr, &typeck_results, type_diffs, param_env, err); | |
3598 | } else { | |
3599 | self.point_at_chain(expr, &typeck_results, type_diffs, param_env, err); | |
3600 | } | |
3601 | } | |
3602 | let call_node = hir.find(call_hir_id); | |
3603 | if let Some(Node::Expr(hir::Expr { | |
3604 | kind: hir::ExprKind::MethodCall(path, rcvr, ..), .. | |
3605 | })) = call_node | |
3606 | { | |
3607 | if Some(rcvr.span) == err.span.primary_span() { | |
3608 | err.replace_span_with(path.ident.span, true); | |
3609 | } | |
3610 | } | |
3611 | if let Some(Node::Expr(hir::Expr { | |
3612 | kind: | |
3613 | hir::ExprKind::Call(hir::Expr { span, .. }, _) | |
3614 | | hir::ExprKind::MethodCall(hir::PathSegment { ident: Ident { span, .. }, .. }, ..), | |
3615 | .. | |
3616 | })) = hir.find(call_hir_id) | |
3617 | { | |
3618 | if Some(*span) != err.span.primary_span() { | |
3619 | err.span_label(*span, "required by a bound introduced by this call"); | |
3620 | } | |
3621 | } | |
3622 | } | |
3623 | ||
3624 | fn point_at_chain( | |
3625 | &self, | |
3626 | expr: &hir::Expr<'_>, | |
3627 | typeck_results: &TypeckResults<'tcx>, | |
3628 | type_diffs: Vec<TypeError<'tcx>>, | |
3629 | param_env: ty::ParamEnv<'tcx>, | |
3630 | err: &mut Diagnostic, | |
3631 | ) { | |
3632 | let mut primary_spans = vec![]; | |
3633 | let mut span_labels = vec![]; | |
3634 | ||
3635 | let tcx = self.tcx; | |
3636 | ||
3637 | let mut print_root_expr = true; | |
3638 | let mut assocs = vec![]; | |
3639 | let mut expr = expr; | |
3640 | let mut prev_ty = self.resolve_vars_if_possible( | |
9ffffee4 | 3641 | typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error_misc()), |
9c376795 FG |
3642 | ); |
3643 | while let hir::ExprKind::MethodCall(_path_segment, rcvr_expr, _args, span) = expr.kind { | |
3644 | // Point at every method call in the chain with the resulting type. | |
3645 | // vec![1, 2, 3].iter().map(mapper).sum<i32>() | |
3646 | // ^^^^^^ ^^^^^^^^^^^ | |
3647 | expr = rcvr_expr; | |
3648 | let assocs_in_this_method = | |
3649 | self.probe_assoc_types_at_expr(&type_diffs, span, prev_ty, expr.hir_id, param_env); | |
3650 | assocs.push(assocs_in_this_method); | |
3651 | prev_ty = self.resolve_vars_if_possible( | |
9ffffee4 | 3652 | typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error_misc()), |
9c376795 FG |
3653 | ); |
3654 | ||
3655 | if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind | |
3656 | && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path | |
3657 | && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id) | |
3658 | && let Some(parent) = self.tcx.hir().find_parent(binding.hir_id) | |
3659 | { | |
3660 | // We've reached the root of the method call chain... | |
3661 | if let hir::Node::Local(local) = parent | |
3662 | && let Some(binding_expr) = local.init | |
3663 | { | |
3664 | // ...and it is a binding. Get the binding creation and continue the chain. | |
3665 | expr = binding_expr; | |
3666 | } | |
3667 | if let hir::Node::Param(param) = parent { | |
3668 | // ...and it is a an fn argument. | |
3669 | let prev_ty = self.resolve_vars_if_possible( | |
9ffffee4 | 3670 | typeck_results.node_type_opt(param.hir_id).unwrap_or(tcx.ty_error_misc()), |
9c376795 FG |
3671 | ); |
3672 | let assocs_in_this_method = self.probe_assoc_types_at_expr(&type_diffs, param.ty_span, prev_ty, param.hir_id, param_env); | |
3673 | if assocs_in_this_method.iter().any(|a| a.is_some()) { | |
3674 | assocs.push(assocs_in_this_method); | |
3675 | print_root_expr = false; | |
3676 | } | |
3677 | break; | |
3678 | } | |
3679 | } | |
3680 | } | |
3681 | // We want the type before deref coercions, otherwise we talk about `&[_]` | |
3682 | // instead of `Vec<_>`. | |
3683 | if let Some(ty) = typeck_results.expr_ty_opt(expr) && print_root_expr { | |
3684 | let ty = with_forced_trimmed_paths!(self.ty_to_string(ty)); | |
3685 | // Point at the root expression | |
3686 | // vec![1, 2, 3].iter().map(mapper).sum<i32>() | |
3687 | // ^^^^^^^^^^^^^ | |
3688 | span_labels.push((expr.span, format!("this expression has type `{ty}`"))); | |
3689 | }; | |
3690 | // Only show this if it is not a "trivial" expression (not a method | |
3691 | // chain) and there are associated types to talk about. | |
3692 | let mut assocs = assocs.into_iter().peekable(); | |
3693 | while let Some(assocs_in_method) = assocs.next() { | |
3694 | let Some(prev_assoc_in_method) = assocs.peek() else { | |
3695 | for entry in assocs_in_method { | |
3696 | let Some((span, (assoc, ty))) = entry else { continue; }; | |
3697 | if primary_spans.is_empty() || type_diffs.iter().any(|diff| { | |
3698 | let Sorts(expected_found) = diff else { return false; }; | |
9ffffee4 | 3699 | self.can_eq(param_env, expected_found.found, ty) |
9c376795 FG |
3700 | }) { |
3701 | // FIXME: this doesn't quite work for `Iterator::collect` | |
3702 | // because we have `Vec<i32>` and `()`, but we'd want `i32` | |
3703 | // to point at the `.into_iter()` call, but as long as we | |
3704 | // still point at the other method calls that might have | |
3705 | // introduced the issue, this is fine for now. | |
3706 | primary_spans.push(span); | |
3707 | } | |
3708 | span_labels.push(( | |
3709 | span, | |
3710 | with_forced_trimmed_paths!(format!( | |
3711 | "`{}` is `{ty}` here", | |
3712 | self.tcx.def_path_str(assoc), | |
3713 | )), | |
3714 | )); | |
3715 | } | |
3716 | break; | |
3717 | }; | |
3718 | for (entry, prev_entry) in | |
3719 | assocs_in_method.into_iter().zip(prev_assoc_in_method.into_iter()) | |
3720 | { | |
3721 | match (entry, prev_entry) { | |
3722 | (Some((span, (assoc, ty))), Some((_, (_, prev_ty)))) => { | |
3723 | let ty_str = with_forced_trimmed_paths!(self.ty_to_string(ty)); | |
3724 | ||
3725 | let assoc = with_forced_trimmed_paths!(self.tcx.def_path_str(assoc)); | |
9ffffee4 | 3726 | if !self.can_eq(param_env, ty, *prev_ty) { |
9c376795 FG |
3727 | if type_diffs.iter().any(|diff| { |
3728 | let Sorts(expected_found) = diff else { return false; }; | |
9ffffee4 | 3729 | self.can_eq(param_env, expected_found.found, ty) |
9c376795 FG |
3730 | }) { |
3731 | primary_spans.push(span); | |
3732 | } | |
3733 | span_labels | |
3734 | .push((span, format!("`{assoc}` changed to `{ty_str}` here"))); | |
3735 | } else { | |
3736 | span_labels.push((span, format!("`{assoc}` remains `{ty_str}` here"))); | |
3737 | } | |
3738 | } | |
3739 | (Some((span, (assoc, ty))), None) => { | |
3740 | span_labels.push(( | |
3741 | span, | |
3742 | with_forced_trimmed_paths!(format!( | |
3743 | "`{}` is `{}` here", | |
3744 | self.tcx.def_path_str(assoc), | |
3745 | self.ty_to_string(ty), | |
3746 | )), | |
3747 | )); | |
3748 | } | |
3749 | (None, Some(_)) | (None, None) => {} | |
3750 | } | |
3751 | } | |
3752 | } | |
3753 | if !primary_spans.is_empty() { | |
3754 | let mut multi_span: MultiSpan = primary_spans.into(); | |
3755 | for (span, label) in span_labels { | |
3756 | multi_span.push_span_label(span, label); | |
3757 | } | |
3758 | err.span_note( | |
3759 | multi_span, | |
3760 | "the method call chain might not have had the expected associated types", | |
3761 | ); | |
3762 | } | |
3763 | } | |
3764 | ||
3765 | fn probe_assoc_types_at_expr( | |
3766 | &self, | |
3767 | type_diffs: &[TypeError<'tcx>], | |
3768 | span: Span, | |
3769 | prev_ty: Ty<'tcx>, | |
3770 | body_id: hir::HirId, | |
3771 | param_env: ty::ParamEnv<'tcx>, | |
3772 | ) -> Vec<Option<(Span, (DefId, Ty<'tcx>))>> { | |
3773 | let ocx = ObligationCtxt::new_in_snapshot(self.infcx); | |
3774 | let mut assocs_in_this_method = Vec::with_capacity(type_diffs.len()); | |
3775 | for diff in type_diffs { | |
3776 | let Sorts(expected_found) = diff else { continue; }; | |
3777 | let ty::Alias(ty::Projection, proj) = expected_found.expected.kind() else { continue; }; | |
3778 | ||
3779 | let origin = TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }; | |
3780 | let trait_def_id = proj.trait_def_id(self.tcx); | |
3781 | // Make `Self` be equivalent to the type of the call chain | |
3782 | // expression we're looking at now, so that we can tell what | |
3783 | // for example `Iterator::Item` is at this point in the chain. | |
3784 | let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| { | |
3785 | match param.kind { | |
3786 | ty::GenericParamDefKind::Type { .. } => { | |
3787 | if param.index == 0 { | |
3788 | return prev_ty.into(); | |
3789 | } | |
3790 | } | |
3791 | ty::GenericParamDefKind::Lifetime | ty::GenericParamDefKind::Const { .. } => {} | |
3792 | } | |
3793 | self.var_for_def(span, param) | |
3794 | }); | |
3795 | // This will hold the resolved type of the associated type, if the | |
3796 | // current expression implements the trait that associated type is | |
3797 | // in. For example, this would be what `Iterator::Item` is here. | |
3798 | let ty_var = self.infcx.next_ty_var(origin); | |
3799 | // This corresponds to `<ExprTy as Iterator>::Item = _`. | |
3800 | let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::Projection( | |
3801 | ty::ProjectionPredicate { | |
3802 | projection_ty: self.tcx.mk_alias_ty(proj.def_id, substs), | |
3803 | term: ty_var.into(), | |
3804 | }, | |
3805 | ))); | |
9ffffee4 | 3806 | let body_def_id = self.tcx.hir().enclosing_body_owner(body_id); |
9c376795 FG |
3807 | // Add `<ExprTy as Iterator>::Item = _` obligation. |
3808 | ocx.register_obligation(Obligation::misc( | |
9ffffee4 FG |
3809 | self.tcx, |
3810 | span, | |
3811 | body_def_id, | |
3812 | param_env, | |
3813 | projection, | |
9c376795 FG |
3814 | )); |
3815 | if ocx.select_where_possible().is_empty() { | |
3816 | // `ty_var` now holds the type that `Item` is for `ExprTy`. | |
3817 | let ty_var = self.resolve_vars_if_possible(ty_var); | |
3818 | assocs_in_this_method.push(Some((span, (proj.def_id, ty_var)))); | |
3819 | } else { | |
3820 | // `<ExprTy as Iterator>` didn't select, so likely we've | |
3821 | // reached the end of the iterator chain, like the originating | |
3822 | // `Vec<_>`. | |
3823 | // Keep the space consistent for later zipping. | |
3824 | assocs_in_this_method.push(None); | |
3825 | } | |
3826 | } | |
3827 | assocs_in_this_method | |
3828 | } | |
3829 | } | |
3830 | ||
3831 | /// Add a hint to add a missing borrow or remove an unnecessary one. | |
3832 | fn hint_missing_borrow<'tcx>( | |
3833 | infcx: &InferCtxt<'tcx>, | |
3834 | param_env: ty::ParamEnv<'tcx>, | |
3835 | span: Span, | |
3836 | found: Ty<'tcx>, | |
3837 | expected: Ty<'tcx>, | |
3838 | found_node: Node<'_>, | |
3839 | err: &mut Diagnostic, | |
3840 | ) { | |
3841 | let found_args = match found.kind() { | |
9ffffee4 | 3842 | ty::FnPtr(f) => infcx.instantiate_binder_with_placeholders(*f).inputs().iter(), |
9c376795 FG |
3843 | kind => { |
3844 | span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind) | |
3845 | } | |
3846 | }; | |
3847 | let expected_args = match expected.kind() { | |
9ffffee4 | 3848 | ty::FnPtr(f) => infcx.instantiate_binder_with_placeholders(*f).inputs().iter(), |
9c376795 FG |
3849 | kind => { |
3850 | span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind) | |
3851 | } | |
3852 | }; | |
3853 | ||
3854 | // This could be a variant constructor, for example. | |
3855 | let Some(fn_decl) = found_node.fn_decl() else { return; }; | |
3856 | ||
3857 | let args = fn_decl.inputs.iter().map(|ty| ty); | |
3858 | ||
9ffffee4 FG |
3859 | fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) { |
3860 | let mut refs = vec![]; | |
9c376795 | 3861 | |
9ffffee4 | 3862 | while let ty::Ref(_, new_ty, mutbl) = ty.kind() { |
9c376795 | 3863 | ty = *new_ty; |
9ffffee4 | 3864 | refs.push(*mutbl); |
9c376795 FG |
3865 | } |
3866 | ||
3867 | (ty, refs) | |
3868 | } | |
3869 | ||
3870 | let mut to_borrow = Vec::new(); | |
3871 | let mut remove_borrow = Vec::new(); | |
3872 | ||
3873 | for ((found_arg, expected_arg), arg) in found_args.zip(expected_args).zip(args) { | |
3874 | let (found_ty, found_refs) = get_deref_type_and_refs(*found_arg); | |
3875 | let (expected_ty, expected_refs) = get_deref_type_and_refs(*expected_arg); | |
3876 | ||
9ffffee4 FG |
3877 | if infcx.can_eq(param_env, found_ty, expected_ty) { |
3878 | // FIXME: This could handle more exotic cases like mutability mismatches too! | |
3879 | if found_refs.len() < expected_refs.len() | |
3880 | && found_refs[..] == expected_refs[expected_refs.len() - found_refs.len()..] | |
3881 | { | |
3882 | to_borrow.push(( | |
3883 | arg.span.shrink_to_lo(), | |
3884 | expected_refs[..expected_refs.len() - found_refs.len()] | |
3885 | .iter() | |
3886 | .map(|mutbl| format!("&{}", mutbl.prefix_str())) | |
3887 | .collect::<Vec<_>>() | |
3888 | .join(""), | |
3889 | )); | |
3890 | } else if found_refs.len() > expected_refs.len() { | |
9c376795 | 3891 | let mut span = arg.span.shrink_to_lo(); |
9ffffee4 | 3892 | let mut left = found_refs.len() - expected_refs.len(); |
9c376795 FG |
3893 | let mut ty = arg; |
3894 | while let hir::TyKind::Ref(_, mut_ty) = &ty.kind && left > 0 { | |
3895 | span = span.with_hi(mut_ty.ty.span.lo()); | |
3896 | ty = mut_ty.ty; | |
3897 | left -= 1; | |
3898 | } | |
3899 | let sugg = if left == 0 { | |
3900 | (span, String::new()) | |
3901 | } else { | |
3902 | (arg.span, expected_arg.to_string()) | |
3903 | }; | |
3904 | remove_borrow.push(sugg); | |
3905 | } | |
3906 | } | |
3907 | } | |
3908 | ||
3909 | if !to_borrow.is_empty() { | |
3910 | err.multipart_suggestion_verbose( | |
3911 | "consider borrowing the argument", | |
3912 | to_borrow, | |
3913 | Applicability::MaybeIncorrect, | |
3914 | ); | |
3915 | } | |
3916 | ||
3917 | if !remove_borrow.is_empty() { | |
3918 | err.multipart_suggestion_verbose( | |
3919 | "do not borrow the argument", | |
3920 | remove_borrow, | |
3921 | Applicability::MaybeIncorrect, | |
3922 | ); | |
3923 | } | |
dfeec247 XL |
3924 | } |
3925 | ||
dfeec247 XL |
3926 | /// Collect all the returned expressions within the input expression. |
3927 | /// Used to point at the return spans when we want to suggest some change to them. | |
3928 | #[derive(Default)] | |
f035d41b XL |
3929 | pub struct ReturnsVisitor<'v> { |
3930 | pub returns: Vec<&'v hir::Expr<'v>>, | |
dfeec247 XL |
3931 | in_block_tail: bool, |
3932 | } | |
3933 | ||
3934 | impl<'v> Visitor<'v> for ReturnsVisitor<'v> { | |
dfeec247 XL |
3935 | fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { |
3936 | // Visit every expression to detect `return` paths, either through the function's tail | |
3937 | // expression or `return` statements. We walk all nodes to find `return` statements, but | |
3938 | // we only care about tail expressions when `in_block_tail` is `true`, which means that | |
3939 | // they're in the return path of the function body. | |
3940 | match ex.kind { | |
3941 | hir::ExprKind::Ret(Some(ex)) => { | |
3942 | self.returns.push(ex); | |
3943 | } | |
3944 | hir::ExprKind::Block(block, _) if self.in_block_tail => { | |
3945 | self.in_block_tail = false; | |
3946 | for stmt in block.stmts { | |
3947 | hir::intravisit::walk_stmt(self, stmt); | |
3948 | } | |
3949 | self.in_block_tail = true; | |
3950 | if let Some(expr) = block.expr { | |
3951 | self.visit_expr(expr); | |
3952 | } | |
3953 | } | |
5869c6ff XL |
3954 | hir::ExprKind::If(_, then, else_opt) if self.in_block_tail => { |
3955 | self.visit_expr(then); | |
3956 | if let Some(el) = else_opt { | |
3957 | self.visit_expr(el); | |
3958 | } | |
3959 | } | |
dfeec247 XL |
3960 | hir::ExprKind::Match(_, arms, _) if self.in_block_tail => { |
3961 | for arm in arms { | |
3962 | self.visit_expr(arm.body); | |
3963 | } | |
3964 | } | |
3965 | // We need to walk to find `return`s in the entire body. | |
3966 | _ if !self.in_block_tail => hir::intravisit::walk_expr(self, ex), | |
3967 | _ => self.returns.push(ex), | |
3968 | } | |
3969 | } | |
3970 | ||
3971 | fn visit_body(&mut self, body: &'v hir::Body<'v>) { | |
3972 | assert!(!self.in_block_tail); | |
3973 | if body.generator_kind().is_none() { | |
3974 | if let hir::ExprKind::Block(block, None) = body.value.kind { | |
3975 | if block.expr.is_some() { | |
3976 | self.in_block_tail = true; | |
3977 | } | |
3978 | } | |
3979 | } | |
3980 | hir::intravisit::walk_body(self, body); | |
3981 | } | |
3982 | } | |
ba9703b0 XL |
3983 | |
3984 | /// Collect all the awaited expressions within the input expression. | |
3985 | #[derive(Default)] | |
3986 | struct AwaitsVisitor { | |
3987 | awaits: Vec<hir::HirId>, | |
3988 | } | |
3989 | ||
3990 | impl<'v> Visitor<'v> for AwaitsVisitor { | |
ba9703b0 XL |
3991 | fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { |
3992 | if let hir::ExprKind::Yield(_, hir::YieldSource::Await { expr: Some(id) }) = ex.kind { | |
3993 | self.awaits.push(id) | |
3994 | } | |
3995 | hir::intravisit::walk_expr(self, ex) | |
3996 | } | |
3997 | } | |
3998 | ||
3999 | pub trait NextTypeParamName { | |
4000 | fn next_type_param_name(&self, name: Option<&str>) -> String; | |
4001 | } | |
4002 | ||
4003 | impl NextTypeParamName for &[hir::GenericParam<'_>] { | |
4004 | fn next_type_param_name(&self, name: Option<&str>) -> String { | |
f035d41b | 4005 | // This is the list of possible parameter names that we might suggest. |
ba9703b0 | 4006 | let name = name.and_then(|n| n.chars().next()).map(|c| c.to_string().to_uppercase()); |
f9f354fc | 4007 | let name = name.as_deref(); |
ba9703b0 XL |
4008 | let possible_names = [name.unwrap_or("T"), "T", "U", "V", "X", "Y", "Z", "A", "B", "C"]; |
4009 | let used_names = self | |
4010 | .iter() | |
4011 | .filter_map(|p| match p.name { | |
4012 | hir::ParamName::Plain(ident) => Some(ident.name), | |
4013 | _ => None, | |
4014 | }) | |
4015 | .collect::<Vec<_>>(); | |
4016 | ||
4017 | possible_names | |
4018 | .iter() | |
4019 | .find(|n| !used_names.contains(&Symbol::intern(n))) | |
4020 | .unwrap_or(&"ParamName") | |
4021 | .to_string() | |
4022 | } | |
4023 | } | |
f9f354fc XL |
4024 | |
4025 | fn suggest_trait_object_return_type_alternatives( | |
5e7ed085 | 4026 | err: &mut Diagnostic, |
f9f354fc XL |
4027 | ret_ty: Span, |
4028 | trait_obj: &str, | |
4029 | is_object_safe: bool, | |
4030 | ) { | |
f9f354fc XL |
4031 | err.span_suggestion( |
4032 | ret_ty, | |
4033 | &format!( | |
4034 | "use `impl {}` as the return type if all return paths have the same type but you \ | |
4035 | want to expose only the trait in the signature", | |
4036 | trait_obj, | |
4037 | ), | |
4038 | format!("impl {}", trait_obj), | |
4039 | Applicability::MaybeIncorrect, | |
4040 | ); | |
4041 | if is_object_safe { | |
04454e1e | 4042 | err.multipart_suggestion( |
f9f354fc XL |
4043 | &format!( |
4044 | "use a boxed trait object if all return paths implement trait `{}`", | |
4045 | trait_obj, | |
4046 | ), | |
04454e1e FG |
4047 | vec![ |
4048 | (ret_ty.shrink_to_lo(), "Box<".to_string()), | |
4049 | (ret_ty.shrink_to_hi(), ">".to_string()), | |
4050 | ], | |
f9f354fc XL |
4051 | Applicability::MaybeIncorrect, |
4052 | ); | |
4053 | } | |
4054 | } | |
923072b8 FG |
4055 | |
4056 | /// Collect the spans that we see the generic param `param_did` | |
4057 | struct ReplaceImplTraitVisitor<'a> { | |
4058 | ty_spans: &'a mut Vec<Span>, | |
4059 | param_did: DefId, | |
4060 | } | |
4061 | ||
4062 | impl<'a, 'hir> hir::intravisit::Visitor<'hir> for ReplaceImplTraitVisitor<'a> { | |
4063 | fn visit_ty(&mut self, t: &'hir hir::Ty<'hir>) { | |
4064 | if let hir::TyKind::Path(hir::QPath::Resolved( | |
4065 | None, | |
4066 | hir::Path { res: hir::def::Res::Def(_, segment_did), .. }, | |
4067 | )) = t.kind | |
4068 | { | |
4069 | if self.param_did == *segment_did { | |
4070 | // `fn foo(t: impl Trait)` | |
4071 | // ^^^^^^^^^^ get this to suggest `T` instead | |
4072 | ||
4073 | // There might be more than one `impl Trait`. | |
4074 | self.ty_spans.push(t.span); | |
4075 | return; | |
4076 | } | |
4077 | } | |
4078 | ||
4079 | hir::intravisit::walk_ty(self, t); | |
4080 | } | |
4081 | } | |
4082 | ||
4083 | // Replace `param` with `replace_ty` | |
4084 | struct ReplaceImplTraitFolder<'tcx> { | |
4085 | tcx: TyCtxt<'tcx>, | |
4086 | param: &'tcx ty::GenericParamDef, | |
4087 | replace_ty: Ty<'tcx>, | |
4088 | } | |
4089 | ||
9ffffee4 | 4090 | impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceImplTraitFolder<'tcx> { |
923072b8 FG |
4091 | fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { |
4092 | if let ty::Param(ty::ParamTy { index, .. }) = t.kind() { | |
4093 | if self.param.index == *index { | |
4094 | return self.replace_ty; | |
4095 | } | |
4096 | } | |
4097 | t.super_fold_with(self) | |
4098 | } | |
4099 | ||
9ffffee4 | 4100 | fn interner(&self) -> TyCtxt<'tcx> { |
923072b8 FG |
4101 | self.tcx |
4102 | } | |
4103 | } |