1 //! Give useful errors and suggestions to users when an item can't be
2 //! found or is otherwise invalid.
4 use crate::check::FnCtxt;
5 use crate::middle::lang_items::FnOnceTraitLangItem;
6 use crate::namespace::Namespace;
7 use crate::util::nodemap::FxHashSet;
8 use errors::{Applicability, DiagnosticBuilder, pluralise};
9 use rustc::hir::{self, ExprKind, Node, QPath};
10 use rustc::hir::def::{Res, DefKind};
11 use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
12 use rustc::hir::map as hir_map;
13 use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
14 use rustc::traits::Obligation;
15 use rustc::ty::{self, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable};
16 use rustc::ty::print::with_crate_prefix;
17 use syntax_pos::{Span, FileName};
19 use syntax::util::lev_distance;
21 use std::cmp::Ordering;
23 use super::{MethodError, NoMatchData, CandidateSource};
24 use super::probe::Mode;
26 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
27 fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
30 // Not all of these (e.g., unsafe fns) implement `FnOnce`,
31 // so we look for these beforehand.
35 // If it's not a simple function, look for things which implement `FnOnce`.
37 let fn_once = match tcx.lang_items().require(FnOnceTraitLangItem) {
38 Ok(fn_once) => fn_once,
39 Err(..) => return false,
42 self.autoderef(span, ty).any(|(ty, _)| {
44 let fn_once_substs = tcx.mk_substs_trait(ty, &[
45 self.next_ty_var(TypeVariableOrigin {
46 kind: TypeVariableOriginKind::MiscVariable,
50 let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
51 let poly_trait_ref = trait_ref.to_poly_trait_ref();
53 Obligation::misc(span,
56 poly_trait_ref.to_predicate());
57 self.predicate_may_hold(&obligation)
64 pub fn report_method_error<'b>(
68 item_name: ast::Ident,
69 source: SelfSource<'b>,
70 error: MethodError<'tcx>,
71 args: Option<&'tcx [hir::Expr]>,
72 ) -> Option<DiagnosticBuilder<'_>> {
75 // Avoid suggestions when we don't know what's going on.
76 if rcvr_ty.references_error() {
80 let print_disambiguation_help = |
81 err: &mut DiagnosticBuilder<'_>,
85 "to disambiguate the method call, write `{}::{}({}{})` instead",
88 if rcvr_ty.is_region_ptr() && args.is_some() {
89 if rcvr_ty.is_mutable_ptr() {
99 .map(|arg| self.tcx.sess.source_map().span_to_snippet(arg.span)
100 .unwrap_or_else(|_| "...".to_owned()))
103 ).unwrap_or_else(|| "...".to_owned())
107 let report_candidates = |
109 err: &mut DiagnosticBuilder<'_>,
110 mut sources: Vec<CandidateSource>,
114 // Dynamic limit to avoid hiding just one candidate, which is silly.
115 let limit = if sources.len() == 5 { 5 } else { 4 };
117 for (idx, source) in sources.iter().take(limit).enumerate() {
119 CandidateSource::ImplSource(impl_did) => {
120 // Provide the best span we can. Use the item, if local to crate, else
121 // the impl, if local to crate (item may be defaulted), else nothing.
122 let item = match self.associated_item(
127 let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
128 self.associated_item(
129 impl_trait_ref.def_id,
137 let note_span = self.tcx.hir().span_if_local(item.def_id).or_else(|| {
138 self.tcx.hir().span_if_local(impl_did)
141 let impl_ty = self.impl_self_ty(span, impl_did).ty;
143 let insertion = match self.tcx.impl_trait_ref(impl_did) {
144 None => String::new(),
146 format!(" of the trait `{}`",
147 self.tcx.def_path_str(trait_ref.def_id))
151 let note_str = if sources.len() > 1 {
152 format!("candidate #{} is defined in an impl{} for the type `{}`",
157 format!("the candidate is defined in an impl{} for the type `{}`",
161 if let Some(note_span) = note_span {
162 // We have a span pointing to the method. Show note with snippet.
163 err.span_note(self.tcx.sess.source_map().def_span(note_span),
168 if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
169 print_disambiguation_help(err, self.tcx.def_path_str(trait_ref.def_id));
172 CandidateSource::TraitSource(trait_did) => {
173 let item = match self.associated_item(
181 let item_span = self.tcx.sess.source_map()
182 .def_span(self.tcx.def_span(item.def_id));
183 if sources.len() > 1 {
186 "candidate #{} is defined in the trait `{}`",
188 self.tcx.def_path_str(trait_did));
192 "the candidate is defined in the trait `{}`",
193 self.tcx.def_path_str(trait_did));
195 print_disambiguation_help(err, self.tcx.def_path_str(trait_did));
199 if sources.len() > limit {
200 err.note(&format!("and {} others", sources.len() - limit));
205 MethodError::NoMatch(NoMatchData {
206 static_candidates: static_sources,
207 unsatisfied_predicates,
214 let actual = self.resolve_vars_if_possible(&rcvr_ty);
215 let ty_str = self.ty_to_string(actual);
216 let is_method = mode == Mode::MethodCall;
217 let item_kind = if is_method {
219 } else if actual.is_enum() {
220 "variant or associated item"
222 match (item_name.as_str().chars().next(), actual.is_fresh_ty()) {
223 (Some(name), false) if name.is_lowercase() => {
224 "function or associated item"
226 (Some(_), false) => "associated item",
227 (Some(_), true) | (None, false) => {
228 "variant or associated item"
230 (None, true) => "variant",
233 let mut err = if !actual.references_error() {
234 // Suggest clamping down the type if the method that is being attempted to
235 // be used exists at all, and the type is an ambiguous numeric type
236 // ({integer}/{float}).
237 let mut candidates = all_traits(self.tcx)
240 self.associated_item(info.def_id, item_name, Namespace::Value)
242 if let (true, false, SelfSource::MethodCall(expr), Some(_)) =
243 (actual.is_numeric(),
244 actual.has_concrete_skeleton(),
247 let mut err = struct_span_err!(
251 "can't call {} `{}` on ambiguous numeric type `{}`",
256 let concrete_type = if actual.is_integral() {
262 ExprKind::Lit(ref lit) => {
264 let snippet = tcx.sess.source_map().span_to_snippet(lit.span)
265 .unwrap_or_else(|_| "<numeric literal>".to_owned());
269 &format!("you must specify a concrete type for \
270 this numeric value, like `{}`", concrete_type),
271 format!("{}_{}", snippet, concrete_type),
272 Applicability::MaybeIncorrect,
275 ExprKind::Path(ref qpath) => {
277 if let &QPath::Resolved(_, ref path) = &qpath {
278 if let hir::def::Res::Local(hir_id) = path.res {
279 let span = tcx.hir().span(hir_id);
280 let snippet = tcx.sess.source_map().span_to_snippet(span);
281 let filename = tcx.sess.source_map().span_to_filename(span);
283 let parent_node = self.tcx.hir().get(
284 self.tcx.hir().get_parent_node(hir_id),
287 "you must specify a type for this binding, like `{}`",
291 match (filename, parent_node, snippet) {
292 (FileName::Real(_), Node::Local(hir::Local {
293 source: hir::LocalSource::Normal,
296 }), Ok(ref snippet)) => {
298 // account for `let x: _ = 42;`
300 span.to(ty.as_ref().map(|ty| ty.span)
303 format!("{}: {}", snippet, concrete_type),
304 Applicability::MaybeIncorrect,
308 err.span_label(span, msg);
319 span = item_name.span;
320 let mut err = struct_span_err!(
324 "no {} named `{}` found for type `{}` in the current scope",
329 if let Some(span) = tcx.sess.confused_type_with_std_module.borrow()
332 if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*span) {
335 "you are looking for the module in `std`, \
336 not the primitive type",
337 format!("std::{}", snippet),
338 Applicability::MachineApplicable,
342 if let ty::RawPtr(_) = &actual.kind {
343 err.note("try using `<*const T>::as_ref()` to get a reference to the \
344 type behind the pointer: https://doc.rust-lang.org/std/\
345 primitive.pointer.html#method.as_ref");
346 err.note("using `<*const T>::as_ref()` on a pointer \
347 which is unaligned or points to invalid \
348 or uninitialized memory is undefined behavior");
353 tcx.sess.diagnostic().struct_dummy()
356 if let Some(def) = actual.ty_adt_def() {
357 if let Some(full_sp) = tcx.hir().span_if_local(def.did) {
358 let def_sp = tcx.sess.source_map().def_span(full_sp);
359 err.span_label(def_sp, format!("{} `{}` not found {}",
362 if def.is_enum() && !is_method {
370 // If the method name is the name of a field with a function or closure type,
371 // give a helping note that it has to be called as `(x.f)(...)`.
372 if let SelfSource::MethodCall(expr) = source {
373 let field_receiver = self
374 .autoderef(span, rcvr_ty)
375 .find_map(|(ty, _)| match ty.kind {
376 ty::Adt(def, substs) if !def.is_enum() => {
377 let variant = &def.non_enum_variant();
378 self.tcx.find_field_index(item_name, variant).map(|index| {
379 let field = &variant.fields[index];
380 let field_ty = field.ty(tcx, substs);
387 if let Some((field, field_ty)) = field_receiver {
388 let scope = self.tcx.hir().get_module_parent(self.body_id);
389 let is_accessible = field.vis.is_accessible_from(scope, self.tcx);
392 if self.is_fn_ty(&field_ty, span) {
393 let expr_span = expr.span.to(item_name.span);
394 err.multipart_suggestion(
396 "to call the function stored in `{}`, \
397 surround the field access with parentheses",
401 (expr_span.shrink_to_lo(), '('.to_string()),
402 (expr_span.shrink_to_hi(), ')'.to_string()),
404 Applicability::MachineApplicable,
407 let call_expr = self.tcx.hir().expect_expr(
408 self.tcx.hir().get_parent_node(expr.hir_id),
411 if let Some(span) = call_expr.span.trim_start(item_name.span) {
414 "remove the arguments",
416 Applicability::MaybeIncorrect,
422 let field_kind = if is_accessible {
427 err.span_label(item_name.span, format!("{}, not a method", field_kind));
428 } else if lev_candidate.is_none() && static_sources.is_empty() {
429 err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
430 self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
433 err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
434 self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
437 if self.is_fn_ty(&rcvr_ty, span) {
438 macro_rules! report_function {
439 ($span:expr, $name:expr) => {
440 err.note(&format!("{} is a function, perhaps you wish to call it",
445 if let SelfSource::MethodCall(expr) = source {
446 if let Ok(expr_string) = tcx.sess.source_map().span_to_snippet(expr.span) {
447 report_function!(expr.span, expr_string);
448 } else if let ExprKind::Path(QPath::Resolved(_, ref path)) =
451 if let Some(segment) = path.segments.last() {
452 report_function!(expr.span, segment.ident);
458 if !static_sources.is_empty() {
459 err.note("found the following associated functions; to be used as methods, \
460 functions must have a `self` parameter");
461 err.span_label(span, "this is an associated function, not a method");
463 if static_sources.len() == 1 {
464 let ty_str = if let Some(CandidateSource::ImplSource(
466 )) = static_sources.get(0) {
467 // When the "method" is resolved through dereferencing, we really want the
468 // original type that has the associated function for accurate suggestions.
470 let ty = self.impl_self_ty(span, *impl_did).ty;
471 match (&ty.peel_refs().kind, &actual.peel_refs().kind) {
472 (ty::Adt(def, _), ty::Adt(def_actual, _)) if def == def_actual => {
473 // Use `actual` as it will have more `substs` filled in.
474 self.ty_to_value_string(actual.peel_refs())
476 _ => self.ty_to_value_string(ty.peel_refs()),
479 self.ty_to_value_string(actual.peel_refs())
481 if let SelfSource::MethodCall(expr) = source {
484 "use associated function syntax instead",
485 format!("{}::{}", ty_str, item_name),
486 Applicability::MachineApplicable,
496 report_candidates(span, &mut err, static_sources);
497 } else if static_sources.len() > 1 {
498 report_candidates(span, &mut err, static_sources);
501 if !unsatisfied_predicates.is_empty() {
502 let mut bound_list = unsatisfied_predicates.iter()
503 .map(|p| format!("`{} : {}`", p.self_ty(), p))
504 .collect::<Vec<_>>();
506 bound_list.dedup(); // #35677
507 let bound_list = bound_list.join("\n");
508 err.note(&format!("the method `{}` exists but the following trait bounds \
509 were not satisfied:\n{}",
514 if actual.is_numeric() && actual.is_fresh() {
517 self.suggest_traits_to_import(&mut err,
522 out_of_scope_traits);
525 if actual.is_enum() {
526 let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
527 if let Some(suggestion) = lev_distance::find_best_match_for_name(
528 adt_def.variants.iter().map(|s| &s.ident.name),
534 "there is a variant with a similar name",
535 suggestion.to_string(),
536 Applicability::MaybeIncorrect,
541 let mut fallback_span = true;
542 let msg = "remove this method call";
543 if item_name.as_str() == "as_str" && actual.peel_refs().is_str() {
544 if let SelfSource::MethodCall(expr) = source {
545 let call_expr = self.tcx.hir().expect_expr(
546 self.tcx.hir().get_parent_node(expr.hir_id),
548 if let Some(span) = call_expr.span.trim_start(expr.span) {
553 Applicability::MachineApplicable,
555 fallback_span = false;
559 err.span_label(span, msg);
561 } else if let Some(lev_candidate) = lev_candidate {
562 let def_kind = lev_candidate.def_kind();
566 "there is {} {} with a similar name",
568 def_kind.descr(lev_candidate.def_id),
570 lev_candidate.ident.to_string(),
571 Applicability::MaybeIncorrect,
578 MethodError::Ambiguity(sources) => {
579 let mut err = struct_span_err!(self.sess(),
582 "multiple applicable items in scope");
583 err.span_label(span, format!("multiple `{}` found", item_name));
585 report_candidates(span, &mut err, sources);
589 MethodError::PrivateMatch(kind, def_id, out_of_scope_traits) => {
590 let mut err = struct_span_err!(self.tcx.sess, span, E0624,
591 "{} `{}` is private", kind.descr(def_id), item_name);
592 self.suggest_valid_traits(&mut err, out_of_scope_traits);
596 MethodError::IllegalSizedBound(candidates, needs_mut) => {
597 let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
598 let mut err = self.sess().struct_span_err(span, &msg);
599 if !candidates.is_empty() {
601 "{an}other candidate{s} {were} found in the following trait{s}, perhaps \
602 add a `use` for {one_of_them}:",
603 an = if candidates.len() == 1 {"an" } else { "" },
604 s = pluralise!(candidates.len()),
605 were = if candidates.len() == 1 { "was" } else { "were" },
606 one_of_them = if candidates.len() == 1 {
612 self.suggest_use_candidates(&mut err, help, candidates);
614 if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind {
616 let trait_type = self.tcx.mk_ref(region, ty::TypeAndMut {
618 mutbl: mutability.invert(),
620 err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty));
626 MethodError::BadReturnType => {
627 bug!("no return type expectations but got BadReturnType")
633 /// Print out the type for use in value namespace.
634 fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
636 ty::Adt(def, substs) => format!("{}", ty::Instance::new(def.did, substs)),
637 _ => self.ty_to_string(ty),
641 fn suggest_use_candidates(&self,
642 err: &mut DiagnosticBuilder<'_>,
644 candidates: Vec<DefId>) {
645 let module_did = self.tcx.hir().get_module_parent(self.body_id);
646 let module_id = self.tcx.hir().as_local_hir_id(module_did).unwrap();
647 let krate = self.tcx.hir().krate();
648 let (span, found_use) = UsePlacementFinder::check(self.tcx, krate, module_id);
649 if let Some(span) = span {
650 let path_strings = candidates.iter().map(|did| {
651 // Produce an additional newline to separate the new use statement
652 // from the directly following item.
653 let additional_newline = if found_use {
660 with_crate_prefix(|| self.tcx.def_path_str(*did)),
665 err.span_suggestions(span, &msg, path_strings, Applicability::MaybeIncorrect);
667 let limit = if candidates.len() == 5 { 5 } else { 4 };
668 for (i, trait_did) in candidates.iter().take(limit).enumerate() {
669 if candidates.len() > 1 {
672 "\ncandidate #{}: `use {};`",
674 with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
681 with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
686 if candidates.len() > limit {
687 msg.push_str(&format!("\nand {} others", candidates.len() - limit));
693 fn suggest_valid_traits(
695 err: &mut DiagnosticBuilder<'_>,
696 valid_out_of_scope_traits: Vec<DefId>,
698 if !valid_out_of_scope_traits.is_empty() {
699 let mut candidates = valid_out_of_scope_traits;
702 err.help("items from traits can only be used if the trait is in scope");
704 "the following {traits_are} implemented but not in scope; \
705 perhaps add a `use` for {one_of_them}:",
706 traits_are = if candidates.len() == 1 {
711 one_of_them = if candidates.len() == 1 {
718 self.suggest_use_candidates(err, msg, candidates);
725 fn suggest_traits_to_import<'b>(
727 err: &mut DiagnosticBuilder<'_>,
730 item_name: ast::Ident,
731 source: SelfSource<'b>,
732 valid_out_of_scope_traits: Vec<DefId>,
734 if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
738 let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source);
740 // There are no traits implemented, so lets suggest some traits to
741 // implement, by finding ones that have the item name, and are
742 // legal to implement.
743 let mut candidates = all_traits(self.tcx)
746 // We approximate the coherence rules to only suggest
747 // traits that are legal to implement by requiring that
748 // either the type or trait is local. Multi-dispatch means
749 // this isn't perfect (that is, there are cases when
750 // implementing a trait would be legal but is rejected
752 (type_is_local || info.def_id.is_local()) &&
753 self.associated_item(info.def_id, item_name, Namespace::Value)
755 // We only want to suggest public or local traits (#45781).
756 item.vis == ty::Visibility::Public || info.def_id.is_local()
760 .collect::<Vec<_>>();
762 if !candidates.is_empty() {
763 // Sort from most relevant to least relevant.
764 candidates.sort_by(|a, b| a.cmp(b).reverse());
767 let param_type = match rcvr_ty.kind {
768 ty::Param(param) => Some(param),
769 ty::Ref(_, ty, _) => match ty.kind {
770 ty::Param(param) => Some(param),
775 err.help(if param_type.is_some() {
776 "items from traits can only be used if the type parameter is bounded by the trait"
778 "items from traits can only be used if the trait is implemented and in scope"
780 let message = |action| format!(
781 "the following {traits_define} an item `{name}`, perhaps you need to {action} \
783 traits_define = if candidates.len() == 1 {
789 one_of_them = if candidates.len() == 1 {
796 // Obtain the span for `param` and use it for a structured suggestion.
797 let mut suggested = false;
798 if let (Some(ref param), Some(ref table)) = (param_type, self.in_progress_tables) {
799 let table = table.borrow();
800 if let Some(did) = table.local_id_root {
801 let generics = self.tcx.generics_of(did);
802 let type_param = generics.type_param(param, self.tcx);
803 let hir = &self.tcx.hir();
804 if let Some(id) = hir.as_local_hir_id(type_param.def_id) {
805 // Get the `hir::Param` to verify whether it already has any bounds.
806 // We do this to avoid suggesting code that ends up as `T: FooBar`,
807 // instead we suggest `T: Foo + Bar` in that case.
809 Node::GenericParam(ref param) => {
810 let mut impl_trait = false;
811 let has_bounds = if let hir::GenericParamKind::Type {
812 synthetic: Some(_), ..
814 // We've found `fn foo(x: impl Trait)` instead of
815 // `fn foo<T>(x: T)`. We want to suggest the correct
816 // `fn foo(x: impl Trait + TraitBound)` instead of
817 // `fn foo<T: TraitBound>(x: T)`. (#63706)
823 let sp = hir.span(id);
824 let sp = if let Some(first_bound) = has_bounds {
825 // `sp` only covers `T`, change it so that it covers
826 // `T:` when appropriate
827 sp.until(first_bound.span())
831 // FIXME: contrast `t.def_id` against `param.bounds` to not suggest
832 // traits already there. That can happen when the cause is that
833 // we're in a const scope or associated function used as a method.
834 err.span_suggestions(
837 "restrict type parameter `{}` with",
838 param.name.ident().as_str(),
840 candidates.iter().map(|t| format!(
842 param.name.ident().as_str(),
843 if impl_trait { " +" } else { ":" },
844 self.tcx.def_path_str(t.def_id),
845 if has_bounds.is_some() { " + "} else { "" },
847 Applicability::MaybeIncorrect,
851 Node::Item(hir::Item {
852 kind: hir::ItemKind::Trait(.., bounds, _), ident, ..
854 let (sp, sep, article) = if bounds.is_empty() {
855 (ident.span.shrink_to_hi(), ":", "a")
857 (bounds.last().unwrap().span().shrink_to_hi(), " +", "another")
859 err.span_suggestions(
861 &message(format!("add {} supertrait for", article)),
862 candidates.iter().map(|t| format!(
865 self.tcx.def_path_str(t.def_id),
867 Applicability::MaybeIncorrect,
878 let mut msg = message(if let Some(param) = param_type {
879 format!("restrict type parameter `{}` with", param)
881 "implement".to_string()
883 for (i, trait_info) in candidates.iter().enumerate() {
884 msg.push_str(&format!(
885 "\ncandidate #{}: `{}`",
887 self.tcx.def_path_str(trait_info.def_id),
895 /// Checks whether there is a local type somewhere in the chain of
896 /// autoderefs of `rcvr_ty`.
897 fn type_derefs_to_local(&self,
900 source: SelfSource<'_>) -> bool {
901 fn is_local(ty: Ty<'_>) -> bool {
903 ty::Adt(def, _) => def.did.is_local(),
904 ty::Foreign(did) => did.is_local(),
906 ty::Dynamic(ref tr, ..) =>
907 tr.principal().map(|d| d.def_id().is_local()).unwrap_or(false),
909 ty::Param(_) => true,
911 // Everything else (primitive types, etc.) is effectively
912 // non-local (there are "edge" cases, e.g., `(LocalType,)`, but
913 // the noise from these sort of types is usually just really
914 // annoying, rather than any sort of help).
919 // This occurs for UFCS desugaring of `T::method`, where there is no
920 // receiver expression for the method call, and thus no autoderef.
921 if let SelfSource::QPath(_) = source {
922 return is_local(self.resolve_vars_with_obligations(rcvr_ty));
925 self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
929 #[derive(Copy, Clone)]
930 pub enum SelfSource<'a> {
932 MethodCall(&'a hir::Expr /* rcvr */),
935 #[derive(Copy, Clone)]
936 pub struct TraitInfo {
940 impl PartialEq for TraitInfo {
941 fn eq(&self, other: &TraitInfo) -> bool {
942 self.cmp(other) == Ordering::Equal
945 impl Eq for TraitInfo {}
946 impl PartialOrd for TraitInfo {
947 fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> {
948 Some(self.cmp(other))
951 impl Ord for TraitInfo {
952 fn cmp(&self, other: &TraitInfo) -> Ordering {
953 // Local crates are more important than remote ones (local:
954 // `cnum == 0`), and otherwise we throw in the defid for totality.
956 let lhs = (other.def_id.krate, other.def_id);
957 let rhs = (self.def_id.krate, self.def_id);
962 /// Retrieves all traits in this crate and any dependent crates.
963 pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
964 tcx.all_traits(LOCAL_CRATE).iter().map(|&def_id| TraitInfo { def_id }).collect()
967 /// Computes all traits in this crate and any dependent crates.
968 fn compute_all_traits(tcx: TyCtxt<'_>) -> Vec<DefId> {
969 use hir::itemlikevisit;
971 let mut traits = vec![];
975 struct Visitor<'a, 'tcx> {
976 map: &'a hir_map::Map<'tcx>,
977 traits: &'a mut Vec<DefId>,
980 impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> {
981 fn visit_item(&mut self, i: &'v hir::Item) {
983 hir::ItemKind::Trait(..) |
984 hir::ItemKind::TraitAlias(..) => {
985 let def_id = self.map.local_def_id(i.hir_id);
986 self.traits.push(def_id);
992 fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {}
994 fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {}
997 tcx.hir().krate().visit_all_item_likes(&mut Visitor {
1004 let mut external_mods = FxHashSet::default();
1005 fn handle_external_res(
1007 traits: &mut Vec<DefId>,
1008 external_mods: &mut FxHashSet<DefId>,
1012 Res::Def(DefKind::Trait, def_id) |
1013 Res::Def(DefKind::TraitAlias, def_id) => {
1014 traits.push(def_id);
1016 Res::Def(DefKind::Mod, def_id) => {
1017 if !external_mods.insert(def_id) {
1020 for child in tcx.item_children(def_id).iter() {
1021 handle_external_res(tcx, traits, external_mods, child.res)
1027 for &cnum in tcx.crates().iter() {
1028 let def_id = DefId {
1030 index: CRATE_DEF_INDEX,
1032 handle_external_res(tcx, &mut traits, &mut external_mods, Res::Def(DefKind::Mod, def_id));
1038 pub fn provide(providers: &mut ty::query::Providers<'_>) {
1039 providers.all_traits = |tcx, cnum| {
1040 assert_eq!(cnum, LOCAL_CRATE);
1041 &tcx.arena.alloc(compute_all_traits(tcx))[..]
1045 struct UsePlacementFinder<'tcx> {
1046 target_module: hir::HirId,
1052 impl UsePlacementFinder<'tcx> {
1055 krate: &'tcx hir::Crate,
1056 target_module: hir::HirId,
1057 ) -> (Option<Span>, bool) {
1058 let mut finder = UsePlacementFinder {
1064 hir::intravisit::walk_crate(&mut finder, krate);
1065 (finder.span, finder.found_use)
1069 impl hir::intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> {
1072 module: &'tcx hir::Mod,
1076 if self.span.is_some() {
1079 if hir_id != self.target_module {
1080 hir::intravisit::walk_mod(self, module, hir_id);
1083 // Find a `use` statement.
1084 for item_id in &module.item_ids {
1085 let item = self.tcx.hir().expect_item(item_id.id);
1087 hir::ItemKind::Use(..) => {
1088 // Don't suggest placing a `use` before the prelude
1089 // import or other generated ones.
1090 if !item.span.from_expansion() {
1091 self.span = Some(item.span.shrink_to_lo());
1092 self.found_use = true;
1096 // Don't place `use` before `extern crate`...
1097 hir::ItemKind::ExternCrate(_) => {}
1098 // ...but do place them before the first other item.
1099 _ => if self.span.map_or(true, |span| item.span < span ) {
1100 if !item.span.from_expansion() {
1101 // Don't insert between attributes and an item.
1102 if item.attrs.is_empty() {
1103 self.span = Some(item.span.shrink_to_lo());
1105 // Find the first attribute on the item.
1106 for attr in &item.attrs {
1107 if self.span.map_or(true, |span| attr.span < span) {
1108 self.span = Some(attr.span.shrink_to_lo());
1118 fn nested_visit_map<'this>(
1120 ) -> hir::intravisit::NestedVisitorMap<'this, 'tcx> {
1121 hir::intravisit::NestedVisitorMap::None