Skip to content

Commit 0aa7ba9

Browse files
committed
Normalize bounds also in the UFCS cases (and get more systematic about it)
1 parent 90252b8 commit 0aa7ba9

File tree

7 files changed

+123
-26
lines changed

7 files changed

+123
-26
lines changed

src/librustc/middle/traits/project.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,8 @@ fn confirm_candidate<'cx,'tcx>(
363363
break;
364364
}
365365

366+
// TODO we need the impl_vtable items here
367+
366368
match impl_ty {
367369
Some(ty) => ty,
368370
None => {

src/librustc/middle/ty.rs

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6385,7 +6385,7 @@ pub fn construct_parameter_environment<'tcx>(
63856385
}
63866386

63876387
fn push_types_from_defs<'tcx>(tcx: &ty::ctxt<'tcx>,
6388-
types: &mut subst::VecPerParamSpace<Ty<'tcx>>,
6388+
types: &mut VecPerParamSpace<Ty<'tcx>>,
63896389
defs: &[TypeParameterDef<'tcx>]) {
63906390
for def in defs.iter() {
63916391
debug!("construct_parameter_environment(): push_types_from_defs: def={}",
@@ -6915,12 +6915,49 @@ impl<'tcx> RegionEscape for Ty<'tcx> {
69156915
}
69166916
}
69176917

6918+
impl<'tcx,T:RegionEscape> RegionEscape for VecPerParamSpace<T> {
6919+
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
6920+
self.iter_enumerated().any(|(space, _, t)| {
6921+
if space == subst::FnSpace {
6922+
t.has_regions_escaping_depth(depth+1)
6923+
} else {
6924+
t.has_regions_escaping_depth(depth)
6925+
}
6926+
})
6927+
}
6928+
}
6929+
6930+
impl<'tcx> RegionEscape for TypeScheme<'tcx> {
6931+
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
6932+
self.ty.has_regions_escaping_depth(depth) ||
6933+
self.generics.has_regions_escaping_depth(depth)
6934+
}
6935+
}
6936+
69186937
impl RegionEscape for Region {
69196938
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
69206939
self.escapes_depth(depth)
69216940
}
69226941
}
69236942

6943+
impl<'tcx> RegionEscape for Generics<'tcx> {
6944+
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
6945+
self.predicates.has_regions_escaping_depth(depth)
6946+
}
6947+
}
6948+
6949+
impl<'tcx> RegionEscape for Predicate<'tcx> {
6950+
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
6951+
match *self {
6952+
Predicate::Trait(ref data) => data.has_regions_escaping_depth(depth),
6953+
Predicate::Equate(ref data) => data.has_regions_escaping_depth(depth),
6954+
Predicate::RegionOutlives(ref data) => data.has_regions_escaping_depth(depth),
6955+
Predicate::TypeOutlives(ref data) => data.has_regions_escaping_depth(depth),
6956+
Predicate::Projection(ref data) => data.has_regions_escaping_depth(depth),
6957+
}
6958+
}
6959+
}
6960+
69246961
impl<'tcx> RegionEscape for TraitRef<'tcx> {
69256962
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
69266963
self.substs.types.iter().any(|t| t.has_regions_escaping_depth(depth)) ||
@@ -6988,9 +7025,15 @@ pub trait HasProjectionTypes {
69887025
fn has_projection_types(&self) -> bool;
69897026
}
69907027

7028+
impl<'tcx,T:HasProjectionTypes> HasProjectionTypes for VecPerParamSpace<T> {
7029+
fn has_projection_types(&self) -> bool {
7030+
self.iter().any(|p| p.has_projection_types())
7031+
}
7032+
}
7033+
69917034
impl<'tcx> HasProjectionTypes for ty::GenericBounds<'tcx> {
69927035
fn has_projection_types(&self) -> bool {
6993-
self.predicates.iter().any(|p| p.has_projection_types())
7036+
self.predicates.has_projection_types()
69947037
}
69957038
}
69967039

