Rework normalization so that it works recursively, since the types extracted from an impl are potentially in need of normalization. This also lays groundwork for further cleanup in other areas by disconnecting normalization from the fulfillment context.

This commit is contained in:
Niko Matsakis 2014-12-30 17:42:02 -05:00
parent 0aa7ba9f5e
commit 6cb425d964
13 changed files with 578 additions and 378 deletions

View File

@ -77,13 +77,7 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
"overflow evaluating the requirement `{}`", "overflow evaluating the requirement `{}`",
predicate.user_string(infcx.tcx)).as_slice()); predicate.user_string(infcx.tcx)).as_slice());
let current_limit = infcx.tcx.sess.recursion_limit.get(); suggest_new_overflow_limit(infcx, obligation.cause.span);
let suggested_limit = current_limit * 2;
infcx.tcx.sess.span_note(
obligation.cause.span,
format!(
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
suggested_limit)[]);
note_obligation_cause(infcx, obligation); note_obligation_cause(infcx, obligation);
} }
@ -165,73 +159,76 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
// ambiguous impls. The latter *ought* to be a // ambiguous impls. The latter *ought* to be a
// coherence violation, so we don't report it here. // coherence violation, so we don't report it here.
let trait_ref = match obligation.predicate { let predicate = infcx.resolve_type_vars_if_possible(&obligation.predicate);
ty::Predicate::Trait(ref trait_predicate) => {
infcx.resolve_type_vars_if_possible(
&trait_predicate.to_poly_trait_ref())
}
_ => {
infcx.tcx.sess.span_bug(
obligation.cause.span,
format!("ambiguity from something other than a trait: {}",
obligation.predicate.repr(infcx.tcx)).as_slice());
}
};
let self_ty = trait_ref.self_ty(); debug!("maybe_report_ambiguity(predicate={}, obligation={})",
predicate.repr(infcx.tcx),
debug!("maybe_report_ambiguity(trait_ref={}, self_ty={}, obligation={})",
trait_ref.repr(infcx.tcx),
self_ty.repr(infcx.tcx),
obligation.repr(infcx.tcx)); obligation.repr(infcx.tcx));
let all_types = &trait_ref.substs().types;
if all_types.iter().any(|&t| ty::type_is_error(t)) { match predicate {
} else if all_types.iter().any(|&t| ty::type_needs_infer(t)) { ty::Predicate::Trait(ref data) => {
// This is kind of a hack: it frequently happens that some earlier let trait_ref = data.to_poly_trait_ref();
// error prevents types from being fully inferred, and then we get let self_ty = trait_ref.self_ty();
// a bunch of uninteresting errors saying something like "<generic let all_types = &trait_ref.substs().types;
// #0> doesn't implement Sized". It may even be true that we if all_types.iter().any(|&t| ty::type_is_error(t)) {
// could just skip over all checks where the self-ty is an } else if all_types.iter().any(|&t| ty::type_needs_infer(t)) {
// inference variable, but I was afraid that there might be an // This is kind of a hack: it frequently happens that some earlier
// inference variable created, registered as an obligation, and // error prevents types from being fully inferred, and then we get
// then never forced by writeback, and hence by skipping here we'd // a bunch of uninteresting errors saying something like "<generic
// be ignoring the fact that we don't KNOW the type works // #0> doesn't implement Sized". It may even be true that we
// out. Though even that would probably be harmless, given that // could just skip over all checks where the self-ty is an
// we're only talking about builtin traits, which are known to be // inference variable, but I was afraid that there might be an
// inhabited. But in any case I just threw in this check for // inference variable created, registered as an obligation, and
// has_errors() to be sure that compilation isn't happening // then never forced by writeback, and hence by skipping here we'd
// anyway. In that case, why inundate the user. // be ignoring the fact that we don't KNOW the type works
if !infcx.tcx.sess.has_errors() { // out. Though even that would probably be harmless, given that
if infcx.tcx.lang_items.sized_trait() // we're only talking about builtin traits, which are known to be
.map_or(false, |sized_id| sized_id == trait_ref.def_id()) { // inhabited. But in any case I just threw in this check for
infcx.tcx.sess.span_err( // has_errors() to be sure that compilation isn't happening
// anyway. In that case, why inundate the user.
if !infcx.tcx.sess.has_errors() {
if
infcx.tcx.lang_items.sized_trait()
.map_or(false, |sized_id| sized_id == trait_ref.def_id())
{
infcx.tcx.sess.span_err(
obligation.cause.span,
format!(
"unable to infer enough type information about `{}`; \
type annotations required",
self_ty.user_string(infcx.tcx)).as_slice());
} else {
infcx.tcx.sess.span_err(
obligation.cause.span,
format!(
"type annotations required: cannot resolve `{}`",
predicate.user_string(infcx.tcx)).as_slice());
note_obligation_cause(infcx, obligation);
}
}
} else if !infcx.tcx.sess.has_errors() {
// Ambiguity. Coherence should have reported an error.
infcx.tcx.sess.span_bug(
obligation.cause.span, obligation.cause.span,
format!( format!(
"unable to infer enough type information about `{}`; type annotations \ "coherence failed to report ambiguity: \
required", cannot locate the impl of the trait `{}` for \
self_ty.user_string(infcx.tcx)).as_slice()); the type `{}`",
} else {
infcx.tcx.sess.span_err(
obligation.cause.span,
format!(
"unable to infer enough type information to \
locate the impl of the trait `{}` for \
the type `{}`; type annotations required",
trait_ref.user_string(infcx.tcx), trait_ref.user_string(infcx.tcx),
self_ty.user_string(infcx.tcx)).as_slice()); self_ty.user_string(infcx.tcx)).as_slice());
}
}
_ => {
if !infcx.tcx.sess.has_errors() {
infcx.tcx.sess.span_err(
obligation.cause.span,
format!(
"type annotations required: cannot resolve `{}`",
predicate.user_string(infcx.tcx)).as_slice());
note_obligation_cause(infcx, obligation); note_obligation_cause(infcx, obligation);
} }
} }
} else if !infcx.tcx.sess.has_errors() {
// Ambiguity. Coherence should have reported an error.
infcx.tcx.sess.span_bug(
obligation.cause.span,
format!(
"coherence failed to report ambiguity: \
cannot locate the impl of the trait `{}` for \
the type `{}`",
trait_ref.user_string(infcx.tcx),
self_ty.user_string(infcx.tcx)).as_slice());
} }
} }
@ -335,3 +332,12 @@ fn note_obligation_cause_code<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
} }
} }
pub fn suggest_new_overflow_limit(infcx: &InferCtxt, span: Span) {
let current_limit = infcx.tcx.sess.recursion_limit.get();
let suggested_limit = current_limit * 2;
infcx.tcx.sess.span_note(
span,
format!(
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
suggested_limit)[]);
}

