Skip to content

Commit 91dba64

Browse files
committed
RFC 2027: Improve Diagnostics
1 parent 29278b4 commit 91dba64

File tree

7 files changed

+100
-22
lines changed

7 files changed

+100
-22
lines changed

src/librustc/infer/error_reporting/mod.rs

+21-4
Original file line numberDiff line numberDiff line change
@@ -979,10 +979,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
979979

980980
let span = cause.span(&self.tcx);
981981

982-
diag.span_label(span, terr.to_string());
983-
if let Some((sp, msg)) = secondary_span {
984-
diag.span_label(sp, msg);
985-
}
982+
// Ignore msg for object safe coercion
983+
// since E0038 message will be printed
984+
match terr {
985+
TypeError::ObjectUnsafeCoercion(_) => {}
986+
_ => {
987+
diag.span_label(span, terr.to_string());
988+
if let Some((sp, msg)) = secondary_span {
989+
diag.span_label(sp, msg);
990+
}
991+
}
992+
};
986993

987994
if let Some((expected, found)) = expected_found {
988995
match (terr, is_simple_error, expected == found) {
@@ -995,6 +1002,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
9951002
&format!(" ({})", values.found.sort_string(self.tcx)),
9961003
);
9971004
}
1005+
(TypeError::ObjectUnsafeCoercion(_), ..) => {
1006+
diag.note_unsuccessfull_coercion(found, expected);
1007+
}
9981008
(_, false, _) => {
9991009
if let Some(exp_found) = exp_found {
10001010
let (def_id, ret_ty) = match exp_found.found.sty {
@@ -1114,6 +1124,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
11141124
let span = trace.cause.span(&self.tcx);
11151125
let failure_code = trace.cause.as_failure_code(terr);
11161126
let mut diag = match failure_code {
1127+
FailureCode::Error0038(did) => {
1128+
let violations = self.tcx.global_tcx()
1129+
.object_safety_violations(did);
1130+
self.tcx.report_object_safety_error(span, did, violations)
1131+
}
11171132
FailureCode::Error0317(failure_str) => {
11181133
struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str)
11191134
}
@@ -1471,6 +1486,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
14711486
}
14721487

14731488
enum FailureCode {
1489+
Error0038(DefId),
14741490
Error0317(&'static str),
14751491
Error0580(&'static str),
14761492
Error0308(&'static str),
@@ -1504,6 +1520,7 @@ impl<'tcx> ObligationCause<'tcx> {
15041520
TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => {
15051521
Error0644("closure/generator type that references itself")
15061522
}
1523+
TypeError::ObjectUnsafeCoercion(did) => Error0038(did.clone()),
15071524
_ => Error0308("mismatched types"),
15081525
},
15091526
}

src/librustc/ty/error.rs

+2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ pub enum TypeError<'tcx> {
4444
ProjectionMismatched(ExpectedFound<DefId>),
4545
ProjectionBoundsLength(ExpectedFound<usize>),
4646
ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>),
47+
ObjectUnsafeCoercion(DefId),
4748
}
4849

4950
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
@@ -158,6 +159,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
158159
report_maybe_different(f, &format!("trait `{}`", values.expected),
159160
&format!("trait `{}`", values.found))
160161
}
162+
ObjectUnsafeCoercion(_) => write!(f, "coercion to object-unsafe trait object"),
161163
}
162164
}
163165
}

src/librustc/ty/structural_impls.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
451451
ProjectionMismatched(x) => ProjectionMismatched(x),
452452
ProjectionBoundsLength(x) => ProjectionBoundsLength(x),
453453
Sorts(ref x) => return tcx.lift(x).map(Sorts),
454-
ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch)
454+
ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch),
455+
ObjectUnsafeCoercion(defid) => ObjectUnsafeCoercion(defid),
455456
})
456457
}
457458
}
@@ -1059,6 +1060,7 @@ EnumTypeFoldableImpl! {
10591060
(ty::error::TypeError::ProjectionBoundsLength)(x),
10601061
(ty::error::TypeError::Sorts)(x),
10611062
(ty::error::TypeError::ExistentialMismatch)(x),
1063+
(ty::error::TypeError::ObjectUnsafeCoercion)(x),
10621064
}
10631065
}
10641066

src/librustc_errors/diagnostic.rs

+26
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,32 @@ impl Diagnostic {
150150
self.note_expected_found_extra(label, expected, found, &"", &"")
151151
}
152152

