Skip to content

Commit 3657ae1

Browse files
committed
Don't normalize associated types when in region binders, wait until we instantiate
them. Also fix some assertions and handling of builtin bounds.
1 parent 2bbd2f9 commit 3657ae1

File tree

11 files changed

+214
-85
lines changed

11 files changed

+214
-85
lines changed

src/librustc/middle/traits/fulfill.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ impl<'tcx> FulfillmentContext<'tcx> {
109109
cause: ObligationCause<'tcx>)
110110
-> Ty<'tcx>
111111
{
112+
debug!("normalize_associated_type(trait_ref={}, item_name={})",
113+
trait_ref.repr(infcx.tcx),
114+
item_name.repr(infcx.tcx));
115+
112116
assert!(!trait_ref.has_escaping_regions());
113117

114118
let ty_var = infcx.next_ty_var();
@@ -120,6 +124,9 @@ impl<'tcx> FulfillmentContext<'tcx> {
120124
});
121125
let obligation = Obligation::new(cause, projection.as_predicate());
122126
self.register_predicate(infcx, obligation);
127+
128+
debug!("normalize_associated_type: result={}", ty_var.repr(infcx.tcx));
129+
123130
ty_var
124131
}
125132

src/librustc/middle/traits/select.rs

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,7 +1141,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11411141
obligation: &TraitObligation<'tcx>)
11421142
-> Result<BuiltinBoundConditions<'tcx>,SelectionError<'tcx>>
11431143
{
1144-
// TODO seems like we ought to skolemize here, oder?
1144+
// Note: these tests operate on types that may contain bound
1145+
// regions. To be proper, we ought to skolemize here, but we
1146+
// forego the skolemization and defer it until the
1147+
// confirmation step.
1148+
11451149
let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty());
11461150
return match self_ty.sty {
11471151
ty::ty_infer(ty::IntVar(_)) |
@@ -1627,13 +1631,31 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16271631
-> VtableBuiltinData<PredicateObligation<'tcx>>
16281632
{
16291633
let derived_cause = self.derived_cause(obligation, BuiltinDerivedObligation);
1630-
let obligations = nested.iter().map(|&t| {
1631-
util::predicate_for_builtin_bound(
1632-
self.tcx(),
1633-
derived_cause.clone(),
1634-
bound,
1635-
obligation.recursion_depth + 1,
1636-
t)
1634+
let obligations = nested.iter().map(|&bound_ty| {
1635+
// the obligation might be higher-ranked, e.g. for<'a> &'a
1636+
// int : Copy. In that case, we will wind up with
1637+
// late-bound regions in the `nested` vector. So for each
1638+
// one we instantiate to a skolemized region, do our work
1639+
// to produce something like `&'0 int : Copy`, and then
1640+
// re-bind it. This is a bit of busy-work but preserves
1641+
// the invariant that we only manipulate free regions, not
1642+
// bound ones.
1643+
self.infcx.try(|snapshot| {
1644+
let (skol_ty, skol_map) =
1645+
self.infcx().skolemize_late_bound_regions(&ty::Binder(bound_ty), snapshot);
1646+
let skol_predicate =
1647+
util::predicate_for_builtin_bound(
1648+
self.tcx(),
1649+
derived_cause.clone(),
1650+
bound,
1651+
obligation.recursion_depth + 1,
1652+
skol_ty);
1653+
match skol_predicate {
1654+
Ok(skol_predicate) => Ok(self.infcx().plug_leaks(skol_map, snapshot,
1655+
&skol_predicate)),
1656+
Err(ErrorReported) => Err(ErrorReported)
1657+
}
1658+
})
16371659
}).collect::<Result<_, _>>();
16381660
let mut obligations = match obligations {
16391661
Ok(o) => o,

src/librustc/middle/ty.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6903,8 +6903,19 @@ impl RegionEscape for Region {
69036903

69046904
impl<'tcx> RegionEscape for TraitRef<'tcx> {
69056905
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
6906-
self.substs.types.iter().any(|t| t.has_regions_escaping_depth(depth)) &&
6907-
self.substs.regions().iter().any(|t| t.has_regions_escaping_depth(depth))
6906+
self.substs.types.iter().any(|t| t.has_regions_escaping_depth(depth)) ||
6907+
self.substs.regions.has_regions_escaping_depth(depth)
6908+
}
6909+
}
6910+
6911+
impl<'tcx> RegionEscape for subst::RegionSubsts {
6912+
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
6913+
match *self {
6914+
subst::ErasedRegions => false,
6915+
subst::NonerasedRegions(ref r) => {
6916+
r.iter().any(|t| t.has_regions_escaping_depth(depth))
6917+
}
6918+
}
69086919
}
69096920
}
69106921

@@ -6921,7 +6932,7 @@ impl<'tcx> RegionEscape for EquatePredicate<'tcx> {
69216932
}
69226933

69236934
impl<'tcx> RegionEscape for TraitPredicate<'tcx> {
6924-
fn has_regions_escaping_depth(&self, depth: uint) -> bool {
6935+
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
69256936
self.trait_ref.has_regions_escaping_depth(depth)
69266937
}
69276938
}
@@ -6933,14 +6944,14 @@ impl<T:RegionEscape,U:RegionEscape> RegionEscape for OutlivesPredicate<T,U> {
69336944
}
69346945

69356946
impl<'tcx> RegionEscape for ProjectionPredicate<'tcx> {
6936-
fn has_regions_escaping_depth(&self, depth: uint) -> bool {
6947+
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
69376948
self.projection_ty.has_regions_escaping_depth(depth) ||
69386949
self.ty.has_regions_escaping_depth(depth)
69396950
}
69406951
}
69416952

69426953
impl<'tcx> RegionEscape for ProjectionTy<'tcx> {
6943-
fn has_regions_escaping_depth(&self, depth: uint) -> bool {
6954+
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
69446955
self.trait_ref.has_regions_escaping_depth(depth)
69456956
}
69466957
}

src/librustc_typeck/check/assoc.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ pub fn normalize_associated_types_in<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
3333
let mut normalizer = AssociatedTypeNormalizer { span: span,
3434
body_id: body_id,
3535
infcx: infcx,
36-
fulfillment_cx: fulfillment_cx };
36+
fulfillment_cx: fulfillment_cx,
37+
region_binders: 0 };
3738
value.fold_with(&mut normalizer)
3839
}
3940

@@ -42,16 +43,37 @@ struct AssociatedTypeNormalizer<'a,'tcx:'a> {
4243
fulfillment_cx: &'a mut FulfillmentContext<'tcx>,
4344
span: Span,
4445
body_id: ast::NodeId,
46+
region_binders: uint,
4547
}
4648