View File

@ -8,9 +8,9 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use middle::infer::{mod, InferCtxt}; use middle::infer::{InferCtxt};
use middle::mem_categorization::Typer; use middle::mem_categorization::Typer;
use middle::ty::{mod, AsPredicate, RegionEscape, Ty, ToPolyTraitRef}; use middle::ty::{mod, RegionEscape, Ty};
use std::collections::HashSet; use std::collections::HashSet;
use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::default::Default; use std::default::Default;
@ -23,7 +23,6 @@ use super::CodeAmbiguity;
use super::CodeProjectionError; use super::CodeProjectionError;
use super::CodeSelectionError; use super::CodeSelectionError;
use super::FulfillmentError; use super::FulfillmentError;
use super::Obligation;
use super::ObligationCause; use super::ObligationCause;
use super::PredicateObligation; use super::PredicateObligation;
use super::project; use super::project;
@ -110,6 +109,8 @@ impl<'tcx> FulfillmentContext<'tcx> {
/// `projection_ty` again. /// `projection_ty` again.
pub fn normalize_projection_type<'a>(&mut self, pub fn normalize_projection_type<'a>(&mut self,
infcx: &InferCtxt<'a,'tcx>, infcx: &InferCtxt<'a,'tcx>,
param_env: &ty::ParameterEnvironment<'tcx>,
typer: &Typer<'tcx>,
projection_ty: ty::ProjectionTy<'tcx>, projection_ty: ty::ProjectionTy<'tcx>,
cause: ObligationCause<'tcx>) cause: ObligationCause<'tcx>)
-> Ty<'tcx> -> Ty<'tcx>
@ -121,18 +122,16 @@ impl<'tcx> FulfillmentContext<'tcx> {
// FIXME(#20304) -- cache // FIXME(#20304) -- cache
let ty_var = infcx.next_ty_var(); let mut selcx = SelectionContext::new(infcx, param_env, typer);
let projection = let normalized = project::normalize_projection_type(&mut selcx, projection_ty, cause, 0);
ty::Binder(ty::ProjectionPredicate {
projection_ty: projection_ty,
ty: ty_var
});
let obligation = Obligation::new(cause, projection.as_predicate());
self.register_predicate(infcx, obligation);
debug!("normalize_associated_type: result={}", ty_var.repr(infcx.tcx)); for obligation in normalized.obligations.into_iter() {
self.register_predicate_obligation(infcx, obligation);
}
ty_var debug!("normalize_associated_type: result={}", normalized.value.repr(infcx.tcx));
normalized.value
} }
pub fn register_builtin_bound<'a>(&mut self, pub fn register_builtin_bound<'a>(&mut self,
@ -143,7 +142,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
{ {
match predicate_for_builtin_bound(infcx.tcx, cause, builtin_bound, 0, ty) { match predicate_for_builtin_bound(infcx.tcx, cause, builtin_bound, 0, ty) {
Ok(predicate) => { Ok(predicate) => {
self.register_predicate(infcx, predicate); self.register_predicate_obligation(infcx, predicate);
} }
Err(ErrorReported) => { } Err(ErrorReported) => { }
} }
@ -158,10 +157,14 @@ impl<'tcx> FulfillmentContext<'tcx> {
register_region_obligation(infcx.tcx, t_a, r_b, cause, &mut self.region_obligations); register_region_obligation(infcx.tcx, t_a, r_b, cause, &mut self.region_obligations);
} }
pub fn register_predicate<'a>(&mut self, pub fn register_predicate_obligation<'a>(&mut self,
infcx: &InferCtxt<'a,'tcx>, infcx: &InferCtxt<'a,'tcx>,
obligation: PredicateObligation<'tcx>) obligation: PredicateObligation<'tcx>)
{ {
// this helps to reduce duplicate errors, as well as making
// debug output much nicer to read and so on.
let obligation = infcx.resolve_type_vars_if_possible(&obligation);
if !self.duplicate_set.insert(obligation.predicate.clone()) { if !self.duplicate_set.insert(obligation.predicate.clone()) {
debug!("register_predicate({}) -- already seen, skip", obligation.repr(infcx.tcx)); debug!("register_predicate({}) -- already seen, skip", obligation.repr(infcx.tcx));
return; return;
@ -290,7 +293,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
// Now go through all the successful ones, // Now go through all the successful ones,
// registering any nested obligations for the future. // registering any nested obligations for the future.
for new_obligation in new_obligations.into_iter() { for new_obligation in new_obligations.into_iter() {
self.register_predicate(selcx.infcx(), new_obligation); self.register_predicate_obligation(selcx.infcx(), new_obligation);
} }
} }
@ -398,104 +401,18 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
project_obligation.repr(tcx), project_obligation.repr(tcx),
result.repr(tcx)); result.repr(tcx));
match result { match result {
Ok(()) => { Ok(Some(obligations)) => {
new_obligations.extend(obligations.into_iter());
true true
} }
Err(project::ProjectionError::TooManyCandidates) => { Ok(None) => {
// Without more type information, we can't say much.
false false
} }
Err(project::ProjectionError::NoCandidate) => { Err(err) => {
// This means that we have a type like `<T as
// Trait>::name = U` but we couldn't find any more
// information. This could just be that we're in a
// function like:
//
// fn foo<T:Trait>(...)
//
// in which case this is not an error. But it
// might also mean we're in a situation where we
// don't actually know that `T : Trait` holds,
// which would be weird (e.g., if `T` was not a
// parameter type but a normal type, like `int`).
//
// So what we do is to (1) add a requirement that
// `T : Trait` (just in case) and (2) try to unify
// `U` with `<T as Trait>::name`.
if !ty::binds_late_bound_regions(selcx.tcx(), data) {
// Check that `T : Trait` holds.
let trait_ref = data.to_poly_trait_ref();
new_obligations.push(obligation.with(trait_ref.as_predicate()));
// Fallback to `<T as Trait>::name`. If this
// fails, then the output must be at least
// somewhat constrained, and we cannot verify
// that constraint, so yield an error.
let ty_projection = ty::mk_projection(tcx,
trait_ref.0.clone(),
data.0.projection_ty.item_name);
debug!("process_predicate: falling back to projection {}",
ty_projection.repr(selcx.tcx()));
match infer::mk_eqty(selcx.infcx(),
true,
infer::EquatePredicate(obligation.cause.span),
ty_projection,
data.0.ty) {
Ok(()) => { }
Err(_) => {
debug!("process_predicate: fallback failed to unify; error");
errors.push(
FulfillmentError::new(
obligation.clone(),
CodeSelectionError(Unimplemented)));
}
}
true
} else {
// If we have something like
//
// for<'a> <T<'a> as Trait>::name == &'a int
//
// there is no "canonical form" for us to
// make, so just report the lack of candidates
// as an error.
debug!("process_predicate: can't fallback, higher-ranked");
errors.push(
FulfillmentError::new(
obligation.clone(),
CodeSelectionError(Unimplemented)));
true
}
}
Err(project::ProjectionError::MismatchedTypes(e)) => {
errors.push( errors.push(
FulfillmentError::new( FulfillmentError::new(
obligation.clone(), obligation.clone(),
CodeProjectionError(e))); CodeProjectionError(err)));
true
}
Err(project::ProjectionError::TraitSelectionError(_)) => {
// There was an error matching `T : Trait` (which
// is a pre-requisite for `<T as Trait>::Name`
// being valid). We could just report the error
// now, but that tends to lead to double error
// reports for the user (one for the obligation `T
// : Trait`, typically incurred somewhere else,
// and one from here). Instead, we'll create the
// `T : Trait` obligation and add THAT as a
// requirement. This will (eventually) trigger the
// same error, but it will also wind up flagged as
// a duplicate if another requirement that `T :
// Trait` arises from somewhere else.
let trait_predicate = data.to_poly_trait_ref();
let trait_obligation = obligation.with(trait_predicate.as_predicate());
new_obligations.push(trait_obligation);
true true
} }
} }

View File

@ -27,8 +27,8 @@ use util::ppaux::Repr;
pub use self::error_reporting::report_fulfillment_errors; pub use self::error_reporting::report_fulfillment_errors;
pub use self::fulfill::{FulfillmentContext, RegionObligation}; pub use self::fulfill::{FulfillmentContext, RegionObligation};
pub use self::project::MismatchedProjectionTypes; pub use self::project::MismatchedProjectionTypes;
pub use self::project::project_type; pub use self::project::normalize;
pub use self::project::ProjectionResult; pub use self::project::Normalized;
pub use self::select::SelectionContext; pub use self::select::SelectionContext;
pub use self::select::SelectionCache; pub use self::select::SelectionCache;
pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch}; pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
@ -320,6 +320,16 @@ impl<'tcx,O> Obligation<'tcx,O> {
predicate: trait_ref } predicate: trait_ref }
} }
fn with_depth(cause: ObligationCause<'tcx>,
recursion_depth: uint,
trait_ref: O)
-> Obligation<'tcx, O>
{
Obligation { cause: cause,
recursion_depth: recursion_depth,
predicate: trait_ref }
}
pub fn misc(span: Span, body_id: ast::NodeId, trait_ref: O) -> Obligation<'tcx, O> { pub fn misc(span: Span, body_id: ast::NodeId, trait_ref: O) -> Obligation<'tcx, O> {
Obligation::new(ObligationCause::misc(span, body_id), trait_ref) Obligation::new(ObligationCause::misc(span, body_id), trait_ref)
} }

