Skip to content

Commit 9116552

Browse files
committed
RFC 2027: Improve Diagnostics
1 parent 38ab0c9 commit 9116552

File tree

7 files changed

+102
-23
lines changed

7 files changed

+102
-23
lines changed

src/librustc/infer/error_reporting/mod.rs

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

944944
let span = cause.span(&self.tcx);
945945

946-
diag.span_label(span, terr.to_string());
947-
if let Some((sp, msg)) = secondary_span {
948-
diag.span_label(sp, msg);
949-
}
946+
// Ignore msg for object safe coercion
947+
// since E0038 message will be printed
948+
match terr {
949+
TypeError::ObjectUnsafeCoercion(_) => {}
950+
_ => {
951+
diag.span_label(span, terr.to_string());
952+
if let Some((sp, msg)) = secondary_span {
953+
diag.span_label(sp, msg);
954+
}
955+
}
956+
};
950957

951958
if let Some((expected, found)) = expected_found {
952959
match (terr, is_simple_error, expected == found) {
@@ -959,6 +966,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
959966
&format!(" ({})", values.found.sort_string(self.tcx)),
960967
);
961968
}
969+
(TypeError::ObjectUnsafeCoercion(_), ..) => {
970+
diag.note_unsuccessfull_coercion(found, expected);
971+
}
962972
(_, false, _) => {
963973
if let Some(exp_found) = exp_found {
964974
let (def_id, ret_ty) = match exp_found.found.sty {
@@ -1078,6 +1088,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
10781088
let span = trace.cause.span(&self.tcx);
10791089
let failure_code = trace.cause.as_failure_code(terr);
10801090
let mut diag = match failure_code {
1091+
FailureCode::Error0038(did) => {
1092+
let violations = self.tcx.global_tcx()
1093+
.object_safety_violations(did);
1094+
self.tcx.report_object_safety_error(span, did, violations)
1095+
}
10811096
FailureCode::Error0317(failure_str) => {
10821097
struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str)
10831098
}
@@ -1436,6 +1451,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
14361451
}
14371452

14381453
enum FailureCode {
1454+
Error0038(DefId),
14391455
Error0317(&'static str),
14401456
Error0580(&'static str),
14411457
Error0308(&'static str),
@@ -1469,6 +1485,7 @@ impl<'tcx> ObligationCause<'tcx> {
14691485
TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => {
14701486
Error0644("closure/generator type that references itself")
14711487
}
1488+
TypeError::ObjectUnsafeCoercion(did) => Error0038(did.clone()),
14721489
_ => Error0308("mismatched types"),
14731490
},
14741491
}

src/librustc/ty/error.rs

+2
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

+3-1
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

+26
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

+5
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,11 @@ impl<'a> DiagnosticBuilder<'a> {
164164
found_extra: &dyn fmt::Display,
165165
) -> &mut Self);
166166

167+
forward!(pub fn note_unsuccessfull_coercion(&mut self,
168+
expected: DiagnosticStyledString,
169+
found: DiagnosticStyledString,
170+
) -> &mut Self);
171+
167172
forward!(pub fn note(&mut self, msg: &str) -> &mut Self);
168173
forward!(pub fn span_note<S: Into<MultiSpan>>(&mut self,
169174
sp: S,

src/librustc_typeck/check/cast.rs

+33-12
Original file line numberDiff line numberDiff line change
@@ -401,22 +401,39 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
401401
self.report_cast_to_unsized_type(fcx);
402402
} else if self.expr_ty.references_error() || self.cast_ty.references_error() {
403403
// No sense in giving duplicate error messages
404-
} else if self.try_coercion_cast(fcx) {
405-
self.trivial_cast_lint(fcx);
406-
debug!(" -> CoercionCast");
407-
fcx.tables.borrow_mut().cast_kinds_mut().insert(self.expr.hir_id,
408-
CastKind::CoercionCast);
409404
} else {
410-
match self.do_check(fcx) {
411-
Ok(k) => {
412-
debug!(" -> {:?}", k);
413-
fcx.tables.borrow_mut().cast_kinds_mut().insert(self.expr.hir_id, k);
405+
match self.try_coercion_cast(fcx) {
406+
Ok(()) => {
407+
self.trivial_cast_lint(fcx);
408+
debug!(" -> CoercionCast");
409+
fcx.tables.borrow_mut().cast_kinds_mut()
410+
.insert(self.expr.hir_id, CastKind::CoercionCast);
411+
}
412+
Err(ty::error::TypeError::ObjectUnsafeCoercion(did)) => {
413+
self.report_object_unsafe_cast(&fcx, did);
414+
}
415+
Err(_) => {
416+
match self.do_check(fcx) {
417+
Ok(k) => {
418+
debug!(" -> {:?}", k);
419+
fcx.tables.borrow_mut().cast_kinds_mut()
420+
.insert(self.expr.hir_id, k);
421+
}
422+
Err(e) => self.report_cast_error(fcx, e),
423+
};
414424
}
415-
Err(e) => self.report_cast_error(fcx, e),
416425
};
417426
}
418427
}
419428

429+
fn report_object_unsafe_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, did: DefId) {
430+
let violations = fcx.tcx.global_tcx().object_safety_violations(did);
431+
let mut err = fcx.tcx.report_object_safety_error(self.cast_span, did, violations);
432+
err.note(&format!("required by cast to type '{}'",
433+
fcx.ty_to_string(self.cast_ty)));
434+
err.emit();
435+
}
436+
420437
/// Check a cast, and report an error if one exists. In some cases, this
421438
/// can return Ok and create type errors in the fcx rather than returning
422439
/// directly. coercion-cast is handled in check instead of here.
@@ -612,8 +629,12 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
612629
}
613630
}
614631

615-
fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> bool {
616-
fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No).is_ok()
632+
fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>)
633+
-> Result<(), ty::error::TypeError> {
634+
match fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No) {
635+
Ok(_) => Ok(()),
636+
Err(err) => Err(err),
637+
}
617638
}
618639
}
619640

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)