Skip to content

Commit ed822d2

Browse files
committed
RFC 2027: Improve Diagnostics
1 parent a5c6d96 commit ed822d2

File tree

7 files changed

+102
-23
lines changed

7 files changed

+102
-23
lines changed

src/librustc/infer/error_reporting/mod.rs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -977,10 +977,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
977977

978978
let span = cause.span(&self.tcx);
979979

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

985992
if let Some((expected, found)) = expected_found {
986993
match (terr, is_simple_error, expected == found) {
@@ -993,6 +1000,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
9931000
&format!(" ({})", values.found.sort_string(self.tcx)),
9941001
);
9951002
}
1003+
(TypeError::ObjectUnsafeCoercion(_), ..) => {
1004+
diag.note_unsuccessfull_coercion(found, expected);
1005+
}
9961006
(_, false, _) => {
9971007
if let Some(exp_found) = exp_found {
9981008
let (def_id, ret_ty) = match exp_found.found.sty {
@@ -1112,6 +1122,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
11121122
let span = trace.cause.span(&self.tcx);
11131123
let failure_code = trace.cause.as_failure_code(terr);
11141124
let mut diag = match failure_code {
1125+
FailureCode::Error0038(did) => {
1126+
let violations = self.tcx.global_tcx()
1127+
.object_safety_violations(did);
1128+
self.tcx.report_object_safety_error(span, did, violations)
1129+
}
11151130
FailureCode::Error0317(failure_str) => {
11161131
struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str)
11171132
}
@@ -1470,6 +1485,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
14701485
}
14711486

14721487
enum FailureCode {
1488+
Error0038(DefId),
14731489
Error0317(&'static str),
14741490
Error0580(&'static str),
14751491
Error0308(&'static str),
@@ -1503,6 +1519,7 @@ impl<'tcx> ObligationCause<'tcx> {
15031519
TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => {
15041520
Error0644("closure/generator type that references itself")
15051521
}
1522+
TypeError::ObjectUnsafeCoercion(did) => Error0038(did.clone()),
15061523
_ => Error0308("mismatched types"),
15071524
},
15081525
}

src/librustc/ty/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ pub enum TypeError<'tcx> {
4242
ProjectionMismatched(ExpectedFound<DefId>),
4343
ProjectionBoundsLength(ExpectedFound<usize>),
4444
ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>),
45+
ObjectUnsafeCoercion(DefId),
4546
}
4647

4748
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
@@ -144,6 +145,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
144145
report_maybe_different(f, &format!("trait `{}`", values.expected),
145146
&format!("trait `{}`", values.found))
146147
}
148+
ObjectUnsafeCoercion(_) => write!(f, "coercion to object-unsafe trait object"),
147149
}
148150
}
149151
}

src/librustc/ty/structural_impls.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
443443
ProjectionMismatched(x) => ProjectionMismatched(x),
444444
ProjectionBoundsLength(x) => ProjectionBoundsLength(x),
445445
Sorts(ref x) => return tcx.lift(x).map(Sorts),
446-
ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch)
446+
ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch),
447+
ObjectUnsafeCoercion(defid) => ObjectUnsafeCoercion(defid),
447448
})
448449
}
449450
}
@@ -1031,6 +1032,7 @@ EnumTypeFoldableImpl! {
10311032
(ty::error::TypeError::ProjectionBoundsLength)(x),
10321033
(ty::error::TypeError::Sorts)(x),
10331034
(ty::error::TypeError::ExistentialMismatch)(x),
1035+
(ty::error::TypeError::ObjectUnsafeCoercion)(x),
10341036
}
10351037
}
10361038

src/librustc_errors/diagnostic.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,32 @@ impl Diagnostic {
149149
self.note_expected_found_extra(label, expected, found, &"", &"")
150150
}
151151

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

src/librustc_errors/diagnostic_builder.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,11 @@ impl<'a> DiagnosticBuilder<'a> {
174174
found_extra: &dyn fmt::Display,
175175
) -> &mut Self);
176176

177+
forward!(pub fn note_unsuccessfull_coercion(&mut self,
178+
expected: DiagnosticStyledString,
179+
found: DiagnosticStyledString,
180+
) -> &mut Self);
181+
177182
forward!(pub fn note(&mut self, msg: &str) -> &mut Self);
178183
forward!(pub fn span_note<S: Into<MultiSpan>>(&mut self,
179184
sp: S,

src/librustc_typeck/check/cast.rs

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -425,22 +425,39 @@ 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().cast_kinds_mut().insert(self.expr.hir_id,
432-
CastKind::CoercionCast);
433428
} else {
434-
match self.do_check(fcx) {
435-
Ok(k) => {
436-
debug!(" -> {:?}", k);
437-
fcx.tables.borrow_mut().cast_kinds_mut().insert(self.expr.hir_id, k);
429+
match self.try_coercion_cast(fcx) {
430+
Ok(()) => {
431+
self.trivial_cast_lint(fcx);
432+
debug!(" -> CoercionCast");
433+
fcx.tables.borrow_mut().cast_kinds_mut()
434+
.insert(self.expr.hir_id, CastKind::CoercionCast);
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+
fcx.tables.borrow_mut().cast_kinds_mut()
444+
.insert(self.expr.hir_id, k);
445+
}
446+
Err(e) => self.report_cast_error(fcx, e),
447+
};
438448
}
439-
Err(e) => self.report_cast_error(fcx, e),
440449
};
441450
}
442451
}
443452

453+
fn report_object_unsafe_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, did: DefId) {
454+
let violations = fcx.tcx.global_tcx().object_safety_violations(did);
455+
let mut err = fcx.tcx.report_object_safety_error(self.cast_span, did, violations);
456+
err.note(&format!("required by cast to type '{}'",
457+
fcx.ty_to_string(self.cast_ty)));
458+
err.emit();
459+
}
460+
444461
/// Check a cast, and report an error if one exists. In some cases, this
445462
/// can return Ok and create type errors in the fcx rather than returning
446463
/// directly. coercion-cast is handled in check instead of here.
@@ -636,8 +653,12 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
636653
}
637654
}
638655

639-
fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> bool {
640-
fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No).is_ok()
656+
fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>)
657+
-> Result<(), ty::error::TypeError> {
658+
match fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No) {
659+
Ok(_) => Ok(()),
660+
Err(err) => Err(err),
661+
}
641662
}
642663
}
643664

src/librustc_typeck/check/coercion.rs

Lines changed: 12 additions & 6 deletions
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)