Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve errors on const mismatches #90987

Closed
27 changes: 23 additions & 4 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1449,7 +1449,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
swap_secondary_and_primary: bool,
) {
let span = cause.span(self.tcx);
debug!("note_type_err cause={:?} values={:?}, terr={:?}", cause, values, terr);

// For some types of errors, expected-found does not make
// sense, so just ignore the values we were given.
Expand Down Expand Up @@ -1581,11 +1580,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}

debug!("note_type_err(diag={:?})", diag);
enum Mismatch<'a> {
Variable(ty::error::ExpectedFound<Ty<'a>>),
Fixed(&'static str),
}

let (expected_found, exp_found, is_simple_error) = match values {
None => (None, Mismatch::Fixed("type"), false),
Some(values) => {
Expand Down Expand Up @@ -1652,6 +1651,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
};

if let Some((expected, found)) = expected_found {
let (expected_label, found_label, exp_found) = match exp_found {
Mismatch::Variable(ef) => (
Expand Down Expand Up @@ -1705,6 +1705,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
(TypeError::ObjectUnsafeCoercion(_), _) => {
diag.note_unsuccessful_coercion(found, expected);
}
(TypeError::ConstMismatchTooGeneric(_, Some(sugg)), _) => {
if !is_simple_error {
let found =
DiagnosticStyledString::highlighted(format!("{}", sugg.clone()));

diag.note_expected_found(
&expected_label,
expected,
&"type".to_string(),
found,
);
}
}
(_, _) => {
debug!(
"note_type_err: exp_found={:?}, expected={:?} found={:?}",
Expand All @@ -1716,10 +1729,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
}

let exp_found = match exp_found {
Mismatch::Variable(exp_found) => Some(exp_found),
Mismatch::Fixed(_) => None,
};

let exp_found = match terr {
// `terr` has more accurate type information than `exp_found` in match expressions.
ty::error::TypeError::Sorts(terr)
Expand All @@ -1730,6 +1745,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
_ => exp_found,
};
debug!("exp_found {:?} terr {:?} cause.code {:?}", exp_found, terr, cause.code());

if let Some(exp_found) = exp_found {
let should_suggest_fixes = if let ObligationCauseCode::Pattern { root_ty, .. } =
cause.code()
Expand All @@ -1756,6 +1772,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
self.tcx.hir().opt_local_def_id(cause.body_id).unwrap_or_else(|| {
self.tcx.hir().body_owner_def_id(hir::BodyId { hir_id: cause.body_id })
});

self.check_and_note_conflicting_crates(diag, terr);
self.tcx.note_and_explain_type_err(diag, terr, cause, span, body_owner_def_id.to_def_id());

Expand Down Expand Up @@ -2021,10 +2038,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
) -> DiagnosticBuilder<'tcx> {
use crate::traits::ObligationCauseCode::MatchExpressionArm;

debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr);

let span = trace.cause.span(self.tcx);
let failure_code = trace.cause.as_failure_code(terr);

let mut diag = match failure_code {
FailureCode::Error0038(did) => {
let violations = self.tcx.object_safety_violations(did);
Expand All @@ -2038,9 +2054,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
FailureCode::Error0308(failure_str) => {
let mut err = struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str);

if let ValuePairs::Types(ty::error::ExpectedFound { expected, found }) =
trace.values
{
debug!(?expected, ?found);

// If a tuple of length one was expected and the found expression has
// parentheses around it, perhaps the user meant to write `(expr,)` to
// build a tuple (issue #86100)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1484,6 +1484,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
self.report_and_explain_type_error(trace, &err)
}

#[instrument(skip(self), level = "debug")]
pub fn report_mismatched_consts(
&self,
cause: &ObligationCause<'tcx>,
Expand Down
74 changes: 73 additions & 1 deletion compiler/rustc_middle/src/mir/interpret/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rustc_apfloat::{
use rustc_macros::HashStable;
use rustc_target::abi::{HasDataLayout, Size};

use crate::ty::{Lift, ParamEnv, ScalarInt, Ty, TyCtxt};
use crate::ty::{self, Lift, ParamEnv, ScalarInt, Ty, TyCtxt};

use super::{
AllocId, AllocRange, Allocation, InterpResult, Pointer, PointerArithmetic, Provenance,
Expand Down Expand Up @@ -456,6 +456,78 @@ impl<'tcx, Tag: Provenance> Scalar<Tag> {
// Going through `u64` to check size and truncation.
Ok(Double::from_bits(self.to_u64()?.into()))
}

#[inline]
pub fn try_to_string(self, t: Ty<'tcx>) -> Option<String> {
#[cfg(target_pointer_width = "32")]
fn usize_to_string<Tag: Provenance>(scalar: Scalar<Tag>) -> Option<String> {
scalar.to_u32().map_or_else(|_| None, |v| Some(format!("{}", v)))
}

#[cfg(target_pointer_width = "64")]
fn usize_to_string<Tag: Provenance>(scalar: Scalar<Tag>) -> Option<String> {
scalar.to_u64().map_or_else(|_| None, |v| Some(format!("{}", v)))
}

#[cfg(target_pointer_width = "32")]
fn isize_to_string<Tag: Provenance>(scalar: Scalar<Tag>) -> Option<String> {
scalar.to_i32().map_or_else(|_| None, |v| Some(format!("{}", v)))
}

#[cfg(target_pointer_width = "64")]
fn isize_to_string<Tag: Provenance>(scalar: Scalar<Tag>) -> Option<String> {
scalar.to_i64().map_or_else(|_| None, |v| Some(format!("{}", v)))
}

#[cfg(target_pointer_width = "128")]
fn isize_to_string<Tag: Provenance>(scalar: Scalar<Tag>) -> Option<String> {
scalar.to_i128().map_or_else(|_| None, |v| Some(format!("{}", v)))
}

#[cfg(target_pointer_width = "128")]
fn usize_to_string<Tag: Provenance>(scalar: Scalar<Tag>) -> Option<String> {
scalar.to_u128().map_or_else(|_| None, |v| Some(format!("{}", v)))
}

match self {
Scalar::Int(_) => match t.kind() {
ty::Int(ty::IntTy::Isize) => isize_to_string(self),
ty::Int(ty::IntTy::I8) => {
self.to_i8().map_or_else(|_| None, |v| Some(format!("{}", v)))
}
ty::Int(ty::IntTy::I16) => {
self.to_i16().map_or_else(|_| None, |v| Some(format!("{}", v)))
}
ty::Int(ty::IntTy::I32) => {
self.to_i32().map_or_else(|_| None, |v| Some(format!("{}", v)))
}
ty::Int(ty::IntTy::I64) => {
self.to_i64().map_or_else(|_| None, |v| Some(format!("{}", v)))
}
ty::Int(ty::IntTy::I128) => {
self.to_i128().map_or_else(|_| None, |v| Some(format!("{}", v)))
}
ty::Uint(ty::UintTy::Usize) => usize_to_string(self),
ty::Uint(ty::UintTy::U8) => {
self.to_u8().map_or_else(|_| None, |v| Some(format!("{}", v)))
}
ty::Uint(ty::UintTy::U16) => {
self.to_u16().map_or_else(|_| None, |v| Some(format!("{}", v)))
}
ty::Uint(ty::UintTy::U32) => {
self.to_u32().map_or_else(|_| None, |v| Some(format!("{}", v)))
}
ty::Uint(ty::UintTy::U64) => {
self.to_u64().map_or_else(|_| None, |v| Some(format!("{}", v)))
}
ty::Uint(ty::UintTy::U128) => {
self.to_u128().map_or_else(|_| None, |v| Some(format!("{}", v)))
}
_ => None,
},
Scalar::Ptr(_, _) => Some(format!("{}", self)),
}
}
}

#[derive(Clone, Copy, Eq, PartialEq, TyEncodable, TyDecodable, HashStable, Hash)]
Expand Down
57 changes: 57 additions & 0 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2328,6 +2328,54 @@ impl BinOp {
use self::BinOp::*;
matches!(self, Add | Sub | Mul | Shl | Shr)
}

pub fn try_as_string(self) -> Option<String> {
use self::BinOp::*;

match self {
Add => Some("+".to_string()),
Sub => Some("-".to_string()),
Mul => Some("*".to_string()),
Div => Some("/".to_string()),
Rem => Some("%".to_string()),
BitXor => Some("^".to_string()),
BitAnd => Some("&".to_string()),
BitOr => Some("|".to_string()),
Shl => Some("<<".to_string()),
Shr => Some(">>".to_string()),
Eq => Some("=".to_string()),
Lt => Some("<".to_string()),
Le => Some("<=".to_string()),
Ne => Some("!=".to_string()),
Ge => Some(">=".to_string()),
Gt => Some(">".to_string()),
Offset => None,
}
}

pub fn get_precedence(self) -> usize {
use self::BinOp::*;

match self {
Add => 7,
Sub => 7,
Mul => 8,
Div => 8,
Rem => 8,
BitXor => 2,
BitAnd => 3,
BitOr => 1,
Shl => 6,
Shr => 6,
Eq => 4,
Lt => 5,
Le => 5,
Ne => 4,
Ge => 5,
Gt => 5,
Offset => 0,
}
}
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
Expand All @@ -2348,6 +2396,15 @@ pub enum UnOp {
Neg,
}

impl fmt::Display for UnOp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
UnOp::Not => write!(f, "!"),
UnOp::Neg => write!(f, "-"),
}
}
}

impl<'tcx> Debug for Rvalue<'tcx> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
use self::Rvalue::*;
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_middle/src/ty/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ pub enum TypeError<'tcx> {
),
ObjectUnsafeCoercion(DefId),
ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>),
ConstMismatchTooGeneric(ExpectedFound<&'tcx ty::Const<'tcx>>, Option<String>),

IntrinsicCast,
/// Safe `#[target_feature]` functions are not assignable to safe function pointers.
Expand Down Expand Up @@ -201,6 +202,12 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
ConstMismatch(ref values) => {
write!(f, "expected `{}`, found `{}`", values.expected, values.found)
}
ConstMismatchTooGeneric(ref values, ref suggestion) => match suggestion {
Some(sugg) => {
write!(f, "expected `{}`, found `{}`", values.expected, sugg)
}
None => write!(f, "expected `{}`, found `{}`", values.expected, values.found),
},
IntrinsicCast => write!(f, "cannot coerce intrinsics to function pointers"),
TargetFeatureCast(_) => write!(
f,
Expand Down Expand Up @@ -233,6 +240,7 @@ impl<'tcx> TypeError<'tcx> {
| ProjectionMismatched(_)
| ExistentialMismatch(_)
| ConstMismatch(_)
| ConstMismatchTooGeneric(_, _)
| IntrinsicCast
| ObjectUnsafeCoercion(_) => true,
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_middle/src/ty/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
Sorts(x) => return tcx.lift(x).map(Sorts),
ExistentialMismatch(x) => return tcx.lift(x).map(ExistentialMismatch),
ConstMismatch(x) => return tcx.lift(x).map(ConstMismatch),
ConstMismatchTooGeneric(x, s) => {
return tcx.lift(x).map(|x| ConstMismatchTooGeneric(x, s));
}
IntrinsicCast => IntrinsicCast,
TargetFeatureCast(x) => TargetFeatureCast(x),
ObjectUnsafeCoercion(x) => return tcx.lift(x).map(ObjectUnsafeCoercion),
Expand Down
Loading