Skip to content

Commit a110d79

Browse files
committed
Implement "perfect forwarding" for HR impls (rust-lang#19730).
1 parent eaf9422 commit a110d79

File tree

31 files changed

+671
-386
lines changed

31 files changed

+671
-386
lines changed

src/librustc/lint/builtin.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1703,9 +1703,7 @@ impl LintPass for Stability {
17031703
method_num: index,
17041704
..
17051705
}) => {
1706-
ty::trait_item(cx.tcx,
1707-
trait_ref.def_id(),
1708-
index).def_id()
1706+
ty::trait_item(cx.tcx, trait_ref.def_id, index).def_id()
17091707
}
17101708
}
17111709
}

src/librustc/metadata/csearch.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ pub fn get_field_type<'tcx>(tcx: &ty::ctxt<'tcx>, class_id: ast::DefId,
262262
// if there is one.
263263
pub fn get_impl_trait<'tcx>(tcx: &ty::ctxt<'tcx>,
264264
def: ast::DefId)
265-
-> Option<Rc<ty::PolyTraitRef<'tcx>>> {
265+
-> Option<Rc<ty::TraitRef<'tcx>>> {
266266
let cstore = &tcx.sess.cstore;
267267
let cdata = cstore.get_crate_data(def.krate);
268268
decoder::get_impl_trait(&*cdata, def.node, tcx)

