Normalize bounds also in the UFCS cases (and get more systematic about it)
This commit is contained in:
parent
90252b8ddb
commit
0aa7ba9f5e
@ -363,6 +363,8 @@ fn confirm_candidate<'cx,'tcx>(
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO we need the impl_vtable items here
|
||||
|
||||
match impl_ty {
|
||||
Some(ty) => ty,
|
||||
None => {
|
||||
|
@ -6385,7 +6385,7 @@ pub fn construct_parameter_environment<'tcx>(
|
||||
}
|
||||
|
||||
fn push_types_from_defs<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
types: &mut subst::VecPerParamSpace<Ty<'tcx>>,
|
||||
types: &mut VecPerParamSpace<Ty<'tcx>>,
|
||||
defs: &[TypeParameterDef<'tcx>]) {
|
||||
for def in defs.iter() {
|
||||
debug!("construct_parameter_environment(): push_types_from_defs: def={}",
|
||||
@ -6915,12 +6915,49 @@ impl<'tcx> RegionEscape for Ty<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx,T:RegionEscape> RegionEscape for VecPerParamSpace<T> {
|
||||
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
|
||||
self.iter_enumerated().any(|(space, _, t)| {
|
||||
if space == subst::FnSpace {
|
||||
t.has_regions_escaping_depth(depth+1)
|
||||
} else {
|
||||
t.has_regions_escaping_depth(depth)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> RegionEscape for TypeScheme<'tcx> {
|
||||
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
|
||||
self.ty.has_regions_escaping_depth(depth) ||
|
||||
self.generics.has_regions_escaping_depth(depth)
|
||||
}
|
||||
}
|
||||
|
||||
impl RegionEscape for Region {
|
||||
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
|
||||
self.escapes_depth(depth)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> RegionEscape for Generics<'tcx> {
|
||||
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
|
||||
self.predicates.has_regions_escaping_depth(depth)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> RegionEscape for Predicate<'tcx> {
|
||||
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
|
||||
match *self {
|
||||
Predicate::Trait(ref data) => data.has_regions_escaping_depth(depth),
|
||||
Predicate::Equate(ref data) => data.has_regions_escaping_depth(depth),
|
||||
Predicate::RegionOutlives(ref data) => data.has_regions_escaping_depth(depth),
|
||||
Predicate::TypeOutlives(ref data) => data.has_regions_escaping_depth(depth),
|
||||
Predicate::Projection(ref data) => data.has_regions_escaping_depth(depth),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> RegionEscape for TraitRef<'tcx> {
|
||||
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
|
||||
self.substs.types.iter().any(|t| t.has_regions_escaping_depth(depth)) ||
|
||||
@ -6988,9 +7025,15 @@ pub trait HasProjectionTypes {
|
||||
fn has_projection_types(&self) -> bool;
|
||||
}
|
||||
|
||||
impl<'tcx,T:HasProjectionTypes> HasProjectionTypes for VecPerParamSpace<T> {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
self.iter().any(|p| p.has_projection_types())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasProjectionTypes for ty::GenericBounds<'tcx> {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
self.predicates.iter().any(|p| p.has_projection_types())
|
||||
self.predicates.has_projection_types()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -216,7 +216,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
|
||||
//
|
||||
// Note that as the method comes from a trait, it should not have
|
||||
// any late-bound regions appearing in its bounds.
|
||||
let method_bounds = method_ty.generics.to_bounds(fcx.tcx(), trait_ref.substs);
|
||||
let method_bounds = fcx.instantiate_bounds(span, trait_ref.substs, &method_ty.generics);
|
||||
assert!(!method_bounds.has_escaping_regions());
|
||||
fcx.add_obligations_for_parameters(
|
||||
traits::ObligationCause::misc(span, fcx.body_id),
|
||||
|
@ -768,6 +768,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
||||
// Check whether the impl imposes obligations we have to worry about.
|
||||
let impl_generics = ty::lookup_item_type(self.tcx(), impl_def_id).generics;
|
||||
let impl_bounds = impl_generics.to_bounds(self.tcx(), substs);
|
||||
// TODO assoc type normalization here?
|
||||
|
||||
// Erase any late-bound regions bound in the impl
|
||||
// which appear in the bounds.
|
||||
|
@ -93,7 +93,7 @@ use middle::subst::{mod, Subst, Substs, VecPerParamSpace, ParamSpace};
|
||||
use middle::traits;
|
||||
use middle::ty::{FnSig, VariantInfo, TypeScheme};
|
||||
use middle::ty::{Disr, ParamTy, ParameterEnvironment};
|
||||
use middle::ty::{mod, HasProjectionTypes, Ty};
|
||||
use middle::ty::{mod, HasProjectionTypes, RegionEscape, Ty};
|
||||
use middle::ty::liberate_late_bound_regions;
|
||||
use middle::ty::{MethodCall, MethodCallee, MethodMap, ObjectCastMap};
|
||||
use middle::ty_fold::{TypeFolder, TypeFoldable};
|
||||
@ -1741,6 +1741,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
result
|
||||
}
|
||||
|
||||
/// As `instantiate_type_scheme`, but for the bounds found in a
|
||||
/// generic type scheme.
|
||||
fn instantiate_bounds(&self,
|
||||
span: Span,
|
||||
substs: &Substs<'tcx>,
|
||||
generics: &ty::Generics<'tcx>)
|
||||
-> ty::GenericBounds<'tcx>
|
||||
{
|
||||
ty::GenericBounds {
|
||||
predicates: self.instantiate_type_scheme(span, substs, &generics.predicates)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
|
||||
where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes
|
||||
{
|
||||
@ -1852,7 +1866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
span,
|
||||
&type_scheme.generics);
|
||||
let bounds =
|
||||
type_scheme.generics.to_bounds(self.tcx(), &substs);
|
||||
self.instantiate_bounds(span, &substs, &type_scheme.generics);
|
||||
self.add_obligations_for_parameters(
|
||||
traits::ObligationCause::new(
|
||||
span,
|
||||
@ -4455,7 +4469,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
if let Some(did) = did {
|
||||
let polytype = ty::lookup_item_type(tcx, did);
|
||||
let substs = Substs::new_type(vec![idx_type], vec![]);
|
||||
let bounds = polytype.generics.to_bounds(tcx, &substs);
|
||||
let bounds = fcx.instantiate_bounds(expr.span, &substs, &polytype.generics);
|
||||
fcx.add_obligations_for_parameters(
|
||||
traits::ObligationCause::new(expr.span,
|
||||
fcx.body_id,
|
||||
@ -5270,31 +5284,20 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
}
|
||||
|
||||
// The things we are substituting into the type should not contain
|
||||
// escaping late-bound regions.
|
||||
// escaping late-bound regions, and nor should the base type scheme.
|
||||
assert!(!substs.has_regions_escaping_depth(0));
|
||||
assert!(!type_scheme.has_escaping_regions());
|
||||
|
||||
// In the case of static items taken from impls, there may be
|
||||
// late-bound regions associated with the impl (not declared on
|
||||
// the fn itself). Those should be replaced with fresh variables
|
||||
// now. These can appear either on the type being referenced, or
|
||||
// on the associated bounds.
|
||||
let bounds = type_scheme.generics.to_bounds(fcx.tcx(), &substs);
|
||||
let (ty_late_bound, bounds) =
|
||||
fcx.infcx().replace_late_bound_regions_with_fresh_var(
|
||||
span,
|
||||
infer::FnCall,
|
||||
&ty::Binder((type_scheme.ty, bounds))).0;
|
||||
|
||||
debug!("after late-bounds have been replaced: ty_late_bound={}", ty_late_bound.repr(fcx.tcx()));
|
||||
debug!("after late-bounds have been replaced: bounds={}", bounds.repr(fcx.tcx()));
|
||||
|
||||
// Add all the obligations that are required, substituting and
|
||||
// normalized appropriately.
|
||||
let bounds = fcx.instantiate_bounds(span, &substs, &type_scheme.generics);
|
||||
fcx.add_obligations_for_parameters(
|
||||
traits::ObligationCause::new(span, fcx.body_id, traits::ItemObligation(def.def_id())),
|
||||
&bounds);
|
||||
|
||||
// Substitute the values for the type parameters into the type of
|
||||
// the referenced item.
|
||||
let ty_substituted = fcx.instantiate_type_scheme(span, &substs, &ty_late_bound);
|
||||
let ty_substituted = fcx.instantiate_type_scheme(span, &substs, &type_scheme.ty);
|
||||
|
||||
fcx.write_ty(node_id, ty_substituted);
|
||||
fcx.write_substs(node_id, ty::ItemSubsts { substs: substs });
|
||||
|
@ -269,7 +269,14 @@ impl<'cx,'tcx> BoundsChecker<'cx,'tcx> {
|
||||
pub fn check_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>) {
|
||||
let trait_def = ty::lookup_trait_def(self.fcx.tcx(), trait_ref.def_id);
|
||||
|
||||
let bounds = trait_def.generics.to_bounds(self.tcx(), trait_ref.substs);
|
||||
// TODO uncommented this line causes failures because the impl
|
||||
// obligations are not registered when we do a projection, and
|
||||
// in this case it's those obligations that make the link
|
||||
// between the normalized type ($1) and the result
|
||||
//
|
||||
// let bounds = self.fcx.instantiate_bounds(self.span, trait_ref.substs, &trait_def.generics);
|
||||
|
||||
let bounds = trait_def.generics.to_bounds(self.fcx.tcx(), trait_ref.substs);
|
||||
self.fcx.add_obligations_for_parameters(
|
||||
traits::ObligationCause::new(
|
||||
self.span,
|
||||
@ -319,13 +326,14 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
|
||||
ty::ty_struct(type_id, substs) |
|
||||
ty::ty_enum(type_id, substs) => {
|
||||
let type_scheme = ty::lookup_item_type(self.fcx.tcx(), type_id);
|
||||
let bounds = self.fcx.instantiate_bounds(self.span, substs, &type_scheme.generics);
|
||||
|
||||
if self.binding_count == 0 {
|
||||
self.fcx.add_obligations_for_parameters(
|
||||
traits::ObligationCause::new(self.span,
|
||||
self.fcx.body_id,
|
||||
traits::ItemObligation(type_id)),
|
||||
&type_scheme.generics.to_bounds(self.tcx(), substs));
|
||||
&bounds);
|
||||
} else {
|
||||
// There are two circumstances in which we ignore
|
||||
// region obligations.
|
||||
@ -349,7 +357,6 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
|
||||
//
|
||||
// (I believe we should do the same for traits, but
|
||||
// that will require an RFC. -nmatsakis)
|
||||
let bounds = type_scheme.generics.to_bounds(self.tcx(), substs);
|
||||
let bounds = filter_to_trait_obligations(bounds);
|
||||
self.fcx.add_obligations_for_parameters(
|
||||
traits::ObligationCause::new(self.span,
|
||||
|
@ -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 {
|
||||
SliceExt2::split2(self, pred);
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() { }
|
Loading…
x
Reference in New Issue
Block a user