Skip to content

Commit efe1a68

Browse files
committed
try to recover the non-matching types in projection errors
The type equation in projection takes place under a binder and a snapshot, which we can't easily take types out of. Instead, when encountering a projection error, try to re-do the projection and find the type error then. This fails to produce a sane type error when the failure was a "leak_check" failure. I can't think of a sane way to show *these*, so I just left them use the old crappy representation, and added a test to make sure we don't break them.
1 parent 7966739 commit efe1a68

File tree

3 files changed

+100
-22
lines changed

3 files changed

+100
-22
lines changed

src/librustc/traits/error_reporting.rs

+60-21
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ use super::{
2626

2727
use fmt_macros::{Parser, Piece, Position};
2828
use hir::def_id::DefId;
29-
use infer::{InferCtxt, TypeOrigin};
29+
use infer::{self, InferCtxt, TypeOrigin};
3030
use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
31+
use ty::error::ExpectedFound;
3132
use ty::fast_reject;
3233
use ty::fold::TypeFolder;
3334
use ty::subst::{self, Subst, TypeSpace};
@@ -107,28 +108,66 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
107108
let predicate =
108109
self.resolve_type_vars_if_possible(&obligation.predicate);
109110

110-
if !predicate.references_error() {
111-
if let Some(warning_node_id) = warning_node_id {
112-
self.tcx.sess.add_lint(
113-
::lint::builtin::UNSIZED_IN_TUPLE,
114-
warning_node_id,
111+
if predicate.references_error() {
112+
return
113+
}
114+
if let Some(warning_node_id) = warning_node_id {
115+
self.tcx.sess.add_lint(
116+
::lint::builtin::UNSIZED_IN_TUPLE,
117+
warning_node_id,
118+
obligation.cause.span,
119+
format!("type mismatch resolving `{}`: {}",
120+
predicate,
121+
error.err));
122+
return
123+
}
124+
self.probe(|_| {
125+
let origin = TypeOrigin::Misc(obligation.cause.span);
126+
let err_buf;
127+
let mut err = &error.err;
128+
let mut values = None;
129+
130+
// try to find the mismatched types to report the error with.
131+
//
132+
// this can fail if the problem was higher-ranked, in which
133+
// cause I have no idea for a good error message.
134+
if let ty::Predicate::Projection(ref data) = predicate {
135+
let mut selcx = SelectionContext::new(self);
136+
let (data, _) = self.replace_late_bound_regions_with_fresh_var(
115137
obligation.cause.span,
116-
format!("type mismatch resolving `{}`: {}",
117-
predicate,
118-
error.err));
119-
} else {
120-
let mut err = type_err!(
121-
self,
122-
TypeOrigin::Misc(obligation.cause.span),
123-
None, // FIXME: be smarter
124-
error.err,
125-
E0271,
126-
"type mismatch resolving `{}`",
127-
predicate);
128-
self.note_obligation_cause(&mut err, obligation);
129-
err.emit();
138+
infer::LateBoundRegionConversionTime::HigherRankedType,
139+
data);
140+
let normalized = super::normalize_projection_type(
141+
&mut selcx,
142+
data.projection_ty,
143+
obligation.cause.clone(),
144+
0
145+
);
146+
let origin = TypeOrigin::Misc(obligation.cause.span);
147+
if let Err(error) = self.eq_types(
148+
false, origin,
149+
data.ty, normalized.value
150+
) {
151+
values = Some(infer::ValuePairs::Types(ExpectedFound {
152+
expected: normalized.value,
153+
found: data.ty,
154+
}));
155+
err_buf = error;
156+
err = &err_buf;
157+
}
130158
}
131-
}
159+
160+
let mut diag = type_err!(
161+
self,
162+
origin,
163+
values,
164+
err,
165+
E0271,
166+
"type mismatch resolving `{}`",
167+
predicate);
168+
self.note_obligation_cause(&mut diag, obligation);
169+
diag.emit();
170+
});
132171
}
133172

134173
fn impl_substs(&self,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2016 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+
#![feature(rustc_attrs)]
12+
13+
// revisions: good bad
14+
15+
trait Mirror {
16+
type Image;
17+
}
18+
19+
impl<T> Mirror for T {
20+
type Image = T;
21+
}
22+
23+
#[cfg(bad)]
24+
fn foo<U, T>(_t: T)
25+
where for<'a> &'a T: Mirror<Image=U>
26+
{}
27+
28+
#[cfg(good)]
29+
fn foo<U, T>(_t: T)
30+
where for<'a> &'a T: Mirror<Image=&'a U>
31+
{}
32+
33+
#[rustc_error]
34+
fn main() { //[good]~ ERROR compilation successful
35+
foo(());
36+
//[bad]~^ ERROR type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _`
37+
//[bad]~| expected bound lifetime parameter 'a, found concrete lifetime
38+
}

src/test/compile-fail/issue-31173.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ pub fn get_tok(it: &mut IntoIter<u8>) {
1919
})
2020
.cloned()
2121
//~^ ERROR type mismatch resolving
22-
//~| expected u8, found &-ptr
22+
//~| expected type `u8`
23+
//~| found type `&_`
2324
.collect(); //~ ERROR no method named `collect`
2425
}
2526

0 commit comments

Comments
 (0)