Skip to content

Commit

Permalink
RFC 2027: "first draft" of implementation
Browse files Browse the repository at this point in the history
These are a squashed series of commits.
  • Loading branch information
bovinebuddha authored and nikomatsakis committed Oct 22, 2019
1 parent d28a9c3 commit ef5acde
Showing 59 changed files with 847 additions and 105 deletions.
24 changes: 20 additions & 4 deletions src/librustc/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
@@ -1146,10 +1146,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {

let span = cause.span(self.tcx);

diag.span_label(span, terr.to_string());
if let Some((sp, msg)) = secondary_span {
diag.span_label(sp, msg);
}
// Ignore msg for object safe coercion
// since E0038 message will be printed
match terr {
TypeError::ObjectUnsafeCoercion(_) => {}
_ => {
diag.span_label(span, terr.to_string());
if let Some((sp, msg)) = secondary_span {
diag.span_label(sp, msg);
}
}
};

if let Some((expected, found)) = expected_found {
match (terr, is_simple_error, expected == found) {
@@ -1169,6 +1176,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
&sort_string(values.found),
);
}
(TypeError::ObjectUnsafeCoercion(_), ..) => {
diag.note_unsuccessfull_coercion(found, expected);
}
(_, false, _) => {
if let Some(exp_found) = exp_found {
self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
@@ -1267,6 +1277,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
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);
self.tcx.report_object_safety_error(span, did, violations)
}
FailureCode::Error0317(failure_str) => {
struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str)
}
@@ -1628,6 +1642,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}

enum FailureCode {
Error0038(DefId),
Error0317(&'static str),
Error0580(&'static str),
Error0308(&'static str),
@@ -1666,6 +1681,7 @@ impl<'tcx> ObligationCause<'tcx> {
TypeError::IntrinsicCast => {
Error0308("cannot coerce intrinsics to function pointers")
}
TypeError::ObjectUnsafeCoercion(did) => Error0038(did.clone()),
_ => Error0308("mismatched types"),
},
}
32 changes: 15 additions & 17 deletions src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
@@ -790,15 +790,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {

ty::Predicate::ObjectSafe(trait_def_id) => {
let violations = self.tcx.object_safety_violations(trait_def_id);
if let Some(err) = self.tcx.report_object_safety_error(
self.tcx.report_object_safety_error(
span,
trait_def_id,
violations,
) {
err
} else {
return;
}
)
}

ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
@@ -934,11 +930,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {

TraitNotObjectSafe(did) => {
let violations = self.tcx.object_safety_violations(did);
if let Some(err) = self.tcx.report_object_safety_error(span, did, violations) {
err
} else {
return;
}
self.tcx.report_object_safety_error(span, did, violations)
}

// already reported in the query
@@ -1493,11 +1485,7 @@ impl<'tcx> TyCtxt<'tcx> {
span: Span,
trait_def_id: DefId,
violations: Vec<ObjectSafetyViolation>,
) -> Option<DiagnosticBuilder<'tcx>> {
if self.sess.trait_methods_not_found.borrow().contains(&span) {
// Avoid emitting error caused by non-existing method (#58734)
return None;
}
) -> DiagnosticBuilder<'tcx> {
let trait_str = self.def_path_str(trait_def_id);
let span = self.sess.source_map().def_span(span);
let mut err = struct_span_err!(
@@ -1515,7 +1503,13 @@ impl<'tcx> TyCtxt<'tcx> {
};
}
}
Some(err)

if self.sess.trait_methods_not_found.borrow().contains(&span) {
// Avoid emitting error caused by non-existing method (#58734)
err.cancel();
}

err
}
}

@@ -1926,6 +1920,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
err.note(&format!("required for the cast to the object type `{}`",
self.ty_to_string(object_ty)));
}
ObligationCauseCode::Coercion { source: _, target } => {
err.note(&format!("required by cast to type `{}`",
self.ty_to_string(target)));
}
ObligationCauseCode::RepeatVec => {
err.note("the `Copy` trait is required because the \
repeated element will be copied");
3 changes: 3 additions & 0 deletions src/librustc/traits/mod.rs
Original file line number Diff line number Diff line change
@@ -188,6 +188,9 @@ pub enum ObligationCauseCode<'tcx> {
/// Obligation incurred due to an object cast.
ObjectCastObligation(/* Object type */ Ty<'tcx>),

/// Obligation incurred due to a coercion.
Coercion { source: Ty<'tcx>, target: Ty<'tcx> },

// Various cases where expressions must be sized/copy/etc:
/// L = X implies that L is Sized
AssignmentLhsSized,
8 changes: 7 additions & 1 deletion src/librustc/traits/select.rs
Original file line number Diff line number Diff line change
@@ -2246,7 +2246,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}

if let Some(principal) = data.principal() {
principal.with_self_ty(self.tcx(), self_ty)
if !self.infcx.tcx.features().object_safe_for_dispatch {
principal.with_self_ty(self.tcx(), self_ty)
} else if self.tcx().is_object_safe(principal.def_id()) {
principal.with_self_ty(self.tcx(), self_ty)
} else {
return;
}
} else {
// Only auto-trait bounds exist.
return;
4 changes: 4 additions & 0 deletions src/librustc/traits/structural_impls.rs
Original file line number Diff line number Diff line change
@@ -481,6 +481,10 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
.and_then(|r| Some(super::ObjectTypeBound(ty, r)))
),
super::ObjectCastObligation(ty) => tcx.lift(&ty).map(super::ObjectCastObligation),
super::Coercion { source, target } => Some(super::Coercion {
source: tcx.lift(&source)?,
target: tcx.lift(&target)?,
}),
super::AssignmentLhsSized => Some(super::AssignmentLhsSized),
super::TupleInitializerSized => Some(super::TupleInitializerSized),
super::StructInitializerSized => Some(super::StructInitializerSized),
3 changes: 2 additions & 1 deletion src/librustc/ty/error.rs
Original file line number Diff line number Diff line change
@@ -45,7 +45,7 @@ pub enum TypeError<'tcx> {
ProjectionMismatched(ExpectedFound<DefId>),
ProjectionBoundsLength(ExpectedFound<usize>),
ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>),