View File

@ -12,6 +12,8 @@
use super::elaborate_predicates; use super::elaborate_predicates;
use super::Obligation; use super::Obligation;
use super::ObligationCause;
use super::Overflow;
use super::PredicateObligation; use super::PredicateObligation;
use super::SelectionContext; use super::SelectionContext;
use super::SelectionError; use super::SelectionError;
@ -19,7 +21,8 @@ use super::VtableImplData;
use middle::infer; use middle::infer;
use middle::subst::Subst; use middle::subst::Subst;
use middle::ty::{mod, AsPredicate, ToPolyTraitRef, Ty}; use middle::ty::{mod, AsPredicate, RegionEscape, HasProjectionTypes, ToPolyTraitRef, Ty};
use middle::ty_fold::{mod, TypeFoldable, TypeFolder};
use util::ppaux::Repr; use util::ppaux::Repr;
pub type PolyProjectionObligation<'tcx> = pub type PolyProjectionObligation<'tcx> =
@ -31,21 +34,11 @@ pub type ProjectionObligation<'tcx> =
pub type ProjectionTyObligation<'tcx> = pub type ProjectionTyObligation<'tcx> =
Obligation<'tcx, ty::ProjectionTy<'tcx>>; Obligation<'tcx, ty::ProjectionTy<'tcx>>;
/// When attempting to resolve `<T as TraitRef>::Name == U`... /// When attempting to resolve `<T as TraitRef>::Name` ...
pub enum ProjectionError<'tcx> { pub enum ProjectionTyError<'tcx> {
/// ...we could not find any helpful information on what `Name`
/// might be. This could occur, for example, if there is a where
/// clause `T : TraitRef` but not `T : TraitRef<Name=V>`. When
/// normalizing, this case is where we opt to normalize back to
/// the projection type `<T as TraitRef>::Name`.
NoCandidate,
/// ...we found multiple sources of information and couldn't resolve the ambiguity. /// ...we found multiple sources of information and couldn't resolve the ambiguity.
TooManyCandidates, TooManyCandidates,
/// ...`<T as TraitRef::Name>` ws resolved to some type `V` that failed to unify with `U`
MismatchedTypes(MismatchedProjectionTypes<'tcx>),
/// ...an error occurred matching `T : TraitRef` /// ...an error occurred matching `T : TraitRef`
TraitSelectionError(SelectionError<'tcx>), TraitSelectionError(SelectionError<'tcx>),
} }
@ -55,8 +48,6 @@ pub struct MismatchedProjectionTypes<'tcx> {
pub err: ty::type_err<'tcx> pub err: ty::type_err<'tcx>
} }
pub type ProjectionResult<'tcx, T> = Result<T, ProjectionError<'tcx>>;
enum ProjectionTyCandidate<'tcx> { enum ProjectionTyCandidate<'tcx> {
ParamEnv(ty::PolyProjectionPredicate<'tcx>), ParamEnv(ty::PolyProjectionPredicate<'tcx>),
Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>), Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>),
@ -70,24 +61,43 @@ struct ProjectionTyCandidateSet<'tcx> {
pub fn poly_project_and_unify_type<'cx,'tcx>( pub fn poly_project_and_unify_type<'cx,'tcx>(
selcx: &mut SelectionContext<'cx,'tcx>, selcx: &mut SelectionContext<'cx,'tcx>,
obligation: &PolyProjectionObligation<'tcx>) obligation: &PolyProjectionObligation<'tcx>)
-> ProjectionResult<'tcx, ()> -> Result<Option<Vec<PredicateObligation<'tcx>>>, MismatchedProjectionTypes<'tcx>>
{ {
debug!("poly_project(obligation={})", debug!("poly_project(obligation={})",
obligation.repr(selcx.tcx())); obligation.repr(selcx.tcx()));
let infcx = selcx.infcx(); let infcx = selcx.infcx();
let result = infcx.try(|snapshot| {
infcx.try(|snapshot| {
let (skol_predicate, skol_map) = let (skol_predicate, skol_map) =
infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot); infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot);
let skol_obligation = obligation.with(skol_predicate); let skol_obligation = obligation.with(skol_predicate);
let () = try!(project_and_unify_type(selcx, &skol_obligation)); match project_and_unify_type(selcx, &skol_obligation) {
match infcx.leak_check(&skol_map, snapshot) { Ok(Some(obligations)) => {
Ok(()) => Ok(()), match infcx.leak_check(&skol_map, snapshot) {
Err(e) => Err(ProjectionError::MismatchedTypes(MismatchedProjectionTypes{err: e})), Ok(()) => Ok(infcx.plug_leaks(skol_map, snapshot, &obligations)),
Err(e) => Err(Some(MismatchedProjectionTypes { err: e })),
}
}
Ok(None) => {
// Signal ambiguity using Err just so that infcx.try()
// rolls back the snapshot. We adapt below.
Err(None)
}
Err(e) => {
Err(Some(e))
}
} }
}) });
// Above, we use Err(None) to signal ambiguity so that the
// snapshot will be rolled back. But here, we want to translate to
// Ok(None). Kind of weird.
match result {
Ok(obligations) => Ok(Some(obligations)),
Err(None) => Ok(None),
Err(Some(e)) => Err(e),
}
} }
/// Compute result of projecting an associated type and unify it with /// Compute result of projecting an associated type and unify it with
@ -95,48 +105,281 @@ pub fn poly_project_and_unify_type<'cx,'tcx>(
pub fn project_and_unify_type<'cx,'tcx>( pub fn project_and_unify_type<'cx,'tcx>(
selcx: &mut SelectionContext<'cx,'tcx>, selcx: &mut SelectionContext<'cx,'tcx>,
obligation: &ProjectionObligation<'tcx>) obligation: &ProjectionObligation<'tcx>)
-> ProjectionResult<'tcx, ()> -> Result<Option<Vec<PredicateObligation<'tcx>>>, MismatchedProjectionTypes<'tcx>>
{ {
debug!("project_and_unify(obligation={})", debug!("project_and_unify(obligation={})",
obligation.repr(selcx.tcx())); obligation.repr(selcx.tcx()));
let ty_obligation = obligation.with(obligation.predicate.projection_ty.clone()); let Normalized { value: normalized_ty, obligations } =
let projected_ty = try!(project_type(selcx, &ty_obligation)); match opt_normalize_projection_type(selcx,
obligation.predicate.projection_ty.clone(),
obligation.cause.clone(),
obligation.recursion_depth) {
Some(n) => n,
None => { return Ok(None); }
};
debug!("project_and_unify_type: normalized_ty={} obligations={}",
normalized_ty.repr(selcx.tcx()),
obligations.repr(selcx.tcx()));
let infcx = selcx.infcx(); let infcx = selcx.infcx();
let origin = infer::RelateOutputImplTypes(obligation.cause.span); let origin = infer::RelateOutputImplTypes(obligation.cause.span);
debug!("project_and_unify_type: projected_ty = {}", projected_ty.repr(selcx.tcx())); match infer::mk_eqty(infcx, true, origin, normalized_ty, obligation.predicate.ty) {
match infer::mk_eqty(infcx, true, origin, projected_ty, obligation.predicate.ty) { Ok(()) => Ok(Some(obligations)),
Ok(()) => Ok(()), Err(err) => Err(MismatchedProjectionTypes { err: err }),
Err(e) => Err(ProjectionError::MismatchedTypes(MismatchedProjectionTypes{err: e})),
} }
} }
pub fn normalize<'a,'b,'tcx,T>(selcx: &'a mut SelectionContext<'b,'tcx>,
cause: ObligationCause<'tcx>,
value: &T)
-> Normalized<'tcx, T>
where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone
{
let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, 0);
let result = normalizer.fold(value);
Normalized {
value: result,
obligations: normalizer.obligations,
}
}
struct AssociatedTypeNormalizer<'a,'b:'a,'tcx:'b> {
selcx: &'a mut SelectionContext<'b,'tcx>,
cause: ObligationCause<'tcx>,
obligations: Vec<PredicateObligation<'tcx>>,
depth: uint,
}
impl<'a,'b,'tcx> AssociatedTypeNormalizer<'a,'b,'tcx> {
fn new(selcx: &'a mut SelectionContext<'b,'tcx>,
cause: ObligationCause<'tcx>,
depth: uint)
-> AssociatedTypeNormalizer<'a,'b,'tcx>
{
AssociatedTypeNormalizer {
selcx: selcx,
cause: cause,
obligations: vec!(),
depth: depth,
}
}
fn fold<T:TypeFoldable<'tcx> + HasProjectionTypes + Clone>(&mut self, value: &T) -> T {
let value = self.selcx.infcx().resolve_type_vars_if_possible(value);
if !value.has_projection_types() {
value.clone()
} else {
value.fold_with(self)
}
}
}
impl<'a,'b,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'b,'tcx> {
fn tcx(&self) -> &ty::ctxt<'tcx> {
self.selcx.tcx()
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
// We don't want to normalize associated types that occur inside of region
// binders, because they may contain bound regions, and we can't cope with that.
//
// Example:
//
// for<'a> fn(<T as Foo<&'a>>::A)
//
// Instead of normalizing `<T as Foo<&'a>>::A` here, we'll
// normalize it when we instantiate those bound regions (which
// should occur eventually).
match ty.sty {
ty::ty_projection(ref data) if !data.has_escaping_regions() => { // (*)
// (*) This is kind of hacky -- we need to be able to
// handle normalization within binders because
// otherwise we wind up a need to normalize when doing
// trait matching (since you can have a trait
// obligation like `for<'a> T::B : Fn(&'a int)`), but
// we can't normalize with bound regions in scope. So
// far now we just ignore binders but only normalize
// if all bound regions are gone (and then we still
// have to renormalize whenever we instantiate a
// binder). It would be better to normalize in a
// binding-aware fashion.
let Normalized { value: ty, obligations } =
normalize_projection_type(self.selcx,
data.clone(),
self.cause.clone(),
self.depth);
self.obligations.extend(obligations.into_iter());
ty
}
_ => {
ty_fold::super_fold_ty(self, ty)
}
}
}
}
pub struct Normalized<'tcx,T> {
pub value: T,
pub obligations: Vec<PredicateObligation<'tcx>>,
}
pub type NormalizedTy<'tcx> = Normalized<'tcx, Ty<'tcx>>;
pub fn normalize_projection_type<'a,'b,'tcx>(
selcx: &'a mut SelectionContext<'b,'tcx>,
projection_ty: ty::ProjectionTy<'tcx>,
cause: ObligationCause<'tcx>,
depth: uint)
-> NormalizedTy<'tcx>
{
opt_normalize_projection_type(selcx, projection_ty.clone(), cause.clone(), depth)
.unwrap_or_else(move || {
// if we bottom out in ambiguity, create a type variable
// and a deferred predicate to resolve this when more type
// information is available.
let ty_var = selcx.infcx().next_ty_var();
let projection = ty::Binder(ty::ProjectionPredicate {
projection_ty: projection_ty,
ty: ty_var
});
let obligation = Obligation::with_depth(cause, depth+1, projection.as_predicate());
Normalized {
value: ty_var,
obligations: vec!(obligation)
}
})
}
fn opt_normalize_projection_type<'a,'b,'tcx>(
selcx: &'a mut SelectionContext<'b,'tcx>,
projection_ty: ty::ProjectionTy<'tcx>,
cause: ObligationCause<'tcx>,
depth: uint)
-> Option<NormalizedTy<'tcx>>
{
debug!("normalize_projection_type(\
projection_ty={}, \
depth={})",
projection_ty.repr(selcx.tcx()),
depth);
let obligation = Obligation::with_depth(cause.clone(), depth, projection_ty.clone());
match project_type(selcx, &obligation) {
Ok(ProjectedTy::Progress(projected_ty, mut obligations)) => {
// if projection succeeded, then what we get out of this
// is also non-normalized (consider: it was derived from
// an impl, where-clause etc) and hence we must
// re-normalize it
debug!("normalize_projection_type: projected_ty={} depth={}",
projected_ty.repr(selcx.tcx()),
depth);
if ty::type_has_projection(projected_ty) {
let tcx = selcx.tcx();
let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, depth);
let normalized_ty = normalizer.fold(&projected_ty);
debug!("normalize_projection_type: normalized_ty={} depth={}",
normalized_ty.repr(tcx),
depth);
obligations.extend(normalizer.obligations.into_iter());
Some(Normalized {
value: normalized_ty,
obligations: obligations,
})
} else {
Some(Normalized {
value: projected_ty,
obligations: obligations,
})
}
}
Ok(ProjectedTy::NoProgress(projected_ty)) => {
Some(Normalized {
value: projected_ty,
obligations: vec!()
})
}
Err(ProjectionTyError::TooManyCandidates) => {
None
}
Err(ProjectionTyError::TraitSelectionError(_)) => {
// if we got an error processing the `T as Trait` part,
// just return `ty::err` but add the obligation `T :
// Trait`, which when processed will cause the error to be
// reported later
Some(normalize_to_error(selcx, projection_ty, cause, depth))
}
}
}
/// in various error cases, we just set ty_err and return an obligation
/// that, when fulfiled, will lead to an error
fn normalize_to_error<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
projection_ty: ty::ProjectionTy<'tcx>,
cause: ObligationCause<'tcx>,
depth: uint)
-> NormalizedTy<'tcx>
{
let trait_ref = projection_ty.trait_ref.to_poly_trait_ref();
let trait_obligation = Obligation { cause: cause,
recursion_depth: depth,
predicate: trait_ref.as_predicate() };
Normalized {
value: selcx.tcx().types.err,
obligations: vec!(trait_obligation)
}
}
enum ProjectedTy<'tcx> {
Progress(Ty<'tcx>, Vec<PredicateObligation<'tcx>>),
NoProgress(Ty<'tcx>),
}
/// Compute the result of a projection type (if we can). /// Compute the result of a projection type (if we can).
pub fn project_type<'cx,'tcx>( fn project_type<'cx,'tcx>(
selcx: &mut SelectionContext<'cx,'tcx>, selcx: &mut SelectionContext<'cx,'tcx>,
obligation: &ProjectionTyObligation<'tcx>) obligation: &ProjectionTyObligation<'tcx>)
-> ProjectionResult<'tcx, Ty<'tcx>> -> Result<ProjectedTy<'tcx>, ProjectionTyError<'tcx>>
{ {
debug!("project(obligation={})", debug!("project(obligation={})",
obligation.repr(selcx.tcx())); obligation.repr(selcx.tcx()));
let recursion_limit = selcx.tcx().sess.recursion_limit.get();
if obligation.recursion_depth >= recursion_limit {
debug!("project: overflow!");
return Err(ProjectionTyError::TraitSelectionError(Overflow));
}
let mut candidates = ProjectionTyCandidateSet { let mut candidates = ProjectionTyCandidateSet {
vec: Vec::new(), vec: Vec::new(),
ambiguous: false, ambiguous: false,
}; };
let () = assemble_candidates_from_object_type(selcx, assemble_candidates_from_object_type(selcx,
obligation, obligation,
&mut candidates); &mut candidates);
if candidates.vec.is_empty() { if candidates.vec.is_empty() {
let () = assemble_candidates_from_param_env(selcx, assemble_candidates_from_param_env(selcx,
obligation, obligation,
&mut candidates); &mut candidates);
let () = try!(assemble_candidates_from_impls(selcx, if let Err(e) = assemble_candidates_from_impls(selcx,
obligation, obligation,
&mut candidates)); &mut candidates) {
return Err(ProjectionTyError::TraitSelectionError(e));
}
} }
debug!("{} candidates, ambiguous={}", debug!("{} candidates, ambiguous={}",
@ -146,15 +389,18 @@ pub fn project_type<'cx,'tcx>(
// We probably need some winnowing logic similar to select here. // We probably need some winnowing logic similar to select here.
if candidates.ambiguous || candidates.vec.len() > 1 { if candidates.ambiguous || candidates.vec.len() > 1 {
return Err(ProjectionError::TooManyCandidates); return Err(ProjectionTyError::TooManyCandidates);
} }
match candidates.vec.pop() { match candidates.vec.pop() {
Some(candidate) => { Some(candidate) => {
Ok(try!(confirm_candidate(selcx, obligation, candidate))) let (ty, obligations) = confirm_candidate(selcx, obligation, candidate);
Ok(ProjectedTy::Progress(ty, obligations))
} }
None => { None => {
Err(ProjectionError::NoCandidate) Ok(ProjectedTy::NoProgress(ty::mk_projection(selcx.tcx(),
obligation.predicate.trait_ref.clone(),
obligation.predicate.item_name)))
} }
} }
} }
@ -230,9 +476,9 @@ fn assemble_candidates_from_object_type<'cx,'tcx>(
fn assemble_candidates_from_impls<'cx,'tcx>( fn assemble_candidates_from_impls<'cx,'tcx>(
selcx: &mut SelectionContext<'cx,'tcx>, selcx: &mut SelectionContext<'cx,'tcx>,
obligation: &ProjectionTyObligation<'tcx>, obligation: &ProjectionTyObligation<'tcx>,
candidate_set: &mut ProjectionTyCandidateSet<'tcx>) candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
-> ProjectionResult<'tcx, ()> -> Result<(), SelectionError<'tcx>>
{ {
// If we are resolving `<T as TraitRef<...>>::Item == Type`, // If we are resolving `<T as TraitRef<...>>::Item == Type`,
// start out by selecting the predicate `T as TraitRef<...>`: // start out by selecting the predicate `T as TraitRef<...>`:
@ -249,7 +495,7 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
Err(e) => { Err(e) => {
debug!("assemble_candidates_from_impls: selection error {}", debug!("assemble_candidates_from_impls: selection error {}",
e.repr(selcx.tcx())); e.repr(selcx.tcx()));
return Err(ProjectionError::TraitSelectionError(e)); return Err(e);
} }
}; };
@ -301,9 +547,9 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
fn confirm_candidate<'cx,'tcx>( fn confirm_candidate<'cx,'tcx>(
selcx: &mut SelectionContext<'cx,'tcx>, selcx: &mut SelectionContext<'cx,'tcx>,
obligation: &ProjectionTyObligation<'tcx>, obligation: &ProjectionTyObligation<'tcx>,
candidate: ProjectionTyCandidate<'tcx>) candidate: ProjectionTyCandidate<'tcx>)
-> ProjectionResult<'tcx, Ty<'tcx>> -> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
{ {
let infcx = selcx.infcx(); let infcx = selcx.infcx();
@ -311,7 +557,7 @@ fn confirm_candidate<'cx,'tcx>(
candidate.repr(infcx.tcx), candidate.repr(infcx.tcx),
obligation.repr(infcx.tcx)); obligation.repr(infcx.tcx));
let projected_ty = match candidate { match candidate {
ProjectionTyCandidate::ParamEnv(poly_projection) => { ProjectionTyCandidate::ParamEnv(poly_projection) => {
let projection = let projection =
infcx.replace_late_bound_regions_with_fresh_var( infcx.replace_late_bound_regions_with_fresh_var(
@ -338,7 +584,7 @@ fn confirm_candidate<'cx,'tcx>(
} }
} }
projection.ty (projection.ty, vec!())
} }
ProjectionTyCandidate::Impl(impl_vtable) => { ProjectionTyCandidate::Impl(impl_vtable) => {
@ -363,10 +609,8 @@ fn confirm_candidate<'cx,'tcx>(
break; break;
} }
// TODO we need the impl_vtable items here
match impl_ty { match impl_ty {
Some(ty) => ty, Some(ty) => (ty, impl_vtable.nested.to_vec()),
None => { None => {
selcx.tcx().sess.span_bug( selcx.tcx().sess.span_bug(
obligation.cause.span, obligation.cause.span,
@ -376,21 +620,15 @@ fn confirm_candidate<'cx,'tcx>(
} }
} }
} }
}; }
Ok(projected_ty)
} }
impl<'tcx> Repr<'tcx> for ProjectionError<'tcx> { impl<'tcx> Repr<'tcx> for ProjectionTyError<'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
match *self { match *self {
ProjectionError::NoCandidate => ProjectionTyError::TooManyCandidates =>
format!("NoCandidate"), format!("NoCandidate"),
ProjectionError::TooManyCandidates => ProjectionTyError::TraitSelectionError(ref e) =>
format!("NoCandidate"),
ProjectionError::MismatchedTypes(ref m) =>
format!("MismatchedTypes({})", m.repr(tcx)),
ProjectionError::TraitSelectionError(ref e) =>
format!("TraitSelectionError({})", e.repr(tcx)), format!("TraitSelectionError({})", e.repr(tcx)),
} }
} }
@ -406,4 +644,3 @@ impl<'tcx> Repr<'tcx> for ProjectionTyCandidate<'tcx> {
} }
} }
} }

