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};
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 ambiuous 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.sty {
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.sty {
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));
430 err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
431 self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
434 if self.is_fn_ty(&rcvr_ty, span) {
435 macro_rules! report_function {
436 ($span:expr, $name:expr) => {
437 err.note(&format!("{} is a function, perhaps you wish to call it",
442 if let SelfSource::MethodCall(expr) = source {
443 if let Ok(expr_string) = tcx.sess.source_map().span_to_snippet(expr.span) {
444 report_function!(expr.span, expr_string);
445 } else if let ExprKind::Path(QPath::Resolved(_, ref path)) =
448 if let Some(segment) = path.segments.last() {
449 report_function!(expr.span, segment.ident);
455 if !static_sources.is_empty() {
456 err.note("found the following associated functions; to be used as methods, \
457 functions must have a `self` parameter");
458 err.span_label(span, "this is an associated function, not a method");
460 if static_sources.len() == 1 {
461 if let SelfSource::MethodCall(expr) = source {
462 err.span_suggestion(expr.span.to(span),
463 "use associated function syntax instead",
465 self.ty_to_string(actual),
467 Applicability::MachineApplicable);
469 err.help(&format!("try with `{}::{}`",
470 self.ty_to_string(actual), item_name));
473 report_candidates(span, &mut err, static_sources);
474 } else if static_sources.len() > 1 {
475 report_candidates(span, &mut err, static_sources);
478 if !unsatisfied_predicates.is_empty() {
479 let mut bound_list = unsatisfied_predicates.iter()
480 .map(|p| format!("`{} : {}`", p.self_ty(), p))
481 .collect::<Vec<_>>();
483 bound_list.dedup(); // #35677
484 let bound_list = bound_list.join("\n");
485 err.note(&format!("the method `{}` exists but the following trait bounds \
486 were not satisfied:\n{}",
491 if actual.is_numeric() && actual.is_fresh() {
494 self.suggest_traits_to_import(&mut err,
499 out_of_scope_traits);
502 if actual.is_enum() {
503 let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
504 if let Some(suggestion) = lev_distance::find_best_match_for_name(
505 adt_def.variants.iter().map(|s| &s.ident.name),
511 "there is a variant with a similar name",
512 suggestion.to_string(),
513 Applicability::MaybeIncorrect,
518 if let Some(lev_candidate) = lev_candidate {
519 let def_kind = lev_candidate.def_kind();
523 "there is {} {} with a similar name",
525 def_kind.descr(lev_candidate.def_id),
527 lev_candidate.ident.to_string(),
528 Applicability::MaybeIncorrect,
535 MethodError::Ambiguity(sources) => {
536 let mut err = struct_span_err!(self.sess(),
539 "multiple applicable items in scope");
540 err.span_label(span, format!("multiple `{}` found", item_name));
542 report_candidates(span, &mut err, sources);
546 MethodError::PrivateMatch(kind, def_id, out_of_scope_traits) => {
547 let mut err = struct_span_err!(self.tcx.sess, span, E0624,
548 "{} `{}` is private", kind.descr(def_id), item_name);
549 self.suggest_valid_traits(&mut err, out_of_scope_traits);
553 MethodError::IllegalSizedBound(candidates) => {
554 let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
555 let mut err = self.sess().struct_span_err(span, &msg);
556 if !candidates.is_empty() {
557 let help = format!("{an}other candidate{s} {were} found in the following \
558 trait{s}, perhaps add a `use` for {one_of_them}:",
559 an = if candidates.len() == 1 {"an" } else { "" },
560 s = if candidates.len() == 1 { "" } else { "s" },
561 were = if candidates.len() == 1 { "was" } else { "were" },
562 one_of_them = if candidates.len() == 1 {
567 self.suggest_use_candidates(&mut err, help, candidates);
572 MethodError::BadReturnType => {
573 bug!("no return type expectations but got BadReturnType")
579 fn suggest_use_candidates(&self,
580 err: &mut DiagnosticBuilder<'_>,
582 candidates: Vec<DefId>) {
583 let module_did = self.tcx.hir().get_module_parent(self.body_id);
584 let module_id = self.tcx.hir().as_local_hir_id(module_did).unwrap();
585 let krate = self.tcx.hir().krate();
586 let (span, found_use) = UsePlacementFinder::check(self.tcx, krate, module_id);
587 if let Some(span) = span {
588 let path_strings = candidates.iter().map(|did| {
589 // Produce an additional newline to separate the new use statement
590 // from the directly following item.
591 let additional_newline = if found_use {
598 with_crate_prefix(|| self.tcx.def_path_str(*did)),
603 err.span_suggestions(span, &msg, path_strings, Applicability::MaybeIncorrect);
605 let limit = if candidates.len() == 5 { 5 } else { 4 };
606 for (i, trait_did) in candidates.iter().take(limit).enumerate() {
607 if candidates.len() > 1 {
610 "\ncandidate #{}: `use {};`",
612 with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
619 with_crate_prefix(|| self.tcx.def_path_str(*trait_did))
624 if candidates.len() > limit {
625 msg.push_str(&format!("\nand {} others", candidates.len() - limit));
631 fn suggest_valid_traits(&self,
632 err: &mut DiagnosticBuilder<'_>,
633 valid_out_of_scope_traits: Vec<DefId>) -> bool {
634 if !valid_out_of_scope_traits.is_empty() {
635 let mut candidates = valid_out_of_scope_traits;
638 err.help("items from traits can only be used if the trait is in scope");
639 let msg = format!("the following {traits_are} implemented but not in scope, \
640 perhaps add a `use` for {one_of_them}:",
641 traits_are = if candidates.len() == 1 {
646 one_of_them = if candidates.len() == 1 {
652 self.suggest_use_candidates(err, msg, candidates);
659 fn suggest_traits_to_import<'b>(
661 err: &mut DiagnosticBuilder<'_>,
664 item_name: ast::Ident,
665 source: SelfSource<'b>,
666 valid_out_of_scope_traits: Vec<DefId>,
668 if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
672 let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source);
674 // There are no traits implemented, so lets suggest some traits to
675 // implement, by finding ones that have the item name, and are
676 // legal to implement.
677 let mut candidates = all_traits(self.tcx)
680 // We approximate the coherence rules to only suggest
681 // traits that are legal to implement by requiring that
682 // either the type or trait is local. Multi-dispatch means
683 // this isn't perfect (that is, there are cases when
684 // implementing a trait would be legal but is rejected
686 (type_is_local || info.def_id.is_local()) &&
687 self.associated_item(info.def_id, item_name, Namespace::Value)
689 // We only want to suggest public or local traits (#45781).
690 item.vis == ty::Visibility::Public || info.def_id.is_local()
694 .collect::<Vec<_>>();
696 if !candidates.is_empty() {
697 // Sort from most relevant to least relevant.
698 candidates.sort_by(|a, b| a.cmp(b).reverse());
701 let param_type = match rcvr_ty.sty {
702 ty::Param(param) => Some(param),
703 ty::Ref(_, ty, _) => match ty.sty {
704 ty::Param(param) => Some(param),
709 err.help(if param_type.is_some() {
710 "items from traits can only be used if the type parameter is bounded by the trait"
712 "items from traits can only be used if the trait is implemented and in scope"
714 let mut msg = format!(
715 "the following {traits_define} an item `{name}`, perhaps you need to {action} \
717 traits_define = if candidates.len() == 1 {
722 action = if let Some(param) = param_type {
723 format!("restrict type parameter `{}` with", param)
725 "implement".to_string()
727 one_of_them = if candidates.len() == 1 {
734 // Obtain the span for `param` and use it for a structured suggestion.
735 let mut suggested = false;
736 if let (Some(ref param), Some(ref table)) = (param_type, self.in_progress_tables) {
737 let table = table.borrow();
738 if let Some(did) = table.local_id_root {
739 let generics = self.tcx.generics_of(did);
740 let type_param = generics.type_param(param, self.tcx);
741 let hir = &self.tcx.hir();
742 if let Some(id) = hir.as_local_hir_id(type_param.def_id) {
743 // Get the `hir::Param` to verify whether it already has any bounds.
744 // We do this to avoid suggesting code that ends up as `T: FooBar`,
745 // instead we suggest `T: Foo + Bar` in that case.
746 let mut has_bounds = false;
747 let mut impl_trait = false;
748 if let Node::GenericParam(ref param) = hir.get(id) {
750 hir::GenericParamKind::Type { synthetic: Some(_), .. } => {
751 // We've found `fn foo(x: impl Trait)` instead of
752 // `fn foo<T>(x: T)`. We want to suggest the correct
753 // `fn foo(x: impl Trait + TraitBound)` instead of
754 // `fn foo<T: TraitBound>(x: T)`. (#63706)
756 has_bounds = param.bounds.len() > 1;
759 has_bounds = !param.bounds.is_empty();
763 let sp = hir.span(id);
764 // `sp` only covers `T`, change it so that it covers
765 // `T:` when appropriate
766 let sp = if has_bounds {
770 .next_point(self.tcx.sess.source_map().next_point(sp)))
775 // FIXME: contrast `t.def_id` against `param.bounds` to not suggest traits
776 // already there. That can happen when the cause is that we're in a const
777 // scope or associated function used as a method.
778 err.span_suggestions(
781 candidates.iter().map(|t| format!(
784 if impl_trait { " +" } else { ":" },
785 self.tcx.def_path_str(t.def_id),
786 if has_bounds { " +"} else { "" },
788 Applicability::MaybeIncorrect,
796 for (i, trait_info) in candidates.iter().enumerate() {
797 msg.push_str(&format!(
798 "\ncandidate #{}: `{}`",
800 self.tcx.def_path_str(trait_info.def_id),
808 /// Checks whether there is a local type somewhere in the chain of
809 /// autoderefs of `rcvr_ty`.
810 fn type_derefs_to_local(&self,
813 source: SelfSource<'_>) -> bool {
814 fn is_local(ty: Ty<'_>) -> bool {
816 ty::Adt(def, _) => def.did.is_local(),
817 ty::Foreign(did) => did.is_local(),
819 ty::Dynamic(ref tr, ..) =>
820 tr.principal().map(|d| d.def_id().is_local()).unwrap_or(false),
822 ty::Param(_) => true,
824 // Everything else (primitive types, etc.) is effectively
825 // non-local (there are "edge" cases, e.g., `(LocalType,)`, but
826 // the noise from these sort of types is usually just really
827 // annoying, rather than any sort of help).
832 // This occurs for UFCS desugaring of `T::method`, where there is no
833 // receiver expression for the method call, and thus no autoderef.
834 if let SelfSource::QPath(_) = source {
835 return is_local(self.resolve_type_vars_with_obligations(rcvr_ty));
838 self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
842 #[derive(Copy, Clone)]
843 pub enum SelfSource<'a> {
845 MethodCall(&'a hir::Expr /* rcvr */),
848 #[derive(Copy, Clone)]
849 pub struct TraitInfo {
853 impl PartialEq for TraitInfo {
854 fn eq(&self, other: &TraitInfo) -> bool {
855 self.cmp(other) == Ordering::Equal
858 impl Eq for TraitInfo {}
859 impl PartialOrd for TraitInfo {
860 fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> {
861 Some(self.cmp(other))
864 impl Ord for TraitInfo {
865 fn cmp(&self, other: &TraitInfo) -> Ordering {
866 // Local crates are more important than remote ones (local:
867 // `cnum == 0`), and otherwise we throw in the defid for totality.
869 let lhs = (other.def_id.krate, other.def_id);
870 let rhs = (self.def_id.krate, self.def_id);
875 /// Retrieves all traits in this crate and any dependent crates.
876 pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
877 tcx.all_traits(LOCAL_CRATE).iter().map(|&def_id| TraitInfo { def_id }).collect()
880 /// Computes all traits in this crate and any dependent crates.
881 fn compute_all_traits(tcx: TyCtxt<'_>) -> Vec<DefId> {
882 use hir::itemlikevisit;
884 let mut traits = vec![];
888 struct Visitor<'a, 'tcx> {
889 map: &'a hir_map::Map<'tcx>,
890 traits: &'a mut Vec<DefId>,
893 impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> {
894 fn visit_item(&mut self, i: &'v hir::Item) {
896 hir::ItemKind::Trait(..) |
897 hir::ItemKind::TraitAlias(..) => {
898 let def_id = self.map.local_def_id(i.hir_id);
899 self.traits.push(def_id);
905 fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {}
907 fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {}
910 tcx.hir().krate().visit_all_item_likes(&mut Visitor {
917 let mut external_mods = FxHashSet::default();
918 fn handle_external_res(
920 traits: &mut Vec<DefId>,
921 external_mods: &mut FxHashSet<DefId>,
925 Res::Def(DefKind::Trait, def_id) |
926 Res::Def(DefKind::TraitAlias, def_id) => {
929 Res::Def(DefKind::Mod, def_id) => {
930 if !external_mods.insert(def_id) {
933 for child in tcx.item_children(def_id).iter() {
934 handle_external_res(tcx, traits, external_mods, child.res)
940 for &cnum in tcx.crates().iter() {
943 index: CRATE_DEF_INDEX,
945 handle_external_res(tcx, &mut traits, &mut external_mods, Res::Def(DefKind::Mod, def_id));
951 pub fn provide(providers: &mut ty::query::Providers<'_>) {
952 providers.all_traits = |tcx, cnum| {
953 assert_eq!(cnum, LOCAL_CRATE);
954 &tcx.arena.alloc(compute_all_traits(tcx))[..]
958 struct UsePlacementFinder<'tcx> {
959 target_module: hir::HirId,
965 impl UsePlacementFinder<'tcx> {
968 krate: &'tcx hir::Crate,
969 target_module: hir::HirId,
970 ) -> (Option<Span>, bool) {
971 let mut finder = UsePlacementFinder {
977 hir::intravisit::walk_crate(&mut finder, krate);
978 (finder.span, finder.found_use)
982 impl hir::intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> {
985 module: &'tcx hir::Mod,
989 if self.span.is_some() {
992 if hir_id != self.target_module {
993 hir::intravisit::walk_mod(self, module, hir_id);
996 // Find a `use` statement.
997 for item_id in &module.item_ids {
998 let item = self.tcx.hir().expect_item(item_id.id);
1000 hir::ItemKind::Use(..) => {
1001 // Don't suggest placing a `use` before the prelude
1002 // import or other generated ones.
1003 if !item.span.from_expansion() {
1004 self.span = Some(item.span.shrink_to_lo());
1005 self.found_use = true;
1009 // Don't place `use` before `extern crate`...
1010 hir::ItemKind::ExternCrate(_) => {}
1011 // ...but do place them before the first other item.
1012 _ => if self.span.map_or(true, |span| item.span < span ) {
1013 if !item.span.from_expansion() {
1014 // Don't insert between attributes and an item.
1015 if item.attrs.is_empty() {
1016 self.span = Some(item.span.shrink_to_lo());
1018 // Find the first attribute on the item.
1019 for attr in &item.attrs {
1020 if self.span.map_or(true, |span| attr.span < span) {
1021 self.span = Some(attr.span.shrink_to_lo());
1031 fn nested_visit_map<'this>(
1033 ) -> hir::intravisit::NestedVisitorMap<'this, 'tcx> {
1034 hir::intravisit::NestedVisitorMap::None