ObjectUnsafeCoercion(DefId),
ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>),

IntrinsicCast,
@@ -179,6 +179,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
IntrinsicCast => {
write!(f, "cannot coerce intrinsics to function pointers")
}
ObjectUnsafeCoercion(_) => write!(f, "coercion to object-unsafe trait object"),
}
}
}
2 changes: 2 additions & 0 deletions src/librustc/ty/structural_impls.rs
Original file line number Diff line number Diff line change
@@ -749,6 +749,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch),
ConstMismatch(ref x) => return tcx.lift(x).map(ConstMismatch),
IntrinsicCast => IntrinsicCast,
ObjectUnsafeCoercion(ref x) => return tcx.lift(x).map(ObjectUnsafeCoercion),
})
}
}
@@ -1356,6 +1357,7 @@ EnumTypeFoldableImpl! {
(ty::error::TypeError::ExistentialMismatch)(x),
(ty::error::TypeError::ConstMismatch)(x),
(ty::error::TypeError::IntrinsicCast),
(ty::error::TypeError::ObjectUnsafeCoercion)(x),
}
}

25 changes: 15 additions & 10 deletions src/librustc/ty/wf.rs
Original file line number Diff line number Diff line change
@@ -380,16 +380,21 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
// obligations that don't refer to Self and
// checking those

let cause = self.cause(traits::MiscObligation);
let component_traits =
data.auto_traits().chain(data.principal_def_id());
self.out.extend(
component_traits.map(|did| traits::Obligation::new(
cause.clone(),
param_env,
ty::Predicate::ObjectSafe(did)
))
);
let defer_to_coercion =
self.infcx.tcx.features().object_safe_for_dispatch;

if !defer_to_coercion {
let cause = self.cause(traits::MiscObligation);
let component_traits =
data.auto_traits().chain(data.principal_def_id());
self.out.extend(
component_traits.map(|did| traits::Obligation::new(
cause.clone(),
param_env,
ty::Predicate::ObjectSafe(did)
))
);
}
}

// Inference variables are the complicated case, since we don't
26 changes: 26 additions & 0 deletions src/librustc_errors/diagnostic.rs
Original file line number Diff line number Diff line change
@@ -152,6 +152,32 @@ impl Diagnostic {
self.note_expected_found_extra(label, expected, found, &"", &"")
}

