Refactor compare_impl_method to use all bounds

Refactor compare_impl_method into its own file. Modify the
code to stop comparing individual parameter bounds.
Instead we now use the predicates list attached to the trait
and implementation generics. This ensures consistency even
when bounds are declared in different places (i.e on
a parameter vs. in a where clause).
This commit is contained in:
Jared Roesch 2015-01-14 13:43:17 -08:00
parent 896cb36eca
commit 6a66b32270
13 changed files with 571 additions and 574 deletions

View file

@ -19,7 +19,7 @@ use util::ppaux::Repr;
use std::fmt;
use std::slice::Iter;
use std::vec::Vec;
use std::vec::{Vec, IntoIter};
use syntax::codemap::{Span, DUMMY_SP};
///////////////////////////////////////////////////////////////////////////
@ -397,6 +397,10 @@ impl<T> VecPerParamSpace<T> {
self.content.iter()
}
pub fn into_iter(self) -> IntoIter<T> {
self.content.into_iter()
}
pub fn iter_enumerated<'a>(&'a self) -> EnumeratedItems<'a,T> {
EnumeratedItems::new(self)
}

View file

@ -161,66 +161,80 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
note_obligation_cause(infcx, obligation);
}
SelectionError::Unimplemented => {
match obligation.predicate {
ty::Predicate::Trait(ref trait_predicate) => {
let trait_predicate =
infcx.resolve_type_vars_if_possible(trait_predicate);
if !trait_predicate.references_error() {
let trait_ref = trait_predicate.to_poly_trait_ref();
infcx.tcx.sess.span_err(
obligation.cause.span,
format!(
"the trait `{}` is not implemented for the type `{}`",
trait_ref.user_string(infcx.tcx),
trait_ref.self_ty().user_string(infcx.tcx)).as_slice());
// 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.as_slice());
match &obligation.cause.code {
&ObligationCauseCode::CompareImplMethodObligation => {
infcx.tcx.sess.span_err(
obligation.cause.span,
format!(
"the requirement `{}` appears on the impl \
method but not on the corresponding trait method",
obligation.predicate.user_string(infcx.tcx)).as_slice());
}
_ => {
match obligation.predicate {
ty::Predicate::Trait(ref trait_predicate) => {
let trait_predicate =
infcx.resolve_type_vars_if_possible(trait_predicate);
if !trait_predicate.references_error() {
let trait_ref = trait_predicate.to_poly_trait_ref();
infcx.tcx.sess.span_err(
obligation.cause.span,
format!(
"the trait `{}` is not implemented for the type `{}`",
trait_ref.user_string(infcx.tcx),
trait_ref.self_ty().user_string(infcx.tcx)).as_slice());
// 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.as_slice());
}
}
}
ty::Predicate::Equate(ref predicate) => {
let predicate = infcx.resolve_type_vars_if_possible(predicate);
let err = infcx.equality_predicate(obligation.cause.span,
&predicate).unwrap_err();
infcx.tcx.sess.span_err(
obligation.cause.span,
format!(
"the requirement `{}` is not satisfied (`{}`)",
predicate.user_string(infcx.tcx),
ty::type_err_to_str(infcx.tcx, &err)).as_slice());
}
ty::Predicate::RegionOutlives(ref predicate) => {
let predicate = infcx.resolve_type_vars_if_possible(predicate);
let err = infcx.region_outlives_predicate(obligation.cause.span,
&predicate).unwrap_err();
infcx.tcx.sess.span_err(
obligation.cause.span,
format!(
"the requirement `{}` is not satisfied (`{}`)",
predicate.user_string(infcx.tcx),
ty::type_err_to_str(infcx.tcx, &err)).as_slice());
}
ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
let predicate =
infcx.resolve_type_vars_if_possible(&obligation.predicate);
infcx.tcx.sess.span_err(
obligation.cause.span,
format!(
"the requirement `{}` is not satisfied",
predicate.user_string(infcx.tcx)).as_slice());
}
}
}
ty::Predicate::Equate(ref predicate) => {
let predicate = infcx.resolve_type_vars_if_possible(predicate);
let err = infcx.equality_predicate(obligation.cause.span,
&predicate).unwrap_err();
infcx.tcx.sess.span_err(
obligation.cause.span,
format!(
"the requirement `{}` is not satisfied (`{}`)",
predicate.user_string(infcx.tcx),
ty::type_err_to_str(infcx.tcx, &err)).as_slice());
}
ty::Predicate::RegionOutlives(ref predicate) => {
let predicate = infcx.resolve_type_vars_if_possible(predicate);
let err = infcx.region_outlives_predicate(obligation.cause.span,
&predicate).unwrap_err();
infcx.tcx.sess.span_err(
obligation.cause.span,
format!(
"the requirement `{}` is not satisfied (`{}`)",
predicate.user_string(infcx.tcx),
ty::type_err_to_str(infcx.tcx, &err)).as_slice());
}
ty::Predicate::Projection(..) |
ty::Predicate::TypeOutlives(..) => {
let predicate =
infcx.resolve_type_vars_if_possible(&obligation.predicate);
infcx.tcx.sess.span_err(
obligation.cause.span,
format!(
"the requirement `{}` is not satisfied",
predicate.user_string(infcx.tcx)).as_slice());
}
}
}
OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => {
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);
@ -229,12 +243,12 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
obligation.cause.span,
format!(
"type mismatch: the type `{}` implements the trait `{}`, \
but the trait `{}` is required ({})",
but the trait `{}` is required ({})",
expected_trait_ref.self_ty().user_string(infcx.tcx),
expected_trait_ref.user_string(infcx.tcx),
actual_trait_ref.user_string(infcx.tcx),
ty::type_err_to_str(infcx.tcx, e)).as_slice());
note_obligation_cause(infcx, obligation);
note_obligation_cause(infcx, obligation);
}
}
}
@ -330,7 +344,7 @@ fn note_obligation_cause<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
}
fn note_obligation_cause_code<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
_predicate: &ty::Predicate<'tcx>,
predicate: &ty::Predicate<'tcx>,
cause_span: Span,
cause_code: &ObligationCauseCode<'tcx>)
{
@ -417,6 +431,12 @@ fn note_obligation_cause_code<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
let parent_predicate = parent_trait_ref.as_predicate();
note_obligation_cause_code(infcx, &parent_predicate, cause_span, &*data.parent_code);
}
ObligationCauseCode::CompareImplMethodObligation => {
span_note!(tcx.sess, cause_span,
"the requirement `{}` appears on the impl method\
but not on the corresponding trait method",
predicate.user_string(infcx.tcx));
}
}
}

