|
1 | 1 | use std::cmp::Reverse;
|
| 2 | +use std::ptr; |
2 | 3 |
|
3 | 4 | use log::debug;
|
4 | 5 | use rustc::bug;
|
@@ -936,26 +937,62 @@ impl<'a> Resolver<'a> {
|
936 | 937 | crate fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) {
|
937 | 938 | let PrivacyError { ident, binding, .. } = *privacy_error;
|
938 | 939 |
|
| 940 | + let res = binding.res(); |
939 | 941 | let ctor_fields_span = self.ctor_fields_span(binding);
|
940 |
| - let mut descr = binding.res().descr().to_string(); |
941 |
| - if ctor_fields_span.is_some() { |
942 |
| - descr += " constructor"; |
943 |
| - } |
944 |
| - if binding.is_import() { |
945 |
| - descr += " import"; |
946 |
| - } |
947 |
| - |
| 942 | + let plain_descr = res.descr().to_string(); |
| 943 | + let nonimport_descr = |
| 944 | + if ctor_fields_span.is_some() { plain_descr + " constructor" } else { plain_descr }; |
| 945 | + let import_descr = nonimport_descr.clone() + " import"; |
| 946 | + let get_descr = |
| 947 | + |b: &NameBinding<'_>| if b.is_import() { &import_descr } else { &nonimport_descr }; |
| 948 | + |
| 949 | + // Print the primary message. |
| 950 | + let descr = get_descr(binding); |
948 | 951 | let mut err =
|
949 | 952 | struct_span_err!(self.session, ident.span, E0603, "{} `{}` is private", descr, ident);
|
950 | 953 | err.span_label(ident.span, &format!("this {} is private", descr));
|
951 | 954 | if let Some(span) = ctor_fields_span {
|
952 | 955 | err.span_label(span, "a constructor is private if any of the fields is private");
|
953 | 956 | }
|
954 | 957 |
|
955 |
| - err.span_note( |
956 |
| - self.session.source_map().def_span(binding.span), |
957 |
| - &format!("the {} `{}` is defined here", descr, ident), |
958 |
| - ); |
| 958 | + // Print the whole import chain to make it easier to see what happens. |
| 959 | + let first_binding = binding; |
| 960 | + let mut next_binding = Some(binding); |
| 961 | + let mut next_ident = ident; |
| 962 | + while let Some(binding) = next_binding { |
| 963 | + let name = next_ident; |
| 964 | + next_binding = match binding.kind { |
| 965 | + _ if res == Res::Err => None, |
| 966 | + NameBindingKind::Import { binding, import, .. } => match import.kind { |
| 967 | + _ if binding.span.is_dummy() => None, |
| 968 | + ImportKind::Single { source, .. } => { |
| 969 | + next_ident = source; |
| 970 | + Some(binding) |
| 971 | + } |
| 972 | + ImportKind::Glob { .. } | ImportKind::MacroUse => Some(binding), |
| 973 | + ImportKind::ExternCrate { .. } => None, |
| 974 | + }, |
| 975 | + _ => None, |
| 976 | + }; |
| 977 | + |
| 978 | + let first = ptr::eq(binding, first_binding); |
| 979 | + let descr = get_descr(binding); |
| 980 | + let msg = format!( |
| 981 | + "{and_refers_to}the {item} `{name}`{which} is defined here{dots}", |
| 982 | + and_refers_to = if first { "" } else { "...and refers to " }, |
| 983 | + item = descr, |
| 984 | + name = name, |
| 985 | + which = if first { "" } else { " which" }, |
| 986 | + dots = if next_binding.is_some() { "..." } else { "" }, |
| 987 | + ); |
| 988 | + let def_span = self.session.source_map().def_span(binding.span); |
| 989 | + let mut note_span = MultiSpan::from_span(def_span); |
| 990 | + if !first && next_binding.is_none() && binding.vis == ty::Visibility::Public { |
| 991 | + note_span.push_span_label(def_span, "consider importing it directly".into()); |
| 992 | + } |
| 993 | + err.span_note(note_span, &msg); |
| 994 | + } |
| 995 | + |
959 | 996 | err.emit();
|
960 | 997 | }
|
961 | 998 | }
|
|
0 commit comments