pub fn note_unsuccessfull_coercion(&mut self,
expected: DiagnosticStyledString,
found: DiagnosticStyledString)
-> &mut Self
{
let mut msg: Vec<_> =
vec![(format!("required when trying to coerce from type `"),
Style::NoStyle)];
msg.extend(expected.0.iter()
.map(|x| match *x {
StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
}));
msg.push((format!("` to type '"), Style::NoStyle));
msg.extend(found.0.iter()
.map(|x| match *x {
StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
}));
msg.push((format!("`"), Style::NoStyle));

// For now, just attach these as notes
self.highlighted_note(msg);
self
}

pub fn note_expected_found_extra(&mut self,
label: &dyn fmt::Display,
expected: DiagnosticStyledString,
5 changes: 5 additions & 0 deletions src/librustc_errors/diagnostic_builder.rs
Original file line number Diff line number Diff line change
@@ -209,6 +209,11 @@ impl<'a> DiagnosticBuilder<'a> {
found_extra: &dyn fmt::Display,
) -> &mut Self);

forward!(pub fn note_unsuccessfull_coercion(&mut self,
expected: DiagnosticStyledString,
found: DiagnosticStyledString,
) -> &mut Self);

forward!(pub fn note(&mut self, msg: &str) -> &mut Self);
forward!(pub fn span_note<S: Into<MultiSpan>>(&mut self,
sp: S,
3 changes: 1 addition & 2 deletions src/librustc_typeck/astconv.rs
Original file line number Diff line number Diff line change
@@ -1275,8 +1275,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
span,
item.trait_ref().def_id(),
object_safety_violations
)
.map(|mut err| err.emit());
).emit();
return tcx.types.err;
}
}
43 changes: 32 additions & 11 deletions src/librustc_typeck/check/cast.rs
Original file line number Diff line number Diff line change
@@ -428,21 +428,36 @@ impl<'a, 'tcx> CastCheck<'tcx> {
self.report_cast_to_unsized_type(fcx);
} else if self.expr_ty.references_error() || self.cast_ty.references_error() {
// No sense in giving duplicate error messages
} else if self.try_coercion_cast(fcx) {
self.trivial_cast_lint(fcx);
debug!(" -> CoercionCast");
fcx.tables.borrow_mut().set_coercion_cast(self.expr.hir_id.local_id);

} else {
match self.do_check(fcx) {
Ok(k) => {
debug!(" -> {:?}", k);
match self.try_coercion_cast(fcx) {
Ok(()) => {
self.trivial_cast_lint(fcx);
debug!(" -> CoercionCast");
fcx.tables.borrow_mut()
.set_coercion_cast(self.expr.hir_id.local_id);
}
Err(ty::error::TypeError::ObjectUnsafeCoercion(did)) => {
self.report_object_unsafe_cast(&fcx, did);
}
Err(_) => {
match self.do_check(fcx) {
Ok(k) => {
debug!(" -> {:?}", k);
}
Err(e) => self.report_cast_error(fcx, e),
};
}
Err(e) => self.report_cast_error(fcx, e),
};
}
}

fn report_object_unsafe_cast(&self, fcx: &FnCtxt<'a, 'tcx>, did: DefId) {
let violations = fcx.tcx.object_safety_violations(did);
let mut err = fcx.tcx.report_object_safety_error(self.cast_span, did, violations);
err.note(&format!("required by cast to type '{}'", fcx.ty_to_string(self.cast_ty)));
err.emit();
}

/// Checks a cast, and report an error if one exists. In some cases, this
/// can return Ok and create type errors in the fcx rather than returning
/// directly. coercion-cast is handled in check instead of here.
@@ -646,8 +661,14 @@ impl<'a, 'tcx> CastCheck<'tcx> {
}
}

fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'tcx>) -> bool {
fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No).is_ok()
fn try_coercion_cast(
&self,
fcx: &FnCtxt<'a, 'tcx>,
) -> Result<(), ty::error::TypeError<'_>> {
match fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No) {
Ok(_) => Ok(()),
Err(err) => Err(err),
}
}
}

Loading

0 comments on commit ef5acde

Please sign in to comment.