Normalize associated types in bounds too. Also, make the workaround
for lack of impl-trait-for-trait just a bit more targeted (don't substitute err, just drop the troublesome bound for now) -- otherwise substituting false types leads us into trouble when we normalize etc.
This commit is contained in:
parent
cdd5ff842d
commit
518ec1259a
@ -6970,13 +6970,67 @@ pub trait HasProjectionTypes {
|
||||
fn has_projection_types(&self) -> bool;
|
||||
}
|
||||
|
||||
impl<'tcx> HasProjectionTypes for ty::GenericBounds<'tcx> {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
self.predicates.iter().any(|p| p.has_projection_types())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasProjectionTypes for Predicate<'tcx> {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
match *self {
|
||||
Predicate::Trait(ref data) => data.has_projection_types(),
|
||||
Predicate::Equate(ref data) => data.has_projection_types(),
|
||||
Predicate::RegionOutlives(ref data) => data.has_projection_types(),
|
||||
Predicate::TypeOutlives(ref data) => data.has_projection_types(),
|
||||
Predicate::Projection(ref data) => data.has_projection_types(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasProjectionTypes for TraitPredicate<'tcx> {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
self.trait_ref.has_projection_types()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasProjectionTypes for EquatePredicate<'tcx> {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
self.0.has_projection_types() || self.1.has_projection_types()
|
||||
}
|
||||
}
|
||||
|
||||
impl HasProjectionTypes for Region {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:HasProjectionTypes,U:HasProjectionTypes> HasProjectionTypes for OutlivesPredicate<T,U> {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
self.0.has_projection_types() || self.1.has_projection_types()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasProjectionTypes for ProjectionPredicate<'tcx> {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
self.projection_ty.has_projection_types() || self.ty.has_projection_types()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasProjectionTypes for ProjectionTy<'tcx> {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
self.trait_ref.has_projection_types()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasProjectionTypes for Ty<'tcx> {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
ty::type_has_projection(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasProjectionTypes for ty::TraitRef<'tcx> {
|
||||
impl<'tcx> HasProjectionTypes for TraitRef<'tcx> {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
self.substs.has_projection_types()
|
||||
}
|
||||
@ -7012,7 +7066,7 @@ impl<'tcx,T> HasProjectionTypes for Box<T>
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> HasProjectionTypes for ty::Binder<T>
|
||||
impl<T> HasProjectionTypes for Binder<T>
|
||||
where T : HasProjectionTypes
|
||||
{
|
||||
fn has_projection_types(&self) -> bool {
|
||||
@ -7020,23 +7074,23 @@ impl<T> HasProjectionTypes for ty::Binder<T>
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasProjectionTypes for ty::FnOutput<'tcx> {
|
||||
impl<'tcx> HasProjectionTypes for FnOutput<'tcx> {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
match *self {
|
||||
ty::FnConverging(t) => t.has_projection_types(),
|
||||
ty::FnDiverging => false,
|
||||
FnConverging(t) => t.has_projection_types(),
|
||||
FnDiverging => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasProjectionTypes for ty::FnSig<'tcx> {
|
||||
impl<'tcx> HasProjectionTypes for FnSig<'tcx> {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
self.inputs.iter().any(|t| t.has_projection_types()) ||
|
||||
self.output.has_projection_types()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasProjectionTypes for ty::BareFnTy<'tcx> {
|
||||
impl<'tcx> HasProjectionTypes for BareFnTy<'tcx> {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
self.sig.has_projection_types()
|
||||
}
|
||||
@ -7046,7 +7100,7 @@ pub trait ReferencesError {
|
||||
fn references_error(&self) -> bool;
|
||||
}
|
||||
|
||||
impl<T:ReferencesError> ReferencesError for ty::Binder<T> {
|
||||
impl<T:ReferencesError> ReferencesError for Binder<T> {
|
||||
fn references_error(&self) -> bool {
|
||||
self.0.references_error()
|
||||
}
|
||||
@ -7058,43 +7112,43 @@ impl<T:ReferencesError> ReferencesError for Rc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ReferencesError for ty::TraitPredicate<'tcx> {
|
||||
impl<'tcx> ReferencesError for TraitPredicate<'tcx> {
|
||||
fn references_error(&self) -> bool {
|
||||
self.trait_ref.references_error()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ReferencesError for ty::ProjectionPredicate<'tcx> {
|
||||
impl<'tcx> ReferencesError for ProjectionPredicate<'tcx> {
|
||||
fn references_error(&self) -> bool {
|
||||
self.projection_ty.trait_ref.references_error() || self.ty.references_error()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ReferencesError for ty::TraitRef<'tcx> {
|
||||
impl<'tcx> ReferencesError for TraitRef<'tcx> {
|
||||
fn references_error(&self) -> bool {
|
||||
self.input_types().iter().any(|t| t.references_error())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ReferencesError for ty::Ty<'tcx> {
|
||||
impl<'tcx> ReferencesError for Ty<'tcx> {
|
||||
fn references_error(&self) -> bool {
|
||||
ty::type_is_error(*self)
|
||||
type_is_error(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ReferencesError for ty::Predicate<'tcx> {
|
||||
impl<'tcx> ReferencesError for Predicate<'tcx> {
|
||||
fn references_error(&self) -> bool {
|
||||
match *self {
|
||||
ty::Predicate::Trait(ref data) => data.references_error(),
|
||||
ty::Predicate::Equate(ref data) => data.references_error(),
|
||||
ty::Predicate::RegionOutlives(ref data) => data.references_error(),
|
||||
ty::Predicate::TypeOutlives(ref data) => data.references_error(),
|
||||
ty::Predicate::Projection(ref data) => data.references_error(),
|
||||
Predicate::Trait(ref data) => data.references_error(),
|
||||
Predicate::Equate(ref data) => data.references_error(),
|
||||
Predicate::RegionOutlives(ref data) => data.references_error(),
|
||||
Predicate::TypeOutlives(ref data) => data.references_error(),
|
||||
Predicate::Projection(ref data) => data.references_error(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A,B> ReferencesError for ty::OutlivesPredicate<A,B>
|
||||
impl<A,B> ReferencesError for OutlivesPredicate<A,B>
|
||||
where A : ReferencesError, B : ReferencesError
|
||||
{
|
||||
fn references_error(&self) -> bool {
|
||||
@ -7102,14 +7156,14 @@ impl<A,B> ReferencesError for ty::OutlivesPredicate<A,B>
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ReferencesError for ty::EquatePredicate<'tcx>
|
||||
impl<'tcx> ReferencesError for EquatePredicate<'tcx>
|
||||
{
|
||||
fn references_error(&self) -> bool {
|
||||
self.0.references_error() || self.1.references_error()
|
||||
}
|
||||
}
|
||||
|
||||
impl ReferencesError for ty::Region
|
||||
impl ReferencesError for Region
|
||||
{
|
||||
fn references_error(&self) -> bool {
|
||||
false
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
use middle::infer::InferCtxt;
|
||||
use middle::traits::{ObligationCause, ObligationCauseCode, FulfillmentContext};
|
||||
use middle::ty::{mod, HasProjectionTypes, Ty};
|
||||
use middle::ty::{mod, RegionEscape, HasProjectionTypes, Ty};
|
||||
use middle::ty_fold::{mod, TypeFoldable, TypeFolder};
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
@ -32,8 +32,7 @@ pub fn normalize_associated_types_in<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
|
||||
let mut normalizer = AssociatedTypeNormalizer { span: span,
|
||||
body_id: body_id,
|
||||
infcx: infcx,
|
||||
fulfillment_cx: fulfillment_cx,
|
||||
region_binders: 0 };
|
||||
fulfillment_cx: fulfillment_cx };
|
||||
value.fold_with(&mut normalizer)
|
||||
}
|
||||
|
||||
@ -42,7 +41,6 @@ struct AssociatedTypeNormalizer<'a,'tcx:'a> {
|
||||
fulfillment_cx: &'a mut FulfillmentContext<'tcx>,
|
||||
span: Span,
|
||||
body_id: ast::NodeId,
|
||||
region_binders: uint,
|
||||
}
|
||||
|
||||
impl<'a,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'tcx> {
|
||||
@ -50,14 +48,6 @@ impl<'a,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
||||
fn enter_region_binder(&mut self) {
|
||||
self.region_binders += 1;
|
||||
}
|
||||
|
||||
fn exit_region_binder(&mut self) {
|
||||
self.region_binders -= 1;
|
||||
}
|
||||
|
||||
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.
|
||||
@ -69,10 +59,22 @@ impl<'a,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'tcx> {
|
||||
// Instead of normalizing `<T as Foo<&'a>>::A` here, we'll
|
||||
// normalize it when we instantiate those bound regions (which
|
||||
// should occur eventually).
|
||||
let no_region_binders = self.region_binders == 0;
|
||||
|
||||
match ty.sty {
|
||||
ty::ty_projection(ref data) if no_region_binders => {
|
||||
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,
|
||||
|
@ -42,12 +42,6 @@ struct InstantiatedMethodSig<'tcx> {
|
||||
/// the method.
|
||||
all_substs: subst::Substs<'tcx>,
|
||||
|
||||
/// Substitution to use when adding obligations from the method
|
||||
/// bounds. Normally equal to `all_substs` except for object
|
||||
/// receivers. See FIXME in instantiate_method_sig() for
|
||||
/// explanation.
|
||||
method_bounds_substs: subst::Substs<'tcx>,
|
||||
|
||||
/// Generic bounds on the method's parameters which must be added
|
||||
/// as pending obligations.
|
||||
method_bounds: ty::GenericBounds<'tcx>,
|
||||
@ -103,7 +97,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
||||
|
||||
// Create the final signature for the method, replacing late-bound regions.
|
||||
let InstantiatedMethodSig {
|
||||
method_sig, all_substs, method_bounds_substs, method_bounds
|
||||
method_sig, all_substs, method_bounds
|
||||
} = self.instantiate_method_sig(&pick, all_substs);
|
||||
let method_self_ty = method_sig.inputs[0];
|
||||
|
||||
@ -111,7 +105,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
||||
self.unify_receivers(self_ty, method_self_ty);
|
||||
|
||||
// Add any trait/regions obligations specified on the method's type parameters.
|
||||
self.add_obligations(&pick, &method_bounds_substs, &method_bounds);
|
||||
self.add_obligations(&pick, &all_substs, &method_bounds);
|
||||
|
||||
// Create the final `MethodCallee`.
|
||||
let fty = ty::mk_bare_fn(self.tcx(), None, self.tcx().mk_bare_fn(ty::BareFnTy {
|
||||
@ -403,24 +397,17 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
||||
// type `Trait`, this leads to an obligation
|
||||
// `Trait:Trait`. Until such time we DST is fully implemented,
|
||||
// that obligation is not necessarily satisfied. (In the
|
||||
// future, it would be.)
|
||||
//
|
||||
// To sidestep this, we overwrite the binding for `Self` with
|
||||
// `err` (just for trait objects) when we generate the
|
||||
// obligations. This causes us to generate the obligation
|
||||
// `err:Trait`, and the error type is considered to implement
|
||||
// all traits, so we're all good. Hack hack hack.
|
||||
let method_bounds_substs = match pick.kind {
|
||||
// future, it would be.) But we know that the true `Self` DOES implement
|
||||
// the trait. So we just delete this requirement. Hack hack hack.
|
||||
let mut method_bounds = pick.method_ty.generics.to_bounds(self.tcx(), &all_substs);
|
||||
match pick.kind {
|
||||
probe::ObjectPick(..) => {
|
||||
let mut temp_substs = all_substs.clone();
|
||||
temp_substs.types.get_mut_slice(subst::SelfSpace)[0] = self.tcx().types.err;
|
||||
temp_substs
|
||||
assert_eq!(method_bounds.predicates.get_slice(subst::SelfSpace).len(), 1);
|
||||
method_bounds.predicates.pop(subst::SelfSpace);
|
||||
}
|
||||
_ => {
|
||||
all_substs.clone()
|
||||
}
|
||||
};
|
||||
let method_bounds = pick.method_ty.generics.to_bounds(self.tcx(), &method_bounds_substs);
|
||||
_ => { }
|
||||
}
|
||||
let method_bounds = self.fcx.normalize_associated_types_in(self.span, &method_bounds);
|
||||
|
||||
debug!("method_bounds after subst = {}",
|
||||
method_bounds.repr(self.tcx()));
|
||||
@ -442,18 +429,17 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
||||
InstantiatedMethodSig {
|
||||
method_sig: method_sig,
|
||||
all_substs: all_substs,
|
||||
method_bounds_substs: method_bounds_substs,
|
||||
method_bounds: method_bounds,
|
||||
}
|
||||
}
|
||||
|
||||
fn add_obligations(&mut self,
|
||||
pick: &probe::Pick<'tcx>,
|
||||
method_bounds_substs: &subst::Substs<'tcx>,
|
||||
all_substs: &subst::Substs<'tcx>,
|
||||
method_bounds: &ty::GenericBounds<'tcx>) {
|
||||
debug!("add_obligations: pick={} method_bounds_substs={} method_bounds={}",
|
||||
debug!("add_obligations: pick={} all_substs={} method_bounds={}",
|
||||
pick.repr(self.tcx()),
|
||||
method_bounds_substs.repr(self.tcx()),
|
||||
all_substs.repr(self.tcx()),
|
||||
method_bounds.repr(self.tcx()));
|
||||
|
||||
self.fcx.add_obligations_for_parameters(
|
||||
@ -461,7 +447,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
||||
method_bounds);
|
||||
|
||||
self.fcx.add_default_region_param_bounds(
|
||||
method_bounds_substs,
|
||||
all_substs,
|
||||
self.call_expr);
|
||||
}
|
||||
|
||||
|
@ -1071,7 +1071,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
debug!("ty_generics_for_trait: assoc_predicates={}", assoc_predicates.repr(ccx.tcx));
|
||||
|
||||
for assoc_predicate in assoc_predicates.into_iter() {
|
||||
generics.predicates.push(subst::SelfSpace, assoc_predicate);
|
||||
generics.predicates.push(subst::TypeSpace, assoc_predicate);
|
||||
}
|
||||
|
||||
return generics;
|
||||
|
41
src/test/run-pass/associated-types-normalize-in-bounds.rs
Normal file
41
src/test/run-pass/associated-types-normalize-in-bounds.rs
Normal file
@ -0,0 +1,41 @@
|
||||
// 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 that we normalize associated types that appear in bounds; if
|
||||
// we didn't, the call to `self.split2()` fails to type check.
|
||||
|
||||
#![feature(associated_types)]
|
||||
|
||||
struct Splits<'a, T, P>;
|
||||
struct SplitsN<I>;
|
||||
|
||||
trait SliceExt2 for Sized? {
|
||||
type Item;
|
||||
|
||||
fn split2<'a, P>(&'a self, pred: P) -> Splits<'a, Self::Item, P>
|
||||
where P: FnMut(&Self::Item) -> bool;
|
||||
fn splitn2<'a, P>(&'a self, n: uint, pred: P) -> SplitsN<Splits<'a, Self::Item, P>>
|
||||
where P: FnMut(&Self::Item) -> bool;
|
||||
}
|
||||
|
||||
impl<T> SliceExt2 for [T] {
|
||||
type Item = T;
|
||||
|
||||
fn split2<P>(&self, pred: P) -> Splits<T, P> where P: FnMut(&T) -> bool {
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn splitn2<P>(&self, n: uint, pred: P) -> SplitsN<Splits<T, P>> where P: FnMut(&T) -> bool {
|
||||
self.split2(pred);
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() { }
|
Loading…
x
Reference in New Issue
Block a user