Skip to content

Commit 787d9da

Browse files
committed
Auto merge of #41840 - arielb1:deduplicate-selection-errors, r=nikomatsakis
Suppress trait errors that are implied by other errors this is currently a hack and should be cleaned up somewhat. Posting this to get some feedback. r? @nikomatsakis cc @estebank
2 parents c3627e2 + 7b9519a commit 787d9da

23 files changed

+277
-265
lines changed

src/librustc/infer/error_reporting/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ use syntax_pos::{Pos, Span};
7474
use errors::{DiagnosticBuilder, DiagnosticStyledString};
7575

7676
mod note;
77+
mod need_type_info;
7778

7879
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
7980
pub fn note_and_explain_region(self,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use hir::{self, map, Local, Pat, Body};
12+
use hir::intravisit::{self, Visitor, NestedVisitorMap};
13+
use infer::InferCtxt;
14+
use infer::type_variable::TypeVariableOrigin;
15+
use ty::{self, Ty, TyInfer, TyVar};
16+
17+
use syntax::ast::NodeId;
18+
use syntax_pos::Span;
19+
20+
struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
21+
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
22+
target_ty: &'a Ty<'tcx>,
23+
hir_map: &'a hir::map::Map<'gcx>,
24+
found_local_pattern: Option<&'gcx Pat>,
25+
found_arg_pattern: Option<&'gcx Pat>,
26+
}
27+
28+
impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
29+
fn node_matches_type(&mut self, node_id: NodeId) -> bool {
30+
let ty_opt = self.infcx.in_progress_tables.and_then(|tables| {
31+
tables.borrow().node_id_to_type_opt(node_id)
32+
});
33+
match ty_opt {
34+
Some(ty) => {
35+
let ty = self.infcx.resolve_type_vars_if_possible(&ty);
36+
ty.walk().any(|inner_ty| {
37+
inner_ty == *self.target_ty || match (&inner_ty.sty, &self.target_ty.sty) {
38+
(&TyInfer(TyVar(a_vid)), &TyInfer(TyVar(b_vid))) => {
39+
self.infcx
40+
.type_variables
41+
.borrow_mut()
42+
.sub_unified(a_vid, b_vid)
43+
}
44+
_ => false,
45+
}
46+
})
47+
}
48+
None => false,
49+
}
50+
}
51+
}
52+
53+
impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
54+
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
55+
NestedVisitorMap::OnlyBodies(&self.hir_map)
56+
}
57+
58+
fn visit_local(&mut self, local: &'gcx Local) {
59+
if self.found_local_pattern.is_none() && self.node_matches_type(local.id) {
60+
self.found_local_pattern = Some(&*local.pat);
61+
}
62+
intravisit::walk_local(self, local);
63+
}
64+
65+
fn visit_body(&mut self, body: &'gcx Body) {
66+
for argument in &body.arguments {
67+
if self.found_arg_pattern.is_none() && self.node_matches_type(argument.id) {
68+
self.found_arg_pattern = Some(&*argument.pat);
69+
}
70+
}
71+
intravisit::walk_body(self, body);
72+
}
73+
}
74+
75+
76+
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
77+
fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String {
78+
if let ty::TyInfer(ty::TyVar(ty_vid)) = (*ty).sty {
79+
let ty_vars = self.type_variables.borrow();
80+
if let TypeVariableOrigin::TypeParameterDefinition(_, name) =
81+
*ty_vars.var_origin(ty_vid) {
82+
name.to_string()
83+
} else {
84+
ty.to_string()
85+
}
86+
} else {
87+
ty.to_string()
88+
}
89+
}
90+
91+
pub fn need_type_info(&self, body_id: hir::BodyId, span: Span, ty: Ty<'tcx>) {
92+
let ty = self.resolve_type_vars_if_possible(&ty);
93+
let name = self.extract_type_name(&ty);
94+
95+
let mut err_span = span;
96+
let mut labels = vec![(span, format!("cannot infer type for `{}`", name))];
97+
98+
let mut local_visitor = FindLocalByTypeVisitor {
99+
infcx: &self,
100+
target_ty: &ty,
101+
hir_map: &self.tcx.hir,
102+
found_local_pattern: None,
103+
found_arg_pattern: None,
104+
};
105+
106+
// #40294: cause.body_id can also be a fn declaration.
107+
// Currently, if it's anything other than NodeExpr, we just ignore it
108+
match self.tcx.hir.find(body_id.node_id) {
109+
Some(map::NodeExpr(expr)) => local_visitor.visit_expr(expr),
110+
_ => ()
111+
}
112+
113+
if let Some(pattern) = local_visitor.found_arg_pattern {
114+
err_span = pattern.span;
115+
// We don't want to show the default label for closures.
116+
//
117+
// So, before clearing, the output would look something like this:
118+
// ```
119+
// let x = |_| { };
120+
// - ^^^^ cannot infer type for `[_; 0]`
121+
// |
122+
// consider giving this closure parameter a type
123+
// ```
124+
//
125+
// After clearing, it looks something like this:
126+
// ```
127+
// let x = |_| { };
128+
// ^ consider giving this closure parameter a type
129+
// ```
130+
labels.clear();
131+
labels.push((pattern.span, format!("consider giving this closure parameter a type")));
132+
}
133+
134+
if let Some(pattern) = local_visitor.found_local_pattern {
135+
if let Some(simple_name) = pattern.simple_name() {
136+
labels.push((pattern.span, format!("consider giving `{}` a type", simple_name)));
137+
} else {
138+
labels.push((pattern.span, format!("consider giving the pattern a type")));
139+
}
140+
}
141+
142+
let mut err = struct_span_err!(self.tcx.sess,
143+
err_span,
144+
E0282,
145+
"type annotations needed");
146+
147+
for (target_span, label_message) in labels {
148+
err.span_label(target_span, label_message);
149+
}
150+
151+
err.emit();
152+
}
153+
}

src/librustc/infer/mod.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use std::fmt;
3636
use syntax::ast;
3737
use errors::DiagnosticBuilder;
3838
use syntax_pos::{self, Span, DUMMY_SP};
39-
use util::nodemap::{FxHashMap, FxHashSet};
39+
use util::nodemap::FxHashMap;
4040
use arena::DroplessArena;
4141

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

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

115115
// When an error occurs, we want to avoid reporting "derived"
116116
// errors that are due to this original failure. Normally, we
@@ -350,6 +350,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
350350
global_tcx: self,
351351
arena: DroplessArena::new(),
352352
fresh_tables: None,
353+
353354
}
354355
}
355356
}
@@ -381,7 +382,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
381382
region_vars: RegionVarBindings::new(tcx),
382383
selection_cache: traits::SelectionCache::new(),
383384
evaluation_cache: traits::EvaluationCache::new(),
384-
reported_trait_errors: RefCell::new(FxHashSet()),
385+
reported_trait_errors: RefCell::new(FxHashMap()),
385386
tainted_by_errors_flag: Cell::new(false),
386387
err_count_on_creation: tcx.sess.err_count(),
387388
in_snapshot: Cell::new(false),

0 commit comments

Comments
 (0)