View File

@ -960,7 +960,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
// iterating early. // iterating early.
let mut fulfill_cx = traits::FulfillmentContext::new(); let mut fulfill_cx = traits::FulfillmentContext::new();
let vtable = selection.map_move_nested(|predicate| { let vtable = selection.map_move_nested(|predicate| {
fulfill_cx.register_predicate(&infcx, predicate); fulfill_cx.register_predicate_obligation(&infcx, predicate);
}); });
match fulfill_cx.select_all_or_error(&infcx, &param_env, tcx) { match fulfill_cx.select_all_or_error(&infcx, &param_env, tcx) {
Ok(()) => { } Ok(()) => { }

View File

@ -16,7 +16,7 @@ use middle::infer;
use middle::subst; use middle::subst;
use middle::subst::{Subst, Substs}; use middle::subst::{Subst, Substs};
use middle::traits; use middle::traits;
use middle::ty_fold::{mod, TypeFolder, TypeFoldable}; use middle::ty_fold::{TypeFolder, TypeFoldable};
use trans::base::{set_llvm_fn_attrs, set_inline_hint}; use trans::base::{set_llvm_fn_attrs, set_inline_hint};
use trans::base::{trans_enum_variant, push_ctxt, get_item_val}; use trans::base::{trans_enum_variant, push_ctxt, get_item_val};
use trans::base::{trans_fn, decl_internal_rust_fn}; use trans::base::{trans_fn, decl_internal_rust_fn};
@ -32,7 +32,6 @@ use syntax::ast_map;
use syntax::ast_util::{local_def, PostExpansionMethod}; use syntax::ast_util::{local_def, PostExpansionMethod};
use syntax::attr; use syntax::attr;
use std::hash::{sip, Hash}; use std::hash::{sip, Hash};
use std::rc::Rc;
pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
fn_id: ast::DefId, fn_id: ast::DefId,
@ -310,13 +309,13 @@ pub fn apply_param_substs<'tcx,T>(tcx: &ty::ctxt<'tcx>,
/// monomorphization, we know that only concrete types are involved, /// monomorphization, we know that only concrete types are involved,
/// and hence we can be sure that all associated types will be /// and hence we can be sure that all associated types will be
/// completely normalized away. /// completely normalized away.
pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, t: &T) -> T pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
{ {
debug!("normalize_associated_type(t={})", t.repr(tcx)); debug!("normalize_associated_type(t={})", value.repr(tcx));
if !t.has_projection_types() { if !value.has_projection_types() {
return t.clone(); return value.clone();
} }
// FIXME(#20304) -- cache // FIXME(#20304) -- cache
@ -324,52 +323,15 @@ pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, t: &T) -> T
let infcx = infer::new_infer_ctxt(tcx); let infcx = infer::new_infer_ctxt(tcx);
let param_env = ty::empty_parameter_environment(); let param_env = ty::empty_parameter_environment();
let mut selcx = traits::SelectionContext::new(&infcx, &param_env, tcx); let mut selcx = traits::SelectionContext::new(&infcx, &param_env, tcx);
let mut normalizer = AssociatedTypeNormalizer { selcx: &mut selcx }; let cause = traits::ObligationCause::dummy();
let result = t.fold_with(&mut normalizer); let traits::Normalized { value: result, obligations } =
traits::normalize(&mut selcx, cause, value);
debug!("normalize_associated_type: t={} result={}", debug!("normalize_associated_type: result={} obligations={}",
t.repr(tcx), result.repr(tcx),
result.repr(tcx)); obligations.repr(tcx));
assert_eq!(obligations.len(), 0); // TODO not good enough
result result
} }
struct AssociatedTypeNormalizer<'a,'tcx:'a> {
selcx: &'a mut traits::SelectionContext<'a,'tcx>,
}
impl<'a,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'tcx> {
fn tcx(&self) -> &ty::ctxt<'tcx> { self.selcx.tcx() }
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
match ty.sty {
ty::ty_projection(ref data) => {
debug!("ty_projection({})", data.repr(self.tcx()));
let tcx = self.selcx.tcx();
let substs = data.trait_ref.substs.clone().erase_regions();
let substs = self.tcx().mk_substs(substs);
assert!(substs.types.iter().all(|&t| (!ty::type_has_params(t) &&
!ty::type_has_self(t))));
let trait_ref = Rc::new(ty::TraitRef::new(data.trait_ref.def_id, substs));
let projection_ty = ty::ProjectionTy { trait_ref: trait_ref.clone(),
item_name: data.item_name };
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
projection_ty);
match traits::project_type(self.selcx, &obligation) {
Ok(ty) => ty,
Err(errors) => {
tcx.sess.bug(
format!("Encountered error(s) `{}` selecting `{}` during trans",
errors.repr(tcx),
trait_ref.repr(tcx)).as_slice());
}
}
}
_ => {
ty_fold::super_fold_ty(self, ty)
}
}
}
}

