Skip to content

Commit 53712f8

Browse files
committed
Auto merge of #66389 - estebank:type-err-labels, r=petrochenkov
Specific labels when referring to "expected" and "found" types
2 parents 35ef33a + 468722b commit 53712f8

File tree

581 files changed

+2544
-3540
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

581 files changed

+2544
-3540
lines changed

src/librustc/infer/error_reporting/mod.rs

+46-25
Original file line numberDiff line numberDiff line change
@@ -1163,8 +1163,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
11631163
Some(values) => {
11641164
let (is_simple_error, exp_found) = match values {
11651165
ValuePairs::Types(exp_found) => {
1166-
let is_simple_err =
1167-
exp_found.expected.is_primitive() && exp_found.found.is_primitive();
1166+
let is_simple_err = exp_found.expected.is_simple_text()
1167+
&& exp_found.found.is_simple_text();
11681168

11691169
(is_simple_err, Some(exp_found))
11701170
}
@@ -1197,40 +1197,61 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
11971197
};
11981198

11991199
if let Some((expected, found)) = expected_found {
1200-
match (terr, is_simple_error, expected == found) {
1201-
(&TypeError::Sorts(ref values), false, true) => {
1202-
let sort_string = | a_type: Ty<'tcx> |
1203-
if let ty::Opaque(def_id, _) = a_type.kind {
1204-
format!(" (opaque type at {})", self.tcx.sess.source_map()
1205-
.mk_substr_filename(self.tcx.def_span(def_id)))
1206-
} else {
1207-
format!(" ({})", a_type.sort_string(self.tcx))
1208-
};
1209-
diag.note_expected_found_extra(
1210-
&"type",
1211-
expected,
1212-
found,
1213-
&sort_string(values.expected),
1214-
&sort_string(values.found),
1215-
);
1200+
let expected_label = exp_found.map_or("type".into(), |ef| ef.expected.prefix_string());
1201+
let found_label = exp_found.map_or("type".into(), |ef| ef.found.prefix_string());
1202+
match (&terr, expected == found) {
1203+
(TypeError::Sorts(values), extra) => {
1204+
let sort_string = |ty: Ty<'tcx>| match (extra, &ty.kind) {
1205+
(true, ty::Opaque(def_id, _)) => format!(
1206+
" (opaque type at {})",
1207+
self.tcx.sess.source_map()
1208+
.mk_substr_filename(self.tcx.def_span(*def_id)),
1209+
),
1210+
(true, _) => format!(" ({})", ty.sort_string(self.tcx)),
1211+
(false, _) => "".to_string(),
1212+
};
1213+
if !(values.expected.is_simple_text() && values.found.is_simple_text()) || (
1214+
exp_found.map_or(false, |ef| {
1215+
// This happens when the type error is a subset of the expectation,
1216+
// like when you have two references but one is `usize` and the other
1217+
// is `f32`. In those cases we still want to show the `note`. If the
1218+
// value from `ef` is `Infer(_)`, then we ignore it.
1219+
if !ef.expected.is_ty_infer() {
1220+
ef.expected != values.expected
1221+
} else if !ef.found.is_ty_infer() {
1222+
ef.found != values.found
1223+
} else {
1224+
false
1225+
}
1226+
})
1227+
) {
1228+
diag.note_expected_found_extra(
1229+
&expected_label,
1230+
expected,
1231+
&found_label,
1232+
found,
1233+
&sort_string(values.expected),
1234+
&sort_string(values.found),
1235+
);
1236+
}
12161237
}
1217-
(TypeError::ObjectUnsafeCoercion(_), ..) => {
1238+
(TypeError::ObjectUnsafeCoercion(_), _) => {
12181239
diag.note_unsuccessfull_coercion(found, expected);
12191240
}
1220-
(_, false, _) => {
1241+
(_, _) => {
12211242
debug!(
12221243
"note_type_err: exp_found={:?}, expected={:?} found={:?}",
12231244
exp_found, expected, found
12241245
);
1225-
if let Some(exp_found) = exp_found {
1226-
self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
1246+
if !is_simple_error || terr.must_include_note() {
1247+
diag.note_expected_found(&expected_label, expected, &found_label, found);
12271248
}
1228-
1229-
diag.note_expected_found(&"type", expected, found);
12301249
}
1231-
_ => (),
12321250
}
12331251
}
1252+
if let Some(exp_found) = exp_found {
1253+
self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
1254+
}
12341255

12351256
// In some (most?) cases cause.body_id points to actual body, but in some cases
12361257
// it's a actual definition. According to the comments (e.g. in

src/librustc/ty/diagnostics.rs

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//! Diagnostics related methods for `TyS`.
2+
3+
use crate::ty::TyS;
4+
use crate::ty::TyKind::*;
5+
use crate::ty::sty::InferTy;
6+
7+
impl<'tcx> TyS<'tcx> {
8+
/// Similar to `TyS::is_primitive`, but also considers inferred numeric values to be primitive.
9+
pub fn is_primitive_ty(&self) -> bool {
10+
match self.kind {
11+
Bool | Char | Str | Int(_) | Uint(_) | Float(_) |
12+
Infer(InferTy::IntVar(_)) | Infer(InferTy::FloatVar(_)) |
13+
Infer(InferTy::FreshIntTy(_)) | Infer(InferTy::FreshFloatTy(_)) => true,
14+
_ => false,
15+
}
16+
}
17+
18+
/// Whether the type is succinctly representable as a type instead of just refered to with a
19+
/// description in error messages. This is used in the main error message.
20+
pub fn is_simple_ty(&self) -> bool {
21+
match self.kind {
22+
Bool | Char | Str | Int(_) | Uint(_) | Float(_) |
23+
Infer(InferTy::IntVar(_)) | Infer(InferTy::FloatVar(_)) |
24+
Infer(InferTy::FreshIntTy(_)) | Infer(InferTy::FreshFloatTy(_)) => true,
25+
Ref(_, x, _) | Array(x, _) | Slice(x) => x.peel_refs().is_simple_ty(),
26+
Tuple(tys) if tys.is_empty() => true,
27+
_ => false,
28+
}
29+
}
30+
31+
/// Whether the type is succinctly representable as a type instead of just refered to with a
32+
/// description in error messages. This is used in the primary span label. Beyond what
33+
/// `is_simple_ty` includes, it also accepts ADTs with no type arguments and references to
34+
/// ADTs with no type arguments.
35+
pub fn is_simple_text(&self) -> bool {
36+
match self.kind {
37+
Adt(_, substs) => substs.types().next().is_none(),
38+
Ref(_, ty, _) => ty.is_simple_text(),
39+
_ => self.is_simple_ty(),
40+
}
41+
}
42+
43+
/// Whether the type can be safely suggested during error recovery.
44+
pub fn is_suggestable(&self) -> bool {
45+
match self.kind {
46+
Opaque(..) |
47+
FnDef(..) |
48+
FnPtr(..) |
49+
Dynamic(..) |
50+
Closure(..) |
51+
Infer(..) |
52+
Projection(..) => false,
53+
_ => true,
54+
}
55+
}
56+
}

src/librustc/ty/error.rs

+84-20
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,11 @@ pub enum UnconstrainedNumeric {
6464
impl<'tcx> fmt::Display for TypeError<'tcx> {
6565
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
6666
use self::TypeError::*;
67-
fn report_maybe_different(f: &mut fmt::Formatter<'_>,
68-
expected: &str, found: &str) -> fmt::Result {
67+
fn report_maybe_different(
68+
f: &mut fmt::Formatter<'_>,
69+
expected: &str,
70+
found: &str,
71+
) -> fmt::Result {
6972
// A naive approach to making sure that we're not reporting silly errors such as:
7073
// (expected closure, found closure).
7174
if expected == found {
@@ -183,46 +186,77 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
183186
}
184187
}
185188

189+
impl<'tcx> TypeError<'tcx> {
190+
pub fn must_include_note(&self) -> bool {
191+
use self::TypeError::*;
192+
match self {
193+
CyclicTy(_) |
194+
UnsafetyMismatch(_) |
195+
Mismatch |
196+
AbiMismatch(_) |
197+
FixedArraySize(_) |
198+
Sorts(_) |
199+
IntMismatch(_) |
200+
FloatMismatch(_) |
201+
VariadicMismatch(_) => false,
202+
203+
Mutability |
204+
TupleSize(_) |
205+
ArgCount |
206+
RegionsDoesNotOutlive(..) |
207+
RegionsInsufficientlyPolymorphic(..) |
208+
RegionsOverlyPolymorphic(..) |
209+
RegionsPlaceholderMismatch |
210+
Traits(_) |
211+
ProjectionMismatched(_) |
212+
ProjectionBoundsLength(_) |
213+
ExistentialMismatch(_) |
214+
ConstMismatch(_) |
215+
IntrinsicCast |
216+
ObjectUnsafeCoercion(_) => true,
217+
}
218+
}
219+
}
220+
186221
impl<'tcx> ty::TyS<'tcx> {
187222
pub fn sort_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
188223
match self.kind {
189224
ty::Bool | ty::Char | ty::Int(_) |
190-
ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => self.to_string().into(),
191-
ty::Tuple(ref tys) if tys.is_empty() => self.to_string().into(),
225+
ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => format!("`{}`", self).into(),
226+
ty::Tuple(ref tys) if tys.is_empty() => format!("`{}`", self).into(),
192227

193228
ty::Adt(def, _) => format!("{} `{}`", def.descr(), tcx.def_path_str(def.did)).into(),
194229
ty::Foreign(def_id) => format!("extern type `{}`", tcx.def_path_str(def_id)).into(),
195-
ty::Array(_, n) => {
230+
ty::Array(t, n) => {
196231
let n = tcx.lift(&n).unwrap();
197232
match n.try_eval_usize(tcx, ty::ParamEnv::empty()) {
198-
Some(n) => {
199-
format!("array of {} element{}", n, pluralize!(n)).into()
200-
}
233+
_ if t.is_simple_ty() => format!("array `{}`", self).into(),
234+
Some(n) => format!("array of {} element{} ", n, pluralize!(n)).into(),
201235
None => "array".into(),
202236
}
203237
}
238+
ty::Slice(ty) if ty.is_simple_ty() => format!("slice `{}`", self).into(),
204239
ty::Slice(_) => "slice".into(),
205240
ty::RawPtr(_) => "*-ptr".into(),
206-
ty::Ref(region, ty, mutbl) => {
241+
ty::Ref(_, ty, mutbl) => {
207242
let tymut = ty::TypeAndMut { ty, mutbl };
208243
let tymut_string = tymut.to_string();
209-
if tymut_string == "_" || //unknown type name,
210-
tymut_string.len() > 10 || //name longer than saying "reference",
211-
region.to_string() != "'_" //... or a complex type
212-
{
213-
format!("{}reference", match mutbl {
214-
hir::Mutability::Mutable => "mutable ",
215-
_ => ""
216-
}).into()
217-
} else {
218-
format!("&{}", tymut_string).into()
244+
if tymut_string != "_" && (
245+
ty.is_simple_text() || tymut_string.len() < "mutable reference".len()
246+
) {
247+
format!("`&{}`", tymut_string).into()
248+
} else { // Unknown type name, it's long or has type arguments
249+
match mutbl {
250+
hir::Mutability::Mutable => "mutable reference",
251+
_ => "reference",
252+
}.into()
219253
}
220254
}
221255
ty::FnDef(..) => "fn item".into(),
222256
ty::FnPtr(_) => "fn pointer".into(),
223257
ty::Dynamic(ref inner, ..) => {
224258
if let Some(principal) = inner.principal() {
225-
format!("trait {}", tcx.def_path_str(principal.def_id())).into()
259+
format!("trait `{}`", tcx.def_path_str(principal.def_id())).into()
226260
} else {
227261
"trait".into()
228262
}
@@ -246,6 +280,36 @@ impl<'tcx> ty::TyS<'tcx> {
246280
ty::Error => "type error".into(),
247281
}
248282
}
283+
284+
pub fn prefix_string(&self) -> Cow<'static, str> {
285+
match self.kind {
286+
ty::Infer(_) | ty::Error | ty::Bool | ty::Char | ty::Int(_) |
287+
ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => "type".into(),
288+
ty::Tuple(ref tys) if tys.is_empty() => "unit type".into(),
289+
ty::Adt(def, _) => def.descr().into(),
290+
ty::Foreign(_) => "extern type".into(),
291+
ty::Array(..) => "array".into(),
292+
ty::Slice(_) => "slice".into(),
293+
ty::RawPtr(_) => "raw pointer".into(),
294+
ty::Ref(.., mutbl) => match mutbl {
295+
hir::Mutability::Mutable => "mutable reference",
296+
_ => "reference"
297+
}.into(),
298+
ty::FnDef(..) => "fn item".into(),
299+
ty::FnPtr(_) => "fn pointer".into(),
300+
ty::Dynamic(..) => "trait object".into(),
301+
ty::Closure(..) => "closure".into(),
302+
ty::Generator(..) => "generator".into(),
303+
ty::GeneratorWitness(..) => "generator witness".into(),
304+
ty::Tuple(..) => "tuple".into(),
305+
ty::Placeholder(..) => "higher-ranked type".into(),
306+
ty::Bound(..) => "bound type variable".into(),
307+
ty::Projection(_) => "associated type".into(),
308+
ty::UnnormalizedProjection(_) => "associated type".into(),
309+
ty::Param(_) => "type parameter".into(),
310+
ty::Opaque(..) => "opaque type".into(),
311+
}
312+
}
249313
}
250314

251315
impl<'tcx> TyCtxt<'tcx> {

src/librustc/ty/mod.rs

+2-31
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ pub use self::sty::BoundRegion::*;
7171
pub use self::sty::InferTy::*;
7272
pub use self::sty::RegionKind::*;
7373
pub use self::sty::TyKind::*;
74+
pub use crate::ty::diagnostics::*;
7475

7576
pub use self::binding::BindingMode;
7677
pub use self::binding::BindingMode::*;
@@ -122,6 +123,7 @@ mod instance;
122123
mod structural_impls;
123124
mod structural_match;
124125
mod sty;
126+
mod diagnostics;
125127

126128
// Data types
127129

@@ -552,37 +554,6 @@ impl<'tcx> Hash for TyS<'tcx> {
552554
}
553555
}
554556

555-
impl<'tcx> TyS<'tcx> {
556-
pub fn is_primitive_ty(&self) -> bool {
557-
match self.kind {
558-
Bool |
559-
Char |
560-
Int(_) |
561-
Uint(_) |
562-
Float(_) |
563-
Infer(InferTy::IntVar(_)) |
564-
Infer(InferTy::FloatVar(_)) |
565-
Infer(InferTy::FreshIntTy(_)) |
566-
Infer(InferTy::FreshFloatTy(_)) => true,
567-
Ref(_, x, _) => x.is_primitive_ty(),
568-
_ => false,
569-
}
570-
}
571-
572-
pub fn is_suggestable(&self) -> bool {
573-
match self.kind {
574-
Opaque(..) |
575-
FnDef(..) |
576-
FnPtr(..) |
577-
Dynamic(..) |
578-
Closure(..) |
579-
Infer(..) |
580-
Projection(..) => false,
581-
_ => true,
582-
}
583-
}
584-
}
585-
586557
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ty::TyS<'tcx> {
587558
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
588559
let ty::TyS {

src/librustc/ty/wf.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
209209
// LL | impl Bar for Foo {
210210
// | ---------------- in this `impl` item
211211
// LL | type Ok = ();
212-
// | ^^^^^^^^^^^^^ expected u32, found ()
212+
// | ^^^^^^^^^^^^^ expected `u32`, found `()`
213213
// |
214214
// = note: expected type `u32`
215215
// found type `()`
@@ -228,7 +228,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
228228
// LL | impl Bar for Foo {
229229
// | ---------------- in this `impl` item
230230
// LL | type Ok = ();
231-
// | ^^^^^^^^^^^^^ expected u32, found ()
231+
// | ^^^^^^^^^^^^^ expected `u32`, found `()`
232232
// ...
233233
// LL | impl Bar2 for Foo2 {
234234
// | ---------------- in this `impl` item

0 commit comments

Comments
 (0)