153+
pub fn note_unsuccessfull_coercion(&mut self,
154+
expected: DiagnosticStyledString,
155+
found: DiagnosticStyledString)
156+
-> &mut Self
157+
{
158+
let mut msg: Vec<_> =
159+
vec![(format!("required when trying to coerce from type `"),
160+
Style::NoStyle)];
161+
msg.extend(expected.0.iter()
162+
.map(|x| match *x {
163+
StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
164+
StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
165+
}));
166+
msg.push((format!("` to type '"), Style::NoStyle));
167+
msg.extend(found.0.iter()
168+
.map(|x| match *x {
169+
StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
170+
StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
171+
}));
172+
msg.push((format!("`"), Style::NoStyle));
173+
174+
// For now, just attach these as notes
175+
self.highlighted_note(msg);
176+
self
177+
}
178+
153179
pub fn note_expected_found_extra(&mut self,
154180
label: &dyn fmt::Display,
155181
expected: DiagnosticStyledString,

src/librustc_errors/diagnostic_builder.rs

+5
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,11 @@ impl<'a> DiagnosticBuilder<'a> {
177177
found_extra: &dyn fmt::Display,
178178
) -> &mut Self);
179179

180+
forward!(pub fn note_unsuccessfull_coercion(&mut self,
181+
expected: DiagnosticStyledString,
182+
found: DiagnosticStyledString,
183+
) -> &mut Self);
184+
180185
forward!(pub fn note(&mut self, msg: &str) -> &mut Self);
181186
forward!(pub fn span_note<S: Into<MultiSpan>>(&mut self,
182187
sp: S,

src/librustc_typeck/check/cast.rs

+31-11
Original file line numberDiff line numberDiff line change
@@ -425,21 +425,37 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
425425
self.report_cast_to_unsized_type(fcx);
426426
} else if self.expr_ty.references_error() || self.cast_ty.references_error() {
427427
// No sense in giving duplicate error messages
428-
} else if self.try_coercion_cast(fcx) {
429-
self.trivial_cast_lint(fcx);
430-
debug!(" -> CoercionCast");
431-
fcx.tables.borrow_mut().set_coercion_cast(self.expr.hir_id.local_id);
432-
433428
} else {
434-
match self.do_check(fcx) {
435-
Ok(k) => {
436-
debug!(" -> {:?}", k);
429+
match self.try_coercion_cast(fcx) {
430+
Ok(()) => {
431+
self.trivial_cast_lint(fcx);
432+
debug!(" -> CoercionCast");
433+
fcx.tables.borrow_mut()
434+
.set_coercion_cast(self.expr.hir_id.local_id);
435+
}
436+
Err(ty::error::TypeError::ObjectUnsafeCoercion(did)) => {
437+
self.report_object_unsafe_cast(&fcx, did);
438+
}
439+
Err(_) => {
440+
match self.do_check(fcx) {
441+
Ok(k) => {
442+
debug!(" -> {:?}", k);
443+
}
444+
Err(e) => self.report_cast_error(fcx, e),
445+
};
437446
}
438-
Err(e) => self.report_cast_error(fcx, e),
439447
};
440448
}
441449
}
442450

451+
fn report_object_unsafe_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, did: DefId) {
452+
let violations = fcx.tcx.global_tcx().object_safety_violations(did);
453+
let mut err = fcx.tcx.report_object_safety_error(self.cast_span, did, violations);
454+
err.note(&format!("required by cast to type '{}'",
455+
fcx.ty_to_string(self.cast_ty)));
456+
err.emit();
457+
}
458+
443459
/// Checks a cast, and report an error if one exists. In some cases, this
444460
/// can return Ok and create type errors in the fcx rather than returning
445461
/// directly. coercion-cast is handled in check instead of here.
@@ -635,8 +651,12 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
635651
}
636652
}
637653

638-
fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> bool {
639-
fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No).is_ok()
654+
fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>)
655+
-> Result<(), ty::error::TypeError<'_>> {
656+
match fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No) {
657+
Ok(_) => Ok(()),
658+
Err(err) => Err(err),
659+
}
640660
}
641661
}
642662

src/librustc_typeck/check/coercion.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,16 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
186186
// a "spurious" type variable, and we don't want to have that
187187
// type variable in memory if the coercion fails.
188188
let unsize = self.commit_if_ok(|_| self.coerce_unsized(a, b));
189-
if unsize.is_ok() {
190-
debug!("coerce: unsize successful");
191-
return unsize;
189+
match unsize {
190+
Ok(_) => {
191+
debug!("coerce: unsize successful");
192+
return unsize;
193+
}
194+
Err(TypeError::ObjectUnsafeCoercion(did)) => {
195+
debug!("coerce: unsize not object safe");
196+
return Err(TypeError::ObjectUnsafeCoercion(did));
197+
}
198+
Err(_) => {}
192199
}
193200
debug!("coerce: unsize failed");
194201

@@ -657,9 +664,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
657664
);
658665
match selcx.select(&obj_safe.with(pred.clone())) {
659666
Ok(_) => (),
660-
Err(err) => {
661-
self.report_selection_error(&obj_safe, &err, false);
662-
return Err(TypeError::Mismatch)
667+
Err(_) => {
668+
return Err(TypeError::ObjectUnsafeCoercion(target_def_id))
663669
}
664670
}
665671
}

0 commit comments

Comments
 (0)