Introduce a "origin/cause" for new requirements (or bugfixes...) introduced by RFC 1214,

and issue a warning (and explanatory note) when we encounter such a
thing.
This commit is contained in:
Niko Matsakis 2015-08-07 10:28:51 -04:00
parent 39d164d042
commit 75ee8f1562
7 changed files with 337 additions and 130 deletions

View file

@ -239,8 +239,7 @@ pub trait ErrorReporting<'tcx> {
fn report_generic_bound_failure(&self,
origin: SubregionOrigin<'tcx>,
kind: GenericKind<'tcx>,
sub: Region,
sups: Vec<Region>);
sub: Region);
fn report_sub_sup_conflict(&self,
var_origin: RegionVariableOrigin,
@ -292,8 +291,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
self.report_concrete_failure(origin, sub, sup);
}
GenericBoundFailure(kind, param_ty, sub, sups) => {
self.report_generic_bound_failure(kind, param_ty, sub, sups);
GenericBoundFailure(kind, param_ty, sub) => {
self.report_generic_bound_failure(kind, param_ty, sub);
}
SubSupConflict(var_origin,
@ -527,14 +526,18 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
fn report_generic_bound_failure(&self,
origin: SubregionOrigin<'tcx>,
bound_kind: GenericKind<'tcx>,
sub: Region,
_sups: Vec<Region>)
sub: Region)
{
// FIXME: it would be better to report the first error message
// with the span of the parameter itself, rather than the span
// where the error was detected. But that span is not readily
// accessible.
let is_warning = match origin {
infer::RFC1214Subregion(_) => true,
_ => false,
};
let labeled_user_string = match bound_kind {
GenericKind::Param(ref p) =>
format!("the parameter type `{}`", p),
@ -545,7 +548,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
match sub {
ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
// Does the required lifetime have a nice name we can print?
span_err!(self.tcx.sess, origin.span(), E0309,
span_err_or_warn!(
is_warning, self.tcx.sess, origin.span(), E0309,
"{} may not live long enough", labeled_user_string);
self.tcx.sess.fileline_help(
origin.span(),
@ -557,7 +561,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
ty::ReStatic => {
// Does the required lifetime have a nice name we can print?
span_err!(self.tcx.sess, origin.span(), E0310,
span_err_or_warn!(
is_warning, self.tcx.sess, origin.span(), E0310,
"{} may not live long enough", labeled_user_string);
self.tcx.sess.fileline_help(
origin.span(),
@ -568,9 +573,10 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
_ => {
// If not, be less specific.
span_err!(self.tcx.sess, origin.span(), E0311,
"{} may not live long enough",
labeled_user_string);
span_err_or_warn!(
is_warning, self.tcx.sess, origin.span(), E0311,
"{} may not live long enough",
labeled_user_string);
self.tcx.sess.fileline_help(
origin.span(),
&format!(
@ -583,6 +589,10 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
}
}
if is_warning {
self.tcx.sess.note_rfc_1214(origin.span());
}
self.note_region_origin(&origin);
}
@ -591,6 +601,13 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
sub: Region,
sup: Region) {
match origin {
infer::RFC1214Subregion(ref suborigin) => {
// Ideally, this would be a warning, but it doesn't
// seem to come up in practice, since the changes from
// RFC1214 mostly trigger errors in type definitions
// that don't wind up coming down this path.
self.report_concrete_failure((**suborigin).clone(), sub, sup);
}
infer::Subtype(trace) => {
let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
self.report_and_explain_type_error(trace, &terr);
@ -819,6 +836,23 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
sup,
"");
}
infer::ParameterInScope(_, span) => {
self.tcx.sess.span_err(
span,
&format!("type/lifetime parameter not in scope here"));
self.tcx.note_and_explain_region(
"the parameter is only valid for ",
sub,
"");
}
infer::DataBorrowed(ty, span) => {
self.tcx.sess.span_err(
span,
&format!("a value of type `{}` is borrowed for too long",
self.ty_to_string(ty)));
self.tcx.note_and_explain_region("the type is valid for ", sub, "");
self.tcx.note_and_explain_region("but the borrow lasts for ", sup, "");
}
infer::ReferenceOutlivesReferent(ty, span) => {
self.tcx.sess.span_err(
span,
@ -1567,6 +1601,9 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
fn note_region_origin(&self, origin: &SubregionOrigin<'tcx>) {
match *origin {
infer::RFC1214Subregion(ref suborigin) => {
self.note_region_origin(suborigin);
}
infer::Subtype(ref trace) => {
let desc = match trace.origin {
infer::Misc(_) => {
@ -1714,6 +1751,17 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
span,
"...so that variable is valid at time of its declaration");
}
infer::ParameterInScope(_, span) => {
self.tcx.sess.span_note(
span,
&format!("...so that a type/lifetime parameter is in scope here"));
}
infer::DataBorrowed(ty, span) => {
self.tcx.sess.span_note(
span,
&format!("...so that the type `{}` is not borrowed for too long",
self.ty_to_string(ty)));
}
infer::ReferenceOutlivesReferent(ty, span) => {
self.tcx.sess.span_note(
span,

View file

@ -35,6 +35,7 @@ use middle::ty_relate::{Relate, RelateResult, TypeRelation};
use rustc_data_structures::unify::{self, UnificationTable};
use std::cell::{RefCell, Ref};
use std::fmt;
use std::rc::Rc;
use syntax::ast;
use syntax::codemap;
use syntax::codemap::{Span, DUMMY_SP};
@ -188,6 +189,8 @@ pub struct TypeTrace<'tcx> {
/// See `error_reporting.rs` for more details
#[derive(Clone, Debug)]
pub enum SubregionOrigin<'tcx> {
RFC1214Subregion(Rc<SubregionOrigin<'tcx>>),
// Arose from a subtyping relation
Subtype(TypeTrace<'tcx>),
@ -229,9 +232,15 @@ pub enum SubregionOrigin<'tcx> {
// Creating a pointer `b` to contents of an upvar
ReborrowUpvar(Span, ty::UpvarId),
// Data with type `Ty<'tcx>` was borrowed
DataBorrowed(Ty<'tcx>, Span),
// (&'a &'b T) where a >= b
ReferenceOutlivesReferent(Ty<'tcx>, Span),
// Type or region parameters must be in scope.
ParameterInScope(ParameterOrigin, Span),
// The type T of an expression E must outlive the lifetime for E.
ExprTypeIsNotInScope(Ty<'tcx>, Span),
@ -260,6 +269,15 @@ pub enum SubregionOrigin<'tcx> {
SafeDestructor(Span),
}
/// Places that type/region parameters can appear.
#[derive(Clone, Copy, Debug)]
pub enum ParameterOrigin {
Path, // foo::bar
MethodCall, // foo.bar() <-- parameters on impl providing bar()
OverloadedOperator, // a + b when overloaded
OverloadedDeref, // *a when overloaded
}
/// Times when we replace late-bound regions with variables:
#[derive(Clone, Copy, Debug)]
pub enum LateBoundRegionConversionTime {
@ -1565,6 +1583,7 @@ impl TypeOrigin {
impl<'tcx> SubregionOrigin<'tcx> {
pub fn span(&self) -> Span {
match *self {
RFC1214Subregion(ref a) => a.span(),
Subtype(ref a) => a.span(),
InfStackClosure(a) => a,
InvokeClosure(a) => a,
@ -1577,7 +1596,9 @@ impl<'tcx> SubregionOrigin<'tcx> {
RelateDefaultParamBound(a, _) => a,
Reborrow(a) => a,
ReborrowUpvar(a, _) => a,
DataBorrowed(_, a) => a,
ReferenceOutlivesReferent(_, a) => a,
ParameterInScope(_, a) => a,
ExprTypeIsNotInScope(_, a) => a,
BindingTypeIsNotValidAtDecl(a) => a,
CallRcvr(a) => a,

View file

@ -25,11 +25,12 @@ use super::{
use fmt_macros::{Parser, Piece, Position};
use middle::infer::InferCtxt;
use middle::ty::{self, ToPredicate, HasTypeFlags, ToPolyTraitRef, TraitRef};
use middle::ty::{self, ToPredicate, HasTypeFlags, ToPolyTraitRef, TraitRef, Ty};
use middle::ty_fold::TypeFoldable;
use std::collections::HashMap;
use std::fmt;
use syntax::codemap::Span;
use syntax::ast;
use syntax::attr::{AttributeMethods, AttrMetaMethods};
pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
@ -54,22 +55,28 @@ fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
}
}
fn is_warning<T>(obligation: &Obligation<T>) -> bool {
obligation.cause.code.is_rfc1214()
}
pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
obligation: &PredicateObligation<'tcx>,
error: &MismatchedProjectionTypes<'tcx>)
{
let predicate =
infcx.resolve_type_vars_if_possible(&obligation.predicate);
// The TyError created by normalize_to_error can end up being unified
// into all obligations: for example, if our obligation is something
// like `$X = <() as Foo<$X>>::Out` and () does not implement Foo<_>,
// then $X will be unified with TyError, but the error still needs to be
// reported.
if !infcx.tcx.sess.has_errors() || !predicate.references_error() {
span_err!(infcx.tcx.sess, obligation.cause.span, E0271,
"type mismatch resolving `{}`: {}",
predicate,
error.err);
span_err_or_warn!(
is_warning(obligation), infcx.tcx.sess, obligation.cause.span, E0271,
"type mismatch resolving `{}`: {}",
predicate,
error.err);
note_obligation_cause(infcx, obligation);
}
}
@ -173,66 +180,93 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
obligation: &PredicateObligation<'tcx>,
error: &SelectionError<'tcx>)
{
let is_warning = is_warning(obligation);
match *error {
SelectionError::Unimplemented => {
match &obligation.cause.code {
&ObligationCauseCode::CompareImplMethodObligation => {
span_err!(infcx.tcx.sess, obligation.cause.span, E0276,
"the requirement `{}` appears on the impl \
method but not on the corresponding trait method",
obligation.predicate);;
}
_ => {
match obligation.predicate {
ty::Predicate::Trait(ref trait_predicate) => {
let trait_predicate =
infcx.resolve_type_vars_if_possible(trait_predicate);
if let ObligationCauseCode::CompareImplMethodObligation = obligation.cause.code {
span_err_or_warn!(
is_warning, infcx.tcx.sess, obligation.cause.span, E0276,
"the requirement `{}` appears on the impl \
method but not on the corresponding trait method",
obligation.predicate);;
} else {
match obligation.predicate {
ty::Predicate::Trait(ref trait_predicate) => {
let trait_predicate =
infcx.resolve_type_vars_if_possible(trait_predicate);
if !infcx.tcx.sess.has_errors() ||
!trait_predicate.references_error() {
let trait_ref = trait_predicate.to_poly_trait_ref();
span_err!(infcx.tcx.sess, obligation.cause.span, E0277,
"the trait `{}` is not implemented for the type `{}`",
trait_ref,
trait_ref.self_ty());
// Check if it has a custom "#[rustc_on_unimplemented]"
// error message, report with that message if it does
let custom_note = report_on_unimplemented(infcx, &trait_ref.0,
obligation.cause.span);
if let Some(s) = custom_note {
infcx.tcx.sess.span_note(obligation.cause.span,
&s);
}
if !infcx.tcx.sess.has_errors() || !trait_predicate.references_error() {
let trait_ref = trait_predicate.to_poly_trait_ref();
span_err_or_warn!(
is_warning, infcx.tcx.sess, obligation.cause.span, E0277,
"the trait `{}` is not implemented for the type `{}`",
trait_ref, trait_ref.self_ty());
// Check if it has a custom "#[rustc_on_unimplemented]"
// error message, report with that message if it does
let custom_note = report_on_unimplemented(infcx, &trait_ref.0,
obligation.cause.span);
if is_warning {
note_obligation_cause(infcx, obligation);
} else if let Some(s) = custom_note {
infcx.tcx.sess.span_note(obligation.cause.span, &s);
} else {
note_obligation_cause(infcx, obligation);
}
}
}
ty::Predicate::Equate(ref predicate) => {
let predicate = infcx.resolve_type_vars_if_possible(predicate);
let err = infcx.equality_predicate(obligation.cause.span,
&predicate).err().unwrap();
span_err!(infcx.tcx.sess, obligation.cause.span, E0278,
"the requirement `{}` is not satisfied (`{}`)",
predicate,
err);
}
ty::Predicate::Equate(ref predicate) => {
let predicate = infcx.resolve_type_vars_if_possible(predicate);
let err = infcx.equality_predicate(obligation.cause.span,
&predicate).err().unwrap();
span_err_or_warn!(
is_warning, infcx.tcx.sess, obligation.cause.span, E0278,
"the requirement `{}` is not satisfied (`{}`)",
predicate,
err);
note_obligation_cause(infcx, obligation);
}
ty::Predicate::RegionOutlives(ref predicate) => {
let predicate = infcx.resolve_type_vars_if_possible(predicate);
let err = infcx.region_outlives_predicate(obligation.cause.span,
&predicate).err().unwrap();
span_err!(infcx.tcx.sess, obligation.cause.span, E0279,
"the requirement `{}` is not satisfied (`{}`)",
predicate,
err);
}
ty::Predicate::RegionOutlives(ref predicate) => {
let predicate = infcx.resolve_type_vars_if_possible(predicate);
let err = infcx.region_outlives_predicate(obligation.cause.span,
&predicate).err().unwrap();
span_err_or_warn!(
is_warning, infcx.tcx.sess, obligation.cause.span, E0279,
"the requirement `{}` is not satisfied (`{}`)",
predicate,
err);
note_obligation_cause(infcx, obligation);
}
ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
let predicate =
infcx.resolve_type_vars_if_possible(&obligation.predicate);
span_err!(infcx.tcx.sess, obligation.cause.span, E0280,
"the requirement `{}` is not satisfied",
predicate);
}
ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
let predicate =
infcx.resolve_type_vars_if_possible(&obligation.predicate);
span_err_or_warn!(
is_warning, infcx.tcx.sess, obligation.cause.span, E0280,
"the requirement `{}` is not satisfied",
predicate);
note_obligation_cause(infcx, obligation);
}
ty::Predicate::ObjectSafe(trait_def_id) => {
report_object_safety_error(infcx.tcx,
obligation.cause.span,
trait_def_id,
is_warning);
note_obligation_cause(infcx, obligation);
}
ty::Predicate::WellFormed(ty) => {
// WF predicates cannot themselves make
// errors. They can only block due to
// ambiguity; otherwise, they always
// degenerate into other obligations
// (which may fail).
infcx.tcx.sess.span_bug(
obligation.cause.span,
&format!("WF predicate not satisfied for {:?}", ty));
}
}
}
@ -242,62 +276,73 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
let expected_trait_ref = infcx.resolve_type_vars_if_possible(&*expected_trait_ref);
let actual_trait_ref = infcx.resolve_type_vars_if_possible(&*actual_trait_ref);
if !actual_trait_ref.self_ty().references_error() {
span_err!(infcx.tcx.sess, obligation.cause.span, E0281,
"type mismatch: the type `{}` implements the trait `{}`, \
but the trait `{}` is required ({})",
expected_trait_ref.self_ty(),
expected_trait_ref,
actual_trait_ref,
e);
note_obligation_cause(infcx, obligation);
span_err_or_warn!(
is_warning, infcx.tcx.sess, obligation.cause.span, E0281,
"type mismatch: the type `{}` implements the trait `{}`, \
but the trait `{}` is required ({})",
expected_trait_ref.self_ty(),
expected_trait_ref,
actual_trait_ref,
e);
note_obligation_cause(infcx, obligation);
}
}
TraitNotObjectSafe(did) => {
span_err!(infcx.tcx.sess, obligation.cause.span, E0038,
"cannot convert to a trait object because trait `{}` is not object-safe",
infcx.tcx.item_path_str(did));
report_object_safety_error(infcx.tcx, obligation.cause.span, did, is_warning);
note_obligation_cause(infcx, obligation);
}
}
}
for violation in object_safety_violations(infcx.tcx, did) {
match violation {
ObjectSafetyViolation::SizedSelf => {
infcx.tcx.sess.span_note(
obligation.cause.span,
"the trait cannot require that `Self : Sized`");
}
pub fn report_object_safety_error<'tcx>(tcx: &ty::ctxt<'tcx>,
span: Span,
trait_def_id: ast::DefId,
is_warning: bool)
{
span_err_or_warn!(
is_warning, tcx.sess, span, E0038,
"the trait `{}` cannot be made into an object",
tcx.item_path_str(trait_def_id));
ObjectSafetyViolation::SupertraitSelf => {
infcx.tcx.sess.span_note(
obligation.cause.span,
"the trait cannot use `Self` as a type parameter \
in the supertrait listing");
}
for violation in object_safety_violations(tcx, trait_def_id) {
match violation {
ObjectSafetyViolation::SizedSelf => {
tcx.sess.span_note(
span,
"the trait cannot require that `Self : Sized`");
}
ObjectSafetyViolation::Method(method,
MethodViolationCode::StaticMethod) => {
infcx.tcx.sess.span_note(
obligation.cause.span,
&format!("method `{}` has no receiver",
method.name));
}
ObjectSafetyViolation::SupertraitSelf => {
tcx.sess.span_note(
span,
"the trait cannot use `Self` as a type parameter \
in the supertrait listing");
}
ObjectSafetyViolation::Method(method,
MethodViolationCode::ReferencesSelf) => {
infcx.tcx.sess.span_note(
obligation.cause.span,
&format!("method `{}` references the `Self` type \
in its arguments or return type",
method.name));
}
ObjectSafetyViolation::Method(method,
MethodViolationCode::StaticMethod) => {
tcx.sess.span_note(
span,
&format!("method `{}` has no receiver",
method.name));
}
ObjectSafetyViolation::Method(method,
MethodViolationCode::Generic) => {
infcx.tcx.sess.span_note(
obligation.cause.span,
&format!("method `{}` has generic type parameters",
method.name));
}
}
ObjectSafetyViolation::Method(method,
MethodViolationCode::ReferencesSelf) => {
tcx.sess.span_note(
span,
&format!("method `{}` references the `Self` type \
in its arguments or return type",
method.name));
}
ObjectSafetyViolation::Method(method,
MethodViolationCode::Generic) => {
tcx.sess.span_note(
span,
&format!("method `{}` has generic type parameters",
method.name));
}
}
}
@ -342,14 +387,11 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
infcx.tcx.lang_items.sized_trait()
.map_or(false, |sized_id| sized_id == trait_ref.def_id())
{
span_err!(infcx.tcx.sess, obligation.cause.span, E0282,
"unable to infer enough type information about `{}`; \
type annotations or generic parameter binding required",
self_ty);
need_type_info(infcx, obligation.cause.span, self_ty);
} else {
span_err!(infcx.tcx.sess, obligation.cause.span, E0283,
"type annotations required: cannot resolve `{}`",
predicate);;
predicate);
note_obligation_cause(infcx, obligation);
}
}
@ -366,6 +408,14 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
}
}
ty::Predicate::WellFormed(ty) => {
// Same hacky approach as above to avoid deluging user
// with error messages.
if !ty.references_error() && !infcx.tcx.sess.has_errors() {
need_type_info(infcx, obligation.cause.span, ty);
}
}
_ => {
if !infcx.tcx.sess.has_errors() {
span_err!(infcx.tcx.sess, obligation.cause.span, E0284,
@ -377,6 +427,16 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
}
}
fn need_type_info<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
span: Span,
ty: Ty<'tcx>)
{
span_err!(infcx.tcx.sess, span, E0282,
"unable to infer enough type information about `{}`; \
type annotations or generic parameter binding required",
ty);
}
fn note_obligation_cause<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
obligation: &Obligation<'tcx, T>)
where T: fmt::Display
@ -396,6 +456,27 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
let tcx = infcx.tcx;
match *cause_code {
ObligationCauseCode::MiscObligation => { }
ObligationCauseCode::RFC1214(ref subcode) => {
tcx.sess.note_rfc_1214(cause_span);
note_obligation_cause_code(infcx, predicate, cause_span, subcode);
}
ObligationCauseCode::SliceOrArrayElem => {
tcx.sess.span_note(
cause_span,
&format!("slice and array elements must have `Sized` type"));
}
ObligationCauseCode::ProjectionWf(data) => {
tcx.sess.span_note(
cause_span,
&format!("required so that the projection `{}` is well-formed",
data));
}
ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => {
tcx.sess.span_note(
cause_span,
&format!("required so that reference `{}` does not outlive its referent",
ref_ty));
}
ObligationCauseCode::ItemObligation(item_def_id) => {
let item_name = tcx.item_path_str(item_def_id);
tcx.sess.span_note(

View file

@ -27,6 +27,7 @@ use syntax::codemap::{Span, DUMMY_SP};
pub use self::error_reporting::report_fulfillment_errors;
pub use self::error_reporting::report_overflow_error;
pub use self::error_reporting::report_selection_error;
pub use self::error_reporting::report_object_safety_error;
pub use self::error_reporting::suggest_new_overflow_limit;
pub use self::coherence::orphan_check;
pub use self::coherence::overlapping_impls;
@ -80,7 +81,7 @@ pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
/// Why did we incur this obligation? Used for error reporting.
#[derive(Clone, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ObligationCause<'tcx> {
pub span: Span,
@ -95,15 +96,27 @@ pub struct ObligationCause<'tcx> {
pub code: ObligationCauseCode<'tcx>
}
#[derive(Clone, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ObligationCauseCode<'tcx> {
/// Not well classified or should be obvious from span.
MiscObligation,
/// Obligation that triggers warning until RFC 1214 is fully in place.
RFC1214(Rc<ObligationCauseCode<'tcx>>),
/// This is the trait reference from the given projection
SliceOrArrayElem,
/// This is the trait reference from the given projection
ProjectionWf(ty::ProjectionTy<'tcx>),
/// In an impl of trait X for type Y, type Y must
/// also implement all supertraits of X.
ItemObligation(ast::DefId),
/// A type like `&'a T` is WF only if `T: 'a`.
ReferenceOutlivesReferent(Ty<'tcx>),
/// Obligation incurred due to an object cast.
ObjectCastObligation(/* Object type */ Ty<'tcx>),
@ -124,7 +137,6 @@ pub enum ObligationCauseCode<'tcx> {
// static items must have `Sync` type
SharedStatic,
BuiltinDerivedObligation(DerivedObligationCause<'tcx>),
ImplDerivedObligation(DerivedObligationCause<'tcx>),
@ -132,7 +144,7 @@ pub enum ObligationCauseCode<'tcx> {
CompareImplMethodObligation,
}
#[derive(Clone, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct DerivedObligationCause<'tcx> {
/// The trait reference of the parent obligation that led to the
/// current obligation. Note that only trait obligations lead to
@ -516,6 +528,15 @@ impl<'tcx> ObligationCause<'tcx> {
}
}
impl<'tcx> ObligationCauseCode<'tcx> {
pub fn is_rfc1214(&self) -> bool {
match *self {
ObligationCauseCode::RFC1214(..) => true,
_ => false,
}
}
}
impl<'tcx, N> Vtable<'tcx, N> {
pub fn nested_obligations(self) -> Vec<N> {
match self {

View file

@ -2920,13 +2920,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// chain. Ideally, we should have a way to configure this either
// by using -Z verbose or just a CLI argument.
if obligation.recursion_depth >= 0 {
let derived_cause = DerivedObligationCause {
parent_trait_ref: obligation.predicate.to_poly_trait_ref(),
parent_code: Rc::new(obligation.cause.code.clone()),
let derived_code = match obligation.cause.code {
ObligationCauseCode::RFC1214(ref base_code) => {
let derived_cause = DerivedObligationCause {
parent_trait_ref: obligation.predicate.to_poly_trait_ref(),
parent_code: base_code.clone(),
};
ObligationCauseCode::RFC1214(Rc::new(variant(derived_cause)))
}
_ => {
let derived_cause = DerivedObligationCause {
parent_trait_ref: obligation.predicate.to_poly_trait_ref(),
parent_code: Rc::new(obligation.cause.code.clone())
};
variant(derived_cause)
}
};
ObligationCause::new(obligation.cause.span,
obligation.cause.body_id,
variant(derived_cause))
ObligationCause::new(obligation.cause.span, obligation.cause.body_id, derived_code)
} else {
obligation.cause.clone()
}

View file

@ -90,6 +90,13 @@ impl Session {
}
self.diagnostic().handler().fatal(msg)
}
pub fn span_err_or_warn(&self, is_warning: bool, sp: Span, msg: &str) {
if is_warning {
self.span_warn(sp, msg);
} else {
self.span_err(sp, msg);
}
}
pub fn span_err(&self, sp: Span, msg: &str) {
if self.opts.treat_err_as_bug {
self.span_bug(sp, msg);
@ -99,6 +106,13 @@ impl Session {
None => self.diagnostic().span_err(sp, msg)
}
}
pub fn note_rfc_1214(&self, span: Span) {
self.span_note(
span,
&format!("this warning results from recent bug fixes and clarifications; \
it will become a HARD ERROR in the next release. \
See RFC 1214 for details."));
}
pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) {
if self.opts.treat_err_as_bug {
self.span_bug(sp, msg);

View file

@ -30,6 +30,18 @@ macro_rules! span_err {
})
}
#[macro_export]
macro_rules! span_err_or_warn {
($is_warning:expr, $session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
__diagnostic_used!($code);
if $is_warning {
$session.span_warn_with_code($span, &format!($($message)*), stringify!($code))
} else {
$session.span_err_with_code($span, &format!($($message)*), stringify!($code))
}
})
}
#[macro_export]
macro_rules! span_warn {
($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({