Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
suppress trait errors that are implied by other errors
Instead of suppressing only trait errors that are "exact duplicates",
display only the "most high-level" error when there are multiple trait
errors with the same span that imply each-other.

e.g. when there are both `[closure]: Fn` and `[closure]: FnOnce`, omit
displaying the `[closure]: FnOnce` bound.
  • Loading branch information
arielb1 committed Jun 14, 2017
1 parent dfa7e21 commit 7b9519a
Show file tree
Hide file tree
Showing 23 changed files with 277 additions and 265 deletions.
1 change: 1 addition & 0 deletions src/librustc/infer/error_reporting/mod.rs
Expand Up @@ -74,6 +74,7 @@ use syntax_pos::{Pos, Span};
use errors::{DiagnosticBuilder, DiagnosticStyledString};

mod note;
mod need_type_info;

impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn note_and_explain_region(self,
Expand Down
153 changes: 153 additions & 0 deletions src/librustc/infer/error_reporting/need_type_info.rs
@@ -0,0 +1,153 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use hir::{self, map, Local, Pat, Body};
use hir::intravisit::{self, Visitor, NestedVisitorMap};
use infer::InferCtxt;
use infer::type_variable::TypeVariableOrigin;
use ty::{self, Ty, TyInfer, TyVar};

use syntax::ast::NodeId;
use syntax_pos::Span;

struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
target_ty: &'a Ty<'tcx>,
hir_map: &'a hir::map::Map<'gcx>,
found_local_pattern: Option<&'gcx Pat>,
found_arg_pattern: Option<&'gcx Pat>,
}

impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
fn node_matches_type(&mut self, node_id: NodeId) -> bool {
let ty_opt = self.infcx.in_progress_tables.and_then(|tables| {
tables.borrow().node_id_to_type_opt(node_id)
});
match ty_opt {
Some(ty) => {
let ty = self.infcx.resolve_type_vars_if_possible(&ty);
ty.walk().any(|inner_ty| {
inner_ty == *self.target_ty || match (&inner_ty.sty, &self.target_ty.sty) {
(&TyInfer(TyVar(a_vid)), &TyInfer(TyVar(b_vid))) => {
self.infcx
.type_variables
.borrow_mut()
.sub_unified(a_vid, b_vid)
}
_ => false,
}
})
}
None => false,
}
}
}

impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
NestedVisitorMap::OnlyBodies(&self.hir_map)
}

fn visit_local(&mut self, local: &'gcx Local) {
if self.found_local_pattern.is_none() && self.node_matches_type(local.id) {
self.found_local_pattern = Some(&*local.pat);
}
intravisit::walk_local(self, local);
}

fn visit_body(&mut self, body: &'gcx Body) {
for argument in &body.arguments {
if self.found_arg_pattern.is_none() && self.node_matches_type(argument.id) {
self.found_arg_pattern = Some(&*argument.pat);
}
}
intravisit::walk_body(self, body);
}
}


impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String {
if let ty::TyInfer(ty::TyVar(ty_vid)) = (*ty).sty {
let ty_vars = self.type_variables.borrow();
if let TypeVariableOrigin::TypeParameterDefinition(_, name) =
*ty_vars.var_origin(ty_vid) {
name.to_string()
} else {
ty.to_string()
}
} else {
ty.to_string()
}
}

pub fn need_type_info(&self, body_id: hir::BodyId, span: Span, ty: Ty<'tcx>) {
let ty = self.resolve_type_vars_if_possible(&ty);
let name = self.extract_type_name(&ty);

let mut err_span = span;
let mut labels = vec![(span, format!("cannot infer type for `{}`", name))];

let mut local_visitor = FindLocalByTypeVisitor {
infcx: &self,
target_ty: &ty,
hir_map: &self.tcx.hir,
found_local_pattern: None,
found_arg_pattern: None,
};

// #40294: cause.body_id can also be a fn declaration.
// Currently, if it's anything other than NodeExpr, we just ignore it
match self.tcx.hir.find(body_id.node_id) {
Some(map::NodeExpr(expr)) => local_visitor.visit_expr(expr),
_ => ()
}

if let Some(pattern) = local_visitor.found_arg_pattern {
err_span = pattern.span;
// We don't want to show the default label for closures.
//
// So, before clearing, the output would look something like this:
// ```
// let x = |_| { };
// - ^^^^ cannot infer type for `[_; 0]`
// |
// consider giving this closure parameter a type
// ```
//
// After clearing, it looks something like this:
// ```
// let x = |_| { };
// ^ consider giving this closure parameter a type
// ```
labels.clear();
labels.push((pattern.span, format!("consider giving this closure parameter a type")));
}

if let Some(pattern) = local_visitor.found_local_pattern {
if let Some(simple_name) = pattern.simple_name() {
labels.push((pattern.span, format!("consider giving `{}` a type", simple_name)));
} else {
labels.push((pattern.span, format!("consider giving the pattern a type")));
}
}

let mut err = struct_span_err!(self.tcx.sess,
err_span,
E0282,
"type annotations needed");

for (target_span, label_message) in labels {
err.span_label(target_span, label_message);
}

err.emit();
}
}
7 changes: 4 additions & 3 deletions src/librustc/infer/mod.rs
Expand Up @@ -36,7 +36,7 @@ use std::fmt;
use syntax::ast;
use errors::DiagnosticBuilder;
use syntax_pos::{self, Span, DUMMY_SP};
use util::nodemap::{FxHashMap, FxHashSet};
use util::nodemap::FxHashMap;
use arena::DroplessArena;

use self::combine::CombineFields;
Expand Down Expand Up @@ -110,7 +110,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {

// the set of predicates on which errors have been reported, to
// avoid reporting the same error twice.
pub reported_trait_errors: RefCell<FxHashSet<traits::TraitErrorKey<'tcx>>>,
pub reported_trait_errors: RefCell<FxHashMap<Span, Vec<ty::Predicate<'tcx>>>>,

// When an error occurs, we want to avoid reporting "derived"
// errors that are due to this original failure. Normally, we
Expand Down Expand Up @@ -350,6 +350,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
global_tcx: self,
arena: DroplessArena::new(),
fresh_tables: None,

}
}
}
Expand Down Expand Up @@ -381,7 +382,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
region_vars: RegionVarBindings::new(tcx),
selection_cache: traits::SelectionCache::new(),
evaluation_cache: traits::EvaluationCache::new(),
reported_trait_errors: RefCell::new(FxHashSet()),
reported_trait_errors: RefCell::new(FxHashMap()),
tainted_by_errors_flag: Cell::new(false),
err_count_on_creation: tcx.sess.err_count(),
in_snapshot: Cell::new(false),
Expand Down

0 comments on commit 7b9519a

Please sign in to comment.