4749
impl<'a,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'tcx> {
4850
fn tcx(&self) -> &ty::ctxt<'tcx> {
4951
self.infcx.tcx
5052
}
5153

54+
fn enter_region_binder(&mut self) {
55+
self.region_binders += 1;
56+
}
57+
58+
fn exit_region_binder(&mut self) {
59+
self.region_binders -= 1;
60+
}
61+
5262
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
63+
// We don't want to normalize associated types that occur inside of region
64+
// binders, because they may contain bound regions, and we can't cope with that.
65+
//
66+
// Example:
67+
//
68+
// for<'a> fn(<T as Foo<&'a>>::A)
69+
//
70+
// Instead of normalizing `<T as Foo<&'a>>::A` here, we'll
71+
// normalize it when we instantiate those bound regions (which
72+
// should occur eventually).
73+
let no_region_binders = self.region_binders == 0;
74+
5375
match ty.sty {
54-
ty::ty_projection(ref data) => {
76+
ty::ty_projection(ref data) if no_region_binders => {
5577
let cause =
5678
ObligationCause::new(
5779
self.span,

src/librustc_typeck/check/closure.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use super::{check_fn, Expectation, FnCtxt};
1414

1515
use astconv;
1616
use middle::infer;
17+
use middle::region::CodeExtent;
1718
use middle::subst;
1819
use middle::ty::{mod, ToPolyTraitRef, Ty};
1920
use rscope::RegionScope;
@@ -132,10 +133,13 @@ fn check_unboxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
132133

133134
fcx.write_ty(expr.id, closure_type);
134135

136+
let fn_sig =
137+
ty::liberate_late_bound_regions(fcx.tcx(), CodeExtent::from_node_id(body.id), &fn_ty.sig);
138+
135139
check_fn(fcx.ccx,
136140
ast::Unsafety::Normal,
137141
expr.id,
138-
&fn_ty.sig,
142+
&fn_sig,
139143
decl,
140144
expr.id,
141145
&*body,
@@ -310,7 +314,7 @@ fn check_boxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
310314
decl,
311315
abi::Rust,
312316
expected_sig);
313-
let fty_sig = fn_ty.sig.clone();
317+
let fn_sig = fn_ty.sig.clone();
314318
let fty = ty::mk_closure(tcx, fn_ty);
315319
debug!("check_expr_fn fty={}", fcx.infcx().ty_to_string(fty));
316320

@@ -325,10 +329,13 @@ fn check_boxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
325329
ty::UniqTraitStore => (ast::Unsafety::Normal, expr.id)
326330
};
327331

332+
let fn_sig =
333+
ty::liberate_late_bound_regions(tcx, CodeExtent::from_node_id(body.id), &fn_sig);
334+
328335
check_fn(fcx.ccx,
329336
inherited_style,
330337
inherited_style_id,
331-
&fty_sig,
338+
&fn_sig,
332339
&*decl,
333340
expr.id,
334341
&*body,

src/librustc_typeck/check/method/confirm.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -424,17 +424,18 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
424424
debug!("method_bounds after subst = {}",
425425
method_bounds.repr(self.tcx()));
426426

427-
// Substitute the type/early-bound-regions into the method
428-
// signature. In addition, the method signature may bind
429-
// late-bound regions, so instantiate those.
430-
let method_sig = self.fcx.instantiate_type_scheme(self.span,
431-
&all_substs,
432-
&pick.method_ty.fty.sig);
433-
debug!("late-bound lifetimes from method substituted, method_sig={}",
427+
// Instantiate late-bound regions and substitute the trait
428+
// parameters into the method type to get the actual method type.
429+
//
430+
// NB: Instantiate late-bound regions first so that
431+
// `instantiate_type_scheme` can normalize associated types that
432+
// may reference those regions.
433+
let method_sig = self.replace_late_bound_regions_with_fresh_var(&pick.method_ty.fty.sig);
434+
debug!("late-bound lifetimes from method instantiated, method_sig={}",
434435
method_sig.repr(self.tcx()));
435436

436-
let method_sig = self.replace_late_bound_regions_with_fresh_var(&method_sig);
437-
debug!("late-bound lifetimes from method instantiated, method_sig={}",
437+
let method_sig = self.fcx.instantiate_type_scheme(self.span, &all_substs, &method_sig);
438+
debug!("type scheme substituted, method_sig={}",
438439
method_sig.repr(self.tcx()));
439440

440441
InstantiatedMethodSig {

src/librustc_typeck/check/method/mod.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -190,19 +190,21 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
190190
debug!("lookup_in_trait_adjusted: method_num={} method_ty={}",
191191
method_num, method_ty.repr(fcx.tcx()));
192192

193-
// Substitute the trait parameters into the method type and
194-
// instantiate late-bound regions to get the actual method type.
195-
let bare_fn_ty = fcx.instantiate_type_scheme(span,
196-
&trait_ref.substs,
197-
&method_ty.fty);
193+
// Instantiate late-bound regions and substitute the trait
194+
// parameters into the method type to get the actual method type.
195+
//
196+
// NB: Instantiate late-bound regions first so that
197+
// `instantiate_type_scheme` can normalize associated types that
198+
// may reference those regions.
198199
let fn_sig = fcx.infcx().replace_late_bound_regions_with_fresh_var(span,
199200
infer::FnCall,
200-
&bare_fn_ty.sig).0;
201+
&method_ty.fty.sig).0;
202+
let fn_sig = fcx.instantiate_type_scheme(span, &trait_ref.substs, &fn_sig);
201203
let transformed_self_ty = fn_sig.inputs[0];
202204
let fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(ty::BareFnTy {
203205
sig: ty::Binder(fn_sig),
204-
unsafety: bare_fn_ty.unsafety,
205-
abi: bare_fn_ty.abi.clone(),
206+
unsafety: method_ty.fty.unsafety,
207+
abi: method_ty.fty.abi.clone(),
206208
}));
207209

208210
debug!("lookup_in_trait_adjusted: matched method fty={} obligation={}",

0 commit comments

Comments
 (0)