about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2019-08-08 23:32:58 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2019-08-10 13:16:06 +0300
commit9c86ce76e51439a39765343f2f9ac03e12f04898 (patch)
treef300e8da57f0653f0fd4e19b3fb6716e19a43511
parent6a347f3701665a2e01f1f762d6be3b201b73bf42 (diff)
downloadrust-9c86ce76e51439a39765343f2f9ac03e12f04898.tar.gz
rust-9c86ce76e51439a39765343f2f9ac03e12f04898.zip
resolve: Turn `resolve_error` into a method on `Resolver`
Rename it to `report_error` and move into `diagnostics.rs`

Also turn `check_unused` into a method on `Resolver`
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs13
-rw-r--r--src/librustc_resolve/check_unused.rs172
-rw-r--r--src/librustc_resolve/diagnostics.rs285
-rw-r--r--src/librustc_resolve/late.rs40
-rw-r--r--src/librustc_resolve/lib.rs313
-rw-r--r--src/librustc_resolve/macros.rs5
-rw-r--r--src/librustc_resolve/resolve_imports.rs5
7 files changed, 411 insertions, 422 deletions
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 25d80021269..a6fbb0babbe 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -9,7 +9,7 @@ use crate::resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleIm
 use crate::{Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding};
 use crate::{ModuleOrUniformRoot, ParentScope, PerNS, Resolver, ResolverArenas, ExternPreludeEntry};
 use crate::Namespace::{self, TypeNS, ValueNS, MacroNS};
-use crate::{resolve_error, resolve_struct_error, ResolutionError, Determinacy};
+use crate::{ResolutionError, Determinacy};
 
 use rustc::bug;
 use rustc::hir::def::{self, *};
