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