Normalize bounds also in the UFCS cases (and get more systematic about it)

This commit is contained in:
Niko Matsakis 2014-12-30 14:49:13 -05:00
parent 90252b8ddb
commit 0aa7ba9f5e
7 changed files with 123 additions and 26 deletions

View File

@ -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 => {

View File

@ -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()
}
}

View File

@ -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),

View File

@ -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.

View File

@ -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 });

View File

@ -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,

View 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 {
SliceExt2::split2(self, pred);
loop {}
}
}
fn main() { }