Auto merge of #34907 - arielb1:found-parse-error, r=nikomatsakis
Centralize and clean type error reporting Refactors the code that handles type errors to be cleaner and fixes various edge cases. This made the already-bad "type mismatch resolving" error message somewhat uglier. I want to fix that in another commit before this PR is merged. Fixes #31173 r? @jonathandturner, cc @nikomatsakis
This commit is contained in:
commit
f2e59cc6aa
@ -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,42 +504,102 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
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 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 => {
|
||||
// Derived error. Cancel the emitter.
|
||||
self.tcx.sess.diagnostic().cancel(diag);
|
||||
return
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let span = origin.span();
|
||||
|
||||
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() {
|
||||
diag.note_expected_found(&"type", &expected, &found);
|
||||
}
|
||||
}
|
||||
|
||||
if !is_simple_error && check_old_school() {
|
||||
diag.span_note(span, &format!("{}", terr));
|
||||
} else {
|
||||
diag.span_label(span, &terr);
|
||||
}
|
||||
|
||||
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,
|
||||
trace: TypeTrace<'tcx>,
|
||||
terr: &TypeError<'tcx>)
|
||||
-> DiagnosticBuilder<'tcx> {
|
||||
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);
|
||||
err
|
||||
-> DiagnosticBuilder<'tcx>
|
||||
{
|
||||
// FIXME: do we want to use a different error code for each origin?
|
||||
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 `{}`", or None if this is a derived
|
||||
/// error.
|
||||
/// 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,
|
||||
@ -1608,59 +1622,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"
|
||||
}
|
||||
};
|
||||
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) => {
|
||||
@ -1803,32 +1779,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> {
|
||||
|
@ -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};
|
||||
@ -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),
|
||||
|
||||
@ -219,16 +213,26 @@ 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),
|
||||
|
||||
// method receiver
|
||||
MethodReceiver(Span),
|
||||
}
|
||||
|
||||
impl TypeOrigin {
|
||||
fn as_str(&self) -> &'static str {
|
||||
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",
|
||||
@ -238,13 +242,31 @@ 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",
|
||||
&TypeOrigin::MethodReceiver(_) => "mismatched method receiver",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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::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",
|
||||
&TypeOrigin::MethodReceiver(_) => "method receiver has the correct type",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1468,104 +1490,50 @@ 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,
|
||||
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();
|
||||
}
|
||||
|
||||
// FIXME: this results in errors without an error code. Deprecate?
|
||||
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,
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
self.type_error_struct_str(sp,
|
||||
move |_e, a| { mk_msg(a) },
|
||||
self.ty_to_string(actual_ty), err)
|
||||
mk_diag(self.ty_to_string(actual_ty))
|
||||
}
|
||||
|
||||
pub fn report_mismatched_types(&self,
|
||||
@ -1833,14 +1801,16 @@ 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,
|
||||
TypeOrigin::IfExpressionWithNoElse(span) => span,
|
||||
TypeOrigin::RangeExpression(span) => span,
|
||||
TypeOrigin::EquatePredicate(span) => span,
|
||||
TypeOrigin::MainFunctionType(span) => span,
|
||||
TypeOrigin::StartFunctionType(span) => span,
|
||||
TypeOrigin::IntrinsicType(span) => span,
|
||||
TypeOrigin::MethodReceiver(span) => span,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1891,3 +1861,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)
|
||||
}
|
||||
}
|
||||
|
@ -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>,
|
||||
|
@ -26,8 +26,9 @@ use super::{
|
||||
|
||||
use fmt_macros::{Parser, Piece, Position};
|
||||
use hir::def_id::DefId;
|
||||
use infer::{InferCtxt};
|
||||
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,24 +108,63 @@ 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 = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271,
|
||||
"type mismatch resolving `{}`: {}",
|
||||
predicate,
|
||||
error.err);
|
||||
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 = 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();
|
||||
});
|
||||
}
|
||||
|
||||
fn impl_substs(&self,
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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" }
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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,71 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 +453,7 @@ pub enum ErrKind {
|
||||
IntermediateUnsignedNegative,
|
||||
/// Expected, Got
|
||||
TypeMismatch(String, ConstInt),
|
||||
|
||||
BadType(ConstVal),
|
||||
ErroneousReferencedConstant(Box<ConstEvalErr>),
|
||||
CharCast(ConstInt),
|
||||
@ -411,57 +465,79 @@ impl From<ConstMathErr> for ErrKind {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ConstEvalErrDescription<'a> {
|
||||
Simple(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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
simple!("expected {}, found {}", expected, got.description())
|
||||
},
|
||||
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())
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1199,8 +1275,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)),
|
||||
@ -1208,62 +1286,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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
@ -1414,7 +1415,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]
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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) => {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,10 +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);
|
||||
span_err!(tcx.sess, impl_m_span, E0053,
|
||||
"method `{}` has an incompatible type for trait: {}",
|
||||
trait_m.name,
|
||||
terr);
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@ -437,10 +447,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 +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);
|
||||
span_err!(tcx.sess, impl_c_span, E0326,
|
||||
"implemented const `{}` has an incompatible type for \
|
||||
trait: {}",
|
||||
trait_c.name,
|
||||
terr);
|
||||
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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -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
|
||||
@ -54,16 +61,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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
@ -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);
|
||||
}
|
||||
@ -3029,17 +3028,18 @@ 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,
|
||||
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 +3272,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;
|
||||
}
|
||||
}
|
||||
@ -3541,7 +3541,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) => {
|
||||
@ -3647,8 +3648,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 +4523,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;
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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,14 +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.require_same_types(span, sig.inputs[0], rcvr_ty,
|
||||
"mismatched method receiver");
|
||||
let origin = TypeOrigin::MethodReceiver(span);
|
||||
fcx.demand_eqtype_with_origin(origin, rcvr_ty, sig.inputs[0]);
|
||||
}
|
||||
|
||||
fn check_variances_for_type_defn(&self,
|
||||
@ -553,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)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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,
|
||||
@ -2660,6 +2641,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 +2721,7 @@ impl Foo {
|
||||
}
|
||||
```
|
||||
"##,
|
||||
*/
|
||||
|
||||
E0214: r##"
|
||||
A generic type was described using parentheses rather than angle brackets. For
|
||||
@ -2968,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
|
||||
@ -4029,6 +3980,57 @@ 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.
|
||||
|
||||
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! {
|
||||
@ -4086,6 +4088,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
|
||||
|
@ -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,
|
||||
|
1
src/rustc/Cargo.lock
generated
1
src/rustc/Cargo.lock
generated
@ -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",
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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() {}
|
||||
|
@ -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() {
|
||||
|
@ -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`
|
||||
}
|
||||
|
@ -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
|
||||
}
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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"),
|
||||
}
|
||||
}
|
||||
|
@ -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)]
|
||||
|
||||
|
@ -20,9 +20,8 @@ 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]
|
||||
//~| expected i8, found u8
|
||||
= [0; (i8::MAX as usize) + 1];
|
||||
|
||||
|
||||
@ -33,7 +32,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() {}
|
||||
|
@ -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() {
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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() {
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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!();
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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"),
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
@ -25,7 +25,8 @@ fn f_i8() {
|
||||
Ok = i8::MAX - 1,
|
||||
Ok2,
|
||||
OhNo = 0_u8,
|
||||
//~^ ERROR mismatched types
|
||||
//~^ ERROR E0080
|
||||
//~| expected i8, found u8
|
||||
}
|
||||
|
||||
let x = A::Ok;
|
||||
@ -37,7 +38,8 @@ fn f_u8() {
|
||||
Ok = u8::MAX - 1,
|
||||
Ok2,
|
||||
OhNo = 0_i8,
|
||||
//~^ ERROR mismatched types
|
||||
//~^ ERROR E0080
|
||||
//~| expected u8, found i8
|
||||
}
|
||||
|
||||
let x = A::Ok;
|
||||
@ -49,7 +51,8 @@ fn f_i16() {
|
||||
Ok = i16::MAX - 1,
|
||||
Ok2,
|
||||
OhNo = 0_u16,
|
||||
//~^ ERROR mismatched types
|
||||
//~^ ERROR E0080
|
||||
//~| expected i16, found u16
|
||||
}
|
||||
|
||||
let x = A::Ok;
|
||||
@ -61,7 +64,8 @@ fn f_u16() {
|
||||
Ok = u16::MAX - 1,
|
||||
Ok2,
|
||||
OhNo = 0_i16,
|
||||
//~^ ERROR mismatched types
|
||||
//~^ ERROR E0080
|
||||
//~| expected u16, found i16
|
||||
}
|
||||
|
||||
let x = A::Ok;
|
||||
@ -73,7 +77,8 @@ fn f_i32() {
|
||||
Ok = i32::MAX - 1,
|
||||
Ok2,
|
||||
OhNo = 0_u32,
|
||||
//~^ ERROR mismatched types
|
||||
//~^ ERROR E0080
|
||||
//~| expected i32, found u32
|
||||
}
|
||||
|
||||
let x = A::Ok;
|
||||
@ -85,7 +90,8 @@ fn f_u32() {
|
||||
Ok = u32::MAX - 1,
|
||||
Ok2,
|
||||
OhNo = 0_i32,
|
||||
//~^ ERROR mismatched types
|
||||
//~^ ERROR E0080
|
||||
//~| expected u32, found i32
|
||||
}
|
||||
|
||||
let x = A::Ok;
|
||||
@ -97,7 +103,8 @@ fn f_i64() {
|
||||
Ok = i64::MAX - 1,
|
||||
Ok2,
|
||||
OhNo = 0_u64,
|
||||
//~^ ERROR mismatched types
|
||||
//~^ ERROR E0080
|
||||
//~| expected i64, found u64
|
||||
}
|
||||
|
||||
let x = A::Ok;
|
||||
@ -109,7 +116,8 @@ fn f_u64() {
|
||||
Ok = u64::MAX - 1,
|
||||
Ok2,
|
||||
OhNo = 0_i64,
|
||||
//~^ ERROR mismatched types
|
||||
//~^ ERROR E0080
|
||||
//~| expected u64, found i64
|
||||
}
|
||||
|
||||
let x = A::Ok;
|
||||
|
@ -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
|
||||
|
@ -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() {}
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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() {}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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() {}
|
||||
|
@ -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() {}
|
||||
|
@ -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() {}
|
||||
|
@ -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);
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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"),
|
||||
}
|
||||
}
|
||||
|
@ -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() { }
|
||||
|
27
src/test/compile-fail/issue-31173.rs
Normal file
27
src/test/compile-fail/issue-31173.rs
Normal file
@ -0,0 +1,27 @@
|
||||
// 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 type `u8`
|
||||
//~| found type `&_`
|
||||
.collect(); //~ ERROR no method named `collect`
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -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);
|
||||
|
@ -10,13 +10,11 @@
|
||||
|
||||
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() {}
|
||||
|
@ -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`
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
};
|
||||
}
|
||||
|
@ -13,39 +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
|
||||
//~| expected `usize`
|
||||
//~| found `isize`
|
||||
//~| ERROR mismatched types:
|
||||
//~^ ERROR constant evaluation error
|
||||
//~| expected usize, found isize
|
||||
//~| ERROR mismatched types
|
||||
//~| expected usize, found isize
|
||||
let f = [0_usize; -1_isize];
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected `usize`
|
||||
//~| found `isize`
|
||||
//~^ ERROR constant evaluation error
|
||||
//~| expected usize, found isize
|
||||
//~| ERROR mismatched types
|
||||
//~| expected usize, found isize
|
||||
struct G {
|
||||
@ -56,5 +55,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]
|
||||
}
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
||||
|
@ -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() { }
|
||||
|
Loading…
x
Reference in New Issue
Block a user