@@ -165,8 +165,7 @@ impl<'a> BuildReducedGraphVisitor<'_, 'a> {
                         type_ns_only = true;
 
                         if empty_for_self(&module_path) {
-                            resolve_error(
-                                &self.r,
+                            self.r.report_error(
                                 use_tree.span,
                                 ResolutionError::
                                 SelfImportOnlyInImportListWithNonEmptyPrefix
@@ -183,9 +182,9 @@ impl<'a> BuildReducedGraphVisitor<'_, 'a> {
                 } else {
                     // Disallow `self`
                     if source.ident.name == kw::SelfLower {
-                        resolve_error(&self.r,
-                                      use_tree.span,
-                                      ResolutionError::SelfImportsOnlyAllowedWithin);
+                        self.r.report_error(
+                            use_tree.span, ResolutionError::SelfImportsOnlyAllowedWithin
+                        );
                     }
 
                     // Disallow `use $crate;`
@@ -283,7 +282,7 @@ impl<'a> BuildReducedGraphVisitor<'_, 'a> {
                     None
                 }).collect::<Vec<_>>();
                 if self_spans.len() > 1 {
-                    let mut e = resolve_struct_error(&self.r,
+                    let mut e = self.r.into_struct_error(
                         self_spans[0],
                         ResolutionError::SelfImportCanOnlyAppearOnceInTheList);
 
diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs
index 922da7eef7a..96d44b4b4c0 100644
--- a/src/librustc_resolve/check_unused.rs
+++ b/src/librustc_resolve/check_unused.rs
@@ -221,100 +221,102 @@ fn calc_unused_spans(
     }
 }
 
-pub fn check_crate(resolver: &mut Resolver<'_>, krate: &ast::Crate) {
-    for directive in resolver.potentially_unused_imports.iter() {
-        match directive.subclass {
-            _ if directive.used.get() ||
-                 directive.vis.get() == ty::Visibility::Public ||
-                 directive.span.is_dummy() => {
-                if let ImportDirectiveSubclass::MacroUse = directive.subclass {
-                    if !directive.span.is_dummy() {
-                        resolver.session.buffer_lint(
-                            lint::builtin::MACRO_USE_EXTERN_CRATE,
-                            directive.id,
-                            directive.span,
-                            "deprecated `#[macro_use]` directive used to \
-                             import macros should be replaced at use sites \
-                             with a `use` statement to import the macro \
-                             instead",
-                        );
+impl Resolver<'_> {
+    crate fn check_unused(&mut self, krate: &ast::Crate) {
+        for directive in self.potentially_unused_imports.iter() {
+            match directive.subclass {
+                _ if directive.used.get() ||
+                    directive.vis.get() == ty::Visibility::Public ||
+                    directive.span.is_dummy() => {
+                    if let ImportDirectiveSubclass::MacroUse = directive.subclass {
+                        if !directive.span.is_dummy() {
+                            self.session.buffer_lint(
+                                lint::builtin::MACRO_USE_EXTERN_CRATE,
+                                directive.id,
+                                directive.span,
+                                "deprecated `#[macro_use]` directive used to \
+                                import macros should be replaced at use sites \
+                                with a `use` statement to import the macro \
+                                instead",
+                            );
+                        }
                     }
                 }
+                ImportDirectiveSubclass::ExternCrate { .. } => {
+                    self.maybe_unused_extern_crates.push((directive.id, directive.span));
+                }
+                ImportDirectiveSubclass::MacroUse => {
+                    let lint = lint::builtin::UNUSED_IMPORTS;
+                    let msg = "unused `#[macro_use]` import";
+                    self.session.buffer_lint(lint, directive.id, directive.span, msg);
+                }
+                _ => {}
             }
-            ImportDirectiveSubclass::ExternCrate { .. } => {
-                resolver.maybe_unused_extern_crates.push((directive.id, directive.span));
-            }
-            ImportDirectiveSubclass::MacroUse => {
-                let lint = lint::builtin::UNUSED_IMPORTS;
-                let msg = "unused `#[macro_use]` import";
-                resolver.session.buffer_lint(lint, directive.id, directive.span, msg);
-            }
-            _ => {}
         }
-    }
 
-    let mut visitor = UnusedImportCheckVisitor {
-        r: resolver,
-        unused_imports: Default::default(),
-        base_use_tree: None,
-        base_id: ast::DUMMY_NODE_ID,
-        item_span: DUMMY_SP,
-    };
-    visit::walk_crate(&mut visitor, krate);
-
-    for unused in visitor.unused_imports.values() {
-        let mut fixes = Vec::new();
-        let mut spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) {
-            UnusedSpanResult::Used => continue,
-            UnusedSpanResult::FlatUnused(span, remove) => {
-                fixes.push((remove, String::new()));
-                vec![span]
-            }
-            UnusedSpanResult::NestedFullUnused(spans, remove) => {
-                fixes.push((remove, String::new()));
-                spans
-            }
-            UnusedSpanResult::NestedPartialUnused(spans, remove) => {
-                for fix in &remove {
-                    fixes.push((*fix, String::new()));
-                }
-                spans
-            }
+        let mut visitor = UnusedImportCheckVisitor {
+            r: self,
+            unused_imports: Default::default(),
+            base_use_tree: None,
+            base_id: ast::DUMMY_NODE_ID,
+            item_span: DUMMY_SP,
         };
+        visit::walk_crate(&mut visitor, krate);
 
-        let len = spans.len();
-        spans.sort();
-        let ms = MultiSpan::from_spans(spans.clone());
-        let mut span_snippets = spans.iter()
-            .filter_map(|s| {
-                match visitor.r.session.source_map().span_to_snippet(*s) {
-                    Ok(s) => Some(format!("`{}`", s)),
-                    _ => None,
+        for unused in visitor.unused_imports.values() {
+            let mut fixes = Vec::new();
+            let mut spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) {
+                UnusedSpanResult::Used => continue,
+                UnusedSpanResult::FlatUnused(span, remove) => {
+                    fixes.push((remove, String::new()));
+                    vec![span]
+                }
+                UnusedSpanResult::NestedFullUnused(spans, remove) => {
+                    fixes.push((remove, String::new()));
+                    spans
                 }
-            }).collect::<Vec<String>>();
-        span_snippets.sort();
-        let msg = format!("unused import{}{}",
-                          if len > 1 { "s" } else { "" },
-                          if !span_snippets.is_empty() {
-                              format!(": {}", span_snippets.join(", "))
-                          } else {
-                              String::new()
-                          });
+                UnusedSpanResult::NestedPartialUnused(spans, remove) => {
+                    for fix in &remove {
+                        fixes.push((*fix, String::new()));
+                    }
+                    spans
+                }
+            };
 
-        let fix_msg = if fixes.len() == 1 && fixes[0].0 == unused.item_span {
-            "remove the whole `use` item"
-        } else if spans.len() > 1 {
-            "remove the unused imports"
-        } else {
-            "remove the unused import"
-        };
+            let len = spans.len();
+            spans.sort();
+            let ms = MultiSpan::from_spans(spans.clone());
+            let mut span_snippets = spans.iter()
+                .filter_map(|s| {
+                    match visitor.r.session.source_map().span_to_snippet(*s) {
+                        Ok(s) => Some(format!("`{}`", s)),
+                        _ => None,
+                    }
+                }).collect::<Vec<String>>();
+            span_snippets.sort();
+            let msg = format!("unused import{}{}",
+                            if len > 1 { "s" } else { "" },
+                            if !span_snippets.is_empty() {
+                                format!(": {}", span_snippets.join(", "))
+                            } else {
+                                String::new()
+                            });
 
-        visitor.r.session.buffer_lint_with_diagnostic(
-            lint::builtin::UNUSED_IMPORTS,
-            unused.use_tree_id,
-            ms,
-            &msg,
-            lint::builtin::BuiltinLintDiagnostics::UnusedImports(fix_msg.into(), fixes),
-        );
+            let fix_msg = if fixes.len() == 1 && fixes[0].0 == unused.item_span {
+                "remove the whole `use` item"
+            } else if spans.len() > 1 {
+                "remove the unused imports"
+            } else {
+                "remove the unused import"
+            };
+
+            visitor.r.session.buffer_lint_with_diagnostic(
+                lint::builtin::UNUSED_IMPORTS,
+                unused.use_tree_id,
+                ms,
+                &msg,
+                lint::builtin::BuiltinLintDiagnostics::UnusedImports(fix_msg.into(), fixes),
+            );
+        }
     }
 }
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index 3a39307849e..01a4a3c4bb2 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -1,7 +1,8 @@
 use std::cmp::Reverse;
 
-use errors::{Applicability, DiagnosticBuilder};
+use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
 use log::debug;
+use rustc::bug;
 use rustc::hir::def::{self, DefKind, NonMacroAttrKind};
 use rustc::hir::def::Namespace::{self, *};
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
@@ -11,14 +12,16 @@ use rustc::util::nodemap::FxHashSet;
 use syntax::ast::{self, Ident, Path};
 use syntax::ext::base::MacroKind;
 use syntax::feature_gate::BUILTIN_ATTRIBUTES;
+use syntax::source_map::SourceMap;
+use syntax::struct_span_err;
 use syntax::symbol::{Symbol, kw};
 use syntax::util::lev_distance::find_best_match_for_name;
-use syntax_pos::{BytePos, Span};
+use syntax_pos::{BytePos, Span, MultiSpan};
 
 use crate::resolve_imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver};
 use crate::{path_names_to_string, KNOWN_TOOLS};
 use crate::{CrateLint, LegacyScope, Module, ModuleOrUniformRoot};
-use crate::{PathResult, ParentScope, Resolver, Scope, ScopeSet, Segment};
+use crate::{PathResult, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Segment};
 
 type Res = def::Res<ast::NodeId>;
 
@@ -42,6 +45,19 @@ crate struct ImportSuggestion {
     pub path: Path,
 }
 
+/// Adjust the impl span so that just the `impl` keyword is taken by removing
+/// everything after `<` (`"impl<T> Iterator for A<T> {}" -> "impl"`) and
+/// everything after the first whitespace (`"impl Iterator for A" -> "impl"`).
+///
+/// *Attention*: the method used is very fragile since it essentially duplicates the work of the
+/// parser. If you need to use this function or something similar, please consider updating the
+/// `source_map` functions and this function to something more robust.
+fn reduce_impl_span_to_impl_keyword(cm: &SourceMap, impl_span: Span) -> Span {
+    let impl_span = cm.span_until_char(impl_span, '<');
+    let impl_span = cm.span_until_whitespace(impl_span);
+    impl_span
+}
+
 crate fn add_typo_suggestion(
     err: &mut DiagnosticBuilder<'_>, suggestion: Option<TypoSuggestion>, span: Span
 ) -> bool {
@@ -71,6 +87,269 @@ crate fn add_module_candidates(
 }
 
 impl<'a> Resolver<'a> {
+    /// Combines an error with provided span and emits it.
+    ///
+    /// This takes the error provided, combines it with the span and any additional spans inside the
+    /// error and emits it.
+    crate fn report_error(&self, span: Span, resolution_error: ResolutionError<'_>) {
+        self.into_struct_error(span, resolution_error).emit();
+    }
+
+    crate fn into_struct_error(
+        &self, span: Span, resolution_error: ResolutionError<'_>
+    ) -> DiagnosticBuilder<'_> {
+        match resolution_error {
+            ResolutionError::GenericParamsFromOuterFunction(outer_res) => {
+                let mut err = struct_span_err!(self.session,
+                    span,
+                    E0401,
+                    "can't use generic parameters from outer function",
+                );
+                err.span_label(span, format!("use of generic parameter from outer function"));
+
+                let cm = self.session.source_map();
+                match outer_res {
+                    Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => {
+                        if let Some(impl_span) = maybe_impl_defid.and_then(|def_id| {
+                            self.definitions.opt_span(def_id)
+                        }) {
+                            err.span_label(
+                                reduce_impl_span_to_impl_keyword(cm, impl_span),
+                                "`Self` type implicitly declared here, by this `impl`",
+                            );
+                        }
+                        match (maybe_trait_defid, maybe_impl_defid) {
+                            (Some(_), None) => {
+                                err.span_label(span, "can't use `Self` here");
+                            }
+                            (_, Some(_)) => {
+                                err.span_label(span, "use a type here instead");
+                            }
+                            (None, None) => bug!("`impl` without trait nor type?"),
+                        }
+                        return err;
+                    },
+                    Res::Def(DefKind::TyParam, def_id) => {
+                        if let Some(span) = self.definitions.opt_span(def_id) {
+                            err.span_label(span, "type parameter from outer function");
+                        }
+                    }
+                    Res::Def(DefKind::ConstParam, def_id) => {
+                        if let Some(span) = self.definitions.opt_span(def_id) {
+                            err.span_label(span, "const parameter from outer function");
+                        }
+                    }
+                    _ => {
+                        bug!("GenericParamsFromOuterFunction should only be used with Res::SelfTy, \
+                            DefKind::TyParam");
+                    }
+                }
+
+                // Try to retrieve the span of the function signature and generate a new message
+                // with a local type or const parameter.
+                let sugg_msg = &format!("try using a local generic parameter instead");
+                if let Some((sugg_span, new_snippet)) = cm.generate_local_type_param_snippet(span) {
+                    // Suggest the modification to the user
+                    err.span_suggestion(
+                        sugg_span,
+                        sugg_msg,
+                        new_snippet,
+                        Applicability::MachineApplicable,
+                    );
+                } else if let Some(sp) = cm.generate_fn_name_span(span) {
+                    err.span_label(sp,
+                        format!("try adding a local generic parameter in this method instead"));
+                } else {
+                    err.help(&format!("try using a local generic parameter instead"));
+                }
+
+                err
+            }
+            ResolutionError::NameAlreadyUsedInParameterList(name, first_use_span) => {
+                let mut err = struct_span_err!(self.session,
+                                                span,
+                                                E0403,
+                                                "the name `{}` is already used for a generic \
+                                                parameter in this list of generic parameters",
+                                                name);
+                err.span_label(span, "already used");
+                err.span_label(first_use_span, format!("first use of `{}`", name));
+                err
+            }
+            ResolutionError::MethodNotMemberOfTrait(method, trait_) => {
+                let mut err = struct_span_err!(self.session,
+                                            span,
+                                            E0407,
+                                            "method `{}` is not a member of trait `{}`",
+                                            method,
+                                            trait_);
+                err.span_label(span, format!("not a member of trait `{}`", trait_));
+                err
+            }
+            ResolutionError::TypeNotMemberOfTrait(type_, trait_) => {
+                let mut err = struct_span_err!(self.session,
+                                span,
+                                E0437,
+                                "type `{}` is not a member of trait `{}`",
+                                type_,
+                                trait_);
+                err.span_label(span, format!("not a member of trait `{}`", trait_));
+                err
+            }
+            ResolutionError::ConstNotMemberOfTrait(const_, trait_) => {
+                let mut err = struct_span_err!(self.session,
+                                span,
+                                E0438,
+                                "const `{}` is not a member of trait `{}`",
+                                const_,
+                                trait_);
+                err.span_label(span, format!("not a member of trait `{}`", trait_));
+                err
+            }
+            ResolutionError::VariableNotBoundInPattern(binding_error) => {
+                let target_sp = binding_error.target.iter().cloned().collect::<Vec<_>>();
+                let msp = MultiSpan::from_spans(target_sp.clone());
+                let msg = format!("variable `{}` is not bound in all patterns", binding_error.name);
+                let mut err = self.session.struct_span_err_with_code(
+                    msp,
+                    &msg,
+                    DiagnosticId::Error("E0408".into()),
+                );
+                for sp in target_sp {
+                    err.span_label(sp, format!("pattern doesn't bind `{}`", binding_error.name));
+                }
+                let origin_sp = binding_error.origin.iter().cloned();
+                for sp in origin_sp {
+                    err.span_label(sp, "variable not in all patterns");
+                }
+                err
+            }
+            ResolutionError::VariableBoundWithDifferentMode(variable_name,
+                                                            first_binding_span) => {
+                let mut err = struct_span_err!(self.session,
+                                span,
+                                E0409,
+                                "variable `{}` is bound in inconsistent \
+                                ways within the same match arm",
+                                variable_name);
+                err.span_label(span, "bound in different ways");
+                err.span_label(first_binding_span, "first binding");
+                err
+            }
+            ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => {
+                let mut err = struct_span_err!(self.session,
+                                span,
+                                E0415,
+                                "identifier `{}` is bound more than once in this parameter list",
+                                identifier);
+                err.span_label(span, "used as parameter more than once");
+                err
+            }
+            ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(identifier) => {
+                let mut err = struct_span_err!(self.session,
+                                span,
+                                E0416,
+                                "identifier `{}` is bound more than once in the same pattern",
+                                identifier);
+                err.span_label(span, "used in a pattern more than once");
+                err
+            }
+            ResolutionError::UndeclaredLabel(name, lev_candidate) => {
+                let mut err = struct_span_err!(self.session,
+                                            span,
+                                            E0426,
+                                            "use of undeclared label `{}`",
+                                            name);
+                if let Some(lev_candidate) = lev_candidate {
+                    err.span_suggestion(
+                        span,
+                        "a label with a similar name exists in this scope",
+                        lev_candidate.to_string(),
+                        Applicability::MaybeIncorrect,
+                    );
+                } else {
+                    err.span_label(span, format!("undeclared label `{}`", name));
+                }
+                err
+            }
+            ResolutionError::SelfImportsOnlyAllowedWithin => {
+                struct_span_err!(self.session,
+                                span,
+                                E0429,
+                                "{}",
+                                "`self` imports are only allowed within a { } list")
+            }
+            ResolutionError::SelfImportCanOnlyAppearOnceInTheList => {
+                let mut err = struct_span_err!(self.session, span, E0430,
+                                            "`self` import can only appear once in an import list");
+                err.span_label(span, "can only appear once in an import list");
+                err
+            }
+            ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => {
+                let mut err = struct_span_err!(self.session, span, E0431,
+                                            "`self` import can only appear in an import list with \
+                                                a non-empty prefix");
+                err.span_label(span, "can only appear in an import list with a non-empty prefix");
+                err
+            }
+            ResolutionError::FailedToResolve { label, suggestion } => {
+                let mut err = struct_span_err!(self.session, span, E0433,
+                                            "failed to resolve: {}", &label);
+                err.span_label(span, label);
+
+                if let Some((suggestions, msg, applicability)) = suggestion {
+                    err.multipart_suggestion(&msg, suggestions, applicability);
+                }
+
+                err
+            }
+            ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
+                let mut err = struct_span_err!(self.session,
+                                            span,
+                                            E0434,
+                                            "{}",
+                                            "can't capture dynamic environment in a fn item");
+                err.help("use the `|| { ... }` closure form instead");
+                err
+            }
+            ResolutionError::AttemptToUseNonConstantValueInConstant => {
+                let mut err = struct_span_err!(self.session, span, E0435,
+                                            "attempt to use a non-constant value in a constant");
+                err.span_label(span, "non-constant value");
+                err
+            }
+            ResolutionError::BindingShadowsSomethingUnacceptable(what_binding, name, binding) => {
+                let shadows_what = binding.descr();
+                let mut err = struct_span_err!(self.session, span, E0530, "{}s cannot shadow {}s",
+                                            what_binding, shadows_what);
+                err.span_label(span, format!("cannot be named the same as {} {}",
+                                            binding.article(), shadows_what));
+                let participle = if binding.is_import() { "imported" } else { "defined" };
+                let msg = format!("the {} `{}` is {} here", shadows_what, name, participle);
+                err.span_label(binding.span, msg);
+                err
+            }
+            ResolutionError::ForwardDeclaredTyParam => {
+                let mut err = struct_span_err!(self.session, span, E0128,
+                                            "type parameters with a default cannot use \
+                                                forward declared identifiers");
+                err.span_label(
+                    span, "defaulted type parameters cannot be forward declared".to_string());
+                err
+            }
+            ResolutionError::ConstParamDependentOnTypeParam => {
+                let mut err = struct_span_err!(
+                    self.session,
+                    span,
+                    E0671,
+                    "const parameters cannot depend on type parameters"
+                );
+                err.span_label(span, format!("const parameter depends on type parameter"));
+                err
+            }
+        }
+    }
+
     /// Lookup typo candidate in scope for a macro or import.
     fn early_lookup_typo_candidate(
         &mut self,
diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs
index fe0760364f3..0f68e0c054a 100644
--- a/src/librustc_resolve/late.rs
+++ b/src/librustc_resolve/late.rs
@@ -1,8 +1,7 @@
 use GenericParameters::*;
 
-use crate::{path_names_to_string, resolve_error};
-use crate::{AliasPossibility, BindingError, CrateLint, LexicalScopeBinding, Module};
-use crate::{ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult};
+use crate::{path_names_to_string, AliasPossibility, BindingError, CrateLint, LexicalScopeBinding};
+use crate::{Module, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult};
 use crate::{PathSource, ResolutionError, Resolver, Rib, RibKind, Segment, UseError};
 use crate::RibKind::*;
 
@@ -582,7 +581,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
                                     ident.name,
                                     *span,
                                 );
-                                resolve_error(&self.r, param.ident.span, err);
+                                self.r.report_error(param.ident.span, err);
                             }
                             seen_bindings.entry(ident).or_insert(param.ident.span);
 
@@ -604,7 +603,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
                                     ident.name,
                                     *span,
                                 );
-                                resolve_error(&self.r, param.ident.span, err);
+                                self.r.report_error(param.ident.span, err);
                             }
                             seen_bindings.entry(ident).or_insert(param.ident.span);
 
@@ -873,7 +872,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
                 span,
             ).is_err() {
                 let path = &self.current_trait_ref.as_ref().unwrap().1.path;
-                resolve_error(&self.r, span, err(ident.name, &path_names_to_string(path)));
+                self.r.report_error(span, err(ident.name, &path_names_to_string(path)));
             }
         }
     }
