Skip to content
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