src/librustc_typeck/check/method/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
216216
//
217217
// Note that as the method comes from a trait, it should not have
218218
// any late-bound regions appearing in its bounds.
219-
let method_bounds = method_ty.generics.to_bounds(fcx.tcx(), trait_ref.substs);
219+
let method_bounds = fcx.instantiate_bounds(span, trait_ref.substs, &method_ty.generics);
220220
assert!(!method_bounds.has_escaping_regions());
221221
fcx.add_obligations_for_parameters(
222222
traits::ObligationCause::misc(span, fcx.body_id),

src/librustc_typeck/check/method/probe.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
768768
// Check whether the impl imposes obligations we have to worry about.
769769
let impl_generics = ty::lookup_item_type(self.tcx(), impl_def_id).generics;
770770
let impl_bounds = impl_generics.to_bounds(self.tcx(), substs);
771+
// TODO assoc type normalization here?
771772

772773
// Erase any late-bound regions bound in the impl
773774
// which appear in the bounds.

src/librustc_typeck/check/mod.rs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ use middle::subst::{mod, Subst, Substs, VecPerParamSpace, ParamSpace};
9393
use middle::traits;
9494
use middle::ty::{FnSig, VariantInfo, TypeScheme};
9595
use middle::ty::{Disr, ParamTy, ParameterEnvironment};
96-
use middle::ty::{mod, HasProjectionTypes, Ty};
96+
use middle::ty::{mod, HasProjectionTypes, RegionEscape, Ty};
9797
use middle::ty::liberate_late_bound_regions;
9898
use middle::ty::{MethodCall, MethodCallee, MethodMap, ObjectCastMap};
9999
use middle::ty_fold::{TypeFolder, TypeFoldable};
@@ -1741,6 +1741,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17411741
result
17421742
}
17431743