@@ -971,15 +970,14 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
         let mut missing_vars = missing_vars.iter().collect::<Vec<_>>();
         missing_vars.sort();
         for (_, v) in missing_vars {
-            resolve_error(&self.r,
-                          *v.origin.iter().next().unwrap(),
-                          ResolutionError::VariableNotBoundInPattern(v));
+            self.r.report_error(
+                *v.origin.iter().next().unwrap(), ResolutionError::VariableNotBoundInPattern(v)
+            );
         }
         let mut inconsistent_vars = inconsistent_vars.iter().collect::<Vec<_>>();
         inconsistent_vars.sort();
         for (name, v) in inconsistent_vars {
-            let err = ResolutionError::VariableBoundWithDifferentMode(*name, v.1);
-            resolve_error(&self.r, v.0, err);
+            self.r.report_error(v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1));
         }
     }
 
@@ -1067,8 +1065,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
         match bindings.get(&ident).cloned() {
             Some(id) if id == outer_pat_id => {
                 // `Variant(a, a)`, error
-                resolve_error(
-                    &self.r,
+                self.r.report_error(
                     ident.span,
                     ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(
                         &ident.as_str())
@@ -1076,8 +1073,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
             }
             Some(..) if pat_src == PatternSource::FnParam => {
                 // `fn f(a: u8, a: u8)`, error
-                resolve_error(
-                    &self.r,
+                self.r.report_error(
                     ident.span,
                     ResolutionError::IdentifierBoundMoreThanOnceInParameterList(
                         &ident.as_str())
@@ -1141,8 +1137,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
                                 // to something unusable as a pattern (e.g., constructor function),
                                 // but we still conservatively report an error, see
                                 // issues/33118#issuecomment-233962221 for one reason why.
-                                resolve_error(
-                                    &self.r,
+                                self.r.report_error(
                                     ident.span,
                                     ResolutionError::BindingShadowsSomethingUnacceptable(
                                         pat_src.descr(), ident.name, binding.unwrap())
@@ -1448,8 +1443,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
             PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
                 PartialRes::new(module.res().unwrap()),
             PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => {
-                let err = ResolutionError::FailedToResolve { label, suggestion };
-                resolve_error(&self.r, span, err);
+                self.r.report_error(span, ResolutionError::FailedToResolve { label, suggestion });
                 PartialRes::new(Res::Err)
             }
             PathResult::Module(..) | PathResult::Failed { .. } => return None,
@@ -1539,10 +1533,10 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
                             find_best_match_for_name(names, &*ident.as_str(), None)
                         });
                         self.r.record_partial_res(expr.id, PartialRes::new(Res::Err));
-                        resolve_error(&self.r,
-                                      label.ident.span,
-                                      ResolutionError::UndeclaredLabel(&label.ident.as_str(),
-                                                                       close_match));
+                        self.r.report_error(
+                            label.ident.span,
+                            ResolutionError::UndeclaredLabel(&label.ident.as_str(), close_match),
+                        );
                     }
                     Some(node_id) => {
                         // Since this res is a label, it is never read.
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 4aa3e2f9167..a2b1873c4f2 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -33,7 +33,6 @@ use rustc::{bug, span_bug};
 use rustc_metadata::creader::CrateLoader;
 use rustc_metadata::cstore::CStore;
 
-use syntax::source_map::SourceMap;
 use syntax::ext::hygiene::{ExpnId, Transparency, SyntaxContext};
 use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy};
 use syntax::ext::base::{SyntaxExtension, MacroKind, SpecialDerives};
@@ -45,8 +44,8 @@ use syntax::ast::{CRATE_NODE_ID, Crate, Expr, ExprKind};
 use syntax::ast::{ItemKind, Path};
 use syntax::{span_err, struct_span_err, unwrap_or};
 
-use syntax_pos::{Span, DUMMY_SP, MultiSpan};
-use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
+use syntax_pos::{Span, DUMMY_SP};
+use errors::{Applicability, DiagnosticBuilder};
 
 use log::debug;
 
@@ -200,285 +199,6 @@ enum ResolutionError<'a> {
     ConstParamDependentOnTypeParam,
 }
 
-/// Combines an error with provided span and emits it.
-///
-/// This takes the error provided, combines it with the span and any additional spans inside the
-/// error and emits it.
-fn resolve_error(resolver: &Resolver<'_>,
-                 span: Span,
-                 resolution_error: ResolutionError<'_>) {
-    resolve_struct_error(resolver, span, resolution_error).emit();
-}
-
-fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>,
-                                   span: Span,
-                                   resolution_error: ResolutionError<'a>)
-                                   -> DiagnosticBuilder<'sess> {
-    match resolution_error {
-        ResolutionError::GenericParamsFromOuterFunction(outer_res) => {
-            let mut err = struct_span_err!(resolver.session,
-                span,
-                E0401,
-                "can't use generic parameters from outer function",
-            );
-            err.span_label(span, format!("use of generic parameter from outer function"));
-
-            let cm = resolver.session.source_map();
-            match outer_res {
-                Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => {
-                    if let Some(impl_span) = maybe_impl_defid.and_then(|def_id| {
-                        resolver.definitions.opt_span(def_id)
-                    }) {
-                        err.span_label(
-                            reduce_impl_span_to_impl_keyword(cm, impl_span),
-                            "`Self` type implicitly declared here, by this `impl`",
-                        );
-                    }
-                    match (maybe_trait_defid, maybe_impl_defid) {
-                        (Some(_), None) => {
-                            err.span_label(span, "can't use `Self` here");
-                        }
-                        (_, Some(_)) => {
-                            err.span_label(span, "use a type here instead");
-                        }
-                        (None, None) => bug!("`impl` without trait nor type?"),
-                    }
-                    return err;
-                },
-                Res::Def(DefKind::TyParam, def_id) => {
-                    if let Some(span) = resolver.definitions.opt_span(def_id) {
-                        err.span_label(span, "type parameter from outer function");
-                    }
-                }
-                Res::Def(DefKind::ConstParam, def_id) => {
-                    if let Some(span) = resolver.definitions.opt_span(def_id) {
-                        err.span_label(span, "const parameter from outer function");
-                    }
-                }
-                _ => {
-                    bug!("GenericParamsFromOuterFunction should only be used with Res::SelfTy, \
-                         DefKind::TyParam");
-                }
-            }
-
-            // Try to retrieve the span of the function signature and generate a new message with
-            // a local type or const parameter.
-            let sugg_msg = &format!("try using a local generic parameter instead");
-            if let Some((sugg_span, new_snippet)) = cm.generate_local_type_param_snippet(span) {
-                // Suggest the modification to the user
-                err.span_suggestion(
-                    sugg_span,
-                    sugg_msg,
-                    new_snippet,
-                    Applicability::MachineApplicable,
-                );
-            } else if let Some(sp) = cm.generate_fn_name_span(span) {
-                err.span_label(sp,
-                    format!("try adding a local generic parameter in this method instead"));
-            } else {
-                err.help(&format!("try using a local generic parameter instead"));
-            }
-
-            err
-        }
-        ResolutionError::NameAlreadyUsedInParameterList(name, first_use_span) => {
-             let mut err = struct_span_err!(resolver.session,
-                                            span,
-                                            E0403,
-                                            "the name `{}` is already used for a generic \
-                                            parameter in this list of generic parameters",
-                                            name);
-             err.span_label(span, "already used");
-             err.span_label(first_use_span, format!("first use of `{}`", name));
-             err
-        }
-        ResolutionError::MethodNotMemberOfTrait(method, trait_) => {
-            let mut err = struct_span_err!(resolver.session,
-                                           span,
-                                           E0407,
-                                           "method `{}` is not a member of trait `{}`",
-                                           method,
-                                           trait_);
-            err.span_label(span, format!("not a member of trait `{}`", trait_));
-            err
-        }
-        ResolutionError::TypeNotMemberOfTrait(type_, trait_) => {
-            let mut err = struct_span_err!(resolver.session,
-                             span,
-                             E0437,
-                             "type `{}` is not a member of trait `{}`",
-                             type_,
-                             trait_);
-            err.span_label(span, format!("not a member of trait `{}`", trait_));
-            err
-        }
-        ResolutionError::ConstNotMemberOfTrait(const_, trait_) => {
-            let mut err = struct_span_err!(resolver.session,
-                             span,
-                             E0438,
-                             "const `{}` is not a member of trait `{}`",
-                             const_,
-                             trait_);
-            err.span_label(span, format!("not a member of trait `{}`", trait_));
-            err
-        }
-        ResolutionError::VariableNotBoundInPattern(binding_error) => {
-            let target_sp = binding_error.target.iter().cloned().collect::<Vec<_>>();
-            let msp = MultiSpan::from_spans(target_sp.clone());
-            let msg = format!("variable `{}` is not bound in all patterns", binding_error.name);
-            let mut err = resolver.session.struct_span_err_with_code(
-                msp,
-                &msg,
-                DiagnosticId::Error("E0408".into()),
-            );
-            for sp in target_sp {
-                err.span_label(sp, format!("pattern doesn't bind `{}`", binding_error.name));
-            }
-            let origin_sp = binding_error.origin.iter().cloned();
-            for sp in origin_sp {
-                err.span_label(sp, "variable not in all patterns");
-            }
-            err
-        }
-        ResolutionError::VariableBoundWithDifferentMode(variable_name,
-                                                        first_binding_span) => {
-            let mut err = struct_span_err!(resolver.session,
-                             span,
-                             E0409,
-                             "variable `{}` is bound in inconsistent \
-                             ways within the same match arm",
-                             variable_name);
-            err.span_label(span, "bound in different ways");
-            err.span_label(first_binding_span, "first binding");
-            err
-        }
-        ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => {
-            let mut err = struct_span_err!(resolver.session,
-                             span,
-                             E0415,
-                             "identifier `{}` is bound more than once in this parameter list",
-                             identifier);
-            err.span_label(span, "used as parameter more than once");
-            err
-        }
-        ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(identifier) => {
-            let mut err = struct_span_err!(resolver.session,
-                             span,
-                             E0416,
-                             "identifier `{}` is bound more than once in the same pattern",
-                             identifier);
-            err.span_label(span, "used in a pattern more than once");
-            err
-        }
-        ResolutionError::UndeclaredLabel(name, lev_candidate) => {
-            let mut err = struct_span_err!(resolver.session,
-                                           span,
-                                           E0426,
-                                           "use of undeclared label `{}`",
-                                           name);
-            if let Some(lev_candidate) = lev_candidate {
-                err.span_suggestion(
-                    span,
-                    "a label with a similar name exists in this scope",
-                    lev_candidate.to_string(),
-                    Applicability::MaybeIncorrect,
-                );
-            } else {
-                err.span_label(span, format!("undeclared label `{}`", name));
-            }
-            err
-        }
-        ResolutionError::SelfImportsOnlyAllowedWithin => {
-            struct_span_err!(resolver.session,
-                             span,
-                             E0429,
-                             "{}",
-                             "`self` imports are only allowed within a { } list")
-        }
-        ResolutionError::SelfImportCanOnlyAppearOnceInTheList => {
-            let mut err = struct_span_err!(resolver.session, span, E0430,
-                                           "`self` import can only appear once in an import list");
-            err.span_label(span, "can only appear once in an import list");
-            err
-        }
-        ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => {
-            let mut err = struct_span_err!(resolver.session, span, E0431,
-                                           "`self` import can only appear in an import list with \
-                                            a non-empty prefix");
-            err.span_label(span, "can only appear in an import list with a non-empty prefix");
-            err
-        }
-        ResolutionError::FailedToResolve { label, suggestion } => {
-            let mut err = struct_span_err!(resolver.session, span, E0433,
-                                           "failed to resolve: {}", &label);
-            err.span_label(span, label);
-
-            if let Some((suggestions, msg, applicability)) = suggestion {
-                err.multipart_suggestion(&msg, suggestions, applicability);
-            }
-
-            err
-        }
-        ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
-            let mut err = struct_span_err!(resolver.session,
-                                           span,
-                                           E0434,
-                                           "{}",
-                                           "can't capture dynamic environment in a fn item");
-            err.help("use the `|| { ... }` closure form instead");
-            err
-        }
-        ResolutionError::AttemptToUseNonConstantValueInConstant => {
-            let mut err = struct_span_err!(resolver.session, span, E0435,
-                                           "attempt to use a non-constant value in a constant");
-            err.span_label(span, "non-constant value");
-            err
-        }
-        ResolutionError::BindingShadowsSomethingUnacceptable(what_binding, name, binding) => {
-            let shadows_what = binding.descr();
-            let mut err = struct_span_err!(resolver.session, span, E0530, "{}s cannot shadow {}s",
-                                           what_binding, shadows_what);
-            err.span_label(span, format!("cannot be named the same as {} {}",
-                                         binding.article(), shadows_what));
-            let participle = if binding.is_import() { "imported" } else { "defined" };
-            let msg = format!("the {} `{}` is {} here", shadows_what, name, participle);
-            err.span_label(binding.span, msg);
-            err
-        }
-        ResolutionError::ForwardDeclaredTyParam => {
-            let mut err = struct_span_err!(resolver.session, span, E0128,
-                                           "type parameters with a default cannot use \
-                                            forward declared identifiers");
-            err.span_label(
-                span, "defaulted type parameters cannot be forward declared".to_string());
-            err
-        }
-        ResolutionError::ConstParamDependentOnTypeParam => {
-            let mut err = struct_span_err!(
-                resolver.session,
-                span,
-                E0671,
-                "const parameters cannot depend on type parameters"
-            );
-            err.span_label(span, format!("const parameter depends on type parameter"));
-            err
-        }
-    }
-}
-
-/// Adjust the impl span so that just the `impl` keyword is taken by removing
-/// everything after `<` (`"impl<T> Iterator for A<T> {}" -> "impl"`) and
-/// everything after the first whitespace (`"impl Iterator for A" -> "impl"`).
-///
-/// *Attention*: the method used is very fragile since it essentially duplicates the work of the
-/// parser. If you need to use this function or something similar, please consider updating the
-/// `source_map` functions and this function to something more robust.
-fn reduce_impl_span_to_impl_keyword(cm: &SourceMap, impl_span: Span) -> Span {
-    let impl_span = cm.span_until_char(impl_span, '<');
-    let impl_span = cm.span_until_whitespace(impl_span);
-    impl_span
-}
-
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 enum AliasPossibility {
     No,
@@ -1503,7 +1223,7 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> {
         match self.resolve_ast_path_inner(path, is_value) {
             Ok(r) => r,
             Err((span, error)) => {
-                resolve_error(self, span, error);
+                self.report_error(span, error);
                 Res::Err
             }
         }
@@ -1736,7 +1456,7 @@ impl<'a> Resolver<'a> {
 
         self.late_resolve_crate(krate);
 
-        check_unused::check_crate(self, krate);
+        self.check_unused(krate);
         self.report_errors(krate);
         self.crate_loader.postprocess(krate);
     }
@@ -2581,7 +2301,7 @@ impl<'a> Resolver<'a> {
         // An invalid forward use of a type parameter from a previous default.
         if let ForwardTyParamBanRibKind = all_ribs[rib_index].kind {
             if record_used {
-                resolve_error(self, span, ResolutionError::ForwardDeclaredTyParam);
+                self.report_error(span, ResolutionError::ForwardDeclaredTyParam);
             }
             assert_eq!(res, Res::Err);
             return Res::Err;
@@ -2590,7 +2310,7 @@ impl<'a> Resolver<'a> {
         // An invalid use of a type parameter as the type of a const parameter.
         if let TyParamAsConstParamTy = all_ribs[rib_index].kind {
             if record_used {
-                resolve_error(self, span, ResolutionError::ConstParamDependentOnTypeParam);
+                self.report_error(span, ResolutionError::ConstParamDependentOnTypeParam);
             }
             assert_eq!(res, Res::Err);
             return Res::Err;
@@ -2622,14 +2342,14 @@ impl<'a> Resolver<'a> {
                         ConstantItemRibKind => {
                             // Still doesn't deal with upvars
                             if record_used {
-                                resolve_error(self, span, AttemptToUseNonConstantValueInConstant);
+                                self.report_error(span, AttemptToUseNonConstantValueInConstant);
                             }
                             return Res::Err;
                         }
                     }
                 }
                 if let Some(res_err) = res_err {
-                     resolve_error(self, span, res_err);
+                     self.report_error(span, res_err);
                      return Res::Err;
                 }
             }
@@ -2644,10 +2364,8 @@ impl<'a> Resolver<'a> {
                         ItemRibKind | FnItemRibKind => {
                             // This was an attempt to use a type parameter outside its scope.
                             if record_used {
-                                resolve_error(
-                                    self,
-                                    span,
-                                    ResolutionError::GenericParamsFromOuterFunction(res),
+                                self.report_error(
+                                    span, ResolutionError::GenericParamsFromOuterFunction(res)
                                 );
                             }
                             return Res::Err;
@@ -2667,10 +2385,8 @@ impl<'a> Resolver<'a> {
                     if let ItemRibKind | FnItemRibKind = rib.kind {
                         // This was an attempt to use a const parameter outside its scope.
                         if record_used {
-                            resolve_error(
-                                self,
-                                span,
-                                ResolutionError::GenericParamsFromOuterFunction(res),
+                            self.report_error(
+                                span, ResolutionError::GenericParamsFromOuterFunction(res)
                             );
                         }
                         return Res::Err;
@@ -2773,8 +2489,9 @@ impl<'a> Resolver<'a> {
                         ty::Visibility::Public
                     }
                     PathResult::Failed { span, label, suggestion, .. } => {
-                        let err = ResolutionError::FailedToResolve { label, suggestion };
-                        resolve_error(self, span, err);
+                        self.report_error(
+                            span, ResolutionError::FailedToResolve { label, suggestion }
+                        );
                         ty::Visibility::Public
                     }
                     PathResult::Indeterminate => {
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index fed8e555d2b..78edb685edd 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -1,8 +1,7 @@
 use crate::{AmbiguityError, AmbiguityKind, AmbiguityErrorMisc, Determinacy};
 use crate::{CrateLint, Resolver, ResolutionError, Scope, ScopeSet, ParentScope, Weak};
 use crate::{Module, ModuleKind, NameBinding, PathResult, Segment, ToNameBinding};
-use crate::{resolve_error, KNOWN_TOOLS};
-use crate::ModuleOrUniformRoot;
+use crate::{ModuleOrUniformRoot, KNOWN_TOOLS};
 use crate::Namespace::*;
 use crate::build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport};
 use crate::resolve_imports::ImportResolver;
@@ -768,7 +767,7 @@ impl<'a> Resolver<'a> {
                         (path_span, format!("partially resolved path in {} {}",
                                             kind.article(), kind.descr()))
                     };
-                    resolve_error(self, span, ResolutionError::FailedToResolve {
+                    self.report_error(span, ResolutionError::FailedToResolve {
                         label,
                         suggestion: None
                     });
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index 2ae2b1f3fc3..aef586fe43c 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -5,9 +5,8 @@ use crate::{CrateLint, Module, ModuleOrUniformRoot, PerNS, ScopeSet, ParentScope
 use crate::Determinacy::{self, *};
 use crate::Namespace::{self, TypeNS, MacroNS};
 use crate::{NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError};
-use crate::{Resolver, Segment};
+use crate::{Resolver, ResolutionError, Segment};
 use crate::{names_to_string, module_to_string};
-use crate::{resolve_error, ResolutionError};
 use crate::ModuleKind;
 use crate::build_reduced_graph::BuildReducedGraphVisitor;
 use crate::diagnostics::Suggestion;
@@ -913,7 +912,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
             PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => {
                 if no_ambiguity {
                     assert!(directive.imported_module.get().is_none());
-                    resolve_error(&self.r, span, ResolutionError::FailedToResolve {
+                    self.r.report_error(span, ResolutionError::FailedToResolve {
                         label,
                         suggestion,
                     });