From b2422ab806b9a6c2c52e0bd690486df1950f7339 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda <ariel.byd@gmail.com> Date: Fri, 8 Jul 2016 22:51:29 +0300 Subject: [PATCH 01/14] remove never-called type-error reporting functions --- src/librustc/infer/mod.rs | 88 +++++++++------------------------------ 1 file changed, 19 insertions(+), 69 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 2ea2978b294..fc5625036ae 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1468,75 +1468,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // error type, meaning that an error occurred when typechecking this expression), // this is a derived error. The error cascaded from another error (that was already // reported), so it's not useful to display it to the user. - // The following four methods -- type_error_message_str, type_error_message_str_with_expected, - // type_error_message, and report_mismatched_types -- implement this logic. + // The following methods implement this logic. // They check if either the actual or expected type is TyError, and don't print the error // in this case. The typechecker should only ever report type errors involving mismatched - // types using one of these four methods, and should not call span_err directly for such + // types using one of these methods, and should not call span_err directly for such // errors. - pub fn type_error_message_str<M>(&self, - sp: Span, - mk_msg: M, - actual_ty: String, - err: Option<&TypeError<'tcx>>) - where M: FnOnce(Option<String>, String) -> String, - { - self.type_error_message_str_with_expected(sp, mk_msg, None, actual_ty, err) - } - - pub fn type_error_struct_str<M>(&self, - sp: Span, - mk_msg: M, - actual_ty: String, - err: Option<&TypeError<'tcx>>) - -> DiagnosticBuilder<'tcx> - where M: FnOnce(Option<String>, String) -> String, - { - self.type_error_struct_str_with_expected(sp, mk_msg, None, actual_ty, err) - } - - pub fn type_error_message_str_with_expected<M>(&self, - sp: Span, - mk_msg: M, - expected_ty: Option<Ty<'tcx>>, - actual_ty: String, - err: Option<&TypeError<'tcx>>) - where M: FnOnce(Option<String>, String) -> String, - { - self.type_error_struct_str_with_expected(sp, mk_msg, expected_ty, actual_ty, err) - .emit(); - } - - pub fn type_error_struct_str_with_expected<M>(&self, - sp: Span, - mk_msg: M, - expected_ty: Option<Ty<'tcx>>, - actual_ty: String, - err: Option<&TypeError<'tcx>>) - -> DiagnosticBuilder<'tcx> - where M: FnOnce(Option<String>, String) -> String, - { - debug!("hi! expected_ty = {:?}, actual_ty = {}", expected_ty, actual_ty); - - let resolved_expected = expected_ty.map(|e_ty| self.resolve_type_vars_if_possible(&e_ty)); - - if !resolved_expected.references_error() { - let error_str = err.map_or("".to_string(), |t_err| { - format!(" ({})", t_err) - }); - - let mut db = self.tcx.sess.struct_span_err(sp, &format!("{}{}", - mk_msg(resolved_expected.map(|t| self.ty_to_string(t)), actual_ty), - error_str)); - - if let Some(err) = err { - self.tcx.note_and_explain_type_err(&mut db, err, sp); - } - db - } else { - self.tcx.sess.diagnostic().struct_dummy() - } - } pub fn type_error_message<M>(&self, sp: Span, @@ -1556,6 +1492,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -> DiagnosticBuilder<'tcx> where M: FnOnce(String) -> String, { + debug!("type_error_struct({:?}, {:?}, {:?})", sp, actual_ty, err); + let actual_ty = self.resolve_type_vars_if_possible(&actual_ty); // Don't report an error if actual type is TyError. @@ -1563,9 +1501,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { return self.tcx.sess.diagnostic().struct_dummy(); } - self.type_error_struct_str(sp, - move |_e, a| { mk_msg(a) }, - self.ty_to_string(actual_ty), err) + let error_str = err.map_or("".to_string(), |t_err| { + format!(" ({})", t_err) + }); + + let msg = mk_msg(self.ty_to_string(actual_ty)); + + // FIXME: use an error code. + let mut db = self.tcx.sess.struct_span_err( + sp, &format!("{} {}", msg, error_str)); + + if let Some(err) = err { + self.tcx.note_and_explain_type_err(&mut db, err, sp); + } + + db } pub fn report_mismatched_types(&self, From 8eb12d91aaf95432ca73bda429af04e0710c984d Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda <ariel.byd@gmail.com> Date: Sat, 16 Jul 2016 19:38:17 +0300 Subject: [PATCH 02/14] remove rustc_typeck::same_type_err --- src/librustc/infer/error_reporting.rs | 10 +++ src/librustc/infer/mod.rs | 64 ++++++++++++++++++- src/librustc/ty/structural_impls.rs | 13 ++++ src/librustc_typeck/check/_match.rs | 10 +-- src/librustc_typeck/check/demand.rs | 12 ---- src/librustc_typeck/check/intrinsic.rs | 6 +- src/librustc_typeck/check/wfcheck.rs | 3 +- src/librustc_typeck/diagnostics.rs | 2 + src/librustc_typeck/lib.rs | 36 ++++------- src/test/compile-fail/issue-26194.rs | 2 +- src/test/compile-fail/match-range-fail.rs | 5 +- .../compile-fail/ufcs-explicit-self-bad.rs | 6 +- 12 files changed, 114 insertions(+), 55 deletions(-) diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 96ecad629f5..a0fa188c4f8 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -554,6 +554,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { trace: TypeTrace<'tcx>, terr: &TypeError<'tcx>) -> DiagnosticBuilder<'tcx> { + let trace = self.resolve_type_vars_if_possible(&trace); let span = trace.origin.span(); let mut err = self.report_type_error(trace, terr); self.tcx.note_and_explain_type_err(&mut err, terr, span); @@ -1643,6 +1644,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { TypeOrigin::EquatePredicate(_) => { "equality where clause is satisfied" } + TypeOrigin::MainFunctionType(_) => { + "the `main` function has the correct type" + } + TypeOrigin::StartFunctionType(_) => { + "the `start` function has the correct type" + } + TypeOrigin::IntrinsicType(_) => { + "the intrinsic has the correct type" + } }; match self.values_str(&trace.values) { diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index fc5625036ae..dc262e61dd0 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -32,7 +32,7 @@ use ty::adjustment; use ty::{TyVid, IntVid, FloatVid}; use ty::{self, Ty, TyCtxt}; use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; -use ty::fold::TypeFoldable; +use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use ty::relate::{Relate, RelateResult, TypeRelation}; use traits::{self, PredicateObligations, ProjectionMode}; use rustc_data_structures::unify::{self, UnificationTable}; @@ -219,6 +219,15 @@ pub enum TypeOrigin { // `where a == b` EquatePredicate(Span), + + // `main` has wrong type + MainFunctionType(Span), + + // `start` has wrong type + StartFunctionType(Span), + + // intrinsic has wrong type + IntrinsicType(Span), } impl TypeOrigin { @@ -238,6 +247,9 @@ impl TypeOrigin { &TypeOrigin::IfExpressionWithNoElse(_) => "if may be missing an else clause", &TypeOrigin::RangeExpression(_) => "start and end of range have incompatible types", &TypeOrigin::EquatePredicate(_) => "equality predicate not satisfied", + &TypeOrigin::MainFunctionType(_) => "main function has wrong type", + &TypeOrigin::StartFunctionType(_) => "start function has wrong type", + &TypeOrigin::IntrinsicType(_) => "intrinsic has wrong type", } } } @@ -1791,6 +1803,9 @@ impl TypeOrigin { TypeOrigin::IfExpressionWithNoElse(span) => span, TypeOrigin::RangeExpression(span) => span, TypeOrigin::EquatePredicate(span) => span, + TypeOrigin::MainFunctionType(span) => span, + TypeOrigin::StartFunctionType(span) => span, + TypeOrigin::IntrinsicType(span) => span, } } } @@ -1841,3 +1856,50 @@ impl RegionVariableOrigin { } } } + +impl<'tcx> TypeFoldable<'tcx> for TypeOrigin { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self { + self.clone() + } + + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool { + false + } +} + +impl<'tcx> TypeFoldable<'tcx> for ValuePairs<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + match *self { + ValuePairs::Types(ref ef) => { + ValuePairs::Types(ef.fold_with(folder)) + } + ValuePairs::TraitRefs(ref ef) => { + ValuePairs::TraitRefs(ef.fold_with(folder)) + } + ValuePairs::PolyTraitRefs(ref ef) => { + ValuePairs::PolyTraitRefs(ef.fold_with(folder)) + } + } + } + + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + match *self { + ValuePairs::Types(ref ef) => ef.visit_with(visitor), + ValuePairs::TraitRefs(ref ef) => ef.visit_with(visitor), + ValuePairs::PolyTraitRefs(ref ef) => ef.visit_with(visitor), + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for TypeTrace<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + TypeTrace { + origin: self.origin.fold_with(folder), + values: self.values.fold_with(folder) + } + } + + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + self.origin.visit_with(visitor) || self.values.visit_with(visitor) + } +} diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 1e2920ca87e..16a54c20925 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -1018,3 +1018,16 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeScheme<'tcx> { self.generics.visit_with(visitor) || self.ty.visit_with(visitor) } } + +impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::error::ExpectedFound<T> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + ty::error::ExpectedFound { + expected: self.expected.fold_with(folder), + found: self.found.fold_with(folder), + } + } + + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + self.expected.visit_with(visitor) || self.found.visit_with(visitor) + } +} diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index e90b32cd5df..aae6e3ad36d 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -103,15 +103,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return; } - // Check that the types of the end-points can be unified. - let types_unify = self.require_same_types(pat.span, rhs_ty, lhs_ty, - "mismatched types in range"); - - // It's ok to return without a message as `require_same_types` prints an error. - if !types_unify { - return; - } - // Now that we know the types can be unified we find the unified type and use // it to type the entire expression. let common_type = self.resolve_type_vars_if_possible(&lhs_ty); @@ -120,6 +111,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // subtyping doesn't matter here, as the value is some kind of scalar self.demand_eqtype(pat.span, expected, lhs_ty); + self.demand_eqtype(pat.span, expected, rhs_ty); } PatKind::Binding(bm, _, ref sub) => { let typ = self.local_ty(pat.span, pat.id); diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index eeebd6a7f62..c1f415b3c02 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -54,16 +54,4 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.report_mismatched_types(origin, expected, expr_ty, e); } } - - pub fn require_same_types(&self, span: Span, t1: Ty<'tcx>, t2: Ty<'tcx>, msg: &str) - -> bool { - if let Err(err) = self.eq_types(false, TypeOrigin::Misc(span), t1, t2) { - let found_ty = self.resolve_type_vars_if_possible(&t1); - let expected_ty = self.resolve_type_vars_if_possible(&t2); - ::emit_type_err(self.tcx, span, found_ty, expected_ty, &err, msg); - false - } else { - true - } - } } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 5a3268e9e44..8a53c59b4c7 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -12,6 +12,7 @@ //! intrinsics that the compiler exposes. use intrinsics; +use rustc::infer::TypeOrigin; use rustc::ty::subst::{self, Substs}; use rustc::ty::FnSig; use rustc::ty::{self, Ty}; @@ -56,10 +57,9 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, i_n_tps, n_tps); } else { require_same_types(ccx, - it.span, + TypeOrigin::IntrinsicType(it.span), i_ty.ty, - fty, - "intrinsic has wrong type"); + fty); } } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index d101381e256..2d44a85f9af 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -437,8 +437,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty); - fcx.require_same_types(span, sig.inputs[0], rcvr_ty, - "mismatched method receiver"); + fcx.demand_eqtype(span, rcvr_ty, sig.inputs[0]); } fn check_variances_for_type_defn(&self, diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 8769bc1a32b..683328f4eb4 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -2660,6 +2660,7 @@ For information on the design of the orphan rules, see [RFC 1023]. [RFC 1023]: https://github.com/rust-lang/rfcs/pull/1023 "##, +/* E0211: r##" You used a function or type which doesn't fit the requirements for where it was used. Erroneous code examples: @@ -2739,6 +2740,7 @@ impl Foo { } ``` "##, + */ E0214: r##" A generic type was described using parentheses rather than angle brackets. For diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 84452589dfd..3b2d02dc861 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -186,28 +186,14 @@ fn require_c_abi_if_variadic(tcx: TyCtxt, } } -pub fn emit_type_err<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - span: Span, - found_ty: Ty<'tcx>, - expected_ty: Ty<'tcx>, - terr: &ty::error::TypeError<'tcx>, - msg: &str) { - let mut err = struct_span_err!(tcx.sess, span, E0211, "{}", msg); - err.span_label(span, &terr); - err.note_expected_found(&"type", &expected_ty, &found_ty); - tcx.note_and_explain_type_err(&mut err, terr, span); - err.emit(); -} - fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - span: Span, + origin: TypeOrigin, t1: Ty<'tcx>, - t2: Ty<'tcx>, - msg: &str) + t2: Ty<'tcx>) -> bool { ccx.tcx.infer_ctxt(None, None, ProjectionMode::AnyFinal).enter(|infcx| { - if let Err(err) = infcx.eq_types(false, TypeOrigin::Misc(span), t1, t2) { - emit_type_err(infcx.tcx, span, t1, t2, &err, msg); + if let Err(err) = infcx.eq_types(false, origin.clone(), t1, t2) { + infcx.report_mismatched_types(origin, t1, t2, err); false } else { true @@ -249,8 +235,11 @@ fn check_main_fn_ty(ccx: &CrateCtxt, }) })); - require_same_types(ccx, main_span, main_t, se_ty, - "main function has wrong type"); + require_same_types( + ccx, + TypeOrigin::MainFunctionType(main_span), + main_t, + se_ty); } _ => { span_bug!(main_span, @@ -298,8 +287,11 @@ fn check_start_fn_ty(ccx: &CrateCtxt, }), })); - require_same_types(ccx, start_span, start_t, se_ty, - "start function has wrong type"); + require_same_types( + ccx, + TypeOrigin::StartFunctionType(start_span), + start_t, + se_ty); } _ => { span_bug!(start_span, diff --git a/src/test/compile-fail/issue-26194.rs b/src/test/compile-fail/issue-26194.rs index ef91188c5d1..1bc0a4f9652 100644 --- a/src/test/compile-fail/issue-26194.rs +++ b/src/test/compile-fail/issue-26194.rs @@ -12,7 +12,7 @@ struct S(String); impl S { fn f(self: *mut S) -> String { self.0 } - //~^ ERROR mismatched method receiver + //~^ ERROR mismatched types } fn main() { S("".to_owned()).f(); } diff --git a/src/test/compile-fail/match-range-fail.rs b/src/test/compile-fail/match-range-fail.rs index 526aa83dec7..2c4c2563021 100644 --- a/src/test/compile-fail/match-range-fail.rs +++ b/src/test/compile-fail/match-range-fail.rs @@ -27,6 +27,7 @@ fn main() { 'c' ... 100 => { } _ => { } }; - //~^^^ ERROR mismatched types in range - //~| expected char, found integral variable + //~^^^ ERROR mismatched types + //~| expected type `_` + //~| found type `char` } diff --git a/src/test/compile-fail/ufcs-explicit-self-bad.rs b/src/test/compile-fail/ufcs-explicit-self-bad.rs index f14a3505cde..e997cf47c73 100644 --- a/src/test/compile-fail/ufcs-explicit-self-bad.rs +++ b/src/test/compile-fail/ufcs-explicit-self-bad.rs @@ -15,7 +15,7 @@ struct Foo { } impl Foo { - fn foo(self: isize, x: isize) -> isize { //~ ERROR mismatched method receiver + fn foo(self: isize, x: isize) -> isize { //~ ERROR mismatched types self.f + x } } @@ -25,10 +25,10 @@ struct Bar<T> { } impl<T> Bar<T> { - fn foo(self: Bar<isize>, x: isize) -> isize { //~ ERROR mismatched method receiver + fn foo(self: Bar<isize>, x: isize) -> isize { //~ ERROR mismatched types x } - fn bar(self: &Bar<usize>, x: isize) -> isize { //~ ERROR mismatched method receiver + fn bar(self: &Bar<usize>, x: isize) -> isize { //~ ERROR mismatched types x } } From cea88ebb39402ceee9ec5f7cd61c877ae4cd16dc Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda <ariel.byd@gmail.com> Date: Sat, 16 Jul 2016 23:18:20 +0300 Subject: [PATCH 03/14] refactor type error reporting --- src/librustc/infer/error_reporting.rs | 233 +++++++------------- src/librustc/infer/mod.rs | 48 ++-- src/librustc/macros.rs | 12 + src/librustc_typeck/check/callee.rs | 2 +- src/librustc_typeck/check/cast.rs | 15 +- src/librustc_typeck/check/method/suggest.rs | 3 +- src/librustc_typeck/check/mod.rs | 27 +-- src/librustc_typeck/check/op.rs | 2 +- 8 files changed, 140 insertions(+), 202 deletions(-) diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index a0fa188c4f8..be73818c8a4 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -83,7 +83,7 @@ use hir::def_id::DefId; use infer::{self, TypeOrigin}; use middle::region; use ty::subst; -use ty::{self, Ty, TyCtxt, TypeFoldable}; +use ty::{self, TyCtxt, TypeFoldable}; use ty::{Region, ReFree}; use ty::error::TypeError; @@ -462,52 +462,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - fn report_type_error(&self, - trace: TypeTrace<'tcx>, - terr: &TypeError<'tcx>) - -> DiagnosticBuilder<'tcx> { - let (expected, found) = match self.values_str(&trace.values) { - Some(v) => v, - None => { - return self.tcx.sess.diagnostic().struct_dummy(); /* derived error */ - } - }; - - let is_simple_error = if let &TypeError::Sorts(ref values) = terr { - values.expected.is_primitive() && values.found.is_primitive() - } else { - false - }; - - let mut err = struct_span_err!(self.tcx.sess, - trace.origin.span(), - E0308, - "{}", - trace.origin); - - if !is_simple_error || check_old_school() { - err.note_expected_found(&"type", &expected, &found); - } - - err.span_label(trace.origin.span(), &terr); - - self.check_and_note_conflicting_crates(&mut err, terr, trace.origin.span()); - - match trace.origin { - TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source { - hir::MatchSource::IfLetDesugar{..} => { - err.span_note(arm_span, "`if let` arm with an incompatible type"); - } - _ => { - err.span_note(arm_span, "match arm with an incompatible type"); - } - }, - _ => () - } - - err - } - /// Adds a note if the types come from similarly named crates fn check_and_note_conflicting_crates(&self, err: &mut DiagnosticBuilder, @@ -550,43 +504,91 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - pub fn report_and_explain_type_error(&self, - trace: TypeTrace<'tcx>, - terr: &TypeError<'tcx>) - -> DiagnosticBuilder<'tcx> { - let trace = self.resolve_type_vars_if_possible(&trace); + fn note_error_origin(&self, + err: &mut DiagnosticBuilder<'tcx>, + origin: &TypeOrigin) + { + match origin { + &TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source { + hir::MatchSource::IfLetDesugar {..} => { + err.span_note(arm_span, "`if let` arm with an incompatible type"); + } + _ => { + err.span_note(arm_span, "match arm with an incompatible type"); + } + }, + _ => () + } + } + + pub fn report_and_explain_type_error_with_code(&self, + trace: TypeTrace<'tcx>, + terr: &TypeError<'tcx>, + message: &str, + code: &str) + -> DiagnosticBuilder<'tcx> + { + let (expected, found) = match self.values_str(&trace.values) { + Some((expected, found)) => (expected, found), + None => return self.tcx.sess.diagnostic().struct_dummy() /* derived error */ + }; + let span = trace.origin.span(); - let mut err = self.report_type_error(trace, terr); + + let is_simple_error = if let &TypeError::Sorts(ref values) = terr { + values.expected.is_primitive() && values.found.is_primitive() + } else { + false + }; + + let mut err = self.tcx.sess.struct_span_err_with_code( + trace.origin.span(), + message, + code); + + if !is_simple_error || check_old_school() { + err.note_expected_found(&"type", &expected, &found); + } + + err.span_label(span, &terr); + + self.note_error_origin(&mut err, &trace.origin); + self.check_and_note_conflicting_crates(&mut err, terr, span); self.tcx.note_and_explain_type_err(&mut err, terr, span); + err } - /// Returns a string of the form "expected `{}`, found `{}`", or None if this is a derived - /// error. + pub fn report_and_explain_type_error(&self, + trace: TypeTrace<'tcx>, + terr: &TypeError<'tcx>) + -> DiagnosticBuilder<'tcx> + { + // FIXME: do we want to use a different error code for each origin? + let failure_str = trace.origin.as_failure_str(); + type_err!(self, trace, terr, E0308, "{}", failure_str) + } + + /// Returns a string of the form "expected `{}`, found `{}`". fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<(String, String)> { match *values { infer::Types(ref exp_found) => self.expected_found_str(exp_found), infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found), - infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found) + infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found), } } - fn expected_found_str<T: fmt::Display + Resolvable<'tcx> + TypeFoldable<'tcx>>( + fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>( &self, exp_found: &ty::error::ExpectedFound<T>) -> Option<(String, String)> { - let expected = exp_found.expected.resolve(self); - if expected.references_error() { + let exp_found = self.resolve_type_vars_if_possible(exp_found); + if exp_found.references_error() { return None; } - let found = exp_found.found.resolve(self); - if found.references_error() { - return None; - } - - Some((format!("{}", expected), format!("{}", found))) + Some((format!("{}", exp_found.expected), format!("{}", exp_found.found))) } fn report_generic_bound_failure(&self, @@ -1609,68 +1611,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn note_region_origin(&self, err: &mut DiagnosticBuilder, origin: &SubregionOrigin<'tcx>) { match *origin { infer::Subtype(ref trace) => { - let desc = match trace.origin { - TypeOrigin::Misc(_) => { - "types are compatible" - } - TypeOrigin::MethodCompatCheck(_) => { - "method type is compatible with trait" - } - TypeOrigin::ExprAssignable(_) => { - "expression is assignable" - } - TypeOrigin::RelateTraitRefs(_) => { - "traits are compatible" - } - TypeOrigin::RelateSelfType(_) => { - "self type matches impl self type" - } - TypeOrigin::RelateOutputImplTypes(_) => { - "trait type parameters matches those \ - specified on the impl" - } - TypeOrigin::MatchExpressionArm(_, _, _) => { - "match arms have compatible types" - } - TypeOrigin::IfExpression(_) => { - "if and else have compatible types" - } - TypeOrigin::IfExpressionWithNoElse(_) => { - "if may be missing an else clause" - } - TypeOrigin::RangeExpression(_) => { - "start and end of range have compatible types" - } - TypeOrigin::EquatePredicate(_) => { - "equality where clause is satisfied" - } - TypeOrigin::MainFunctionType(_) => { - "the `main` function has the correct type" - } - TypeOrigin::StartFunctionType(_) => { - "the `start` function has the correct type" - } - TypeOrigin::IntrinsicType(_) => { - "the intrinsic has the correct type" - } - }; + if let Some((expected, found)) = self.values_str(&trace.values) { + // FIXME: do we want a "the" here? + err.span_note( + trace.origin.span(), + &format!("...so that {} (expected {}, found {})", + trace.origin.as_requirement_str(), expected, found)); + } else { + // FIXME: this really should be handled at some earlier stage. Our + // handling of region checking when type errors are present is + // *terrible*. - match self.values_str(&trace.values) { - Some((expected, found)) => { - err.span_note( - trace.origin.span(), - &format!("...so that {} (expected {}, found {})", - desc, expected, found)); - } - None => { - // Really should avoid printing this error at - // all, since it is derived, but that would - // require more refactoring than I feel like - // doing right now. - nmatsakis - err.span_note( - trace.origin.span(), - &format!("...so that {}", desc)); - } + err.span_note( + trace.origin.span(), + &format!("...so that {}", + trace.origin.as_requirement_str())); } } infer::Reborrow(span) => { @@ -1813,32 +1768,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } -pub trait Resolvable<'tcx> { - fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Self; -} - -impl<'tcx> Resolvable<'tcx> for Ty<'tcx> { - fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { - infcx.resolve_type_vars_if_possible(self) - } -} - -impl<'tcx> Resolvable<'tcx> for ty::TraitRef<'tcx> { - fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) - -> ty::TraitRef<'tcx> { - infcx.resolve_type_vars_if_possible(self) - } -} - -impl<'tcx> Resolvable<'tcx> for ty::PolyTraitRef<'tcx> { - fn resolve<'a, 'gcx>(&self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>) - -> ty::PolyTraitRef<'tcx> - { - infcx.resolve_type_vars_if_possible(self) - } -} - fn lifetimes_in_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, scope_id: ast::NodeId) -> Vec<hir::LifetimeDef> { diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index dc262e61dd0..fd65e06ea97 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -231,7 +231,7 @@ pub enum TypeOrigin { } impl TypeOrigin { - fn as_str(&self) -> &'static str { + fn as_failure_str(&self) -> &'static str { match self { &TypeOrigin::Misc(_) | &TypeOrigin::RelateSelfType(_) | @@ -252,11 +252,26 @@ impl TypeOrigin { &TypeOrigin::IntrinsicType(_) => "intrinsic has wrong type", } } -} -impl fmt::Display for TypeOrigin { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(),fmt::Error> { - fmt::Display::fmt(self.as_str(), f) + fn as_requirement_str(&self) -> &'static str { + match self { + &TypeOrigin::Misc(_) => "types are compatible", + &TypeOrigin::MethodCompatCheck(_) => "method type is compatible with trait", + &TypeOrigin::ExprAssignable(_) => "expression is assignable", + &TypeOrigin::RelateTraitRefs(_) => "traits are compatible", + &TypeOrigin::RelateSelfType(_) => "self type matches impl self type", + &TypeOrigin::RelateOutputImplTypes(_) => { + "trait type parameters matches those specified on the impl" + } + &TypeOrigin::MatchExpressionArm(_, _, _) => "match arms have compatible types", + &TypeOrigin::IfExpression(_) => "if and else have compatible types", + &TypeOrigin::IfExpressionWithNoElse(_) => "if missing an else returns ()", + &TypeOrigin::RangeExpression(_) => "start and end of range have compatible types", + &TypeOrigin::EquatePredicate(_) => "equality where clause is satisfied", + &TypeOrigin::MainFunctionType(_) => "`main` function has the correct type", + &TypeOrigin::StartFunctionType(_) => "`start` function has the correct type", + &TypeOrigin::IntrinsicType(_) => "intrinsic has the correct type", + } } } @@ -1489,22 +1504,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn type_error_message<M>(&self, sp: Span, mk_msg: M, - actual_ty: Ty<'tcx>, - err: Option<&TypeError<'tcx>>) + actual_ty: Ty<'tcx>) where M: FnOnce(String) -> String, { - self.type_error_struct(sp, mk_msg, actual_ty, err).emit(); + self.type_error_struct(sp, mk_msg, actual_ty).emit(); } pub fn type_error_struct<M>(&self, sp: Span, mk_msg: M, - actual_ty: Ty<'tcx>, - err: Option<&TypeError<'tcx>>) + actual_ty: Ty<'tcx>) -> DiagnosticBuilder<'tcx> where M: FnOnce(String) -> String, { - debug!("type_error_struct({:?}, {:?}, {:?})", sp, actual_ty, err); + debug!("type_error_struct({:?}, {:?})", sp, actual_ty); let actual_ty = self.resolve_type_vars_if_possible(&actual_ty); @@ -1513,21 +1526,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { return self.tcx.sess.diagnostic().struct_dummy(); } - let error_str = err.map_or("".to_string(), |t_err| { - format!(" ({})", t_err) - }); - let msg = mk_msg(self.ty_to_string(actual_ty)); // FIXME: use an error code. - let mut db = self.tcx.sess.struct_span_err( - sp, &format!("{} {}", msg, error_str)); - - if let Some(err) = err { - self.tcx.note_and_explain_type_err(&mut db, err, sp); - } - - db + self.tcx.sess.struct_span_err(sp, &msg) } pub fn report_mismatched_types(&self, diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index 76dca1bb5b6..52420475db1 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -59,3 +59,15 @@ macro_rules! span_bug { $crate::session::span_bug_fmt(file!(), line!(), $span, format_args!($($message)*)) }) } + +#[macro_export] +macro_rules! type_err { + ($infcx:expr, $trace: expr, $terr: expr, $code:ident, $($message:tt)*) => ({ + __diagnostic_used!($code); + $infcx.report_and_explain_type_error_with_code( + $trace, + $terr, + &format!($($message)*), + stringify!($code)) + }) +} diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 2c7e7d284fa..9c6727ebbfc 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -216,7 +216,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => { let mut err = self.type_error_struct(call_expr.span, |actual| { format!("expected function, found `{}`", actual) - }, callee_ty, None); + }, callee_ty); if let hir::ExprCall(ref expr, _) = call_expr.node { let tcx = self.tcx; diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 22ac8bc5690..7a4cc09a7d5 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -149,7 +149,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { format!("casting `{}` as `{}` is invalid", actual, fcx.ty_to_string(self.cast_ty)) - }, self.expr_ty, None) + }, self.expr_ty) .help(&format!("cast through {} first", match e { CastError::NeedViaPtr => "a raw pointer", CastError::NeedViaThinPtr => "a thin pointer", @@ -167,35 +167,35 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { CastError::CastToChar => { fcx.type_error_message(self.span, |actual| { format!("only `u8` can be cast as `char`, not `{}`", actual) - }, self.expr_ty, None); + }, self.expr_ty); } CastError::NonScalar => { fcx.type_error_message(self.span, |actual| { format!("non-scalar cast: `{}` as `{}`", actual, fcx.ty_to_string(self.cast_ty)) - }, self.expr_ty, None); + }, self.expr_ty); } CastError::IllegalCast => { fcx.type_error_message(self.span, |actual| { format!("casting `{}` as `{}` is invalid", actual, fcx.ty_to_string(self.cast_ty)) - }, self.expr_ty, None); + }, self.expr_ty); } CastError::SizedUnsizedCast => { fcx.type_error_message(self.span, |actual| { format!("cannot cast thin pointer `{}` to fat pointer `{}`", actual, fcx.ty_to_string(self.cast_ty)) - }, self.expr_ty, None) + }, self.expr_ty) } CastError::DifferingKinds => { fcx.type_error_struct(self.span, |actual| { format!("casting `{}` as `{}` is invalid", actual, fcx.ty_to_string(self.cast_ty)) - }, self.expr_ty, None) + }, self.expr_ty) .note("vtable kinds may not match") .emit(); } @@ -213,7 +213,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { let tstr = fcx.ty_to_string(self.cast_ty); let mut err = fcx.type_error_struct(self.span, |actual| { format!("cast to unsized type: `{}` as `{}`", actual, tstr) - }, self.expr_ty, None); + }, self.expr_ty); match self.expr_ty.sty { ty::TyRef(_, ty::TypeAndMut { mutbl: mt, .. }) => { let mtstr = match mt { @@ -484,4 +484,3 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundSized, span) } } - diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index f20dcdc35ae..346449d0a51 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -160,8 +160,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { item_name, actual) }, - rcvr_ty, - None); + rcvr_ty); // If the item has the name of a field, give a help note if let (&ty::TyStruct(def, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index fc1d2236f3f..7076b6a2a90 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2541,21 +2541,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.type_error_message(arg.span, |t| { format!("can't pass an `{}` to variadic \ function, cast to `c_double`", t) - }, arg_ty, None); + }, arg_ty); } ty::TyInt(ast::IntTy::I8) | ty::TyInt(ast::IntTy::I16) | ty::TyBool => { self.type_error_message(arg.span, |t| { format!("can't pass `{}` to variadic \ function, cast to `c_int`", t) - }, arg_ty, None); + }, arg_ty); } ty::TyUint(ast::UintTy::U8) | ty::TyUint(ast::UintTy::U16) => { self.type_error_message(arg.span, |t| { format!("can't pass `{}` to variadic \ function, cast to `c_uint`", t) - }, arg_ty, None); + }, arg_ty); } ty::TyFnDef(_, _, f) => { let ptr_ty = self.tcx.mk_fn_ptr(f); @@ -2564,7 +2564,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { |t| { format!("can't pass `{}` to variadic \ function, cast to `{}`", t, ptr_ty) - }, arg_ty, None); + }, arg_ty); } _ => {} } @@ -2908,9 +2908,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.type_error_struct(field.span, |actual| { format!("attempted to take value of method `{}` on type \ `{}`", field.node, actual) - }, expr_t, None) - .help( - "maybe a `()` to call it is missing? \ + }, expr_t) + .help("maybe a `()` to call it is missing? \ If not, try an anonymous function") .emit(); self.write_error(expr.id); @@ -2919,7 +2918,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { format!("attempted access of field `{}` on type `{}`, \ but no field with that name was found", field.node, actual) - }, expr_t, None); + }, expr_t); if let ty::TyStruct(def, _) = expr_t.sty { Self::suggest_field_names(&mut err, def.struct_variant(), field, vec![]); } @@ -3019,7 +3018,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { actual) } }, - expr_t, None); + expr_t); self.write_error(expr.id); } @@ -3038,8 +3037,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { format!("structure `{}` has no field named `{}`", actual, field.name.node) }, - ty, - None); + ty); // prevent all specified fields from being suggested let skip_fields = skip_fields.iter().map(|ref x| x.name.node.as_str()); Self::suggest_field_names(&mut err, variant, &field.name, skip_fields.collect()); @@ -3272,7 +3270,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.type_error_message(expr.span, |actual| { format!("type `{}` cannot be \ dereferenced", actual) - }, oprnd_t, None); + }, oprnd_t); oprnd_t = tcx.types.err; } } @@ -3647,8 +3645,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { format!("cannot index a value of type `{}`", actual) }, - base_t, - None); + base_t); // Try to give some advice about indexing tuples. if let ty::TyTuple(_) = base_t.sty { let mut needs_note = true; @@ -4523,7 +4520,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if !self.is_tainted_by_errors() { self.type_error_message(sp, |_actual| { "the type of this value must be known in this context".to_string() - }, ty, None); + }, ty); } self.demand_suptype(sp, self.tcx.types.err, ty); ty = self.tcx.types.err; diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 8604dadf46d..d02f87d0b9c 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -239,7 +239,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.type_error_message(ex.span, |actual| { format!("cannot apply unary operator `{}` to type `{}`", op_str, actual) - }, operand_ty, None); + }, operand_ty); self.tcx.types.err } } From b7b2db4da7dc6762d53659b32e5fb4ba8e5c5988 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda <ariel.byd@gmail.com> Date: Mon, 18 Jul 2016 23:13:34 +0300 Subject: [PATCH 04/14] switch compare_method to new-style trait error reporting --- src/librustc_typeck/check/compare_method.rs | 21 ++++++++++--------- .../associated-const-impl-wrong-type.rs | 5 ++--- src/test/compile-fail/issue-13033.rs | 4 +++- src/test/compile-fail/issue-15094.rs | 4 ++-- src/test/compile-fail/issue-21332.rs | 3 +-- src/test/compile-fail/issue-24356.rs | 3 --- .../trait-impl-method-mismatch.rs | 4 ++-- src/test/compile-fail/unsafe-trait-impl.rs | 4 ++-- 8 files changed, 23 insertions(+), 25 deletions(-) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 35a5bc9c609..847dcc90ad3 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -324,10 +324,10 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty); - span_err!(tcx.sess, impl_m_span, E0053, - "method `{}` has an incompatible type for trait: {}", - trait_m.name, - terr); + let trace = infer::TypeTrace::types(origin, false, impl_fty, trait_fty); + type_err!(infcx, trace, &terr, E0053, + "method `{}` has an incompatible type for trait", + trait_m.name).emit(); return } @@ -437,10 +437,9 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Compute skolemized form of impl and trait const tys. let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs); let trait_ty = trait_c.ty.subst(tcx, &trait_to_skol_substs); + let origin = TypeOrigin::Misc(impl_c_span); let err = infcx.commit_if_ok(|_| { - let origin = TypeOrigin::Misc(impl_c_span); - // There is no "body" here, so just pass dummy id. let impl_ty = assoc::normalize_associated_types_in(&infcx, @@ -473,11 +472,13 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, debug!("checking associated const for compatibility: impl ty {:?}, trait ty {:?}", impl_ty, trait_ty); - span_err!(tcx.sess, impl_c_span, E0326, + let values = Some(infer::ValuePairs::Types(ExpectedFound { + expected: trait_ty, + found: impl_ty + })); + type_err!(infcx, origin, values, terr, E0326, "implemented const `{}` has an incompatible type for \ - trait: {}", - trait_c.name, - terr); + trait", trait_c.name).emit(); } }); } diff --git a/src/test/compile-fail/associated-const-impl-wrong-type.rs b/src/test/compile-fail/associated-const-impl-wrong-type.rs index 4658d0f057d..95508a31044 100644 --- a/src/test/compile-fail/associated-const-impl-wrong-type.rs +++ b/src/test/compile-fail/associated-const-impl-wrong-type.rs @@ -18,9 +18,8 @@ struct SignedBar; impl Foo for SignedBar { const BAR: i32 = -1; - //~^ ERROR implemented const `BAR` has an incompatible type for trait - //~| expected u32, - //~| found i32 [E0326] + //~^ ERROR implemented const `BAR` has an incompatible type for trait [E0326] + //~| expected u32, found i32 } fn main() {} diff --git a/src/test/compile-fail/issue-13033.rs b/src/test/compile-fail/issue-13033.rs index 43cf70e5bc3..3d9d81471cb 100644 --- a/src/test/compile-fail/issue-13033.rs +++ b/src/test/compile-fail/issue-13033.rs @@ -16,7 +16,9 @@ struct Baz; impl Foo for Baz { fn bar(&mut self, other: &Foo) {} - //~^ ERROR method `bar` has an incompatible type for trait: values differ in mutability [E0053] + //~^ ERROR method `bar` has an incompatible type for trait + //~| expected type `fn(&mut Baz, &mut Foo)` + //~| found type `fn(&mut Baz, &Foo)` } fn main() {} diff --git a/src/test/compile-fail/issue-15094.rs b/src/test/compile-fail/issue-15094.rs index 42e3456b309..da48bbb3ecd 100644 --- a/src/test/compile-fail/issue-15094.rs +++ b/src/test/compile-fail/issue-15094.rs @@ -20,8 +20,8 @@ impl<T: fmt::Debug> ops::FnOnce<(),> for Debuger<T> { type Output = (); fn call_once(self, _args: ()) { //~^ ERROR `call_once` has an incompatible type for trait - //~| expected "rust-call" fn, - //~| found "Rust" fn + //~| expected type `extern "rust-call" fn + //~| found type `fn println!("{:?}", self.x); } } diff --git a/src/test/compile-fail/issue-21332.rs b/src/test/compile-fail/issue-21332.rs index b36918149fa..db3334834d4 100644 --- a/src/test/compile-fail/issue-21332.rs +++ b/src/test/compile-fail/issue-21332.rs @@ -14,8 +14,7 @@ impl Iterator for S { type Item = i32; fn next(&mut self) -> Result<i32, i32> { Ok(7) } //~^ ERROR method `next` has an incompatible type for trait - //~| expected enum `std::option::Option` - //~| found enum `std::result::Result` [E0053] + //~| expected enum `std::option::Option`, found enum `std::result::Result` } fn main() {} diff --git a/src/test/compile-fail/issue-24356.rs b/src/test/compile-fail/issue-24356.rs index 27d46be40fb..ede81bea32a 100644 --- a/src/test/compile-fail/issue-24356.rs +++ b/src/test/compile-fail/issue-24356.rs @@ -30,9 +30,6 @@ fn main() { impl Deref for Thing { //~^ ERROR not all trait items implemented, missing: `Target` [E0046] fn deref(&self) -> i8 { self.0 } - //~^ ERROR method `deref` has an incompatible type for trait - //~| expected &-ptr - //~| found i8 [E0053] } let thing = Thing(72); diff --git a/src/test/compile-fail/trait-impl-method-mismatch.rs b/src/test/compile-fail/trait-impl-method-mismatch.rs index f86d9b7648b..a05e007d6b7 100644 --- a/src/test/compile-fail/trait-impl-method-mismatch.rs +++ b/src/test/compile-fail/trait-impl-method-mismatch.rs @@ -17,8 +17,8 @@ impl Mumbo for usize { // Cannot have a larger effect than the trait: unsafe fn jumbo(&self, x: &usize) { *self + *x; } //~^ ERROR method `jumbo` has an incompatible type for trait - //~| expected normal fn, - //~| found unsafe fn + //~| expected type `fn + //~| found type `unsafe fn } fn main() {} diff --git a/src/test/compile-fail/unsafe-trait-impl.rs b/src/test/compile-fail/unsafe-trait-impl.rs index 51f876661f6..fb4652affd0 100644 --- a/src/test/compile-fail/unsafe-trait-impl.rs +++ b/src/test/compile-fail/unsafe-trait-impl.rs @@ -17,8 +17,8 @@ trait Foo { impl Foo for u32 { fn len(&self) -> u32 { *self } //~^ ERROR method `len` has an incompatible type for trait - //~| expected unsafe fn, - //~| found normal fn + //~| expected type `unsafe fn(&u32) -> u32` + //~| found type `fn(&u32) -> u32` } fn main() { } From fa4eda8935cc902b0757815e774f11ee791af156 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda <ariel.byd@gmail.com> Date: Tue, 19 Jul 2016 01:02:47 +0300 Subject: [PATCH 05/14] switch projection errors to use the new type error messages Unfortunately, projection errors do not come with a nice set of mismatched types. This is because the type equality check occurs within a higher-ranked context. Therefore, only the type error is reported. This is ugly but was always the situation. I will introduce better errors for the lower-ranked case in another commit. Fixes the last known occurence of #31173 --- src/librustc/infer/error_reporting.rs | 49 +++++++++++-------- src/librustc/macros.rs | 7 +-- src/librustc/traits/error_reporting.rs | 14 ++++-- src/librustc_typeck/check/compare_method.rs | 8 ++- .../compile-fail/associated-types-eq-3.rs | 6 +-- src/test/compile-fail/issue-31173.rs | 26 ++++++++++ 6 files changed, 76 insertions(+), 34 deletions(-) create mode 100644 src/test/compile-fail/issue-31173.rs diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index be73818c8a4..0726d8560ba 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -522,37 +522,46 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } pub fn report_and_explain_type_error_with_code(&self, - trace: TypeTrace<'tcx>, + origin: TypeOrigin, + values: Option<ValuePairs<'tcx>>, terr: &TypeError<'tcx>, message: &str, code: &str) -> DiagnosticBuilder<'tcx> { - let (expected, found) = match self.values_str(&trace.values) { - Some((expected, found)) => (expected, found), - None => return self.tcx.sess.diagnostic().struct_dummy() /* derived error */ - }; - - let span = trace.origin.span(); - - let is_simple_error = if let &TypeError::Sorts(ref values) = terr { - values.expected.is_primitive() && values.found.is_primitive() - } else { - false + let expected_found = match values { + None => None, + Some(values) => match self.values_str(&values) { + Some((expected, found)) => Some((expected, found)), + None => return self.tcx.sess.diagnostic().struct_dummy() /* derived error */ + } }; + let span = origin.span(); let mut err = self.tcx.sess.struct_span_err_with_code( - trace.origin.span(), - message, - code); + span, message, code); - if !is_simple_error || check_old_school() { - err.note_expected_found(&"type", &expected, &found); + let mut is_simple_error = false; + + if let Some((expected, found)) = expected_found { + is_simple_error = if let &TypeError::Sorts(ref values) = terr { + values.expected.is_primitive() && values.found.is_primitive() + } else { + false + }; + + if !is_simple_error || check_old_school() { + err.note_expected_found(&"type", &expected, &found); + } } - err.span_label(span, &terr); + if !is_simple_error && check_old_school() { + err.span_note(span, &format!("{}", terr)); + } else { + err.span_label(span, &terr); + } - self.note_error_origin(&mut err, &trace.origin); + self.note_error_origin(&mut err, &origin); self.check_and_note_conflicting_crates(&mut err, terr, span); self.tcx.note_and_explain_type_err(&mut err, terr, span); @@ -566,7 +575,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { // FIXME: do we want to use a different error code for each origin? let failure_str = trace.origin.as_failure_str(); - type_err!(self, trace, terr, E0308, "{}", failure_str) + type_err!(self, trace.origin, Some(trace.values), terr, E0308, "{}", failure_str) } /// Returns a string of the form "expected `{}`, found `{}`". diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index 52420475db1..190c9b665e0 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -62,11 +62,12 @@ macro_rules! span_bug { #[macro_export] macro_rules! type_err { - ($infcx:expr, $trace: expr, $terr: expr, $code:ident, $($message:tt)*) => ({ + ($infcx:expr, $origin: expr, $values: expr, $terr: expr, $code:ident, $($message:tt)*) => ({ __diagnostic_used!($code); $infcx.report_and_explain_type_error_with_code( - $trace, - $terr, + $origin, + $values, + &$terr, &format!($($message)*), stringify!($code)) }) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 3b9ecb88258..afbe34f89bb 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -26,7 +26,7 @@ use super::{ use fmt_macros::{Parser, Piece, Position}; use hir::def_id::DefId; -use infer::{InferCtxt}; +use infer::{InferCtxt, TypeOrigin}; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use ty::fast_reject; use ty::fold::TypeFolder; @@ -117,10 +117,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { predicate, error.err)); } else { - let mut err = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, - "type mismatch resolving `{}`: {}", - predicate, - error.err); + let mut err = type_err!( + self, + TypeOrigin::Misc(obligation.cause.span), + None, // FIXME: be smarter + error.err, + E0271, + "type mismatch resolving `{}`", + predicate); self.note_obligation_cause(&mut err, obligation); err.emit(); } diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 847dcc90ad3..2c4c6279076 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -12,6 +12,7 @@ use middle::free_region::FreeRegionMap; use rustc::infer::{self, InferOk, TypeOrigin}; use rustc::ty; use rustc::traits::{self, ProjectionMode}; +use rustc::ty::error::ExpectedFound; use rustc::ty::subst::{self, Subst, Substs, VecPerParamSpace}; use syntax::ast; @@ -324,8 +325,11 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty); - let trace = infer::TypeTrace::types(origin, false, impl_fty, trait_fty); - type_err!(infcx, trace, &terr, E0053, + let values = Some(infer::ValuePairs::Types(ExpectedFound { + expected: trait_fty, + found: impl_fty + })); + type_err!(infcx, origin, values, terr, E0053, "method `{}` has an incompatible type for trait", trait_m.name).emit(); return diff --git a/src/test/compile-fail/associated-types-eq-3.rs b/src/test/compile-fail/associated-types-eq-3.rs index 8c66160e8a3..cb952f6534f 100644 --- a/src/test/compile-fail/associated-types-eq-3.rs +++ b/src/test/compile-fail/associated-types-eq-3.rs @@ -47,10 +47,8 @@ pub fn main() { let a = 42; foo1(a); //~^ ERROR type mismatch resolving - //~| expected usize - //~| found struct `Bar` + //~| expected usize, found struct `Bar` baz(&a); //~^ ERROR type mismatch resolving - //~| expected usize - //~| found struct `Bar` + //~| expected usize, found struct `Bar` } diff --git a/src/test/compile-fail/issue-31173.rs b/src/test/compile-fail/issue-31173.rs new file mode 100644 index 00000000000..62d23a99cba --- /dev/null +++ b/src/test/compile-fail/issue-31173.rs @@ -0,0 +1,26 @@ +// Copyright 2016 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 std::vec::IntoIter; + +pub fn get_tok(it: &mut IntoIter<u8>) { + let mut found_e = false; + + let temp: Vec<u8> = it.take_while(|&x| { + found_e = true; + false + }) + .cloned() + //~^ ERROR type mismatch resolving + //~| expected u8, found &-ptr + .collect(); //~ ERROR no method named `collect` +} + +fn main() {} From 37c569627cd285788509f654a6a2658126ba72e4 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda <ariel.byd@gmail.com> Date: Wed, 20 Jul 2016 00:02:56 +0300 Subject: [PATCH 06/14] refactor constant evaluation error reporting Refactor constant evaluation to use a single error reporting function that reports a type-error-like message. Also, unify all error codes with the "constant evaluation error" message to just E0080, and similarly for a few other duplicate codes. The old situation was a total mess, and now that we have *something* we can further iterate on the UX. --- src/librustc_const_eval/Cargo.toml | 1 + src/librustc_const_eval/check_match.rs | 55 ++-- src/librustc_const_eval/diagnostics.rs | 44 +-- src/librustc_const_eval/eval.rs | 256 +++++++++++++----- src/librustc_const_eval/lib.rs | 1 + src/librustc_passes/consts.rs | 28 +- src/librustc_passes/diagnostics.rs | 4 +- src/librustc_trans/_match.rs | 16 +- src/librustc_trans/consts.rs | 21 +- src/librustc_trans/intrinsic.rs | 6 +- src/librustc_trans/mir/constant.rs | 2 +- src/librustc_trans/trans_item.rs | 7 +- src/librustc_trans/tvec.rs | 6 +- src/librustc_typeck/astconv.rs | 37 +-- src/librustc_typeck/check/mod.rs | 5 +- src/librustc_typeck/collect.rs | 12 +- src/librustc_typeck/diagnostics.rs | 52 +--- src/rustc/Cargo.lock | 1 + src/test/compile-fail/array_const_index-0.rs | 3 +- src/test/compile-fail/array_const_index-1.rs | 3 +- .../associated-const-array-len.rs | 2 +- ...ssociated-const-type-parameter-arrays-2.rs | 3 +- src/test/compile-fail/const-array-oob.rs | 3 +- src/test/compile-fail/const-call.rs | 3 +- src/test/compile-fail/const-err.rs | 24 +- .../compile-fail/const-eval-overflow-2.rs | 11 +- .../compile-fail/const-eval-overflow-3.rs | 2 +- .../compile-fail/const-eval-overflow-4b.rs | 10 +- src/test/compile-fail/const-eval-overflow.rs | 84 ++++-- src/test/compile-fail/const-eval-span.rs | 3 +- src/test/compile-fail/const-fn-error.rs | 5 +- .../compile-fail/const-index-feature-gate.rs | 3 +- .../compile-fail/const-integer-bool-ops.rs | 24 +- .../const-len-underflow-separate-spans.rs | 3 +- .../const-len-underflow-subspans.rs | 3 +- .../const-pattern-not-const-evaluable.rs | 16 +- src/test/compile-fail/const-slice-oob.rs | 3 +- src/test/compile-fail/const-tup-index-span.rs | 3 +- src/test/compile-fail/discrim-ill-typed.rs | 24 +- .../compile-fail/enum-discrim-too-small.rs | 12 +- src/test/compile-fail/eval-enum.rs | 6 +- .../feature-gate-negate-unsigned0.rs | 9 +- .../compile-fail/invalid-path-in-const.rs | 3 +- src/test/compile-fail/issue-22933-2.rs | 6 +- src/test/compile-fail/issue-23217.rs | 3 +- src/test/compile-fail/issue-25145.rs | 3 +- src/test/compile-fail/issue-27008.rs | 2 +- src/test/compile-fail/issue-27895.rs | 3 +- src/test/compile-fail/issue-28586.rs | 2 +- src/test/compile-fail/issue-3521.rs | 3 +- src/test/compile-fail/issue-8761.rs | 12 +- .../non-constant-enum-for-vec-repeat.rs | 3 +- .../non-constant-expr-for-vec-repeat.rs | 4 +- .../non-constant-in-const-path.rs | 3 +- src/test/compile-fail/repeat_count.rs | 19 +- 55 files changed, 506 insertions(+), 376 deletions(-) diff --git a/src/librustc_const_eval/Cargo.toml b/src/librustc_const_eval/Cargo.toml index 01872bbe3c0..8967672548b 100644 --- a/src/librustc_const_eval/Cargo.toml +++ b/src/librustc_const_eval/Cargo.toml @@ -14,6 +14,7 @@ serialize = { path = "../libserialize" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_math = { path = "../librustc_const_math" } +rustc_errors = { path = "../librustc_errors" } syntax = { path = "../libsyntax" } graphviz = { path = "../libgraphviz" } syntax_pos = { path = "../libsyntax_pos" } \ No newline at end of file diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 0de00d9d7f6..915a0cf0bdc 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -17,6 +17,7 @@ use rustc::middle::const_val::ConstVal; use ::{eval_const_expr, eval_const_expr_partial, compare_const_vals}; use ::{const_expr_to_pat, lookup_const_by_id}; use ::EvalHint::ExprTypeChecked; +use eval::report_const_eval_err; use rustc::hir::def::*; use rustc::hir::def_id::{DefId}; use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor}; @@ -42,6 +43,7 @@ use syntax_pos::{Span, DUMMY_SP}; use rustc::hir::fold::{Folder, noop_fold_pat}; use rustc::hir::print::pat_to_string; use syntax::ptr::P; +use rustc::util::common::ErrorReported; use rustc::util::nodemap::FnvHashMap; pub const DUMMY_WILD_PAT: &'static Pat = &Pat { @@ -279,13 +281,7 @@ fn check_for_static_nan(cx: &MatchCheckCtxt, pat: &Pat) { Ok(_) => {} Err(err) => { - let mut diag = struct_span_err!(cx.tcx.sess, err.span, E0471, - "constant evaluation error: {}", - err.description()); - if !p.span.contains(err.span) { - diag.span_note(p.span, "in pattern here"); - } - diag.emit(); + report_const_eval_err(cx.tcx, &err, p.span, "pattern").emit(); } } } @@ -838,22 +834,19 @@ pub fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> us } } -fn range_covered_by_constructor(ctor: &Constructor, - from: &ConstVal, to: &ConstVal) -> Option<bool> { +fn range_covered_by_constructor(tcx: TyCtxt, span: Span, + ctor: &Constructor, + from: &ConstVal, to: &ConstVal) + -> Result<bool, ErrorReported> { let (c_from, c_to) = match *ctor { ConstantValue(ref value) => (value, value), ConstantRange(ref from, ref to) => (from, to), - Single => return Some(true), + Single => return Ok(true), _ => bug!() }; - let cmp_from = compare_const_vals(c_from, from); - let cmp_to = compare_const_vals(c_to, to); - match (cmp_from, cmp_to) { - (Some(cmp_from), Some(cmp_to)) => { - Some(cmp_from != Ordering::Less && cmp_to != Ordering::Greater) - } - _ => None - } + let cmp_from = compare_const_vals(tcx, span, c_from, from)?; + let cmp_to = compare_const_vals(tcx, span, c_to, to)?; + Ok(cmp_from != Ordering::Less && cmp_to != Ordering::Greater) } fn wrap_pat<'a, 'b, 'tcx>(cx: &MatchCheckCtxt<'b, 'tcx>, @@ -965,13 +958,12 @@ pub fn specialize<'a, 'b, 'tcx>( Some(vec![(pat, Some(mt.ty))]) } else { let expr_value = eval_const_expr(cx.tcx, &expr); - match range_covered_by_constructor(constructor, &expr_value, &expr_value) { - Some(true) => Some(vec![]), - Some(false) => None, - None => { - span_err!(cx.tcx.sess, pat_span, E0298, "mismatched types between arms"); - None - } + match range_covered_by_constructor( + cx.tcx, expr.span, constructor, &expr_value, &expr_value + ) { + Ok(true) => Some(vec![]), + Ok(false) => None, + Err(ErrorReported) => None, } } } @@ -979,13 +971,12 @@ pub fn specialize<'a, 'b, 'tcx>( PatKind::Range(ref from, ref to) => { let from_value = eval_const_expr(cx.tcx, &from); let to_value = eval_const_expr(cx.tcx, &to); - match range_covered_by_constructor(constructor, &from_value, &to_value) { - Some(true) => Some(vec![]), - Some(false) => None, - None => { - span_err!(cx.tcx.sess, pat_span, E0299, "mismatched types between arms"); - None - } + match range_covered_by_constructor( + cx.tcx, pat_span, constructor, &from_value, &to_value + ) { + Ok(true) => Some(vec![]), + Ok(false) => None, + Err(ErrorReported) => None, } } diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs index f2abdf831a3..45414c33c07 100644 --- a/src/librustc_const_eval/diagnostics.rs +++ b/src/librustc_const_eval/diagnostics.rs @@ -551,6 +551,26 @@ The `op_string_ref` binding has type `&Option<&String>` in both cases. See also https://github.com/rust-lang/rust/issues/14587 "##, +E0080: r##" +This error indicates that the compiler was unable to sensibly evaluate an +constant expression that had to be evaluated. Attempting to divide by 0 +or causing integer overflow are two ways to induce this error. For example: + +```compile_fail +enum Enum { + X = (1 << 500), + Y = (1 / 0) +} +``` + +Ensure that the expressions given can be evaluated as the desired integer type. +See the FFI section of the Reference for more information about using a custom +integer type: + +https://doc.rust-lang.org/reference.html#ffi-attributes +"##, + + E0306: r##" In an array literal `[x; N]`, `N` is the number of elements in the array. This must be an unsigned integer. Erroneous code example: @@ -566,29 +586,11 @@ Working example: let x = [0i32; 2]; ``` "##, - -E0307: r##" -The length of an array is part of its type. For this reason, this length must -be a compile-time constant. Erroneous code example: - -```compile_fail - let len = 10; - let x = [0i32; len]; // error: expected constant integer for repeat count, - // found variable -``` - -Working example: - -``` -let x = [0i32; 10]; -``` -"##, - } register_diagnostics! { -E0298, // mismatched types between arms -E0299, // mismatched types between arms -E0471, // constant evaluation error: .. + E0298, // cannot compare constants +// E0299, // mismatched types between arms +// E0471, // constant evaluation error (in pattern) } diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index a3c707e82a0..03d2f596e21 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -25,6 +25,7 @@ use rustc::hir::pat_util::def_to_path; use rustc::ty::{self, Ty, TyCtxt, subst}; use rustc::ty::util::IntTypeExt; use rustc::traits::ProjectionMode; +use rustc::util::common::ErrorReported; use rustc::util::nodemap::NodeMap; use rustc::lint; @@ -43,6 +44,7 @@ use std::cmp::Ordering; use std::collections::hash_map::Entry::Vacant; use rustc_const_math::*; +use rustc_errors::{DiagnosticBuilder, check_old_school}; macro_rules! math { ($e:expr, $op:expr) => { @@ -338,20 +340,80 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Ok(P(hir::Pat { id: expr.id, node: pat, span: span })) } +pub fn report_const_eval_err<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + err: &ConstEvalErr, + primary_span: Span, + primary_kind: &str) + -> DiagnosticBuilder<'tcx> +{ + let mut err = err; + while let &ConstEvalErr { kind: ErroneousReferencedConstant(box ref i_err), .. } = err { + err = i_err; + } + + let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error"); + note_const_eval_err(tcx, err, primary_span, primary_kind, &mut diag); + diag +} + +pub fn fatal_const_eval_err<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + err: &ConstEvalErr, + primary_span: Span, + primary_kind: &str) + -> ! +{ + report_const_eval_err(tcx, err, primary_span, primary_kind).emit(); + tcx.sess.abort_if_errors(); + unreachable!() +} + +pub fn note_const_eval_err<'a, 'tcx>( + _tcx: TyCtxt<'a, 'tcx, 'tcx>, + err: &ConstEvalErr, + primary_span: Span, + primary_kind: &str, + diag: &mut DiagnosticBuilder) +{ + match err.description() { + ConstEvalErrDescription::Simple(message) => { + if check_old_school() { + diag.note(&message); + } else { + diag.span_label(err.span, &message); + } + } + ConstEvalErrDescription::ExpectedFound { error, expected, found } => { + if check_old_school() { + diag.note(&error); + } else { + diag.span_label(err.span, &error); + } + diag.note(&format!("expected `{}`", expected)); + diag.note(&format!("found `{}`", found)); + } + } + + if !primary_span.contains(err.span) { + diag.span_note(primary_span, + &format!("for {} here", primary_kind)); + } +} + pub fn eval_const_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &Expr) -> ConstVal { match eval_const_expr_partial(tcx, e, ExprTypeChecked, None) { Ok(r) => r, // non-const path still needs to be a fatal error, because enums are funky Err(s) => { + report_const_eval_err(tcx, &s, e.span, "expression").emit(); match s.kind { NonConstPath | - UnimplementedConstVal(_) => tcx.sess.span_fatal(s.span, &s.description()), - _ => { - tcx.sess.span_err(s.span, &s.description()); - Dummy - } + UnimplementedConstVal(_) => tcx.sess.abort_if_errors(), + _ => {} } + Dummy }, } } @@ -400,6 +462,7 @@ pub enum ErrKind { IntermediateUnsignedNegative, /// Expected, Got TypeMismatch(String, ConstInt), + BadType(ConstVal), ErroneousReferencedConstant(Box<ConstEvalErr>), CharCast(ConstInt), @@ -411,57 +474,96 @@ impl From<ConstMathErr> for ErrKind { } } +#[derive(Clone, Debug)] +pub enum ConstEvalErrDescription<'a> { + Simple(Cow<'a, str>), + ExpectedFound { + error: Cow<'a, str>, + expected: Cow<'a, str>, + found: Cow<'a, str> + } +} + +impl<'a> ConstEvalErrDescription<'a> { + /// Return a one-line description of the error, for lints and such + pub fn into_oneline(self) -> Cow<'a, str> { + match self { + ConstEvalErrDescription::Simple(simple) => simple, + ConstEvalErrDescription::ExpectedFound { + error, + expected, + found + } => { + format!("{}: expected `{}`, found `{}`", error, expected, found) + .into_cow() + } + } + } +} + impl ConstEvalErr { - pub fn description(&self) -> Cow<str> { + pub fn description(&self) -> ConstEvalErrDescription { use self::ErrKind::*; + use self::ConstEvalErrDescription::*; + + macro_rules! simple { + ($msg:expr) => ({ Simple($msg.into_cow()) }); + ($fmt:expr, $($arg:tt)+) => ({ + Simple(format!($fmt, $($arg)+).into_cow()) + }) + } match self.kind { - CannotCast => "can't cast this type".into_cow(), - CannotCastTo(s) => format!("can't cast this type to {}", s).into_cow(), - InvalidOpForInts(_) => "can't do this op on integrals".into_cow(), - InvalidOpForBools(_) => "can't do this op on bools".into_cow(), - InvalidOpForFloats(_) => "can't do this op on floats".into_cow(), - InvalidOpForIntUint(..) => "can't do this op on an isize and usize".into_cow(), - InvalidOpForUintInt(..) => "can't do this op on a usize and isize".into_cow(), - NegateOn(ref const_val) => format!("negate on {}", const_val.description()).into_cow(), - NotOn(ref const_val) => format!("not on {}", const_val.description()).into_cow(), - CallOn(ref const_val) => format!("call on {}", const_val.description()).into_cow(), + CannotCast => simple!("can't cast this type"), + CannotCastTo(s) => simple!("can't cast this type to {}", s), + InvalidOpForInts(_) => simple!("can't do this op on integrals"), + InvalidOpForBools(_) => simple!("can't do this op on bools"), + InvalidOpForFloats(_) => simple!("can't do this op on floats"), + InvalidOpForIntUint(..) => simple!("can't do this op on an isize and usize"), + InvalidOpForUintInt(..) => simple!("can't do this op on a usize and isize"), + NegateOn(ref const_val) => simple!("negate on {}", const_val.description()), + NotOn(ref const_val) => simple!("not on {}", const_val.description()), + CallOn(ref const_val) => simple!("call on {}", const_val.description()), - MissingStructField => "nonexistent struct field".into_cow(), - NonConstPath => "non-constant path in constant expression".into_cow(), + MissingStructField => simple!("nonexistent struct field"), + NonConstPath => simple!("non-constant path in constant expression"), UnimplementedConstVal(what) => - format!("unimplemented constant expression: {}", what).into_cow(), - UnresolvedPath => "unresolved path in constant expression".into_cow(), - ExpectedConstTuple => "expected constant tuple".into_cow(), - ExpectedConstStruct => "expected constant struct".into_cow(), - TupleIndexOutOfBounds => "tuple index out of bounds".into_cow(), - IndexedNonVec => "indexing is only supported for arrays".into_cow(), - IndexNegative => "indices must be non-negative integers".into_cow(), - IndexNotInt => "indices must be integers".into_cow(), + simple!("unimplemented constant expression: {}", what), + UnresolvedPath => simple!("unresolved path in constant expression"), + ExpectedConstTuple => simple!("expected constant tuple"), + ExpectedConstStruct => simple!("expected constant struct"), + TupleIndexOutOfBounds => simple!("tuple index out of bounds"), + IndexedNonVec => simple!("indexing is only supported for arrays"), + IndexNegative => simple!("indices must be non-negative integers"), + IndexNotInt => simple!("indices must be integers"), IndexOutOfBounds { len, index } => { - format!("index out of bounds: the len is {} but the index is {}", - len, index).into_cow() + simple!("index out of bounds: the len is {} but the index is {}", + len, index) } - RepeatCountNotNatural => "repeat count must be a natural number".into_cow(), - RepeatCountNotInt => "repeat count must be integers".into_cow(), + RepeatCountNotNatural => simple!("repeat count must be a natural number"), + RepeatCountNotInt => simple!("repeat count must be integers"), - MiscBinaryOp => "bad operands for binary".into_cow(), - MiscCatchAll => "unsupported constant expr".into_cow(), - IndexOpFeatureGated => "the index operation on const values is unstable".into_cow(), - Math(ref err) => err.description().into_cow(), + MiscBinaryOp => simple!("bad operands for binary"), + MiscCatchAll => simple!("unsupported constant expr"), + IndexOpFeatureGated => simple!("the index operation on const values is unstable"), + Math(ref err) => Simple(err.description().into_cow()), - IntermediateUnsignedNegative => "during the computation of an unsigned a negative \ - number was encountered. This is most likely a bug in\ - the constant evaluator".into_cow(), + IntermediateUnsignedNegative => simple!( + "during the computation of an unsigned a negative \ + number was encountered. This is most likely a bug in\ + the constant evaluator"), TypeMismatch(ref expected, ref got) => { - format!("mismatched types: expected `{}`, found `{}`", - expected, got.description()).into_cow() + ExpectedFound { + error: "mismatched types".into_cow(), + expected: <&str>::into_cow(expected), + found: got.description().into_cow() + } }, - BadType(ref i) => format!("value of wrong type: {:?}", i).into_cow(), - ErroneousReferencedConstant(_) => "could not evaluate referenced constant".into_cow(), + BadType(ref i) => simple!("value of wrong type: {:?}", i), + ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"), CharCast(ref got) => { - format!("only `u8` can be cast as `char`, not `{}`", got.description()).into_cow() + simple!("only `u8` can be cast as `char`, not `{}`", got.description()) }, } } @@ -1185,8 +1287,10 @@ fn parse_float(num: &str, fty_hint: Option<ast::FloatTy>, span: Span) -> ConstFl }) } -pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> { - match (a, b) { +pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal) + -> Result<Ordering, ErrorReported> +{ + let result = match (a, b) { (&Integral(a), &Integral(b)) => a.try_cmp(b).ok(), (&Float(a), &Float(b)) => a.try_cmp(b).ok(), (&Str(ref a), &Str(ref b)) => Some(a.cmp(b)), @@ -1194,62 +1298,82 @@ pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> { (&ByteStr(ref a), &ByteStr(ref b)) => Some(a.cmp(b)), (&Char(a), &Char(ref b)) => Some(a.cmp(b)), _ => None, + }; + + match result { + Some(result) => Ok(result), + None => { + // FIXME: can this ever be reached? + span_err!(tcx.sess, span, E0298, + "type mismatch comparing {} and {}", + a.description(), + b.description()); + Err(ErrorReported) + } } } pub fn compare_lit_exprs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + span: Span, a: &Expr, - b: &Expr) -> Option<Ordering> { + b: &Expr) -> Result<Ordering, ErrorReported> { let a = match eval_const_expr_partial(tcx, a, ExprTypeChecked, None) { Ok(a) => a, Err(e) => { - tcx.sess.span_err(a.span, &e.description()); - return None; + report_const_eval_err(tcx, &e, a.span, "expression").emit(); + return Err(ErrorReported); } }; let b = match eval_const_expr_partial(tcx, b, ExprTypeChecked, None) { Ok(b) => b, Err(e) => { - tcx.sess.span_err(b.span, &e.description()); - return None; + report_const_eval_err(tcx, &e, b.span, "expression").emit(); + return Err(ErrorReported); } }; - compare_const_vals(&a, &b) + compare_const_vals(tcx, span, &a, &b) } -/// Returns the repeat count for a repeating vector expression. -pub fn eval_repeat_count<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - count_expr: &hir::Expr) -> usize { +/// Returns the value of the length-valued expression +pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + count_expr: &hir::Expr, + reason: &str) + -> Result<usize, ErrorReported> +{ let hint = UncheckedExprHint(tcx.types.usize); match eval_const_expr_partial(tcx, count_expr, hint, None) { Ok(Integral(Usize(count))) => { let val = count.as_u64(tcx.sess.target.uint_type); assert_eq!(val as usize as u64, val); - val as usize + Ok(val as usize) }, Ok(const_val) => { span_err!(tcx.sess, count_expr.span, E0306, - "expected positive integer for repeat count, found {}", + "expected usize for {}, found {}", + reason, const_val.description()); - 0 + Err(ErrorReported) } Err(err) => { - let err_msg = match count_expr.node { + let mut diag = report_const_eval_err( + tcx, &err, count_expr.span, reason); + + match count_expr.node { hir::ExprPath(None, hir::Path { global: false, ref segments, .. - }) if segments.len() == 1 => - format!("found variable"), - _ => match err.kind { - MiscCatchAll => format!("but found {}", err.description()), - _ => format!("but {}", err.description()) + }) if segments.len() == 1 => { + if let Some(Def::Local(..)) = tcx.expect_def_or_none(count_expr.id) { + diag.note(&format!("`{}` is a variable", segments[0].name)); + } } - }; - span_err!(tcx.sess, count_expr.span, E0307, - "expected constant integer for repeat count, {}", err_msg); - 0 + _ => {} + } + + diag.emit(); + Err(ErrorReported) } } } diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 726ba4fc192..a6714c178e7 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -36,6 +36,7 @@ #[macro_use] extern crate rustc; extern crate rustc_back; extern crate rustc_const_math; +extern crate rustc_errors; extern crate graphviz; extern crate syntax_pos; extern crate serialize as rustc_serialize; // used by deriving diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 27ce03b2d93..b0ba38f1db6 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -40,6 +40,7 @@ use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; use rustc::ty::{self, Ty, TyCtxt}; use rustc::traits::ProjectionMode; +use rustc::util::common::ErrorReported; use rustc::util::nodemap::NodeMap; use rustc::middle::const_qualif::ConstQualif; use rustc::lint::builtin::CONST_ERR; @@ -116,7 +117,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { _ => self.tcx.sess.add_lint(CONST_ERR, expr.id, expr.span, format!("constant evaluation error: {}. This will \ become a HARD ERROR in the future", - err.description())), + err.description().into_oneline())), } } self.with_mode(mode, |this| { @@ -211,15 +212,6 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { } } } - - fn msg(&self) -> &'static str { - match self.mode { - Mode::Const => "constant", - Mode::ConstFn => "constant function", - Mode::StaticMut | Mode::Static => "static", - Mode::Var => bug!(), - } - } } impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { @@ -289,18 +281,14 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { self.global_expr(Mode::Const, &start); self.global_expr(Mode::Const, &end); - match compare_lit_exprs(self.tcx, start, end) { - Some(Ordering::Less) | - Some(Ordering::Equal) => {} - Some(Ordering::Greater) => { + match compare_lit_exprs(self.tcx, p.span, start, end) { + Ok(Ordering::Less) | + Ok(Ordering::Equal) => {} + Ok(Ordering::Greater) => { span_err!(self.tcx.sess, start.span, E0030, "lower range bound must be less than or equal to upper"); } - None => { - span_err!(self.tcx.sess, p.span, E0014, - "paths in {}s may only refer to constants", - self.msg()); - } + Err(ErrorReported) => {} } } _ => intravisit::walk_pat(self, p) @@ -429,7 +417,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { Err(msg) => { self.tcx.sess.add_lint(CONST_ERR, ex.id, msg.span, - msg.description().into_owned()) + msg.description().into_oneline().into_owned()) } } } diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index 918e17d21ea..a616b95ef72 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -11,7 +11,7 @@ #![allow(non_snake_case)] register_long_diagnostics! { - +/* E0014: r##" Constants can only be initialized by a constant value or, in a future version of Rust, a call to a const function. This error indicates the use @@ -30,7 +30,7 @@ const FOO: i32 = { const X : i32 = 0; X }; const FOO2: i32 = { 0 }; // but brackets are useless here ``` "##, - +*/ E0030: r##" When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to diff --git a/src/librustc_trans/_match.rs b/src/librustc_trans/_match.rs index 08e894ffbcf..f7fd970f37f 100644 --- a/src/librustc_trans/_match.rs +++ b/src/librustc_trans/_match.rs @@ -190,7 +190,7 @@ use self::FailureHandler::*; use llvm::{ValueRef, BasicBlockRef}; use rustc_const_eval::check_match::{self, Constructor, StaticInliner}; -use rustc_const_eval::{compare_lit_exprs, eval_const_expr}; +use rustc_const_eval::{compare_lit_exprs, eval_const_expr, fatal_const_eval_err}; use rustc::hir::def::{Def, DefMap}; use rustc::hir::def_id::DefId; use middle::expr_use_visitor as euv; @@ -239,9 +239,9 @@ struct ConstantExpr<'a>(&'a hir::Expr); impl<'a> ConstantExpr<'a> { fn eq<'b, 'tcx>(self, other: ConstantExpr<'a>, tcx: TyCtxt<'b, 'tcx, 'tcx>) -> bool { - match compare_lit_exprs(tcx, self.0, other.0) { - Some(result) => result == Ordering::Equal, - None => bug!("compare_list_exprs: type mismatch"), + match compare_lit_exprs(tcx, self.0.span, self.0, other.0) { + Ok(result) => result == Ordering::Equal, + Err(_) => bug!("compare_list_exprs: type mismatch"), } } } @@ -288,7 +288,9 @@ impl<'a, 'b, 'tcx> Opt<'a, 'tcx> { let expr = consts::const_expr(ccx, &lit_expr, bcx.fcx.param_substs, None, Yes); let llval = match expr { Ok((llval, _)) => llval, - Err(err) => bcx.ccx().sess().span_fatal(lit_expr.span, &err.description()), + Err(err) => { + fatal_const_eval_err(bcx.tcx(), err.as_inner(), lit_expr.span, "pattern"); + } }; let lit_datum = immediate_rvalue(llval, lit_ty); let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx)); @@ -297,11 +299,11 @@ impl<'a, 'b, 'tcx> Opt<'a, 'tcx> { ConstantRange(ConstantExpr(ref l1), ConstantExpr(ref l2), _) => { let l1 = match consts::const_expr(ccx, &l1, bcx.fcx.param_substs, None, Yes) { Ok((l1, _)) => l1, - Err(err) => bcx.ccx().sess().span_fatal(l1.span, &err.description()), + Err(err) => fatal_const_eval_err(bcx.tcx(), err.as_inner(), l1.span, "pattern"), }; let l2 = match consts::const_expr(ccx, &l2, bcx.fcx.param_substs, None, Yes) { Ok((l2, _)) => l2, - Err(err) => bcx.ccx().sess().span_fatal(l2.span, &err.description()), + Err(err) => fatal_const_eval_err(bcx.tcx(), err.as_inner(), l2.span, "pattern"), }; RangeResult(Result::new(bcx, l1), Result::new(bcx, l2)) } diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 00feb2cd1de..f662ba75cc6 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -14,7 +14,7 @@ use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr}; use llvm::{InternalLinkage, ValueRef, Bool, True}; use middle::const_qualif::ConstQualif; use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, lookup_const_by_id, ErrKind}; -use rustc_const_eval::eval_repeat_count; +use rustc_const_eval::{eval_length, report_const_eval_err, note_const_eval_err}; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::hir::map as hir_map; @@ -44,7 +44,6 @@ use rustc_const_math::{ConstInt, ConstUsize, ConstIsize}; use rustc::hir; use std::ffi::{CStr, CString}; -use std::borrow::Cow; use libc::c_uint; use syntax::ast::{self, LitKind}; use syntax::attr::{self, AttrMetaMethods}; @@ -250,10 +249,11 @@ impl ConstEvalFailure { Compiletime(e) => e, } } - pub fn description(&self) -> Cow<str> { + + pub fn as_inner(&self) -> &ConstEvalErr { match self { - &Runtime(ref e) => e.description(), - &Compiletime(ref e) => e.description(), + &Runtime(ref e) => e, + &Compiletime(ref e) => e, } } } @@ -274,7 +274,7 @@ fn get_const_val<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let empty_substs = ccx.tcx().mk_substs(Substs::empty()); match get_const_expr_as_global(ccx, expr, ConstQualif::empty(), empty_substs, TrueConst::Yes) { Err(Runtime(err)) => { - ccx.tcx().sess.span_err(expr.span, &err.description()); + report_const_eval_err(ccx.tcx(), &err, expr.span, "expression").emit(); Err(Compiletime(err)) }, other => other, @@ -526,12 +526,15 @@ pub fn const_err<T>(cx: &CrateContext, (Ok(x), _) => Ok(x), (Err(err), TrueConst::Yes) => { let err = ConstEvalErr{ span: span, kind: err }; - cx.tcx().sess.span_err(span, &err.description()); + report_const_eval_err(cx.tcx(), &err, span, "expression").emit(); Err(Compiletime(err)) }, (Err(err), TrueConst::No) => { let err = ConstEvalErr{ span: span, kind: err }; - cx.tcx().sess.span_warn(span, &err.description()); + let mut diag = cx.tcx().sess.struct_span_warn( + span, "this expression will panic at run-time"); + note_const_eval_err(cx.tcx(), &err, span, "expression", &mut diag); + diag.emit(); Err(Runtime(err)) }, } @@ -875,7 +878,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, hir::ExprRepeat(ref elem, ref count) => { let unit_ty = ety.sequence_element_type(cx.tcx()); let llunitty = type_of::type_of(cx, unit_ty); - let n = eval_repeat_count(cx.tcx(), count); + let n = eval_length(cx.tcx(), count, "repeat count").unwrap(); let unit_val = const_expr(cx, &elem, param_substs, fn_args, trueconst)?.0; let vs = vec![unit_val; n]; if val_ty(unit_val) != llunitty { diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index a721361fce0..bc5f3a0f22e 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -44,6 +44,7 @@ use syntax::ptr::P; use syntax::parse::token; use rustc::session::Session; +use rustc_const_eval::fatal_const_eval_err; use syntax_pos::{Span, DUMMY_SP}; use std::cmp::Ordering; @@ -1408,7 +1409,10 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> // this should probably help simd error reporting consts::TrueConst::Yes) { Ok((vector, _)) => vector, - Err(err) => bcx.sess().span_fatal(span, &err.description()), + Err(err) => { + fatal_const_eval_err(bcx.tcx(), err.as_inner(), span, + "shuffle indices"); + } } } None => llargs[2] diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index da72793abf6..1f3b1320316 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -925,7 +925,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } Err(ConstEvalFailure::Runtime(err)) => { span_bug!(constant.span, - "MIR constant {:?} results in runtime panic: {}", + "MIR constant {:?} results in runtime panic: {:?}", constant, err.description()) } } diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 8b8e658533e..fc95d208f32 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -29,6 +29,7 @@ use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::subst; use rustc::dep_graph::DepNode; +use rustc_const_eval::fatal_const_eval_err; use std::hash::{Hash, Hasher}; use syntax::ast::{self, NodeId}; use syntax::{attr,errors}; @@ -81,7 +82,11 @@ impl<'a, 'tcx> TransItem<'tcx> { if let hir::ItemStatic(_, m, ref expr) = item.node { match consts::trans_static(&ccx, m, expr, item.id, &item.attrs) { Ok(_) => { /* Cool, everything's alright. */ }, - Err(err) => ccx.tcx().sess.span_fatal(expr.span, &err.description()), + Err(err) => { + // FIXME: shouldn't this be a `span_err`? + fatal_const_eval_err( + ccx.tcx(), &err, expr.span, "static"); + } }; } else { span_bug!(item.span, "Mismatch between hir::Item type and TransItem type") diff --git a/src/librustc_trans/tvec.rs b/src/librustc_trans/tvec.rs index f5b9bef5313..92a2d3787bf 100644 --- a/src/librustc_trans/tvec.rs +++ b/src/librustc_trans/tvec.rs @@ -30,7 +30,7 @@ use value::Value; use rustc::ty::{self, Ty}; use rustc::hir; -use rustc_const_eval::eval_repeat_count; +use rustc_const_eval::eval_length; use syntax::ast; use syntax::parse::token::InternedString; @@ -218,7 +218,7 @@ fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, return expr::trans_into(bcx, &element, Ignore); } SaveIn(lldest) => { - match eval_repeat_count(bcx.tcx(), &count_expr) { + match eval_length(bcx.tcx(), &count_expr, "repeat count").unwrap() { 0 => expr::trans_into(bcx, &element, Ignore), 1 => expr::trans_into(bcx, &element, SaveIn(lldest)), count => { @@ -268,7 +268,7 @@ fn elements_required(bcx: Block, content_expr: &hir::Expr) -> usize { }, hir::ExprVec(ref es) => es.len(), hir::ExprRepeat(_, ref count_expr) => { - eval_repeat_count(bcx.tcx(), &count_expr) + eval_length(bcx.tcx(), &count_expr, "repeat count").unwrap() } _ => span_bug!(content_expr.span, "unexpected vec content") } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 9ff30f9ede2..b642a712219 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -48,10 +48,7 @@ //! case but `&a` in the second. Basically, defaults that appear inside //! an rptr (`&r.T`) use the region `r` that appears in the rptr. -use middle::const_val::ConstVal; -use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr}; -use rustc_const_eval::EvalHint::UncheckedExprHint; -use rustc_const_eval::ErrKind::ErroneousReferencedConstant; +use rustc_const_eval::eval_length; use hir::{self, SelfKind}; use hir::def::{Def, PathResolution}; use hir::def_id::DefId; @@ -70,7 +67,6 @@ use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, use util::common::{ErrorReported, FN_OUTPUT_NAME}; use util::nodemap::{NodeMap, FnvHashSet}; -use rustc_const_math::ConstInt; use std::cell::RefCell; use syntax::{abi, ast}; use syntax::feature_gate::{GateIssue, emit_feature_err}; @@ -1741,33 +1737,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { ty } hir::TyFixedLengthVec(ref ty, ref e) => { - let hint = UncheckedExprHint(tcx.types.usize); - match eval_const_expr_partial(tcx.global_tcx(), &e, hint, None) { - Ok(ConstVal::Integral(ConstInt::Usize(i))) => { - let i = i.as_u64(tcx.sess.target.uint_type); - assert_eq!(i as usize as u64, i); - tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), i as usize) - }, - Ok(val) => { - span_err!(tcx.sess, ast_ty.span, E0249, - "expected usize value for array length, got {}", - val.description()); - self.tcx().types.err - }, - // array length errors happen before the global constant check - // so we need to report the real error - Err(ConstEvalErr { kind: ErroneousReferencedConstant(box r), ..}) | - Err(r) => { - let mut err = struct_span_err!(tcx.sess, r.span, E0250, - "array length constant \ - evaluation error: {}", - r.description()); - if !ast_ty.span.contains(r.span) { - span_note!(&mut err, ast_ty.span, "for array length here") - } - err.emit(); - self.tcx().types.err - } + if let Ok(length) = eval_length(tcx.global_tcx(), &e, "array length") { + tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), length) + } else { + self.tcx().types.err } } hir::TyTypeof(ref _e) => { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7076b6a2a90..c01edc568af 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -126,7 +126,7 @@ use rustc::hir::intravisit::{self, Visitor}; use rustc::hir::{self, PatKind}; use rustc::hir::print as pprust; use rustc_back::slice; -use rustc_const_eval::eval_repeat_count; +use rustc_const_eval::eval_length; mod assoc; mod autoderef; @@ -3539,7 +3539,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } hir::ExprRepeat(ref element, ref count_expr) => { self.check_expr_has_type(&count_expr, tcx.types.usize); - let count = eval_repeat_count(self.tcx.global_tcx(), &count_expr); + let count = eval_length(self.tcx.global_tcx(), &count_expr, "repeat count") + .unwrap_or(0); let uty = match expected { ExpectHasType(uty) => { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 41e7a467fa3..57602b55cc9 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -66,8 +66,7 @@ use constrained_type_params as ctp; use middle::lang_items::SizedTraitLangItem; use middle::const_val::ConstVal; use rustc_const_eval::EvalHint::UncheckedExprHint; -use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr}; -use rustc_const_eval::ErrKind::ErroneousReferencedConstant; +use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err}; use rustc::ty::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace}; use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; @@ -1091,14 +1090,9 @@ fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, }, // enum variant evaluation happens before the global constant check // so we need to report the real error - Err(ConstEvalErr { kind: ErroneousReferencedConstant(box err), ..}) | Err(err) => { - let mut diag = struct_span_err!(ccx.tcx.sess, err.span, E0080, - "constant evaluation error: {}", - err.description()); - if !e.span.contains(err.span) { - diag.span_note(e.span, "for enum discriminant here"); - } + let mut diag = report_const_eval_err( + ccx.tcx, &err, e.span, "enum discriminant"); diag.emit(); None } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 683328f4eb4..38bf869119c 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1079,25 +1079,6 @@ impl Foo { ``` "##, -E0080: r##" -This error indicates that the compiler was unable to sensibly evaluate an -integer expression provided as an enum discriminant. Attempting to divide by 0 -or causing integer overflow are two ways to induce this error. For example: - -```compile_fail -enum Enum { - X = (1 << 500), - Y = (1 / 0) -} -``` - -Ensure that the expressions given can be evaluated as the desired integer type. -See the FFI section of the Reference for more information about using a custom -integer type: - -https://doc.rust-lang.org/reference.html#ffi-attributes -"##, - E0081: r##" Enum discriminants are used to differentiate enum variants stored in memory. This error indicates that the same value was used for two or more variants, @@ -2970,38 +2951,6 @@ not a distinct static type. Likewise, it's not legal to attempt to behavior for specific enum variants. "##, -E0249: r##" -This error indicates a constant expression for the array length was found, but -it was not an integer (signed or unsigned) expression. - -Some examples of code that produces this error are: - -```compile_fail -const A: [u32; "hello"] = []; // error -const B: [u32; true] = []; // error -const C: [u32; 0.0] = []; // error -"##, - -E0250: r##" -There was an error while evaluating the expression for the length of a fixed- -size array type. - -Some examples of this error are: - -```compile_fail -// divide by zero in the length expression -const A: [u32; 1/0] = []; - -// Rust currently will not evaluate the function `foo` at compile time -fn foo() -> usize { 12 } -const B: [u32; foo()] = []; - -// it is an error to try to add `u8` and `f64` -use std::{f64, u8}; -const C: [u32; u8::MAX + f64::EPSILON] = []; -``` -"##, - E0318: r##" Default impls for a trait must be located in the same crate where the trait was defined. For more information see the [opt-in builtin traits RFC](https://github @@ -4088,6 +4037,7 @@ register_diagnostics! { E0245, // not a trait // E0246, // invalid recursive type // E0247, +// E0249, // E0319, // trait impls for defaulted traits allowed just for structs/enums E0320, // recursive overflow during dropck E0328, // cannot implement Unsize explicitly diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock index 4def60e485f..0b2287cf233 100644 --- a/src/rustc/Cargo.lock +++ b/src/rustc/Cargo.lock @@ -105,6 +105,7 @@ dependencies = [ "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_math 0.0.0", + "rustc_errors 0.0.0", "serialize 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", diff --git a/src/test/compile-fail/array_const_index-0.rs b/src/test/compile-fail/array_const_index-0.rs index e65230389f9..501c66e75cd 100644 --- a/src/test/compile-fail/array_const_index-0.rs +++ b/src/test/compile-fail/array_const_index-0.rs @@ -10,7 +10,8 @@ const A: &'static [i32] = &[]; const B: i32 = (&A)[1]; -//~^ ERROR index out of bounds: the len is 0 but the index is 1 +//~^ ERROR constant evaluation error +//~| index out of bounds: the len is 0 but the index is 1 fn main() { let _ = B; diff --git a/src/test/compile-fail/array_const_index-1.rs b/src/test/compile-fail/array_const_index-1.rs index 69d84e24c49..d3b43e83bfe 100644 --- a/src/test/compile-fail/array_const_index-1.rs +++ b/src/test/compile-fail/array_const_index-1.rs @@ -10,7 +10,8 @@ const A: [i32; 0] = []; const B: i32 = A[1]; -//~^ ERROR index out of bounds: the len is 0 but the index is 1 +//~^ ERROR constant evaluation error +//~| index out of bounds: the len is 0 but the index is 1 fn main() { let _ = B; diff --git a/src/test/compile-fail/associated-const-array-len.rs b/src/test/compile-fail/associated-const-array-len.rs index 5d8007defc9..0239986f5ad 100644 --- a/src/test/compile-fail/associated-const-array-len.rs +++ b/src/test/compile-fail/associated-const-array-len.rs @@ -14,7 +14,7 @@ trait Foo { const ID: usize; } -const X: [i32; <i32 as Foo>::ID] = [0, 1, 2]; //~ ERROR E0250 +const X: [i32; <i32 as Foo>::ID] = [0, 1, 2]; //~ ERROR E0080 fn main() { assert_eq!(1, X); diff --git a/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs b/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs index 2f687350f34..c3fa39659b9 100644 --- a/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs +++ b/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs @@ -25,7 +25,8 @@ impl Foo for Def { } pub fn test<A: Foo, B: Foo>() { - let _array = [4; <A as Foo>::Y]; //~ error: expected constant integer + let _array = [4; <A as Foo>::Y]; //~ ERROR E0080 + //~| non-constant path in constant } fn main() { diff --git a/src/test/compile-fail/const-array-oob.rs b/src/test/compile-fail/const-array-oob.rs index faabed4fd5e..b980bc02c85 100644 --- a/src/test/compile-fail/const-array-oob.rs +++ b/src/test/compile-fail/const-array-oob.rs @@ -16,7 +16,8 @@ const FOO: [u32; 3] = [1, 2, 3]; const BAR: u32 = FOO[5]; // no error, because the error below occurs before regular const eval const BLUB: [u32; FOO[4]] = [5, 6]; -//~^ ERROR array length constant evaluation error: index out of bounds: the len is 3 but the index is 4 [E0250] +//~^ ERROR constant evaluation error [E0080] +//~| index out of bounds: the len is 3 but the index is 4 fn main() { let _ = BAR; diff --git a/src/test/compile-fail/const-call.rs b/src/test/compile-fail/const-call.rs index 1143d3bd5cd..7e2eabf412d 100644 --- a/src/test/compile-fail/const-call.rs +++ b/src/test/compile-fail/const-call.rs @@ -15,5 +15,6 @@ fn f(x: usize) -> usize { } fn main() { - let _ = [0; f(2)]; //~ ERROR: non-constant path in constant expression [E0307] + let _ = [0; f(2)]; //~ ERROR constant evaluation error [E0080] + //~| non-constant path in constant expression } diff --git a/src/test/compile-fail/const-err.rs b/src/test/compile-fail/const-err.rs index a1d3888e78e..f2079800cad 100644 --- a/src/test/compile-fail/const-err.rs +++ b/src/test/compile-fail/const-err.rs @@ -22,21 +22,29 @@ fn black_box<T>(_: T) { // Make sure that the two uses get two errors. const FOO: u8 = [5u8][1]; -//~^ ERROR index out of bounds: the len is 1 but the index is 1 -//~^^ ERROR index out of bounds: the len is 1 but the index is 1 +//~^ ERROR constant evaluation error +//~| index out of bounds: the len is 1 but the index is 1 +//~^^^ ERROR constant evaluation error +//~| index out of bounds: the len is 1 but the index is 1 fn main() { let a = -std::i8::MIN; - //~^ WARN attempted to negate with overflow + //~^ WARN this expression will panic at run-time + //~| attempted to negate with overflow let b = 200u8 + 200u8 + 200u8; - //~^ WARN attempted to add with overflow - //~| WARN attempted to add with overflow + //~^ WARN this expression will panic at run-time + //~| attempted to add with overflow + //~^^^ WARN this expression will panic at run-time + //~| attempted to add with overflow let c = 200u8 * 4; - //~^ WARN attempted to multiply with overflow + //~^ WARN this expression will panic at run-time + //~| attempted to multiply with overflow let d = 42u8 - (42u8 + 1); - //~^ WARN attempted to subtract with overflow + //~^ WARN this expression will panic at run-time + //~| attempted to subtract with overflow let _e = [5u8][1]; - //~^ WARN index out of bounds: the len is 1 but the index is 1 + //~^ WARN this expression will panic at run-time + //~| index out of bounds: the len is 1 but the index is 1 black_box(a); black_box(b); black_box(c); diff --git a/src/test/compile-fail/const-eval-overflow-2.rs b/src/test/compile-fail/const-eval-overflow-2.rs index 07e27a7dc9a..4749457da88 100644 --- a/src/test/compile-fail/const-eval-overflow-2.rs +++ b/src/test/compile-fail/const-eval-overflow-2.rs @@ -19,13 +19,16 @@ use std::{u8, u16, u32, u64, usize}; const NEG_128: i8 = -128; const NEG_NEG_128: i8 = -NEG_128; -//~^ ERROR constant evaluation error: attempted to negate with overflow -//~| ERROR attempted to negate with overflow -//~| ERROR attempted to negate with overflow +//~^ ERROR constant evaluation error +//~| attempted to negate with overflow +//~| ERROR constant evaluation error +//~| attempted to negate with overflow +//~| ERROR constant evaluation error +//~| attempted to negate with overflow fn main() { match -128i8 { - NEG_NEG_128 => println!("A"), //~ NOTE in pattern here + NEG_NEG_128 => println!("A"), //~ NOTE for pattern here _ => println!("B"), } } diff --git a/src/test/compile-fail/const-eval-overflow-3.rs b/src/test/compile-fail/const-eval-overflow-3.rs index c90ae045f96..c78c74e9e23 100644 --- a/src/test/compile-fail/const-eval-overflow-3.rs +++ b/src/test/compile-fail/const-eval-overflow-3.rs @@ -17,7 +17,7 @@ // self-hosted and a cross-compiled setup; therefore resorting to // error-pattern for now. -// error-pattern: expected constant integer for repeat count, but attempted to add with overflow +// error-pattern: attempted to add with overflow #![allow(unused_imports)] diff --git a/src/test/compile-fail/const-eval-overflow-4b.rs b/src/test/compile-fail/const-eval-overflow-4b.rs index 31e1a72967f..e7639a4ff70 100644 --- a/src/test/compile-fail/const-eval-overflow-4b.rs +++ b/src/test/compile-fail/const-eval-overflow-4b.rs @@ -20,9 +20,10 @@ use std::{u8, u16, u32, u64, usize}; const A_I8_T : [u32; (i8::MAX as i8 + 1u8) as usize] - //~^ ERROR mismatched types: - //~| expected `i8`, - //~| found `u8` [E0250] + //~^ ERROR constant evaluation error [E0080] + //~| mismatched types + //~| expected `i8` + //~| found `u8` = [0; (i8::MAX as usize) + 1]; @@ -33,7 +34,8 @@ const A_CHAR_USIZE const A_BAD_CHAR_USIZE : [u32; 5i8 as char as usize] - //~^ ERROR only `u8` can be cast as `char`, not `i8` + //~^ ERROR constant evaluation error + //~| only `u8` can be cast as `char`, not `i8` = [0; 5]; fn main() {} diff --git a/src/test/compile-fail/const-eval-overflow.rs b/src/test/compile-fail/const-eval-overflow.rs index 3dfcb5bb29a..c1c693544fa 100644 --- a/src/test/compile-fail/const-eval-overflow.rs +++ b/src/test/compile-fail/const-eval-overflow.rs @@ -21,86 +21,114 @@ use std::{u8, u16, u32, u64, usize}; const VALS_I8: (i8, i8, i8, i8) = (-i8::MIN, - //~^ ERROR attempted to negate with overflow + //~^ ERROR constant evaluation error + //~| attempted to negate with overflow i8::MIN - 1, - //~^ ERROR attempted to subtract with overflow + //~^ ERROR constant evaluation error + //~| attempted to subtract with overflow i8::MAX + 1, - //~^ ERROR attempted to add with overflow + //~^ ERROR constant evaluation error + //~| attempted to add with overflow i8::MIN * 2, - //~^ ERROR attempted to multiply with overflow + //~^ ERROR constant evaluation error + //~| attempted to multiply with overflow ); const VALS_I16: (i16, i16, i16, i16) = (-i16::MIN, - //~^ ERROR attempted to negate with overflow + //~^ ERROR constant evaluation error + //~| attempted to negate with overflow i16::MIN - 1, - //~^ ERROR attempted to subtract with overflow + //~^ ERROR constant evaluation error + //~| attempted to subtract with overflow i16::MAX + 1, - //~^ ERROR attempted to add with overflow + //~^ ERROR constant evaluation error + //~| attempted to add with overflow i16::MIN * 2, - //~^ ERROR attempted to multiply with overflow + //~^ ERROR constant evaluation error + //~| attempted to multiply with overflow ); const VALS_I32: (i32, i32, i32, i32) = (-i32::MIN, - //~^ ERROR attempted to negate with overflow + //~^ ERROR constant evaluation error + //~| attempted to negate with overflow i32::MIN - 1, - //~^ ERROR attempted to subtract with overflow + //~^ ERROR constant evaluation error + //~| attempted to subtract with overflow i32::MAX + 1, - //~^ ERROR attempted to add with overflow + //~^ ERROR constant evaluation error + //~| attempted to add with overflow i32::MIN * 2, - //~^ ERROR attempted to multiply with overflow + //~^ ERROR constant evaluation error + //~| attempted to multiply with overflow ); const VALS_I64: (i64, i64, i64, i64) = (-i64::MIN, - //~^ ERROR attempted to negate with overflow + //~^ ERROR constant evaluation error + //~| attempted to negate with overflow i64::MIN - 1, - //~^ ERROR attempted to subtract with overflow + //~^ ERROR constant evaluation error + //~| attempted to subtract with overflow i64::MAX + 1, - //~^ ERROR attempted to add with overflow + //~^ ERROR constant evaluation error + //~| attempted to add with overflow i64::MAX * 2, - //~^ ERROR attempted to multiply with overflow + //~^ ERROR constant evaluation error + //~| attempted to multiply with overflow ); const VALS_U8: (u8, u8, u8, u8) = (-(u8::MIN as i8) as u8, u8::MIN - 1, - //~^ ERROR attempted to subtract with overflow + //~^ ERROR constant evaluation error + //~| attempted to subtract with overflow u8::MAX + 1, - //~^ ERROR attempted to add with overflow + //~^ ERROR constant evaluation error + //~| attempted to add with overflow u8::MAX * 2, - //~^ ERROR attempted to multiply with overflow + //~^ ERROR constant evaluation error + //~| attempted to multiply with overflow ); const VALS_U16: (u16, u16, u16, u16) = (-(u16::MIN as i16) as u16, u16::MIN - 1, - //~^ ERROR attempted to subtract with overflow + //~^ ERROR constant evaluation error + //~| attempted to subtract with overflow u16::MAX + 1, - //~^ ERROR attempted to add with overflow + //~^ ERROR constant evaluation error + //~| attempted to add with overflow u16::MAX * 2, - //~^ ERROR attempted to multiply with overflow + //~^ ERROR constant evaluation error + //~| attempted to multiply with overflow ); const VALS_U32: (u32, u32, u32, u32) = (-(u32::MIN as i32) as u32, u32::MIN - 1, - //~^ ERROR attempted to subtract with overflow + //~^ ERROR constant evaluation error + //~| attempted to subtract with overflow u32::MAX + 1, - //~^ ERROR attempted to add with overflow + //~^ ERROR constant evaluation error + //~| attempted to add with overflow u32::MAX * 2, - //~^ ERROR attempted to multiply with overflow + //~^ ERROR constant evaluation error + //~| attempted to multiply with overflow ); const VALS_U64: (u64, u64, u64, u64) = (-(u64::MIN as i64) as u64, u64::MIN - 1, - //~^ ERROR attempted to subtract with overflow + //~^ ERROR constant evaluation error + //~| attempted to subtract with overflow u64::MAX + 1, - //~^ ERROR attempted to add with overflow + //~^ ERROR constant evaluation error + //~| attempted to add with overflow u64::MAX * 2, - //~^ ERROR attempted to multiply with overflow + //~^ ERROR constant evaluation error + //~| attempted to multiply with overflow ); fn main() { diff --git a/src/test/compile-fail/const-eval-span.rs b/src/test/compile-fail/const-eval-span.rs index 9fdd24c42fd..73351429b50 100644 --- a/src/test/compile-fail/const-eval-span.rs +++ b/src/test/compile-fail/const-eval-span.rs @@ -14,7 +14,8 @@ struct S(i32); const CONSTANT: S = S(0); -//~^ ERROR: unimplemented constant expression: tuple struct constructors [E0080] +//~^ ERROR E0080 +//~| unimplemented constant expression: tuple struct constructors enum E { V = CONSTANT, diff --git a/src/test/compile-fail/const-fn-error.rs b/src/test/compile-fail/const-fn-error.rs index 45a00de48e7..dd0f058f2c9 100644 --- a/src/test/compile-fail/const-fn-error.rs +++ b/src/test/compile-fail/const-fn-error.rs @@ -17,10 +17,11 @@ const fn f(x: usize) -> usize { for i in 0..x { sum += i; } - sum //~ ERROR: E0250 + sum //~ ERROR E0080 + //~| non-constant path in constant } #[allow(unused_variables)] fn main() { - let a : [i32; f(X)]; + let a : [i32; f(X)]; //~ NOTE for array length here } diff --git a/src/test/compile-fail/const-index-feature-gate.rs b/src/test/compile-fail/const-index-feature-gate.rs index 09822e46cc1..4f92770df28 100644 --- a/src/test/compile-fail/const-index-feature-gate.rs +++ b/src/test/compile-fail/const-index-feature-gate.rs @@ -9,7 +9,8 @@ // except according to those terms. const ARR: [usize; 1] = [2]; -const ARR2: [i32; ARR[0]] = [5, 6]; //~ ERROR unstable +const ARR2: [i32; ARR[0]] = [5, 6]; //~ ERROR E0080 + //~| unstable fn main() { } diff --git a/src/test/compile-fail/const-integer-bool-ops.rs b/src/test/compile-fail/const-integer-bool-ops.rs index 0d6cf3bab45..5dadd892f83 100644 --- a/src/test/compile-fail/const-integer-bool-ops.rs +++ b/src/test/compile-fail/const-integer-bool-ops.rs @@ -8,30 +8,34 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -const X: usize = 42 && 39; //~ ERROR: can't do this op on integrals +const X: usize = 42 && 39; //~ ERROR E0080 + //~| can't do this op on integrals const ARR: [i32; X] = [99; 34]; //~ NOTE: for array length here -const X1: usize = 42 || 39; //~ ERROR: can't do this op on integrals +const X1: usize = 42 || 39; //~ ERROR E0080 + //~| can't do this op on integrals const ARR1: [i32; X1] = [99; 47]; //~ NOTE: for array length here -const X2: usize = -42 || -39; //~ ERROR: unary negation of unsigned integer +const X2: usize = -42 || -39; //~ ERROR E0080 + //~| unary negation of unsigned integer const ARR2: [i32; X2] = [99; 18446744073709551607]; //~ NOTE: for array length here -const X3: usize = -42 && -39; //~ ERROR: unary negation of unsigned integer +const X3: usize = -42 && -39; //~ ERROR E0080 + //~| unary negation of unsigned integer const ARR3: [i32; X3] = [99; 6]; //~ NOTE: for array length here const Y: usize = 42.0 == 42.0; -const ARRR: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length +const ARRR: [i32; Y] = [99; 1]; //~ ERROR: expected usize for array length const Y1: usize = 42.0 >= 42.0; -const ARRR1: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length +const ARRR1: [i32; Y] = [99; 1]; //~ ERROR: expected usize for array length const Y2: usize = 42.0 <= 42.0; -const ARRR2: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length +const ARRR2: [i32; Y] = [99; 1]; //~ ERROR: expected usize for array length const Y3: usize = 42.0 > 42.0; -const ARRR3: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length +const ARRR3: [i32; Y] = [99; 0]; //~ ERROR: expected usize for array length const Y4: usize = 42.0 < 42.0; -const ARRR4: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length +const ARRR4: [i32; Y] = [99; 0]; //~ ERROR: expected usize for array length const Y5: usize = 42.0 != 42.0; -const ARRR5: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length +const ARRR5: [i32; Y] = [99; 0]; //~ ERROR: expected usize for array length fn main() { let _ = ARR; diff --git a/src/test/compile-fail/const-len-underflow-separate-spans.rs b/src/test/compile-fail/const-len-underflow-separate-spans.rs index 9c6b774b990..43375ee3d18 100644 --- a/src/test/compile-fail/const-len-underflow-separate-spans.rs +++ b/src/test/compile-fail/const-len-underflow-separate-spans.rs @@ -15,7 +15,8 @@ const ONE: usize = 1; const TWO: usize = 2; const LEN: usize = ONE - TWO; -//~^ ERROR array length constant evaluation error: attempted to subtract with overflow [E0250] +//~^ ERROR E0080 +//~| attempted to subtract with overflow fn main() { let a: [i8; LEN] = unimplemented!(); diff --git a/src/test/compile-fail/const-len-underflow-subspans.rs b/src/test/compile-fail/const-len-underflow-subspans.rs index d51f31087d0..e338f206553 100644 --- a/src/test/compile-fail/const-len-underflow-subspans.rs +++ b/src/test/compile-fail/const-len-underflow-subspans.rs @@ -16,5 +16,6 @@ const TWO: usize = 2; fn main() { let a: [i8; ONE - TWO] = unimplemented!(); - //~^ ERROR array length constant evaluation error: attempted to subtract with overflow [E0250] + //~^ ERROR constant evaluation error [E0080] + //~| attempted to subtract with overflow } diff --git a/src/test/compile-fail/const-pattern-not-const-evaluable.rs b/src/test/compile-fail/const-pattern-not-const-evaluable.rs index 4567cd4a74b..d68d63683a7 100644 --- a/src/test/compile-fail/const-pattern-not-const-evaluable.rs +++ b/src/test/compile-fail/const-pattern-not-const-evaluable.rs @@ -17,22 +17,26 @@ enum Cake { use Cake::*; const BOO: (Cake, Cake) = (Marmor, BlackForest); -//~^ ERROR: constant evaluation error: unimplemented constant expression: enum variants [E0471] +//~^ ERROR: constant evaluation error [E0080] +//~| unimplemented constant expression: enum variants const FOO: Cake = BOO.1; const fn foo() -> Cake { - Marmor //~ ERROR: constant evaluation error: unimplemented constant expression: enum variants - //~^ ERROR: unimplemented constant expression: enum variants + Marmor + //~^ ERROR: constant evaluation error [E0080] + //~| unimplemented constant expression: enum variants + //~^^^ ERROR: constant evaluation error [E0080] + //~| unimplemented constant expression: enum variants } const WORKS: Cake = Marmor; -const GOO: Cake = foo(); +const GOO: Cake = foo(); //~ NOTE for expression here fn main() { match BlackForest { - FOO => println!("hi"), //~ NOTE: in pattern here - GOO => println!("meh"), //~ NOTE: in pattern here + FOO => println!("hi"), //~ NOTE: for pattern here + GOO => println!("meh"), //~ NOTE: for pattern here WORKS => println!("möp"), _ => println!("bye"), } diff --git a/src/test/compile-fail/const-slice-oob.rs b/src/test/compile-fail/const-slice-oob.rs index d63b0097e5a..b1b4bfe2d1c 100644 --- a/src/test/compile-fail/const-slice-oob.rs +++ b/src/test/compile-fail/const-slice-oob.rs @@ -10,7 +10,8 @@ const FOO: &'static[u32] = &[1, 2, 3]; const BAR: u32 = FOO[5]; -//~^ ERROR index out of bounds: the len is 3 but the index is 5 +//~^ ERROR constant evaluation error [E0080] +//~| index out of bounds: the len is 3 but the index is 5 fn main() { let _ = BAR; diff --git a/src/test/compile-fail/const-tup-index-span.rs b/src/test/compile-fail/const-tup-index-span.rs index 9d3c432d148..6f095b3041f 100644 --- a/src/test/compile-fail/const-tup-index-span.rs +++ b/src/test/compile-fail/const-tup-index-span.rs @@ -11,7 +11,8 @@ // Test spans of errors const TUP: (usize,) = 5 << 64; -//~^ ERROR: attempted to shift left with overflow [E0250] +//~^ ERROR E0080 +//~| attempted to shift left with overflow const ARR: [i32; TUP.0] = []; fn main() { diff --git a/src/test/compile-fail/discrim-ill-typed.rs b/src/test/compile-fail/discrim-ill-typed.rs index 23106c99594..5af889cb239 100644 --- a/src/test/compile-fail/discrim-ill-typed.rs +++ b/src/test/compile-fail/discrim-ill-typed.rs @@ -25,7 +25,8 @@ fn f_i8() { Ok = i8::MAX - 1, Ok2, OhNo = 0_u8, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| mismatched types } let x = A::Ok; @@ -37,7 +38,8 @@ fn f_u8() { Ok = u8::MAX - 1, Ok2, OhNo = 0_i8, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| mismatched types } let x = A::Ok; @@ -49,7 +51,8 @@ fn f_i16() { Ok = i16::MAX - 1, Ok2, OhNo = 0_u16, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| mismatched types } let x = A::Ok; @@ -61,7 +64,8 @@ fn f_u16() { Ok = u16::MAX - 1, Ok2, OhNo = 0_i16, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| mismatched types } let x = A::Ok; @@ -73,7 +77,8 @@ fn f_i32() { Ok = i32::MAX - 1, Ok2, OhNo = 0_u32, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| mismatched types } let x = A::Ok; @@ -85,7 +90,8 @@ fn f_u32() { Ok = u32::MAX - 1, Ok2, OhNo = 0_i32, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| mismatched types } let x = A::Ok; @@ -97,7 +103,8 @@ fn f_i64() { Ok = i64::MAX - 1, Ok2, OhNo = 0_u64, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| mismatched types } let x = A::Ok; @@ -109,7 +116,8 @@ fn f_u64() { Ok = u64::MAX - 1, Ok2, OhNo = 0_i64, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| mismatched types } let x = A::Ok; diff --git a/src/test/compile-fail/enum-discrim-too-small.rs b/src/test/compile-fail/enum-discrim-too-small.rs index d6ba09bb4c5..bbdb3891d99 100644 --- a/src/test/compile-fail/enum-discrim-too-small.rs +++ b/src/test/compile-fail/enum-discrim-too-small.rs @@ -13,28 +13,32 @@ enum Eu8 { Au8 = 23, Bu8 = 223, - Cu8 = -23, //~ ERROR unary negation of unsigned integer + Cu8 = -23, //~ ERROR E0080 + //~| unary negation of unsigned integer } #[repr(u16)] enum Eu16 { Au16 = 23, Bu16 = 55555, - Cu16 = -22333, //~ ERROR unary negation of unsigned integer + Cu16 = -22333, //~ ERROR E0080 + //~| unary negation of unsigned integer } #[repr(u32)] enum Eu32 { Au32 = 23, Bu32 = 3_000_000_000, - Cu32 = -2_000_000_000, //~ ERROR unary negation of unsigned integer + Cu32 = -2_000_000_000, //~ ERROR E0080 + //~| unary negation of unsigned integer } #[repr(u64)] enum Eu64 { Au32 = 23, Bu32 = 3_000_000_000, - Cu32 = -2_000_000_000, //~ ERROR unary negation of unsigned integer + Cu32 = -2_000_000_000, //~ ERROR E0080 + //~| unary negation of unsigned integer } // u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`. This is a diff --git a/src/test/compile-fail/eval-enum.rs b/src/test/compile-fail/eval-enum.rs index 7ca274b81e5..57db583aefe 100644 --- a/src/test/compile-fail/eval-enum.rs +++ b/src/test/compile-fail/eval-enum.rs @@ -9,9 +9,11 @@ // except according to those terms. enum test { - div_zero = 1/0, //~ERROR constant evaluation error: attempted to divide by zero + div_zero = 1/0, //~ ERROR E0080 + //~| attempted to divide by zero rem_zero = 1%0, -//~^ ERROR constant evaluation error: attempted to calculate the remainder with a divisor of zero + //~^ ERROR E0080 + //~| attempted to calculate the remainder with a divisor of zero } fn main() {} diff --git a/src/test/compile-fail/feature-gate-negate-unsigned0.rs b/src/test/compile-fail/feature-gate-negate-unsigned0.rs index 05b194345d4..89ae1a09bd3 100644 --- a/src/test/compile-fail/feature-gate-negate-unsigned0.rs +++ b/src/test/compile-fail/feature-gate-negate-unsigned0.rs @@ -18,14 +18,17 @@ impl std::ops::Neg for S { fn main() { let a = -1; - //~^ ERROR unary negation of unsigned integer + //~^ ERROR E0080 + //~| unary negation of unsigned integer let _b : u8 = a; // for infering variable a to u8. let _d = -1u8; - //~^ ERROR unary negation of unsigned integer + //~^ ERROR E0080 + //~| unary negation of unsigned integer for _ in -10..10u8 {} - //~^ ERROR unary negation of unsigned integer + //~^ ERROR E0080 + //~| unary negation of unsigned integer -S; // should not trigger the gate; issue 26840 } diff --git a/src/test/compile-fail/invalid-path-in-const.rs b/src/test/compile-fail/invalid-path-in-const.rs index 3c4ad5a56ec..9a9358b787f 100644 --- a/src/test/compile-fail/invalid-path-in-const.rs +++ b/src/test/compile-fail/invalid-path-in-const.rs @@ -10,5 +10,6 @@ fn main() { fn f(a: [u8; u32::DOESNOTEXIST]) {} - //~^ ERROR unresolved path in constant expression + //~^ ERROR constant evaluation error + //~| unresolved path in constant expression } diff --git a/src/test/compile-fail/issue-22933-2.rs b/src/test/compile-fail/issue-22933-2.rs index 7d619c270d3..54a24089354 100644 --- a/src/test/compile-fail/issue-22933-2.rs +++ b/src/test/compile-fail/issue-22933-2.rs @@ -12,10 +12,12 @@ enum Delicious { Pie = 0x1, Apple = 0x2, ApplePie = Delicious::Apple as isize | Delicious::PIE as isize, - //~^ ERROR constant evaluation error: unresolved path in constant expression + //~^ ERROR constant evaluation error + //~| unresolved path in constant expression } const FOO: [u32; u8::MIN as usize] = []; -//~^ ERROR array length constant evaluation error: unresolved path in constant expression +//~^ ERROR constant evaluation error +//~| unresolved path in constant expression fn main() {} diff --git a/src/test/compile-fail/issue-23217.rs b/src/test/compile-fail/issue-23217.rs index 32cdd6b5ed9..c2bcbb9d54a 100644 --- a/src/test/compile-fail/issue-23217.rs +++ b/src/test/compile-fail/issue-23217.rs @@ -10,7 +10,8 @@ pub enum SomeEnum { B = SomeEnum::A, - //~^ ERROR constant evaluation error: unresolved path in constant expression + //~^ ERROR constant evaluation error + //~| unresolved path in constant expression } fn main() {} diff --git a/src/test/compile-fail/issue-25145.rs b/src/test/compile-fail/issue-25145.rs index e8a9c8d2ea3..93f75e9bfed 100644 --- a/src/test/compile-fail/issue-25145.rs +++ b/src/test/compile-fail/issue-25145.rs @@ -17,6 +17,7 @@ impl S { } static STUFF: [u8; S::N] = [0; S::N]; -//~^ ERROR array length constant evaluation error: unresolved path in constant expression +//~^ ERROR constant evaluation error +//~| unresolved path in constant expression fn main() {} diff --git a/src/test/compile-fail/issue-27008.rs b/src/test/compile-fail/issue-27008.rs index bdcbaf09177..ee6ec527612 100644 --- a/src/test/compile-fail/issue-27008.rs +++ b/src/test/compile-fail/issue-27008.rs @@ -16,5 +16,5 @@ fn main() { //~| expected type `usize` //~| found type `S` //~| expected usize, found struct `S` - //~| ERROR expected positive integer for repeat count, found struct + //~| ERROR expected usize for repeat count, found struct } diff --git a/src/test/compile-fail/issue-27895.rs b/src/test/compile-fail/issue-27895.rs index 3b3abc94a49..ca8d5a1f704 100644 --- a/src/test/compile-fail/issue-27895.rs +++ b/src/test/compile-fail/issue-27895.rs @@ -14,7 +14,8 @@ fn main() { match i { 0...index => println!("winner"), - //~^ ERROR non-constant path in constant expression + //~^ ERROR constant evaluation error + //~| non-constant path in constant expression _ => println!("hello"), } } diff --git a/src/test/compile-fail/issue-28586.rs b/src/test/compile-fail/issue-28586.rs index c8a1e424da2..1dfd146985f 100644 --- a/src/test/compile-fail/issue-28586.rs +++ b/src/test/compile-fail/issue-28586.rs @@ -11,6 +11,6 @@ // Regression test for issue #28586 pub trait Foo {} -impl Foo for [u8; usize::BYTES] {} //~ ERROR E0250 +impl Foo for [u8; usize::BYTES] {} //~ ERROR E0080 fn main() { } diff --git a/src/test/compile-fail/issue-3521.rs b/src/test/compile-fail/issue-3521.rs index 52375ef281a..1b6e4b1d289 100644 --- a/src/test/compile-fail/issue-3521.rs +++ b/src/test/compile-fail/issue-3521.rs @@ -15,7 +15,8 @@ fn main() { enum Stuff { Bar = foo //~^ ERROR attempt to use a non-constant value in a constant - //~^^ ERROR constant evaluation error: non-constant path in constant expression + //~^^ ERROR constant evaluation error + //~| non-constant path in constant expression } println!("{}", Stuff::Bar); diff --git a/src/test/compile-fail/issue-8761.rs b/src/test/compile-fail/issue-8761.rs index 1c98abce030..6352f4f6a04 100644 --- a/src/test/compile-fail/issue-8761.rs +++ b/src/test/compile-fail/issue-8761.rs @@ -10,13 +10,13 @@ enum Foo { A = 1i64, - //~^ ERROR mismatched types: - //~| expected `isize`, - //~| found `i64` [E0080] + //~^ ERROR constant evaluation error + //~| expected `isize` + //~| found `i64` B = 2u8 - //~^ ERROR mismatched types: - //~| expected `isize`, - //~| found `u8` [E0080] + //~^ ERROR constant evaluation error + //~| expected `isize` + //~| found `u8` } fn main() {} diff --git a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs b/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs index 9564a080b8e..cadfec5a38d 100644 --- a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs +++ b/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs @@ -15,5 +15,6 @@ enum State { ST_NULL, ST_WHITESPACE } fn main() { [State::ST_NULL; (State::ST_WHITESPACE as usize)]; - //~^ ERROR expected constant integer for repeat count, but unimplemented constant expression + //~^ ERROR constant evaluation error + //~| unimplemented constant expression: enum variants } diff --git a/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs b/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs index 3ce206ff7fb..a6f88a57b91 100644 --- a/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs +++ b/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs @@ -13,6 +13,8 @@ fn main() { fn bar(n: usize) { let _x = [0; n]; - //~^ ERROR expected constant integer for repeat count, found variable + //~^ ERROR constant evaluation error + //~| non-constant path in constant expression + //~| NOTE `n` is a variable } } diff --git a/src/test/compile-fail/non-constant-in-const-path.rs b/src/test/compile-fail/non-constant-in-const-path.rs index ee88168515d..737f80372de 100644 --- a/src/test/compile-fail/non-constant-in-const-path.rs +++ b/src/test/compile-fail/non-constant-in-const-path.rs @@ -12,6 +12,7 @@ fn main() { let x = 0; match 1 { 0 ... x => {} - //~^ ERROR non-constant path in constant expression + //~^ ERROR constant evaluation error + //~| non-constant path in constant expression }; } diff --git a/src/test/compile-fail/repeat_count.rs b/src/test/compile-fail/repeat_count.rs index ab5af64d95c..d68df973641 100644 --- a/src/test/compile-fail/repeat_count.rs +++ b/src/test/compile-fail/repeat_count.rs @@ -13,37 +13,38 @@ fn main() { let n = 1; let a = [0; n]; - //~^ ERROR expected constant integer for repeat count, found variable [E0307] + //~^ ERROR constant evaluation error + //~| non-constant path in constant expression let b = [0; ()]; //~^ ERROR mismatched types //~| expected type `usize` //~| found type `()` //~| expected usize, found () - //~| ERROR expected positive integer for repeat count, found tuple [E0306] + //~| ERROR expected usize for repeat count, found tuple [E0306] let c = [0; true]; //~^ ERROR mismatched types //~| expected usize, found bool - //~| ERROR expected positive integer for repeat count, found boolean [E0306] + //~| ERROR expected usize for repeat count, found boolean [E0306] let d = [0; 0.5]; //~^ ERROR mismatched types //~| expected type `usize` //~| found type `_` //~| expected usize, found floating-point variable - //~| ERROR expected positive integer for repeat count, found float [E0306] + //~| ERROR expected usize for repeat count, found float [E0306] let e = [0; "foo"]; //~^ ERROR mismatched types //~| expected type `usize` //~| found type `&'static str` //~| expected usize, found &-ptr - //~| ERROR expected positive integer for repeat count, found string literal [E0306] + //~| ERROR expected usize for repeat count, found string literal [E0306] let f = [0; -4_isize]; - //~^ ERROR mismatched types + //~^ ERROR constant evaluation error //~| expected `usize` //~| found `isize` - //~| ERROR mismatched types: + //~| ERROR mismatched types //~| expected usize, found isize let f = [0_usize; -1_isize]; - //~^ ERROR mismatched types + //~^ ERROR constant evaluation error //~| expected `usize` //~| found `isize` //~| ERROR mismatched types @@ -56,5 +57,5 @@ fn main() { //~| expected type `usize` //~| found type `main::G` //~| expected usize, found struct `main::G` - //~| ERROR expected positive integer for repeat count, found struct [E0306] + //~| ERROR expected usize for repeat count, found struct [E0306] } From 712c5cadbbb460a0b313a2fbcdaa9d6e10a25b6b Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda <ariel.byd@gmail.com> Date: Tue, 19 Jul 2016 01:10:19 +0300 Subject: [PATCH 07/14] remove the now-unused multiline error code --- src/librustc/session/mod.rs | 81 ++----------------------------------- 1 file changed, 4 insertions(+), 77 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index fa9bc7c8368..5901c42b525 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -126,20 +126,14 @@ impl Session { sp: S, msg: &str) -> DiagnosticBuilder<'a> { - match split_msg_into_multilines(msg) { - Some(ref msg) => self.diagnostic().struct_span_err(sp, msg), - None => self.diagnostic().struct_span_err(sp, msg), - } + self.diagnostic().struct_span_err(sp, msg) } pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self, sp: S, msg: &str, code: &str) -> DiagnosticBuilder<'a> { - match split_msg_into_multilines(msg) { - Some(ref msg) => self.diagnostic().struct_span_err_with_code(sp, msg, code), - None => self.diagnostic().struct_span_err_with_code(sp, msg, code), - } + self.diagnostic().struct_span_err_with_code(sp, msg, code) } pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { self.diagnostic().struct_err(msg) @@ -178,16 +172,10 @@ impl Session { } } pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { - match split_msg_into_multilines(msg) { - Some(msg) => self.diagnostic().span_err(sp, &msg), - None => self.diagnostic().span_err(sp, msg) - } + self.diagnostic().span_err(sp, msg) } pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) { - match split_msg_into_multilines(msg) { - Some(msg) => self.diagnostic().span_err_with_code(sp, &msg, code), - None => self.diagnostic().span_err_with_code(sp, msg, code) - } + self.diagnostic().span_err_with_code(sp, &msg, code) } pub fn err(&self, msg: &str) { self.diagnostic().err(msg) @@ -343,67 +331,6 @@ impl Session { } } -fn split_msg_into_multilines(msg: &str) -> Option<String> { - // Conditions for enabling multi-line errors: - if !msg.contains("mismatched types") && - !msg.contains("type mismatch resolving") && - !msg.contains("if and else have incompatible types") && - !msg.contains("if may be missing an else clause") && - !msg.contains("match arms have incompatible types") && - !msg.contains("structure constructor specifies a structure of type") && - !msg.contains("has an incompatible type for trait") { - return None - } - let first = msg.match_indices("expected").filter(|s| { - let last = msg[..s.0].chars().rev().next(); - last == Some(' ') || last == Some('(') - }).map(|(a, b)| (a - 1, a + b.len())); - let second = msg.match_indices("found").filter(|s| { - msg[..s.0].chars().rev().next() == Some(' ') - }).map(|(a, b)| (a - 1, a + b.len())); - - let mut new_msg = String::new(); - let mut head = 0; - - // Insert `\n` before expected and found. - for (pos1, pos2) in first.zip(second) { - new_msg = new_msg + - // A `(` may be preceded by a space and it should be trimmed - msg[head..pos1.0].trim_right() + // prefix - "\n" + // insert before first - &msg[pos1.0..pos1.1] + // insert what first matched - &msg[pos1.1..pos2.0] + // between matches - "\n " + // insert before second - // 123 - // `expected` is 3 char longer than `found`. To align the types, - // `found` gets 3 spaces prepended. - &msg[pos2.0..pos2.1]; // insert what second matched - - head = pos2.1; - } - - let mut tail = &msg[head..]; - let third = tail.find("(values differ") - .or(tail.find("(lifetime")) - .or(tail.find("(cyclic type of infinite size")); - // Insert `\n` before any remaining messages which match. - if let Some(pos) = third { - // The end of the message may just be wrapped in `()` without - // `expected`/`found`. Push this also to a new line and add the - // final tail after. - new_msg = new_msg + - // `(` is usually preceded by a space and should be trimmed. - tail[..pos].trim_right() + // prefix - "\n" + // insert before paren - &tail[pos..]; // append the tail - - tail = ""; - } - - new_msg.push_str(tail); - return Some(new_msg); -} - pub fn build_session(sopts: config::Options, dep_graph: &DepGraph, local_crate_source_file: Option<PathBuf>, From f3ee99bd4d9d282c33127449073c521f29b07c21 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda <ariel.byd@gmail.com> Date: Thu, 21 Jul 2016 02:13:14 +0300 Subject: [PATCH 08/14] 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. --- src/librustc/traits/error_reporting.rs | 83 ++++++++++++++----- .../higher-ranked-projection.rs | 38 +++++++++ src/test/compile-fail/issue-31173.rs | 3 +- 3 files changed, 101 insertions(+), 23 deletions(-) create mode 100644 src/test/compile-fail/associated-types/higher-ranked-projection.rs diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index afbe34f89bb..33ca1d05cad 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -26,8 +26,9 @@ use super::{ use fmt_macros::{Parser, Piece, Position}; use hir::def_id::DefId; -use infer::{InferCtxt, TypeOrigin}; +use infer::{self, InferCtxt, TypeOrigin}; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; +use ty::error::ExpectedFound; use ty::fast_reject; use ty::fold::TypeFolder; use ty::subst::{self, Subst, TypeSpace}; @@ -107,28 +108,66 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let predicate = self.resolve_type_vars_if_possible(&obligation.predicate); - if !predicate.references_error() { - if let Some(warning_node_id) = warning_node_id { - self.tcx.sess.add_lint( - ::lint::builtin::UNSIZED_IN_TUPLE, - warning_node_id, - obligation.cause.span, - format!("type mismatch resolving `{}`: {}", - predicate, - error.err)); - } else { - let mut err = type_err!( - self, - TypeOrigin::Misc(obligation.cause.span), - None, // FIXME: be smarter - error.err, - E0271, - "type mismatch resolving `{}`", - predicate); - self.note_obligation_cause(&mut err, obligation); - err.emit(); - } + if predicate.references_error() { + return } + if let Some(warning_node_id) = warning_node_id { + self.tcx.sess.add_lint( + ::lint::builtin::UNSIZED_IN_TUPLE, + warning_node_id, + obligation.cause.span, + format!("type mismatch resolving `{}`: {}", + predicate, + error.err)); + return + } + self.probe(|_| { + let origin = TypeOrigin::Misc(obligation.cause.span); + let err_buf; + let mut err = &error.err; + let mut values = None; + + // try to find the mismatched types to report the error with. + // + // this can fail if the problem was higher-ranked, in which + // cause I have no idea for a good error message. + if let ty::Predicate::Projection(ref data) = predicate { + let mut selcx = SelectionContext::new(self); + let (data, _) = self.replace_late_bound_regions_with_fresh_var( + obligation.cause.span, + infer::LateBoundRegionConversionTime::HigherRankedType, + data); + let normalized = super::normalize_projection_type( + &mut selcx, + data.projection_ty, + obligation.cause.clone(), + 0 + ); + let origin = TypeOrigin::Misc(obligation.cause.span); + if let Err(error) = self.eq_types( + false, origin, + data.ty, normalized.value + ) { + values = Some(infer::ValuePairs::Types(ExpectedFound { + expected: normalized.value, + found: data.ty, + })); + err_buf = error; + err = &err_buf; + } + } + + let mut diag = type_err!( + self, + origin, + values, + err, + E0271, + "type mismatch resolving `{}`", + predicate); + self.note_obligation_cause(&mut diag, obligation); + diag.emit(); + }); } fn impl_substs(&self, diff --git a/src/test/compile-fail/associated-types/higher-ranked-projection.rs b/src/test/compile-fail/associated-types/higher-ranked-projection.rs new file mode 100644 index 00000000000..12341fa8db3 --- /dev/null +++ b/src/test/compile-fail/associated-types/higher-ranked-projection.rs @@ -0,0 +1,38 @@ +// Copyright 2016 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. + +#![feature(rustc_attrs)] + +// revisions: good bad + +trait Mirror { + type Image; +} + +impl<T> Mirror for T { + type Image = T; +} + +#[cfg(bad)] +fn foo<U, T>(_t: T) + where for<'a> &'a T: Mirror<Image=U> +{} + +#[cfg(good)] +fn foo<U, T>(_t: T) + where for<'a> &'a T: Mirror<Image=&'a U> +{} + +#[rustc_error] +fn main() { //[good]~ ERROR compilation successful + foo(()); + //[bad]~^ ERROR type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _` + //[bad]~| expected bound lifetime parameter 'a, found concrete lifetime +} diff --git a/src/test/compile-fail/issue-31173.rs b/src/test/compile-fail/issue-31173.rs index 62d23a99cba..fb1e3cc87e8 100644 --- a/src/test/compile-fail/issue-31173.rs +++ b/src/test/compile-fail/issue-31173.rs @@ -19,7 +19,8 @@ pub fn get_tok(it: &mut IntoIter<u8>) { }) .cloned() //~^ ERROR type mismatch resolving - //~| expected u8, found &-ptr + //~| expected type `u8` + //~| found type `&_` .collect(); //~ ERROR no method named `collect` } From 1e4f6d56836e9f9867bb8b05efc2fffceab6b423 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda <arielb1@mail.tau.ac.il> Date: Thu, 21 Jul 2016 20:12:04 +0300 Subject: [PATCH 09/14] rustc_errors: fix a few bugs --- src/librustc_errors/lib.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 6a48f65714c..610e5647d6d 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -531,10 +531,12 @@ impl Handler { DiagnosticBuilder::new(self, Level::Fatal, msg) } - pub fn cancel(&mut self, err: &mut DiagnosticBuilder) { + pub fn cancel(&self, err: &mut DiagnosticBuilder) { if err.level == Level::Error || err.level == Level::Fatal { - assert!(self.has_errors()); - self.err_count.set(self.err_count.get() + 1); + self.err_count.set( + self.err_count.get().checked_sub(1) + .expect("cancelled an error but err_count is 0") + ); } err.cancel(); } From 93a96835b09fda7aefb886c9c1c9daa5831bdac6 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda <arielb1@mail.tau.ac.il> Date: Thu, 21 Jul 2016 20:12:30 +0300 Subject: [PATCH 10/14] use diagnostic-mutating style for `note_type_err` too that is much cleaner than the `type_err!` style I used earlier. --- src/librustc/infer/error_reporting.rs | 42 +++++++++++---------- src/librustc/macros.rs | 13 ------- src/librustc/traits/error_reporting.rs | 13 +++---- src/librustc_typeck/check/compare_method.rs | 40 +++++++++++++------- 4 files changed, 53 insertions(+), 55 deletions(-) diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 0726d8560ba..511cc32d2e1 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -521,25 +521,25 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - pub fn report_and_explain_type_error_with_code(&self, - origin: TypeOrigin, - values: Option<ValuePairs<'tcx>>, - terr: &TypeError<'tcx>, - message: &str, - code: &str) - -> DiagnosticBuilder<'tcx> + pub fn note_type_err(&self, + diag: &mut DiagnosticBuilder<'tcx>, + origin: TypeOrigin, + values: Option<ValuePairs<'tcx>>, + terr: &TypeError<'tcx>) { let expected_found = match values { None => None, Some(values) => match self.values_str(&values) { Some((expected, found)) => Some((expected, found)), - None => return self.tcx.sess.diagnostic().struct_dummy() /* derived error */ + None => { + // Derived error. Cancel the emitter. + self.tcx.sess.diagnostic().cancel(diag); + return + } } }; let span = origin.span(); - let mut err = self.tcx.sess.struct_span_err_with_code( - span, message, code); let mut is_simple_error = false; @@ -551,21 +551,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }; if !is_simple_error || check_old_school() { - err.note_expected_found(&"type", &expected, &found); + diag.note_expected_found(&"type", &expected, &found); } } if !is_simple_error && check_old_school() { - err.span_note(span, &format!("{}", terr)); + diag.span_note(span, &format!("{}", terr)); } else { - err.span_label(span, &terr); + diag.span_label(span, &terr); } - self.note_error_origin(&mut err, &origin); - self.check_and_note_conflicting_crates(&mut err, terr, span); - self.tcx.note_and_explain_type_err(&mut err, terr, span); - - err + self.note_error_origin(diag, &origin); + self.check_and_note_conflicting_crates(diag, terr, span); + self.tcx.note_and_explain_type_err(diag, terr, span); } pub fn report_and_explain_type_error(&self, @@ -574,8 +572,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -> DiagnosticBuilder<'tcx> { // FIXME: do we want to use a different error code for each origin? - let failure_str = trace.origin.as_failure_str(); - type_err!(self, trace.origin, Some(trace.values), terr, E0308, "{}", failure_str) + let mut diag = struct_span_err!( + self.tcx.sess, trace.origin.span(), E0308, + "{}", trace.origin.as_failure_str() + ); + self.note_type_err(&mut diag, trace.origin, Some(trace.values), terr); + diag } /// Returns a string of the form "expected `{}`, found `{}`". diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index 190c9b665e0..76dca1bb5b6 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -59,16 +59,3 @@ macro_rules! span_bug { $crate::session::span_bug_fmt(file!(), line!(), $span, format_args!($($message)*)) }) } - -#[macro_export] -macro_rules! type_err { - ($infcx:expr, $origin: expr, $values: expr, $terr: expr, $code:ident, $($message:tt)*) => ({ - __diagnostic_used!($code); - $infcx.report_and_explain_type_error_with_code( - $origin, - $values, - &$terr, - &format!($($message)*), - stringify!($code)) - }) -} diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 33ca1d05cad..67ad887530e 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -157,14 +157,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - let mut diag = type_err!( - self, - origin, - values, - err, - E0271, - "type mismatch resolving `{}`", - predicate); + let mut diag = struct_span_err!( + self.tcx.sess, origin.span(), E0271, + "type mismatch resolving `{}`", predicate + ); + self.note_type_err(&mut diag, origin, values, err); self.note_obligation_cause(&mut diag, obligation); diag.emit(); }); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 2c4c6279076..9844377d0bd 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -325,13 +325,19 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty); - let values = Some(infer::ValuePairs::Types(ExpectedFound { - expected: trait_fty, - found: impl_fty - })); - type_err!(infcx, origin, values, terr, E0053, - "method `{}` has an incompatible type for trait", - trait_m.name).emit(); + + let mut diag = struct_span_err!( + tcx.sess, origin.span(), E0053, + "method `{}` has an incompatible type for trait", trait_m.name + ); + infcx.note_type_err( + &mut diag, origin, + Some(infer::ValuePairs::Types(ExpectedFound { + expected: trait_fty, + found: impl_fty + })), &terr + ); + diag.emit(); return } @@ -476,13 +482,19 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, debug!("checking associated const for compatibility: impl ty {:?}, trait ty {:?}", impl_ty, trait_ty); - let values = Some(infer::ValuePairs::Types(ExpectedFound { - expected: trait_ty, - found: impl_ty - })); - type_err!(infcx, origin, values, terr, E0326, - "implemented const `{}` has an incompatible type for \ - trait", trait_c.name).emit(); + let mut diag = struct_span_err!( + tcx.sess, origin.span(), E0326, + "implemented const `{}` has an incompatible type for trait", + trait_c.name + ); + infcx.note_type_err( + &mut diag, origin, + Some(infer::ValuePairs::Types(ExpectedFound { + expected: trait_ty, + found: impl_ty + })), &terr + ); + diag.emit(); } }); } From e76a46a10d9bc0e5a2765addf24c3069555bdc83 Mon Sep 17 00:00:00 2001 From: ggomez <guillaume1.gomez@gmail.com> Date: Thu, 21 Jul 2016 16:07:08 +0200 Subject: [PATCH 11/14] Add new error codes in librustc_typeck --- src/librustc/infer/mod.rs | 19 ++++++++++++++----- src/librustc_typeck/check/mod.rs | 12 +++++++----- src/librustc_typeck/diagnostics.rs | 2 ++ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index fd65e06ea97..1df06e8a007 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1510,6 +1510,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.type_error_struct(sp, mk_msg, actual_ty).emit(); } + // FIXME: this results in errors without an error code. Deprecate? pub fn type_error_struct<M>(&self, sp: Span, mk_msg: M, @@ -1517,19 +1518,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -> DiagnosticBuilder<'tcx> where M: FnOnce(String) -> String, { - debug!("type_error_struct({:?}, {:?})", sp, actual_ty); + self.type_error_struct_with_diag(sp, |actual_ty| { + self.tcx.sess.struct_span_err(sp, &mk_msg(actual_ty)) + }, actual_ty) + } + pub fn type_error_struct_with_diag<M>(&self, + sp: Span, + mk_diag: M, + actual_ty: Ty<'tcx>) + -> DiagnosticBuilder<'tcx> + where M: FnOnce(String) -> DiagnosticBuilder<'tcx>, + { let actual_ty = self.resolve_type_vars_if_possible(&actual_ty); + debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty); // Don't report an error if actual type is TyError. if actual_ty.references_error() { return self.tcx.sess.diagnostic().struct_dummy(); } - let msg = mk_msg(self.ty_to_string(actual_ty)); - - // FIXME: use an error code. - self.tcx.sess.struct_span_err(sp, &msg) + mk_diag(self.ty_to_string(actual_ty)) } pub fn report_mismatched_types(&self, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c01edc568af..6062bd048b3 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3028,14 +3028,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { variant: ty::VariantDef<'tcx>, field: &hir::Field, skip_fields: &[hir::Field]) { - let mut err = self.type_error_struct( + let mut err = self.type_error_struct_with_diag( field.name.span, |actual| if let ty::TyEnum(..) = ty.sty { - format!("struct variant `{}::{}` has no field named `{}`", - actual, variant.name.as_str(), field.name.node) + struct_span_err!(self.tcx.sess, field.name.span, E0559, + "struct variant `{}::{}` has no field named `{}`", + actual, variant.name.as_str(), field.name.node) } else { - format!("structure `{}` has no field named `{}`", - actual, field.name.node) + struct_span_err!(self.tcx.sess, field.name.span, E0560, + "structure `{}` has no field named `{}`", + actual, field.name.node) }, ty); // prevent all specified fields from being suggested diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 38bf869119c..6000ea71bff 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4053,4 +4053,6 @@ register_diagnostics! { E0528, // expected at least {} elements, found {} E0529, // slice pattern expects array or slice, not `{}` E0533, // `{}` does not name a unit variant, unit struct or a constant + E0559, + E0560, } From 0304850942d40c798750c4a1ba194c3992dbde1a Mon Sep 17 00:00:00 2001 From: ggomez <guillaume1.gomez@gmail.com> Date: Thu, 21 Jul 2016 16:18:12 +0200 Subject: [PATCH 12/14] Add E0560 error explanation --- src/librustc_typeck/diagnostics.rs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 6000ea71bff..e7efed905ad 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -3980,6 +3980,32 @@ impl SpaceLlama for i32 { ``` "##, +E0560: r##" +An unknown field was specified into a structure. + +Erroneous code example: + +```compile_fail,E0560 +struct Simba { + mother: u32, +} + +let s = Simba { mother: 1, father: 0 }; +// error: structure `Simba` has no field named `father` +``` + +Verify you didn't misspell the field's name or that the field exists. Example: + +``` +struct Simba { + mother: u32, + father: u32, +} + +let s = Simba { mother: 1, father: 0 }; // ok! +``` +"##, + } register_diagnostics! { @@ -4054,5 +4080,4 @@ register_diagnostics! { E0529, // slice pattern expects array or slice, not `{}` E0533, // `{}` does not name a unit variant, unit struct or a constant E0559, - E0560, } From 23bb1df1e52dd17062cd135b5be70ba55d5af147 Mon Sep 17 00:00:00 2001 From: ggomez <guillaume1.gomez@gmail.com> Date: Thu, 21 Jul 2016 16:47:05 +0200 Subject: [PATCH 13/14] Add E0559 error explanation --- src/librustc_typeck/diagnostics.rs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index e7efed905ad..500f624ea3f 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -3980,6 +3980,31 @@ impl SpaceLlama for i32 { ``` "##, +E0559: r##" +An unknown field was specified into an enum's structure variant. + +Erroneous code example: + +```compile_fail,E0559 +enum Field { + Fool { x: u32 }, +} + +let s = Field::Fool { joke: 0 }; +// error: struct variant `Field::Fool` has no field named `joke` +``` + +Verify you didn't misspell the field's name or that the field exists. Example: + +``` +enum Field { + Fool { joke: u32 }, +} + +let s = Field::Fool { joke: 0 }; // ok! +``` +"##, + E0560: r##" An unknown field was specified into a structure. @@ -4079,5 +4104,4 @@ register_diagnostics! { E0528, // expected at least {} elements, found {} E0529, // slice pattern expects array or slice, not `{}` E0533, // `{}` does not name a unit variant, unit struct or a constant - E0559, } From 717e39294f635d90f8ba9e0968494f741878f37b Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda <ariel.byd@gmail.com> Date: Fri, 22 Jul 2016 23:52:53 +0300 Subject: [PATCH 14/14] address review comments I split the RFC1592 commit out --- src/librustc/infer/mod.rs | 18 +++----- src/librustc_const_eval/eval.rs | 28 +----------- src/librustc_typeck/check/demand.rs | 9 +++- src/librustc_typeck/check/wfcheck.rs | 44 +++++++++++++------ .../compile-fail/const-eval-overflow-4b.rs | 4 +- src/test/compile-fail/discrim-ill-typed.rs | 16 +++---- .../explicit-self-lifetime-mismatch.rs | 8 ++-- src/test/compile-fail/issue-17740.rs | 4 +- src/test/compile-fail/issue-26194.rs | 2 +- src/test/compile-fail/issue-8761.rs | 6 +-- src/test/compile-fail/repeat_count.rs | 6 +-- .../compile-fail/ufcs-explicit-self-bad.rs | 14 +++--- 12 files changed, 74 insertions(+), 85 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 1df06e8a007..87882c5528e 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -196,12 +196,6 @@ pub enum TypeOrigin { // FIXME(eddyb) #11161 is the original Expr required? ExprAssignable(Span), - // Relating trait refs when resolving vtables - RelateTraitRefs(Span), - - // Relating self types when resolving vtables - RelateSelfType(Span), - // Relating trait type parameters to those found in impl etc RelateOutputImplTypes(Span), @@ -228,16 +222,17 @@ pub enum TypeOrigin { // intrinsic has wrong type IntrinsicType(Span), + + // method receiver + MethodReceiver(Span), } impl TypeOrigin { fn as_failure_str(&self) -> &'static str { match self { &TypeOrigin::Misc(_) | - &TypeOrigin::RelateSelfType(_) | &TypeOrigin::RelateOutputImplTypes(_) | &TypeOrigin::ExprAssignable(_) => "mismatched types", - &TypeOrigin::RelateTraitRefs(_) => "mismatched traits", &TypeOrigin::MethodCompatCheck(_) => "method not compatible with trait", &TypeOrigin::MatchExpressionArm(_, _, source) => match source { hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types", @@ -250,6 +245,7 @@ impl TypeOrigin { &TypeOrigin::MainFunctionType(_) => "main function has wrong type", &TypeOrigin::StartFunctionType(_) => "start function has wrong type", &TypeOrigin::IntrinsicType(_) => "intrinsic has wrong type", + &TypeOrigin::MethodReceiver(_) => "mismatched method receiver", } } @@ -258,8 +254,6 @@ impl TypeOrigin { &TypeOrigin::Misc(_) => "types are compatible", &TypeOrigin::MethodCompatCheck(_) => "method type is compatible with trait", &TypeOrigin::ExprAssignable(_) => "expression is assignable", - &TypeOrigin::RelateTraitRefs(_) => "traits are compatible", - &TypeOrigin::RelateSelfType(_) => "self type matches impl self type", &TypeOrigin::RelateOutputImplTypes(_) => { "trait type parameters matches those specified on the impl" } @@ -271,6 +265,7 @@ impl TypeOrigin { &TypeOrigin::MainFunctionType(_) => "`main` function has the correct type", &TypeOrigin::StartFunctionType(_) => "`start` function has the correct type", &TypeOrigin::IntrinsicType(_) => "intrinsic has the correct type", + &TypeOrigin::MethodReceiver(_) => "method receiver has the correct type", } } } @@ -1806,8 +1801,6 @@ impl TypeOrigin { TypeOrigin::MethodCompatCheck(span) => span, TypeOrigin::ExprAssignable(span) => span, TypeOrigin::Misc(span) => span, - TypeOrigin::RelateTraitRefs(span) => span, - TypeOrigin::RelateSelfType(span) => span, TypeOrigin::RelateOutputImplTypes(span) => span, TypeOrigin::MatchExpressionArm(match_span, _, _) => match_span, TypeOrigin::IfExpression(span) => span, @@ -1817,6 +1810,7 @@ impl TypeOrigin { TypeOrigin::MainFunctionType(span) => span, TypeOrigin::StartFunctionType(span) => span, TypeOrigin::IntrinsicType(span) => span, + TypeOrigin::MethodReceiver(span) => span, } } } diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 03d2f596e21..2eb08cab1aa 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -384,15 +384,6 @@ pub fn note_const_eval_err<'a, 'tcx>( diag.span_label(err.span, &message); } } - ConstEvalErrDescription::ExpectedFound { error, expected, found } => { - if check_old_school() { - diag.note(&error); - } else { - diag.span_label(err.span, &error); - } - diag.note(&format!("expected `{}`", expected)); - diag.note(&format!("found `{}`", found)); - } } if !primary_span.contains(err.span) { @@ -477,11 +468,6 @@ impl From<ConstMathErr> for ErrKind { #[derive(Clone, Debug)] pub enum ConstEvalErrDescription<'a> { Simple(Cow<'a, str>), - ExpectedFound { - error: Cow<'a, str>, - expected: Cow<'a, str>, - found: Cow<'a, str> - } } impl<'a> ConstEvalErrDescription<'a> { @@ -489,14 +475,6 @@ impl<'a> ConstEvalErrDescription<'a> { pub fn into_oneline(self) -> Cow<'a, str> { match self { ConstEvalErrDescription::Simple(simple) => simple, - ConstEvalErrDescription::ExpectedFound { - error, - expected, - found - } => { - format!("{}: expected `{}`, found `{}`", error, expected, found) - .into_cow() - } } } } @@ -554,11 +532,7 @@ impl ConstEvalErr { the constant evaluator"), TypeMismatch(ref expected, ref got) => { - ExpectedFound { - error: "mismatched types".into_cow(), - expected: <&str>::into_cow(expected), - found: got.description().into_cow() - } + simple!("expected {}, found {}", expected, got.description()) }, BadType(ref i) => simple!("value of wrong type: {:?}", i), ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"), diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index c1f415b3c02..1f3a83ebc1d 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -33,7 +33,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { - let origin = TypeOrigin::Misc(sp); + self.demand_eqtype_with_origin(TypeOrigin::Misc(sp), expected, actual); + } + + pub fn demand_eqtype_with_origin(&self, + origin: TypeOrigin, + expected: Ty<'tcx>, + actual: Ty<'tcx>) + { match self.eq_types(false, origin, actual, expected) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 2d44a85f9af..907cb734c2f 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -13,6 +13,7 @@ use constrained_type_params::{identify_constrained_type_params, Parameter}; use CrateCtxt; use hir::def_id::DefId; use middle::region::{CodeExtent}; +use rustc::infer::TypeOrigin; use rustc::ty::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace}; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; @@ -157,7 +158,10 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } } - fn check_trait_or_impl_item(&mut self, item_id: ast::NodeId, span: Span) { + fn check_trait_or_impl_item(&mut self, + item_id: ast::NodeId, + span: Span, + sig_if_method: Option<&hir::MethodSig>) { let code = self.code.clone(); self.for_id(item_id, span).with_fcx(|fcx, this| { let free_substs = &fcx.parameter_environment.free_substs; @@ -182,7 +186,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { let predicates = fcx.instantiate_bounds(span, free_substs, &method.predicates); this.check_fn_or_method(fcx, span, &method_ty, &predicates, free_id_outlive, &mut implied_bounds); - this.check_method_receiver(fcx, span, &method, + let sig_if_method = sig_if_method.expect("bad signature for method"); + this.check_method_receiver(fcx, sig_if_method, &method, free_id_outlive, self_ty); } ty::TypeTraitItem(assoc_type) => { @@ -405,20 +410,15 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { fn check_method_receiver<'fcx, 'tcx>(&mut self, fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, - span: Span, + method_sig: &hir::MethodSig, method: &ty::Method<'tcx>, free_id_outlive: CodeExtent, self_ty: ty::Ty<'tcx>) { // check that the type of the method's receiver matches the // method's first parameter. - - let free_substs = &fcx.parameter_environment.free_substs; - let fty = fcx.instantiate_type_scheme(span, free_substs, &method.fty); - let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.sig); - - debug!("check_method_receiver({:?},cat={:?},self_ty={:?},sig={:?})", - method.name, method.explicit_self, self_ty, sig); + debug!("check_method_receiver({:?},cat={:?},self_ty={:?})", + method.name, method.explicit_self, self_ty); let rcvr_ty = match method.explicit_self { ty::ExplicitSelfCategory::Static => return, @@ -431,13 +431,23 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } ty::ExplicitSelfCategory::ByBox => fcx.tcx.mk_box(self_ty) }; + + let span = method_sig.decl.inputs[0].pat.span; + + let free_substs = &fcx.parameter_environment.free_substs; + let fty = fcx.instantiate_type_scheme(span, free_substs, &method.fty); + let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.sig); + + debug!("check_method_receiver: sig={:?}", sig); + let rcvr_ty = fcx.instantiate_type_scheme(span, free_substs, &rcvr_ty); let rcvr_ty = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &ty::Binder(rcvr_ty)); debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty); - fcx.demand_eqtype(span, rcvr_ty, sig.inputs[0]); + let origin = TypeOrigin::MethodReceiver(span); + fcx.demand_eqtype_with_origin(origin, rcvr_ty, sig.inputs[0]); } fn check_variances_for_type_defn(&self, @@ -552,13 +562,21 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> { fn visit_trait_item(&mut self, trait_item: &'v hir::TraitItem) { debug!("visit_trait_item: {:?}", trait_item); - self.check_trait_or_impl_item(trait_item.id, trait_item.span); + let method_sig = match trait_item.node { + hir::TraitItem_::MethodTraitItem(ref sig, _) => Some(sig), + _ => None + }; + self.check_trait_or_impl_item(trait_item.id, trait_item.span, method_sig); intravisit::walk_trait_item(self, trait_item) } fn visit_impl_item(&mut self, impl_item: &'v hir::ImplItem) { debug!("visit_impl_item: {:?}", impl_item); - self.check_trait_or_impl_item(impl_item.id, impl_item.span); + let method_sig = match impl_item.node { + hir::ImplItemKind::Method(ref sig, _) => Some(sig), + _ => None + }; + self.check_trait_or_impl_item(impl_item.id, impl_item.span, method_sig); intravisit::walk_impl_item(self, impl_item) } } diff --git a/src/test/compile-fail/const-eval-overflow-4b.rs b/src/test/compile-fail/const-eval-overflow-4b.rs index e7639a4ff70..9e7a5ecae10 100644 --- a/src/test/compile-fail/const-eval-overflow-4b.rs +++ b/src/test/compile-fail/const-eval-overflow-4b.rs @@ -21,9 +21,7 @@ use std::{u8, u16, u32, u64, usize}; const A_I8_T : [u32; (i8::MAX as i8 + 1u8) as usize] //~^ ERROR constant evaluation error [E0080] - //~| mismatched types - //~| expected `i8` - //~| found `u8` + //~| expected i8, found u8 = [0; (i8::MAX as usize) + 1]; diff --git a/src/test/compile-fail/discrim-ill-typed.rs b/src/test/compile-fail/discrim-ill-typed.rs index 5af889cb239..c73b7e831b3 100644 --- a/src/test/compile-fail/discrim-ill-typed.rs +++ b/src/test/compile-fail/discrim-ill-typed.rs @@ -26,7 +26,7 @@ fn f_i8() { Ok2, OhNo = 0_u8, //~^ ERROR E0080 - //~| mismatched types + //~| expected i8, found u8 } let x = A::Ok; @@ -39,7 +39,7 @@ fn f_u8() { Ok2, OhNo = 0_i8, //~^ ERROR E0080 - //~| mismatched types + //~| expected u8, found i8 } let x = A::Ok; @@ -52,7 +52,7 @@ fn f_i16() { Ok2, OhNo = 0_u16, //~^ ERROR E0080 - //~| mismatched types + //~| expected i16, found u16 } let x = A::Ok; @@ -65,7 +65,7 @@ fn f_u16() { Ok2, OhNo = 0_i16, //~^ ERROR E0080 - //~| mismatched types + //~| expected u16, found i16 } let x = A::Ok; @@ -78,7 +78,7 @@ fn f_i32() { Ok2, OhNo = 0_u32, //~^ ERROR E0080 - //~| mismatched types + //~| expected i32, found u32 } let x = A::Ok; @@ -91,7 +91,7 @@ fn f_u32() { Ok2, OhNo = 0_i32, //~^ ERROR E0080 - //~| mismatched types + //~| expected u32, found i32 } let x = A::Ok; @@ -104,7 +104,7 @@ fn f_i64() { Ok2, OhNo = 0_u64, //~^ ERROR E0080 - //~| mismatched types + //~| expected i64, found u64 } let x = A::Ok; @@ -117,7 +117,7 @@ fn f_u64() { Ok2, OhNo = 0_i64, //~^ ERROR E0080 - //~| mismatched types + //~| expected u64, found i64 } let x = A::Ok; diff --git a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs index b5432fafb1b..f8aa1ea95f0 100644 --- a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs +++ b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs @@ -14,15 +14,17 @@ struct Foo<'a,'b> { } impl<'a,'b> Foo<'a,'b> { - fn bar(self: Foo<'b,'a>) {} - //~^ ERROR mismatched types + fn bar( + self + //~^ ERROR mismatched method receiver //~| expected type `Foo<'a, 'b>` //~| found type `Foo<'b, 'a>` //~| lifetime mismatch - //~| ERROR mismatched types + //~| ERROR mismatched method receiver //~| expected type `Foo<'a, 'b>` //~| found type `Foo<'b, 'a>` //~| lifetime mismatch + : Foo<'b,'a>) {} } fn main() {} diff --git a/src/test/compile-fail/issue-17740.rs b/src/test/compile-fail/issue-17740.rs index 6b9294b2038..664d62e87ae 100644 --- a/src/test/compile-fail/issue-17740.rs +++ b/src/test/compile-fail/issue-17740.rs @@ -14,11 +14,11 @@ struct Foo<'a> { impl <'a> Foo<'a>{ fn bar(self: &mut Foo) { - //~^ mismatched types + //~^ mismatched method receiver //~| expected type `&mut Foo<'a>` //~| found type `&mut Foo<'_>` //~| lifetime mismatch - //~| mismatched types + //~| mismatched method receiver //~| expected type `&mut Foo<'a>` //~| found type `&mut Foo<'_>` //~| lifetime mismatch diff --git a/src/test/compile-fail/issue-26194.rs b/src/test/compile-fail/issue-26194.rs index 1bc0a4f9652..ef91188c5d1 100644 --- a/src/test/compile-fail/issue-26194.rs +++ b/src/test/compile-fail/issue-26194.rs @@ -12,7 +12,7 @@ struct S(String); impl S { fn f(self: *mut S) -> String { self.0 } - //~^ ERROR mismatched types + //~^ ERROR mismatched method receiver } fn main() { S("".to_owned()).f(); } diff --git a/src/test/compile-fail/issue-8761.rs b/src/test/compile-fail/issue-8761.rs index 6352f4f6a04..91a07dd9ba6 100644 --- a/src/test/compile-fail/issue-8761.rs +++ b/src/test/compile-fail/issue-8761.rs @@ -11,12 +11,10 @@ enum Foo { A = 1i64, //~^ ERROR constant evaluation error - //~| expected `isize` - //~| found `i64` + //~| expected isize, found i64 B = 2u8 //~^ ERROR constant evaluation error - //~| expected `isize` - //~| found `u8` + //~| expected isize, found u8 } fn main() {} diff --git a/src/test/compile-fail/repeat_count.rs b/src/test/compile-fail/repeat_count.rs index d68df973641..3a7e9cc4191 100644 --- a/src/test/compile-fail/repeat_count.rs +++ b/src/test/compile-fail/repeat_count.rs @@ -39,14 +39,12 @@ fn main() { //~| ERROR expected usize for repeat count, found string literal [E0306] let f = [0; -4_isize]; //~^ ERROR constant evaluation error - //~| expected `usize` - //~| found `isize` + //~| expected usize, found isize //~| ERROR mismatched types //~| expected usize, found isize let f = [0_usize; -1_isize]; //~^ ERROR constant evaluation error - //~| expected `usize` - //~| found `isize` + //~| expected usize, found isize //~| ERROR mismatched types //~| expected usize, found isize struct G { diff --git a/src/test/compile-fail/ufcs-explicit-self-bad.rs b/src/test/compile-fail/ufcs-explicit-self-bad.rs index e997cf47c73..a98b7cd4309 100644 --- a/src/test/compile-fail/ufcs-explicit-self-bad.rs +++ b/src/test/compile-fail/ufcs-explicit-self-bad.rs @@ -15,7 +15,7 @@ struct Foo { } impl Foo { - fn foo(self: isize, x: isize) -> isize { //~ ERROR mismatched types + fn foo(self: isize, x: isize) -> isize { //~ ERROR mismatched method receiver self.f + x } } @@ -25,10 +25,10 @@ struct Bar<T> { } impl<T> Bar<T> { - fn foo(self: Bar<isize>, x: isize) -> isize { //~ ERROR mismatched types + fn foo(self: Bar<isize>, x: isize) -> isize { //~ ERROR mismatched method receiver x } - fn bar(self: &Bar<usize>, x: isize) -> isize { //~ ERROR mismatched types + fn bar(self: &Bar<usize>, x: isize) -> isize { //~ ERROR mismatched method receiver x } } @@ -41,14 +41,14 @@ trait SomeTrait { impl<'a, T> SomeTrait for &'a Bar<T> { fn dummy1(self: &&'a Bar<T>) { } - fn dummy2(self: &Bar<T>) {} //~ ERROR mismatched types - //~^ ERROR mismatched types + fn dummy2(self: &Bar<T>) {} //~ ERROR mismatched method receiver + //~^ ERROR mismatched method receiver fn dummy3(self: &&Bar<T>) {} - //~^ ERROR mismatched types + //~^ ERROR mismatched method receiver //~| expected type `&&'a Bar<T>` //~| found type `&&Bar<T>` //~| lifetime mismatch - //~| ERROR mismatched types + //~| ERROR mismatched method receiver //~| expected type `&&'a Bar<T>` //~| found type `&&Bar<T>` //~| lifetime mismatch