issue better error message when LUB/GLB diverge under new behavior

This commit is contained in:
Niko Matsakis 2017-11-02 09:42:30 -04:00
parent 397973b601
commit b224397b7c
8 changed files with 138 additions and 1 deletions

View file

@ -762,9 +762,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
}
self.note_error_origin(diag, &cause);
self.check_and_note_conflicting_crates(diag, terr, span);
self.tcx.note_and_explain_type_err(diag, terr, span);
// It reads better to have the error origin as the final
// thing.
self.note_error_origin(diag, &cause);
}
pub fn report_and_explain_type_error(&self,
@ -772,6 +775,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
terr: &TypeError<'tcx>)
-> DiagnosticBuilder<'tcx>
{
debug!("report_and_explain_type_error(trace={:?}, terr={:?})",
trace,
terr);
let span = trace.cause.span;
let failure_str = trace.cause.as_failure_str();
let mut diag = match trace.cause.code {

View file

@ -75,6 +75,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'tcx>
{
debug!("binders(a={:?}, b={:?})", a, b);
let was_error = self.infcx().probe(|_snapshot| {
// Subtle: use a fresh combine-fields here because we recover
// from Err. Doing otherwise could propagate obligations out
@ -84,6 +85,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
.higher_ranked_glb(a, b, self.a_is_expected)
.is_err()
});
debug!("binders: was_error={:?}", was_error);
// When higher-ranked types are involved, computing the LUB is
// very challenging, switch to invariance. This is obviously
@ -91,6 +93,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
match self.relate_with_variance(ty::Variance::Invariant, a, b) {
Ok(_) => Ok(a.clone()),
Err(err) => {
debug!("binders: error occurred, was_error={:?}", was_error);
if !was_error {
Err(TypeError::OldStyleLUB(Box::new(err)))
} else {

View file

@ -75,6 +75,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'tcx>
{
debug!("binders(a={:?}, b={:?})", a, b);
let was_error = self.infcx().probe(|_snapshot| {
// Subtle: use a fresh combine-fields here because we recover
// from Err. Doing otherwise could propagate obligations out
@ -84,6 +85,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
.higher_ranked_lub(a, b, self.a_is_expected)
.is_err()
});
debug!("binders: was_error={:?}", was_error);
// When higher-ranked types are involved, computing the LUB is
// very challenging, switch to invariance. This is obviously
@ -91,6 +93,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
match self.relate_with_variance(ty::Variance::Invariant, a, b) {
Ok(_) => Ok(a.clone()),
Err(err) => {
debug!("binders: error occurred, was_error={:?}", was_error);
if !was_error {
Err(TypeError::OldStyleLUB(Box::new(err)))
} else {

View file

@ -298,6 +298,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
db.span_note(found.origin_span,
"...that also applies to the same type variable here");
}
OldStyleLUB(err) => {
db.note("this was previously accepted by the compiler but has been phased out");
db.note("for more information, see https://github.com/rust-lang/rust/issues/45852");
self.note_and_explain_type_err(db, &err, sp);
}
_ => {}
}
}

View file

@ -0,0 +1,36 @@
// 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.
// Test that we give a note when the old LUB/GLB algorithm would have
// succeeded but the new code (which is stricter) gives an error.
fn foo(
x: fn(&u8, &u8),
y: for<'a> fn(&'a u8, &'a u8),
) {
let z = match 22 {
0 => x,
_ => y,
};
}
fn bar(
x: fn(&u8, &u8),
y: for<'a> fn(&'a u8, &'a u8),
) {
let z = match 22 {
// No error with an explicit cast:
0 => x as for<'a> fn(&'a u8, &'a u8),
_ => y,
};
}
fn main() {
}

View file

@ -0,0 +1,22 @@
error[E0308]: match arms have incompatible types
--> $DIR/old-lub-glb-hr.rs:18:13
|
18 | let z = match 22 {
| _____________^
19 | | 0 => x,
20 | | _ => y,
21 | | };
| |_____^ expected bound lifetime parameter, found concrete lifetime
|
= note: expected type `for<'r, 's> fn(&'r u8, &'s u8)`
found type `for<'a> fn(&'a u8, &'a u8)`
= note: this was previously accepted by the compiler but has been phased out
= note: for more information, see https://github.com/rust-lang/rust/issues/45852
note: match arm with an incompatible type
--> $DIR/old-lub-glb-hr.rs:20:14
|
20 | _ => y,
| ^
error: aborting due to previous error

View file

@ -0,0 +1,38 @@
// 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.
// Test that we give a note when the old LUB/GLB algorithm would have
// succeeded but the new code (which is stricter) gives an error.
trait Foo<T, U> { }
fn foo(
x: &for<'a, 'b> Foo<&'a u8, &'b u8>,
y: &for<'a> Foo<&'a u8, &'a u8>,
) {
let z = match 22 {
0 => x,
_ => y,
};
}
fn bar(
x: &for<'a, 'b> Foo<&'a u8, &'b u8>,
y: &for<'a> Foo<&'a u8, &'a u8>,
) {
// Accepted with explicit case:
let z = match 22 {
0 => x as &for<'a> Foo<&'a u8, &'a u8>,
_ => y,
};
}
fn main() {
}

View file

@ -0,0 +1,22 @@
error[E0308]: match arms have incompatible types
--> $DIR/old-lub-glb-object.rs:20:13
|
20 | let z = match 22 {
| _____________^
21 | | 0 => x,
22 | | _ => y,
23 | | };
| |_____^ expected bound lifetime parameter 'a, found concrete lifetime
|
= note: expected type `&for<'a, 'b> Foo<&'a u8, &'b u8>`
found type `&for<'a> Foo<&'a u8, &'a u8>`
= note: this was previously accepted by the compiler but has been phased out
= note: for more information, see https://github.com/rust-lang/rust/issues/45852
note: match arm with an incompatible type
--> $DIR/old-lub-glb-object.rs:22:14
|
22 | _ => y,
| ^
error: aborting due to previous error