View file

@ -121,9 +121,12 @@ pub enum ObligationCauseCode<'tcx> {
// static items must have `Sync` type
SharedStatic,
BuiltinDerivedObligation(DerivedObligationCause<'tcx>),
ImplDerivedObligation(DerivedObligationCause<'tcx>),
CompareImplMethodObligation,
}
#[derive(Clone)]

View file

@ -7341,3 +7341,15 @@ impl<'tcx> Repr<'tcx> for field<'tcx> {
self.mt.repr(tcx))
}
}
impl<'a, 'tcx> Repr<'tcx> for ParameterEnvironment<'a, 'tcx> {
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
format!("ParameterEnvironment(\
free_substs={}, \
implicit_region_bound={}, \
caller_bounds={})",
self.free_substs.repr(tcx),
self.implicit_region_bound.repr(tcx),
self.caller_bounds.repr(tcx))
}
}

View file

@ -564,6 +564,18 @@ impl<'tcx> TypeFoldable<'tcx> for ty::UnboxedClosureUpvar<'tcx> {
}
}
impl<'a, 'tcx> TypeFoldable<'tcx> for ty::ParameterEnvironment<'a, 'tcx> where 'tcx: 'a {
fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ParameterEnvironment<'a, 'tcx> {
ty::ParameterEnvironment {
tcx: self.tcx,
free_substs: self.free_substs.fold_with(folder),
implicit_region_bound: self.implicit_region_bound.fold_with(folder),
caller_bounds: self.caller_bounds.fold_with(folder),
selection_cache: traits::SelectionCache::new(),
}
}
}
///////////////////////////////////////////////////////////////////////////
// "super" routines: these are the default implementations for TypeFolder.
//