View File

@ -9,85 +9,34 @@
// except according to those terms. // except according to those terms.
use middle::infer::InferCtxt; use middle::infer::InferCtxt;
use middle::traits::{ObligationCause, ObligationCauseCode, FulfillmentContext}; use middle::mem_categorization as mc;
use middle::ty::{mod, RegionEscape, HasProjectionTypes, Ty}; use middle::traits::{mod, FulfillmentContext, Normalized, MiscObligation,
use middle::ty_fold::{mod, TypeFoldable, TypeFolder}; SelectionContext, ObligationCause};
use middle::ty::{mod, HasProjectionTypes};
use middle::ty_fold::{TypeFoldable, TypeFolder};
use syntax::ast; use syntax::ast;
use syntax::codemap::Span; use syntax::codemap::Span;
use util::ppaux::Repr;
pub fn normalize_associated_types_in<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, pub fn normalize_associated_types_in<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
param_env: &ty::ParameterEnvironment<'tcx>,
typer: &(mc::Typer<'tcx>+'a),
fulfillment_cx: &mut FulfillmentContext<'tcx>, fulfillment_cx: &mut FulfillmentContext<'tcx>,
span: Span, span: Span,
body_id: ast::NodeId, body_id: ast::NodeId,
value: &T) value: &T)
-> T -> T
where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone + Repr<'tcx>
{ {
let value = infcx.resolve_type_vars_if_possible(value); debug!("normalize_associated_types_in(value={})", value.repr(infcx.tcx));
let mut selcx = SelectionContext::new(infcx, param_env, typer);
if !value.has_projection_types() { let cause = ObligationCause::new(span, body_id, MiscObligation);
return value.clone(); let Normalized { value: result, obligations } = traits::normalize(&mut selcx, cause, value);
} debug!("normalize_associated_types_in: result={} predicates={}",
result.repr(infcx.tcx),
let mut normalizer = AssociatedTypeNormalizer { span: span, obligations.repr(infcx.tcx));
body_id: body_id, for obligation in obligations.into_iter() {
infcx: infcx, fulfillment_cx.register_predicate_obligation(infcx, obligation);
fulfillment_cx: fulfillment_cx };
value.fold_with(&mut normalizer)
}
struct AssociatedTypeNormalizer<'a,'tcx:'a> {
infcx: &'a InferCtxt<'a, 'tcx>,
fulfillment_cx: &'a mut FulfillmentContext<'tcx>,
span: Span,
body_id: ast::NodeId,
}
impl<'a,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'tcx> {
fn tcx(&self) -> &ty::ctxt<'tcx> {
self.infcx.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
// We don't want to normalize associated types that occur inside of region
// binders, because they may contain bound regions, and we can't cope with that.
//
// Example:
//
// for<'a> fn(<T as Foo<&'a>>::A)
//
// Instead of normalizing `<T as Foo<&'a>>::A` here, we'll
// normalize it when we instantiate those bound regions (which
// should occur eventually).
match ty.sty {
ty::ty_projection(ref data) if !data.has_escaping_regions() => { // (*)
// (*) This is kind of hacky -- we need to be able to
// handle normalization within binders because
// otherwise we wind up a need to normalize when doing
// trait matching (since you can have a trait
// obligation like `for<'a> T::B : Fn(&'a int)`), but
// we can't normalize with bound regions in scope. So
// far now we just ignore binders but only normalize
// if all bound regions are gone (and then we still
// have to renormalize whenever we instantiate a
// binder). It would be better to normalize in a
// binding-aware fashion.
let cause =
ObligationCause::new(
self.span,
self.body_id,
ObligationCauseCode::MiscObligation);
self.fulfillment_cx
.normalize_projection_type(self.infcx,
data.clone(),
cause)
}
_ => {
ty_fold::super_fold_ty(self, ty)
}
}
} }
result
} }