src/librustc/metadata/decoder.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -425,11 +425,11 @@ pub fn get_repr_attrs(cdata: Cmd, id: ast::NodeId) -> Vec<attr::ReprAttr> {
425425
pub fn get_impl_trait<'tcx>(cdata: Cmd,
426426
id: ast::NodeId,
427427
tcx: &ty::ctxt<'tcx>)
428-
-> Option<Rc<ty::PolyTraitRef<'tcx>>>
428+
-> Option<Rc<ty::TraitRef<'tcx>>>
429429
{
430430
let item_doc = lookup_item(id, cdata.data());
431431
reader::maybe_get_doc(item_doc, tag_item_trait_ref).map(|tp| {
432-
Rc::new(ty::Binder(doc_trait_ref(tp, tcx, cdata)))
432+
Rc::new(doc_trait_ref(tp, tcx, cdata))
433433
})
434434
}
435435

src/librustc/middle/astencode.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -883,7 +883,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
883883
this.emit_enum_variant("MethodTypeParam", 2, 1, |this| {
884884
this.emit_struct("MethodParam", 2, |this| {
885885
try!(this.emit_struct_field("trait_ref", 0, |this| {
886-
Ok(this.emit_trait_ref(ecx, &p.trait_ref.0))
886+
Ok(this.emit_trait_ref(ecx, &*p.trait_ref))
887887
}));
888888
try!(this.emit_struct_field("method_num", 0, |this| {
889889
this.emit_uint(p.method_num)
@@ -897,7 +897,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
897897
this.emit_enum_variant("MethodTraitObject", 3, 1, |this| {
898898
this.emit_struct("MethodObject", 2, |this| {
899899
try!(this.emit_struct_field("trait_ref", 0, |this| {
900-
Ok(this.emit_trait_ref(ecx, &o.trait_ref.0))
900+
Ok(this.emit_trait_ref(ecx, &*o.trait_ref))
901901
}));
902902
try!(this.emit_struct_field("object_trait_id", 0, |this| {
903903
Ok(this.emit_def_id(o.object_trait_id))
@@ -1453,7 +1453,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
14531453
ty::MethodParam {
14541454
trait_ref: {
14551455
this.read_struct_field("trait_ref", 0, |this| {
1456-
Ok(this.read_poly_trait_ref(dcx))
1456+
Ok(this.read_trait_ref(dcx))
14571457
}).unwrap()
14581458
},
14591459
method_num: {
@@ -1471,7 +1471,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
14711471
ty::MethodObject {
14721472
trait_ref: {
14731473
this.read_struct_field("trait_ref", 0, |this| {
1474-
Ok(this.read_poly_trait_ref(dcx))
1474+
Ok(this.read_trait_ref(dcx))
14751475
}).unwrap()
14761476
},
14771477
object_trait_id: {

src/librustc/middle/dead.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
112112
..
113113
}) => {
114114
let trait_item = ty::trait_item(self.tcx,
115-
trait_ref.def_id(),
115+
trait_ref.def_id,
116116
index);
117117
match trait_item {
118118
ty::MethodTraitItem(method) => {

src/librustc/middle/expr_use_visitor.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ impl OverloadedCallType {
265265
}
266266
Some(ref trait_ref) => (*trait_ref).clone(),
267267
};
268-
OverloadedCallType::from_trait_id(tcx, trait_ref.def_id())
268+
OverloadedCallType::from_trait_id(tcx, trait_ref.def_id)
269269
}
270270

271271
fn from_unboxed_closure(tcx: &ty::ctxt, closure_did: ast::DefId)
@@ -292,7 +292,7 @@ impl OverloadedCallType {
292292
}
293293
MethodTypeParam(MethodParam { ref trait_ref, .. }) |
294294
MethodTraitObject(MethodObject { ref trait_ref, .. }) => {
295-
OverloadedCallType::from_trait_id(tcx, trait_ref.def_id())
295+
OverloadedCallType::from_trait_id(tcx, trait_ref.def_id)
296296
}
297297
}
298298
}

src/librustc/middle/infer/error_reporting.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
395395
fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<String> {
396396
match *values {
397397
infer::Types(ref exp_found) => self.expected_found_str(exp_found),
398-
infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found)
398+
infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found),
399+
infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found)
399400
}
400401
}
401402

@@ -1647,6 +1648,16 @@ impl<'tcx> Resolvable<'tcx> for Ty<'tcx> {
16471648
}
16481649
}
16491650

1651+
impl<'tcx> Resolvable<'tcx> for Rc<ty::TraitRef<'tcx>> {
1652+
fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>)
1653+
-> Rc<ty::TraitRef<'tcx>> {
1654+
Rc::new(infcx.resolve_type_vars_if_possible(&**self))
1655+
}
1656+
fn contains_error(&self) -> bool {
1657+
ty::trait_ref_contains_error(&**self)
1658+
}
1659+
}
1660+
16501661
impl<'tcx> Resolvable<'tcx> for Rc<ty::PolyTraitRef<'tcx>> {
16511662
fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>)
16521663
-> Rc<ty::PolyTraitRef<'tcx>> {

src/librustc/middle/infer/higher_ranked/mod.rs

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>,
358358
where T : Combineable<'tcx>,
359359
F : FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region,
360360
{
361-
unbound_value.fold_with(&mut ty_fold::RegionFolder::new(tcx, |region, current_depth| {
361+
unbound_value.fold_with(&mut ty_fold::RegionFolder::new(tcx, &mut |region, current_depth| {
362362
// we should only be encountering "escaping" late-bound regions here,
363363
// because the ones at the current level should have been replaced
364364
// with fresh variables
@@ -522,3 +522,93 @@ pub fn leak_check<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
522522
}
523523
Ok(())
524524
}
525+
526+
/// This code converts from skolemized regions back to late-bound
527+
/// regions. It works by replacing each region in the taint set of a
528+
/// skolemized region with a bound-region. The bound region will be bound
529+
/// by the outer-most binder in `value`; the caller must ensure that there is
530+
/// such a binder and it is the right place.
531+
///
532+
/// This routine is only intended to be used when the leak-check has
533+
/// passed; currently, it's used in the trait matching code to create
534+
/// a set of nested obligations frmo an impl that matches against
535+
/// something higher-ranked. More details can be found in
536+
/// `middle::traits::doc.rs`.
537+
///
538+
/// As a brief example, consider the obligation `for<'a> Fn(&'a int)
539+
/// -> &'a int`, and the impl:
540+
///
541+
/// impl<A,R> Fn<A,R> for SomethingOrOther
542+
/// where A : Clone
543+
/// { ... }
544+
///
545+
/// Here we will have replaced `'a` with a skolemized region
546+
/// `'0`. This means that our substitution will be `{A=>&'0
547+
/// int, R=>&'0 int}`.
548+
///
549+
/// When we apply the substitution to the bounds, we will wind up with
550+
/// `&'0 int : Clone` as a predicate. As a last step, we then go and
551+
/// replace `'0` with a late-bound region `'a`. The depth is matched
552+
/// to the depth of the predicate, in this case 1, so that the final
553+
/// predicate is `for<'a> &'a int : Clone`.
554+
pub fn plug_leaks<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
555+
skol_map: SkolemizationMap,
556+
snapshot: &CombinedSnapshot,
557+
value: &T)
558+
-> T
559+
where T : TypeFoldable<'tcx> + Repr<'tcx>
560+
{
561+
debug_assert!(leak_check(infcx, &skol_map, snapshot).is_ok());
562+
563+
debug!("plug_leaks(skol_map={}, value={})",
564+
skol_map.repr(infcx.tcx),
565+
value.repr(infcx.tcx));
566+
567+
// Compute a mapping from the "taint set" of each skolemized
568+
// region back to the `ty::BoundRegion` that it originally
569+
// represented. Because `leak_check` passed, we know that that
570+
// these taint sets are mutually disjoint.
571+
let inv_skol_map: FnvHashMap<ty::Region, ty::BoundRegion> =
572+
skol_map
573+
.into_iter()
574+
.flat_map(|(skol_br, skol)| {
575+
infcx.tainted_regions(snapshot, skol)
576+
.into_iter()
577+
.map(move |tainted_region| (tainted_region, skol_br))
578+
})
579+
.collect();
580+
581+
debug!("plug_leaks: inv_skol_map={}",
582+
inv_skol_map.repr(infcx.tcx));
583+
584+
// Remove any instantiated type variables from `value`; those can hide
585+
// references to regions from the `fold_regions` code below.
586+
let value = infcx.resolve_type_vars_if_possible(value);
587+
588+
// Map any skolemization byproducts back to a late-bound
589+
// region. Put that late-bound region at whatever the outermost
590+
// binder is that we encountered in `value`. The caller is
591+
// responsible for ensuring that (a) `value` contains at least one
592+
// binder and (b) that binder is the one we want to use.
593+
let result = ty_fold::fold_regions(infcx.tcx, &value, |r, current_depth| {
594+
match inv_skol_map.get(&r) {
595+
None => r,
596+
Some(br) => {
597+
// It is the responsibility of the caller to ensure
598+
// that each skolemized region appears within a
599+
// binder. In practice, this routine is only used by
600+
// trait checking, and all of the skolemized regions
601+
// appear inside predicates, which always have
602+
// binders, so this assert is satisfied.
603+
assert!(current_depth > 1);
604+
605+
ty::ReLateBound(ty::DebruijnIndex::new(current_depth - 1), br.clone())
606+
}
607+
}
608+
});
609+
610+
debug!("plug_leaks: result={}",
611+
result.repr(infcx.tcx));
612+
613+
result
614+
}

src/librustc/middle/infer/mod.rs

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,8 @@ impl Copy for TypeOrigin {}
137137
#[deriving(Clone, Show)]
138138
pub enum ValuePairs<'tcx> {
139139
Types(ty::expected_found<Ty<'tcx>>),
140-
TraitRefs(ty::expected_found<Rc<ty::PolyTraitRef<'tcx>>>),
140+
TraitRefs(ty::expected_found<Rc<ty::TraitRef<'tcx>>>),
141+
PolyTraitRefs(ty::expected_found<Rc<ty::PolyTraitRef<'tcx>>>),
141142
}
142143

143144
/// The trace designates the path through inference that we took to
@@ -349,7 +350,7 @@ pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
349350
b: Ty<'tcx>)
350351
-> ures<'tcx> {
351352
debug!("can_mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
352-
cx.probe(|| {
353+
cx.probe(|_| {
353354
let trace = TypeTrace {
354355
origin: Misc(codemap::DUMMY_SP),
355356
values: Types(expected_found(true, a, b))
@@ -362,7 +363,7 @@ pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
362363
a: Ty<'tcx>, b: Ty<'tcx>)
363364
-> ures<'tcx> {
364365
debug!("can_mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
365-
cx.probe(|| {
366+
cx.probe(|_| {
366367
let trace = TypeTrace {
367368
origin: Misc(codemap::DUMMY_SP),
368369
values: Types(expected_found(true, a, b))
@@ -634,11 +635,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
634635

635636
/// Execute `f` then unroll any bindings it creates
636637
pub fn probe<R, F>(&self, f: F) -> R where
637-
F: FnOnce() -> R,
638+
F: FnOnce(&CombinedSnapshot) -> R,
638639
{
639640
debug!("probe()");
640641
let snapshot = self.start_snapshot();
641-
let r = f();
642+
let r = f(&snapshot);
642643
self.rollback_to(snapshot);
643644
r
644645
}
@@ -683,21 +684,39 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
683684
})
684685
}
685686

687+
pub fn sub_trait_refs(&self,
688+
a_is_expected: bool,
689+
origin: TypeOrigin,
690+
a: Rc<ty::TraitRef<'tcx>>,
691+
b: Rc<ty::TraitRef<'tcx>>)
692+
-> ures<'tcx>
693+
{
694+
debug!("sub_trait_refs({} <: {})",
695+
a.repr(self.tcx),
696+
b.repr(self.tcx));
697+
self.commit_if_ok(|| {
698+
let trace = TypeTrace {
699+
origin: origin,
700+
values: TraitRefs(expected_found(a_is_expected, a.clone(), b.clone()))
701+
};
702+
self.sub(a_is_expected, trace).trait_refs(&*a, &*b).to_ures()
703+
})
704+
}
705+
686706
pub fn sub_poly_trait_refs(&self,
687707
a_is_expected: bool,
688708
origin: TypeOrigin,
689709
a: Rc<ty::PolyTraitRef<'tcx>>,
690710
b: Rc<ty::PolyTraitRef<'tcx>>)
691711
-> ures<'tcx>
692712
{
693-
debug!("sub_trait_refs({} <: {})",
713+
debug!("sub_poly_trait_refs({} <: {})",
694714
a.repr(self.tcx),
695715
b.repr(self.tcx));
696716
self.commit_if_ok(|| {
697717
let trace = TypeTrace {
698718
origin: origin,
699-
values: TraitRefs(expected_found(a_is_expected,
700-
a.clone(), b.clone()))
719+
values: PolyTraitRefs(expected_found(a_is_expected, a.clone(), b.clone()))
701720
};
702721
self.sub(a_is_expected, trace).binders(&*a, &*b).to_ures()
703722
})
@@ -727,6 +746,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
727746
}
728747
}
729748

749+
pub fn plug_leaks<T>(&self,
750+
skol_map: SkolemizationMap,
751+
snapshot: &CombinedSnapshot,
752+
value: &T)
753+
-> T
754+
where T : TypeFoldable<'tcx> + Repr<'tcx>
755+
{
756+
/*! See `higher_ranked::leak_check` */
757+
758+
higher_ranked::plug_leaks(self, skol_map, snapshot, value)
759+
}
760+
730761
pub fn equality_predicate(&self,
731762
span: Span,
732763
predicate: &ty::PolyEquatePredicate<'tcx>)

src/librustc/middle/privacy.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
257257
};
258258
let tr = ty::impl_trait_ref(self.tcx, local_def(item.id));
259259
let public_trait = tr.clone().map_or(false, |tr| {
260-
!is_local(tr.def_id()) ||
261-
self.exported_items.contains(&tr.def_id().node)
260+
!is_local(tr.def_id) ||
261+
self.exported_items.contains(&tr.def_id.node)
262262
});
263263

264264
if public_ty || public_trait {
@@ -407,7 +407,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
407407
match ty::impl_trait_ref(self.tcx, id) {
408408
Some(t) => {
409409
debug!("privacy - impl of trait {}", id);
410-
self.def_privacy(t.def_id())
410+
self.def_privacy(t.def_id)
411411
}
412412
None => {
413413
debug!("privacy - found a method {}",
@@ -432,7 +432,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
432432
match ty::impl_trait_ref(self.tcx, id) {
433433
Some(t) => {
434434
debug!("privacy - impl of trait {}", id);
435-
self.def_privacy(t.def_id())
435+
self.def_privacy(t.def_id)
436436
}
437437
None => {
438438
debug!("privacy - found a typedef {}",
@@ -811,7 +811,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
811811
// is whether the trait itself is accessible or not.
812812
MethodTypeParam(MethodParam { ref trait_ref, .. }) |
813813
MethodTraitObject(MethodObject { ref trait_ref, .. }) => {
814-
self.report_error(self.ensure_public(span, trait_ref.def_id(),
814+
self.report_error(self.ensure_public(span, trait_ref.def_id,
815815
None, "source trait"));
816816
}
817817
}

src/librustc/middle/resolve_lifetime.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
108108
ast::ItemTy(_, ref generics) |
109109
ast::ItemEnum(_, ref generics) |
110110
ast::ItemStruct(_, ref generics) |
111-
ast::ItemTrait(_, ref generics, _, _, _) => {
111+
ast::ItemTrait(_, ref generics, _, _, _) |
112+
ast::ItemImpl(_, ref generics, _, _, _) => {
112113
// These kinds of items have only early bound lifetime parameters.
113114
let lifetimes = &generics.lifetimes;
114115
let early_scope = EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE);
@@ -117,12 +118,6 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
117118
visit::walk_item(this, item);
118119
});
119120
}
120-
ast::ItemImpl(_, ref generics, _, _, _) => {
121-
// Impls have both early- and late-bound lifetimes.
122-
this.visit_early_late(subst::TypeSpace, generics, |this| {
123-
visit::walk_item(this, item);
124-
})
125-
}
126121
}
127122
});
128123
}

0 commit comments

Comments
 (0)