]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_typeck/src/astconv/errors.rs
New upstream version 1.65.0+dfsg1
[rustc.git] / compiler / rustc_typeck / src / astconv / errors.rs
CommitLineData
3dfed10e 1use crate::astconv::AstConv;
04454e1e 2use crate::errors::{ManualImplementation, MissingTypeParams};
3dfed10e 3use rustc_data_structures::fx::FxHashMap;
5e7ed085 4use rustc_errors::{pluralize, struct_span_err, Applicability, ErrorGuaranteed};
3dfed10e
XL
5use rustc_hir as hir;
6use rustc_hir::def_id::DefId;
7use rustc_middle::ty;
8use rustc_session::parse::feature_err;
fc512014 9use rustc_span::lev_distance::find_best_match_for_name;
3dfed10e 10use rustc_span::symbol::{sym, Ident};
064997fb 11use rustc_span::{Span, Symbol, DUMMY_SP};
3dfed10e
XL
12
13use std::collections::BTreeSet;
14
15impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
16 /// On missing type parameters, emit an E0393 error and provide a structured suggestion using
17 /// the type parameter's name as a placeholder.
18 pub(crate) fn complain_about_missing_type_params(
19 &self,
064997fb 20 missing_type_params: Vec<Symbol>,
3dfed10e
XL
21 def_id: DefId,
22 span: Span,
23 empty_generic_args: bool,
24 ) {
25 if missing_type_params.is_empty() {
26 return;
27 }
04454e1e
FG
28
29 self.tcx().sess.emit_err(MissingTypeParams {
3dfed10e 30 span,
04454e1e 31 def_span: self.tcx().def_span(def_id),
f2b60f7d 32 span_snippet: self.tcx().sess.source_map().span_to_snippet(span).ok(),
04454e1e 33 missing_type_params,
3dfed10e 34 empty_generic_args,
04454e1e 35 });
3dfed10e
XL
36 }
37
38 /// When the code is using the `Fn` traits directly, instead of the `Fn(A) -> B` syntax, emit
39 /// an error and attempt to build a reasonable structured suggestion.
40 pub(crate) fn complain_about_internal_fn_trait(
41 &self,
42 span: Span,
43 trait_def_id: DefId,
a2a8927a 44 trait_segment: &'_ hir::PathSegment<'_>,
5099ac24 45 is_impl: bool,
3dfed10e 46 ) {
5099ac24
FG
47 if self.tcx().features().unboxed_closures {
48 return;
49 }
50
3dfed10e 51 let trait_def = self.tcx().trait_def(trait_def_id);
5099ac24
FG
52 if !trait_def.paren_sugar {
53 if trait_segment.args().parenthesized {
54 // For now, require that parenthetical notation be used only with `Fn()` etc.
55 let mut err = feature_err(
56 &self.tcx().sess.parse_sess,
57 sym::unboxed_closures,
58 span,
59 "parenthetical notation is only stable when used with `Fn`-family traits",
60 );
61 err.emit();
62 }
3dfed10e 63
5099ac24
FG
64 return;
65 }
66
67 let sess = self.tcx().sess;
68
69 if !trait_segment.args().parenthesized {
3dfed10e 70 // For now, require that parenthetical notation be used only with `Fn()` etc.
5099ac24
FG
71 let mut err = feature_err(
72 &sess.parse_sess,
73 sym::unboxed_closures,
74 span,
75 "the precise format of `Fn`-family traits' type parameters is subject to change",
76 );
77 // Do not suggest the other syntax if we are in trait impl:
5e7ed085 78 // the desugaring would contain an associated type constraint.
5099ac24
FG
79 if !is_impl {
80 let args = trait_segment
81 .args
82 .as_ref()
83 .and_then(|args| args.args.get(0))
84 .and_then(|arg| match arg {
85 hir::GenericArg::Type(ty) => match ty.kind {
86 hir::TyKind::Tup(t) => t
87 .iter()
88 .map(|e| sess.source_map().span_to_snippet(e.span))
89 .collect::<Result<Vec<_>, _>>()
90 .map(|a| a.join(", ")),
91 _ => sess.source_map().span_to_snippet(ty.span),
92 }
93 .map(|s| format!("({})", s))
94 .ok(),
95 _ => None,
96 })
97 .unwrap_or_else(|| "()".to_string());
98 let ret = trait_segment
99 .args()
100 .bindings
101 .iter()
102 .find_map(|b| match (b.ident.name == sym::Output, &b.kind) {
103 (true, hir::TypeBindingKind::Equality { term }) => {
104 let span = match term {
105 hir::Term::Ty(ty) => ty.span,
106 hir::Term::Const(c) => self.tcx().hir().span(c.hir_id),
107 };
108 sess.source_map().span_to_snippet(span).ok()
109 }
110 _ => None,
111 })
112 .unwrap_or_else(|| "()".to_string());
113 err.span_suggestion(
114 span,
115 "use parenthetical notation instead",
116 format!("{}{} -> {}", trait_segment.ident, args, ret),
117 Applicability::MaybeIncorrect,
118 );
3dfed10e
XL
119 }
120 err.emit();
121 }
5099ac24
FG
122
123 if is_impl {
124 let trait_name = self.tcx().def_path_str(trait_def_id);
04454e1e 125 self.tcx().sess.emit_err(ManualImplementation { span, trait_name });
5099ac24 126 }
3dfed10e
XL
127 }
128
129 pub(crate) fn complain_about_assoc_type_not_found<I>(
130 &self,
131 all_candidates: impl Fn() -> I,
132 ty_param_name: &str,
133 assoc_name: Ident,
134 span: Span,
5e7ed085
FG
135 ) -> ErrorGuaranteed
136 where
3dfed10e
XL
137 I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
138 {
139 // The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a
140 // valid span, so we point at the whole path segment instead.
141 let span = if assoc_name.span != DUMMY_SP { assoc_name.span } else { span };
142 let mut err = struct_span_err!(
143 self.tcx().sess,
144 span,
145 E0220,
146 "associated type `{}` not found for `{}`",
147 assoc_name,
148 ty_param_name
149 );
150
151 let all_candidate_names: Vec<_> = all_candidates()
5099ac24 152 .flat_map(|r| self.tcx().associated_items(r.def_id()).in_definition_order())
3dfed10e 153 .filter_map(
5099ac24 154 |item| if item.kind == ty::AssocKind::Type { Some(item.name) } else { None },
3dfed10e
XL
155 )
156 .collect();
157
158 if let (Some(suggested_name), true) = (
fc512014 159 find_best_match_for_name(&all_candidate_names, assoc_name.name, None),
3dfed10e
XL
160 assoc_name.span != DUMMY_SP,
161 ) {
162 err.span_suggestion(
163 assoc_name.span,
164 "there is an associated type with a similar name",
923072b8 165 suggested_name,
3dfed10e
XL
166 Applicability::MaybeIncorrect,
167 );
064997fb 168 return err.emit();
3dfed10e
XL
169 }
170
064997fb
FG
171 // If we didn't find a good item in the supertraits (or couldn't get
172 // the supertraits), like in ItemCtxt, then look more generally from
173 // all visible traits. If there's one clear winner, just suggest that.
174
175 let visible_traits: Vec<_> = self
176 .tcx()
177 .all_traits()
178 .filter(|trait_def_id| {
179 let viz = self.tcx().visibility(*trait_def_id);
180 if let Some(def_id) = self.item_def_id() {
181 viz.is_accessible_from(def_id, self.tcx())
182 } else {
183 viz.is_visible_locally()
184 }
185 })
186 .collect();
187
188 let wider_candidate_names: Vec<_> = visible_traits
189 .iter()
190 .flat_map(|trait_def_id| {
191 self.tcx().associated_items(*trait_def_id).in_definition_order()
192 })
193 .filter_map(
194 |item| if item.kind == ty::AssocKind::Type { Some(item.name) } else { None },
195 )
196 .collect();
197
198 if let (Some(suggested_name), true) = (
199 find_best_match_for_name(&wider_candidate_names, assoc_name.name, None),
200 assoc_name.span != DUMMY_SP,
201 ) {
202 if let [best_trait] = visible_traits
203 .iter()
204 .filter(|trait_def_id| {
205 self.tcx()
206 .associated_items(*trait_def_id)
207 .filter_by_name_unhygienic(suggested_name)
208 .any(|item| item.kind == ty::AssocKind::Type)
209 })
210 .collect::<Vec<_>>()[..]
211 {
212 err.span_label(
213 assoc_name.span,
214 format!(
215 "there is a similarly named associated type `{suggested_name}` in the trait `{}`",
216 self.tcx().def_path_str(*best_trait)
217 ),
218 );
219 return err.emit();
220 }
221 }
222
223 err.span_label(span, format!("associated type `{}` not found", assoc_name));
5e7ed085 224 err.emit()
3dfed10e
XL
225 }
226
227 /// When there are any missing associated types, emit an E0191 error and attempt to supply a
228 /// reasonable suggestion on how to write it. For the case of multiple associated types in the
c295e0f8 229 /// same trait bound have the same name (as they come from different supertraits), we instead
3dfed10e
XL
230 /// emit a generic note suggesting using a `where` clause to constraint instead.
231 pub(crate) fn complain_about_missing_associated_types(
232 &self,
233 associated_types: FxHashMap<Span, BTreeSet<DefId>>,
234 potential_assoc_types: Vec<Span>,
235 trait_bounds: &[hir::PolyTraitRef<'_>],
236 ) {
237 if associated_types.values().all(|v| v.is_empty()) {
238 return;
239 }
240 let tcx = self.tcx();
241 // FIXME: Marked `mut` so that we can replace the spans further below with a more
242 // appropriate one, but this should be handled earlier in the span assignment.
243 let mut associated_types: FxHashMap<Span, Vec<_>> = associated_types
244 .into_iter()
245 .map(|(span, def_ids)| {
246 (span, def_ids.into_iter().map(|did| tcx.associated_item(did)).collect())
247 })
248 .collect();
249 let mut names = vec![];
250
251 // Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
252 // `issue-22560.rs`.
253 let mut trait_bound_spans: Vec<Span> = vec![];
254 for (span, items) in &associated_types {
255 if !items.is_empty() {
256 trait_bound_spans.push(*span);
257 }
258 for assoc_item in items {
064997fb 259 let trait_def_id = assoc_item.container_id(tcx);
3dfed10e
XL
260 names.push(format!(
261 "`{}` (from trait `{}`)",
5099ac24 262 assoc_item.name,
3dfed10e
XL
263 tcx.def_path_str(trait_def_id),
264 ));
265 }
266 }
267 if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) {
6a06907d 268 match bound.trait_ref.path.segments {
3dfed10e
XL
269 // FIXME: `trait_ref.path.span` can point to a full path with multiple
270 // segments, even though `trait_ref.path.segments` is of length `1`. Work
271 // around that bug here, even though it should be fixed elsewhere.
272 // This would otherwise cause an invalid suggestion. For an example, look at
273 // `src/test/ui/issues/issue-28344.rs` where instead of the following:
274 //
275 // error[E0191]: the value of the associated type `Output`
276 // (from trait `std::ops::BitXor`) must be specified
277 // --> $DIR/issue-28344.rs:4:17
278 // |
279 // LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8);
280 // | ^^^^^^ help: specify the associated type:
281 // | `BitXor<Output = Type>`
282 //
283 // we would output:
284 //
285 // error[E0191]: the value of the associated type `Output`
286 // (from trait `std::ops::BitXor`) must be specified
287 // --> $DIR/issue-28344.rs:4:17
288 // |
289 // LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8);
290 // | ^^^^^^^^^^^^^ help: specify the associated type:
291 // | `BitXor::bitor<Output = Type>`
292 [segment] if segment.args.is_none() => {
293 trait_bound_spans = vec![segment.ident.span];
294 associated_types = associated_types
295 .into_iter()
296 .map(|(_, items)| (segment.ident.span, items))
297 .collect();
298 }
299 _ => {}
300 }
301 }
302 names.sort();
303 trait_bound_spans.sort();
304 let mut err = struct_span_err!(
305 tcx.sess,
306 trait_bound_spans,
307 E0191,
308 "the value of the associated type{} {} must be specified",
309 pluralize!(names.len()),
310 names.join(", "),
311 );
312 let mut suggestions = vec![];
313 let mut types_count = 0;
314 let mut where_constraints = vec![];
04454e1e 315 let mut already_has_generics_args_suggestion = false;
3dfed10e
XL
316 for (span, assoc_items) in &associated_types {
317 let mut names: FxHashMap<_, usize> = FxHashMap::default();
318 for item in assoc_items {
319 types_count += 1;
5099ac24 320 *names.entry(item.name).or_insert(0) += 1;
3dfed10e
XL
321 }
322 let mut dupes = false;
323 for item in assoc_items {
5099ac24 324 let prefix = if names[&item.name] > 1 {
064997fb 325 let trait_def_id = item.container_id(tcx);
3dfed10e
XL
326 dupes = true;
327 format!("{}::", tcx.def_path_str(trait_def_id))
328 } else {
329 String::new()
330 };
331 if let Some(sp) = tcx.hir().span_if_local(item.def_id) {
5099ac24 332 err.span_label(sp, format!("`{}{}` defined here", prefix, item.name));
3dfed10e
XL
333 }
334 }
335 if potential_assoc_types.len() == assoc_items.len() {
04454e1e
FG
336 // When the amount of missing associated types equals the number of
337 // extra type arguments present. A suggesting to replace the generic args with
338 // associated types is already emitted.
339 already_has_generics_args_suggestion = true;
3dfed10e
XL
340 } else if let (Ok(snippet), false) =
341 (tcx.sess.source_map().span_to_snippet(*span), dupes)
342 {
343 let types: Vec<_> =
5099ac24 344 assoc_items.iter().map(|item| format!("{} = Type", item.name)).collect();
3dfed10e
XL
345 let code = if snippet.ends_with('>') {
346 // The user wrote `Trait<'a>` or similar and we don't have a type we can
347 // suggest, but at least we can clue them to the correct syntax
348 // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
349 // suggestion.
350 format!("{}, {}>", &snippet[..snippet.len() - 1], types.join(", "))
351 } else {
352 // The user wrote `Iterator`, so we don't have a type we can suggest, but at
353 // least we can clue them to the correct syntax `Iterator<Item = Type>`.
354 format!("{}<{}>", snippet, types.join(", "))
355 };
356 suggestions.push((*span, code));
357 } else if dupes {
358 where_constraints.push(*span);
359 }
360 }
361 let where_msg = "consider introducing a new type parameter, adding `where` constraints \
362 using the fully-qualified path to the associated types";
363 if !where_constraints.is_empty() && suggestions.is_empty() {
364 // If there are duplicates associated type names and a single trait bound do not
c295e0f8 365 // use structured suggestion, it means that there are multiple supertraits with
3dfed10e
XL
366 // the same associated type name.
367 err.help(where_msg);
368 }
04454e1e 369 if suggestions.len() != 1 || already_has_generics_args_suggestion {
3dfed10e
XL
370 // We don't need this label if there's an inline suggestion, show otherwise.
371 for (span, assoc_items) in &associated_types {
372 let mut names: FxHashMap<_, usize> = FxHashMap::default();
373 for item in assoc_items {
374 types_count += 1;
5099ac24 375 *names.entry(item.name).or_insert(0) += 1;
3dfed10e
XL
376 }
377 let mut label = vec![];
378 for item in assoc_items {
5099ac24 379 let postfix = if names[&item.name] > 1 {
064997fb 380 let trait_def_id = item.container_id(tcx);
3dfed10e
XL
381 format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id))
382 } else {
383 String::new()
384 };
5099ac24 385 label.push(format!("`{}`{}", item.name, postfix));
3dfed10e
XL
386 }
387 if !label.is_empty() {
388 err.span_label(
389 *span,
390 format!(
391 "associated type{} {} must be specified",
392 pluralize!(label.len()),
393 label.join(", "),
394 ),
395 );
396 }
397 }
398 }
399 if !suggestions.is_empty() {
400 err.multipart_suggestion(
401 &format!("specify the associated type{}", pluralize!(types_count)),
402 suggestions,
403 Applicability::HasPlaceholders,
404 );
405 if !where_constraints.is_empty() {
406 err.span_help(where_constraints, where_msg);
407 }
408 }
409 err.emit();
410 }
411}