1744+
/// As `instantiate_type_scheme`, but for the bounds found in a
1745+
/// generic type scheme.
1746+
fn instantiate_bounds(&self,
1747+
span: Span,
1748+
substs: &Substs<'tcx>,
1749+
generics: &ty::Generics<'tcx>)
1750+
-> ty::GenericBounds<'tcx>
1751+
{
1752+
ty::GenericBounds {
1753+
predicates: self.instantiate_type_scheme(span, substs, &generics.predicates)
1754+
}
1755+
}
1756+
1757+
17441758
fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
17451759
where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes
17461760
{
@@ -1852,7 +1866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18521866
span,
18531867
&type_scheme.generics);
18541868
let bounds =
1855-
type_scheme.generics.to_bounds(self.tcx(), &substs);
1869+
self.instantiate_bounds(span, &substs, &type_scheme.generics);
18561870
self.add_obligations_for_parameters(
18571871
traits::ObligationCause::new(
18581872
span,
@@ -4455,7 +4469,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
44554469
if let Some(did) = did {
44564470
let polytype = ty::lookup_item_type(tcx, did);
44574471
let substs = Substs::new_type(vec![idx_type], vec![]);
4458-
let bounds = polytype.generics.to_bounds(tcx, &substs);
4472+
let bounds = fcx.instantiate_bounds(expr.span, &substs, &polytype.generics);
44594473
fcx.add_obligations_for_parameters(
44604474
traits::ObligationCause::new(expr.span,
44614475
fcx.body_id,
@@ -5270,31 +5284,20 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
52705284
}
52715285

52725286
// The things we are substituting into the type should not contain
5273-
// escaping late-bound regions.
5287+
// escaping late-bound regions, and nor should the base type scheme.
52745288
assert!(!substs.has_regions_escaping_depth(0));
5289+
assert!(!type_scheme.has_escaping_regions());
52755290

5276-
// In the case of static items taken from impls, there may be
5277-
// late-bound regions associated with the impl (not declared on
5278-
// the fn itself). Those should be replaced with fresh variables
5279-
// now. These can appear either on the type being referenced, or
5280-
// on the associated bounds.
5281-
let bounds = type_scheme.generics.to_bounds(fcx.tcx(), &substs);
5282-
let (ty_late_bound, bounds) =
5283-
fcx.infcx().replace_late_bound_regions_with_fresh_var(
5284-
span,
5285-
infer::FnCall,
5286-
&ty::Binder((type_scheme.ty, bounds))).0;
5287-
5288-
debug!("after late-bounds have been replaced: ty_late_bound={}", ty_late_bound.repr(fcx.tcx()));
5289-
debug!("after late-bounds have been replaced: bounds={}", bounds.repr(fcx.tcx()));
5290-
5291+
// Add all the obligations that are required, substituting and
5292+
// normalized appropriately.
5293+
let bounds = fcx.instantiate_bounds(span, &substs, &type_scheme.generics);
52915294
fcx.add_obligations_for_parameters(
52925295
traits::ObligationCause::new(span, fcx.body_id, traits::ItemObligation(def.def_id())),
52935296
&bounds);
52945297

52955298
// Substitute the values for the type parameters into the type of
52965299
// the referenced item.
5297-
let ty_substituted = fcx.instantiate_type_scheme(span, &substs, &ty_late_bound);
5300+
let ty_substituted = fcx.instantiate_type_scheme(span, &substs, &type_scheme.ty);
52985301

52995302
fcx.write_ty(node_id, ty_substituted);
53005303
fcx.write_substs(node_id, ty::ItemSubsts { substs: substs });

src/librustc_typeck/check/wf.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,14 @@ impl<'cx,'tcx> BoundsChecker<'cx,'tcx> {
269269
pub fn check_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>) {
270270
let trait_def = ty::lookup_trait_def(self.fcx.tcx(), trait_ref.def_id);
271271

272-
let bounds = trait_def.generics.to_bounds(self.tcx(), trait_ref.substs);
272+
// TODO uncommented this line causes failures because the impl
273+
// obligations are not registered when we do a projection, and
274+
// in this case it's those obligations that make the link
275+
// between the normalized type ($1) and the result
276+
//
277+
// let bounds = self.fcx.instantiate_bounds(self.span, trait_ref.substs, &trait_def.generics);
278+
279+
let bounds = trait_def.generics.to_bounds(self.fcx.tcx(), trait_ref.substs);
273280
self.fcx.add_obligations_for_parameters(
274281
traits::ObligationCause::new(
275282
self.span,
@@ -319,13 +326,14 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
319326
ty::ty_struct(type_id, substs) |
320327
ty::ty_enum(type_id, substs) => {
321328
let type_scheme = ty::lookup_item_type(self.fcx.tcx(), type_id);
329+
let bounds = self.fcx.instantiate_bounds(self.span, substs, &type_scheme.generics);
322330

323331
if self.binding_count == 0 {
324332
self.fcx.add_obligations_for_parameters(
325333
traits::ObligationCause::new(self.span,
326334
self.fcx.body_id,
327335
traits::ItemObligation(type_id)),
328-
&type_scheme.generics.to_bounds(self.tcx(), substs));
336+
&bounds);
329337
} else {
330338
// There are two circumstances in which we ignore
331339
// region obligations.
@@ -349,7 +357,6 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
349357
//
350358
// (I believe we should do the same for traits, but
351359
// that will require an RFC. -nmatsakis)
352-
let bounds = type_scheme.generics.to_bounds(self.tcx(), substs);
353360
let bounds = filter_to_trait_obligations(bounds);
354361
self.fcx.add_obligations_for_parameters(
355362
traits::ObligationCause::new(self.span,
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that we normalize associated types that appear in bounds; if
12+
// we didn't, the call to `self.split2()` fails to type check.
13+
14+
#![feature(associated_types)]
15+
16+
struct Splits<'a, T, P>;
17+
struct SplitsN<I>;
18+
19+
trait SliceExt2 for Sized? {
20+
type Item;
21+
22+
fn split2<'a, P>(&'a self, pred: P) -> Splits<'a, Self::Item, P>
23+
where P: FnMut(&Self::Item) -> bool;
24+
fn splitn2<'a, P>(&'a self, n: uint, pred: P) -> SplitsN<Splits<'a, Self::Item, P>>
25+
where P: FnMut(&Self::Item) -> bool;
26+
}
27+
28+
impl<T> SliceExt2 for [T] {
29+
type Item = T;
30+
31+
fn split2<P>(&self, pred: P) -> Splits<T, P> where P: FnMut(&T) -> bool {
32+
loop {}
33+
}
34+
35+
fn splitn2<P>(&self, n: uint, pred: P) -> SplitsN<Splits<T, P>> where P: FnMut(&T) -> bool {
36+
SliceExt2::split2(self, pred);
37+
loop {}
38+
}
39+
}
40+
41+
fn main() { }

0 commit comments

Comments
 (0)