View File

@ -350,11 +350,18 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
} }
} }
fn normalize_associated_types_in<T>(&self, span: Span, body_id: ast::NodeId, value: &T) -> T fn normalize_associated_types_in<T>(&self,
where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes typer: &mc::Typer<'tcx>,
span: Span,
body_id: ast::NodeId,
value: &T)
-> T
where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes + Repr<'tcx>
{ {
let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); let mut fulfillment_cx = self.fulfillment_cx.borrow_mut();
assoc::normalize_associated_types_in(&self.infcx, assoc::normalize_associated_types_in(&self.infcx,
&self.param_env,
typer,
&mut *fulfillment_cx, span, &mut *fulfillment_cx, span,
body_id, body_id,
value) value)
@ -438,7 +445,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let fn_sig = let fn_sig =
liberate_late_bound_regions(ccx.tcx, CodeExtent::from_node_id(body.id), &fn_sig); liberate_late_bound_regions(ccx.tcx, CodeExtent::from_node_id(body.id), &fn_sig);
let fn_sig = let fn_sig =
inh.normalize_associated_types_in(body.span, body.id, &fn_sig); inh.normalize_associated_types_in(ccx.tcx, body.span, body.id, &fn_sig);
let fcx = check_fn(ccx, fn_ty.unsafety, id, &fn_sig, let fcx = check_fn(ccx, fn_ty.unsafety, id, &fn_sig,
decl, id, body, &inh); decl, id, body, &inh);
@ -1190,6 +1197,8 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
impl_sig.subst(tcx, impl_to_skol_substs); impl_sig.subst(tcx, impl_to_skol_substs);
let impl_sig = let impl_sig =
assoc::normalize_associated_types_in(&infcx, assoc::normalize_associated_types_in(&infcx,
&impl_param_env,
infcx.tcx,
&mut fulfillment_cx, &mut fulfillment_cx,
impl_m_span, impl_m_span,
impl_m_body_id, impl_m_body_id,
@ -1209,6 +1218,8 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
trait_sig.subst(tcx, &trait_to_skol_substs); trait_sig.subst(tcx, &trait_to_skol_substs);
let trait_sig = let trait_sig =
assoc::normalize_associated_types_in(&infcx, assoc::normalize_associated_types_in(&infcx,
&impl_param_env,
infcx.tcx,
&mut fulfillment_cx, &mut fulfillment_cx,
impl_m_span, impl_m_span,
impl_m_body_id, impl_m_body_id,
@ -1756,9 +1767,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes + Repr<'tcx>
{ {
self.inh.normalize_associated_types_in(span, self.body_id, value) self.inh.normalize_associated_types_in(self, span, self.body_id, value)
} }
fn normalize_associated_type(&self, fn normalize_associated_type(&self,
@ -1773,6 +1784,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.inh.fulfillment_cx self.inh.fulfillment_cx
.borrow_mut() .borrow_mut()
.normalize_projection_type(self.infcx(), .normalize_projection_type(self.infcx(),
&self.inh.param_env,
self,
ty::ProjectionTy { ty::ProjectionTy {
trait_ref: trait_ref, trait_ref: trait_ref,
item_name: item_name, item_name: item_name,
@ -1943,7 +1956,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.inh.fulfillment_cx self.inh.fulfillment_cx
.borrow_mut() .borrow_mut()
.register_predicate(self.infcx(), obligation); .register_predicate_obligation(self.infcx(), obligation);
} }
pub fn to_ty(&self, ast_t: &ast::Ty) -> Ty<'tcx> { pub fn to_ty(&self, ast_t: &ast::Ty) -> Ty<'tcx> {

View File

@ -25,11 +25,30 @@ pub fn f2<T: Foo>(a: T) -> T::A {
panic!(); panic!();
} }
pub fn main() { pub fn f1_int_int() {
f1(2i, 4i); //~ ERROR expected uint, found int f1(2i, 4i);
f1(2i, 4u); //~^ ERROR expected uint, found int
f1(2u, 4u); //~ ERROR the trait `Foo` is not implemented
f1(2u, 4i); //~ ERROR the trait `Foo` is not implemented
let _: int = f2(2i); //~ERROR expected `int`, found `uint`
} }
pub fn f1_int_uint() {
f1(2i, 4u);
}
pub fn f1_uint_uint() {
f1(2u, 4u);
//~^ ERROR the trait `Foo` is not implemented
//~| ERROR the trait `Foo` is not implemented
}
pub fn f1_uint_int() {
f1(2u, 4i);
//~^ ERROR the trait `Foo` is not implemented
//~| ERROR the trait `Foo` is not implemented
}
pub fn f2_int() {
let _: int = f2(2i);
//~^ ERROR expected `int`, found `uint`
}
pub fn main() { }

View File

@ -29,9 +29,10 @@ fn bar<'a, 'b, I : for<'x> Foo<&'x int>>(
x: <I as Foo<&'a int>>::A, x: <I as Foo<&'a int>>::A,
y: <I as Foo<&'b int>>::A, y: <I as Foo<&'b int>>::A,
cond: bool) cond: bool)
{ //~ ERROR cannot infer {
// x and y here have two distinct lifetimes: // x and y here have two distinct lifetimes:
let z: I::A = if cond { x } else { y }; let z: I::A = if cond { x } else { y };
//~^ ERROR cannot infer
} }
pub fn main() {} pub fn main() {}

View File

@ -0,0 +1,28 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Check that an associated type cannot be bound in an expression path.
#![feature(associated_types)]
trait Foo {
type A;
fn bar() -> int;
}
impl Foo for int {
type A = uint;
fn bar() -> int { 42 }
}
pub fn main() {
let x: int = Foo::bar();
//~^ ERROR type annotations required
}

View File

@ -33,7 +33,7 @@ where T : Convert<U>
} }
fn a() { fn a() {
test(22_i32, 44); //~ ERROR unable to infer test(22_i32, 44); //~ ERROR type annotations required
} }
fn main() {} fn main() {}

View File

@ -0,0 +1,58 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test how resolving a projection interacts with inference. In this
// case, we were eagerly unifying the type variable for the iterator
// type with `I` from the where clause, ignoring the in-scope `impl`
// for `ByRef`. The right answer was to consider the result ambiguous
// until more type information was available.
// ignore-pretty -- FIXME(#17362)
#![feature(associated_types, lang_items, unboxed_closures)]
#![no_implicit_prelude]
use std::option::Option::{None, Some, mod};
trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
}
trait IteratorExt: Iterator {
fn by_ref(&mut self) -> ByRef<Self> {
ByRef(self)
}
}
impl<I> IteratorExt for I where I: Iterator {}
struct ByRef<'a, I: 'a + Iterator>(&'a mut I);
impl<'a, I: Iterator> Iterator for ByRef<'a, I> {
type Item = I::Item;
fn next(&mut self) -> Option< <I as Iterator>::Item > {
self.0.next()
}
}
fn is_iterator_of<A, I: Iterator<Item=A>>(_: &I) {}
fn test<A, I: Iterator<Item=A>>(mut it: I) {
is_iterator_of::<A, _>(&it.by_ref());
}
fn test2<A, I1: Iterator<Item=A>, I2: Iterator<Item=I1::Item>>(mut it: I2) {
is_iterator_of::<A, _>(&it)
}
fn main() { }