From b224397b7cb54e8c25e2285e38432db58790016e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 2 Nov 2017 09:42:30 -0400 Subject: [PATCH] issue better error message when LUB/GLB diverge under new behavior --- src/librustc/infer/error_reporting/mod.rs | 9 ++++- src/librustc/infer/glb.rs | 3 ++ src/librustc/infer/lub.rs | 3 ++ src/librustc/ty/error.rs | 6 +++ src/test/ui/lub-glb/old-lub-glb-hr.rs | 36 ++++++++++++++++++ src/test/ui/lub-glb/old-lub-glb-hr.stderr | 22 +++++++++++ src/test/ui/lub-glb/old-lub-glb-object.rs | 38 +++++++++++++++++++ src/test/ui/lub-glb/old-lub-glb-object.stderr | 22 +++++++++++ 8 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/lub-glb/old-lub-glb-hr.rs create mode 100644 src/test/ui/lub-glb/old-lub-glb-hr.stderr create mode 100644 src/test/ui/lub-glb/old-lub-glb-object.rs create mode 100644 src/test/ui/lub-glb/old-lub-glb-object.stderr diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index d22eb20e70a..4f36193e197 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -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 { diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs index 982784f8c40..fd14e0e40e2 100644 --- a/src/librustc/infer/glb.rs +++ b/src/librustc/infer/glb.rs @@ -75,6 +75,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> -> RelateResult<'tcx, ty::Binder> 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 { diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs index bb2df94edd4..55c7eef607b 100644 --- a/src/librustc/infer/lub.rs +++ b/src/librustc/infer/lub.rs @@ -75,6 +75,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> -> RelateResult<'tcx, ty::Binder> 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 { diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index afd1d04a870..228ca76ed9a 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -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); + } _ => {} } } diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.rs b/src/test/ui/lub-glb/old-lub-glb-hr.rs new file mode 100644 index 00000000000..85c90bb375f --- /dev/null +++ b/src/test/ui/lub-glb/old-lub-glb-hr.rs @@ -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 or the MIT license +// , 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() { +} diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.stderr b/src/test/ui/lub-glb/old-lub-glb-hr.stderr new file mode 100644 index 00000000000..4a310a5e6b2 --- /dev/null +++ b/src/test/ui/lub-glb/old-lub-glb-hr.stderr @@ -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 + diff --git a/src/test/ui/lub-glb/old-lub-glb-object.rs b/src/test/ui/lub-glb/old-lub-glb-object.rs new file mode 100644 index 00000000000..7cf89b68be1 --- /dev/null +++ b/src/test/ui/lub-glb/old-lub-glb-object.rs @@ -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 or the MIT license +// , 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 { } + +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() { +} diff --git a/src/test/ui/lub-glb/old-lub-glb-object.stderr b/src/test/ui/lub-glb/old-lub-glb-object.stderr new file mode 100644 index 00000000000..a1077f40bf5 --- /dev/null +++ b/src/test/ui/lub-glb/old-lub-glb-object.stderr @@ -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 +