Skip to content

Commit f45c0ef

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

38 files changed

+759
-416
lines changed

src/librustc/lint/builtin.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1784,9 +1784,7 @@ impl LintPass for Stability {
17841784
method_num: index,
17851785
..
17861786
}) => {
1787-
ty::trait_item(cx.tcx,
1788-
trait_ref.def_id(),
1789-
index).def_id()
1787+
ty::trait_item(cx.tcx, trait_ref.def_id, index).def_id()
17901788
}
17911789
}
17921790
}

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
@@ -887,7 +887,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
887887
this.emit_enum_variant("MethodTypeParam", 2, 1, |this| {
888888
this.emit_struct("MethodParam", 2, |this| {
889889
try!(this.emit_struct_field("trait_ref", 0, |this| {
890-
Ok(this.emit_trait_ref(ecx, &p.trait_ref.0))
890+
Ok(this.emit_trait_ref(ecx, &*p.trait_ref))
891891
}));
892892
try!(this.emit_struct_field("method_num", 0, |this| {
893893
this.emit_uint(p.method_num)
@@ -901,7 +901,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
901901
this.emit_enum_variant("MethodTraitObject", 3, 1, |this| {
902902
this.emit_struct("MethodObject", 2, |this| {
903903
try!(this.emit_struct_field("trait_ref", 0, |this| {
904-
Ok(this.emit_trait_ref(ecx, &o.trait_ref.0))
904+
Ok(this.emit_trait_ref(ecx, &*o.trait_ref))
905905
}));
906906
try!(this.emit_struct_field("object_trait_id", 0, |this| {
907907
Ok(this.emit_def_id(o.object_trait_id))
@@ -1457,7 +1457,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
14571457
ty::MethodParam {
14581458
trait_ref: {
14591459
this.read_struct_field("trait_ref", 0, |this| {
1460-
Ok(this.read_poly_trait_ref(dcx))
1460+
Ok(this.read_trait_ref(dcx))
14611461
}).unwrap()
14621462
},
14631463
method_num: {
@@ -1475,7 +1475,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
14751475
ty::MethodObject {
14761476
trait_ref: {
14771477
this.read_struct_field("trait_ref", 0, |this| {
1478-
Ok(this.read_poly_trait_ref(dcx))
1478+
Ok(this.read_trait_ref(dcx))
14791479
}).unwrap()
14801480
},
14811481
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: 96 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C
219219
self.infcx().resolve_type_vars_if_possible(&result0);
220220
debug!("glb result0 = {}", result0.repr(self.tcx()));
221221

222-
// Generalize the regions appearing in fn_ty0 if possible
222+
// Generalize the regions appearing in result0 if possible
223223
let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot);
224224
let span = self.trace().origin.span();
225225
let result1 =
@@ -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
@@ -414,11 +414,11 @@ impl<'a,'tcx> InferCtxtExt<'tcx> for InferCtxt<'a,'tcx> {
414414
*
415415
* The reason is that when we walk through the subtyping
416416
* algorith, we begin by replacing `'a` with a skolemized
417-
* variable `'0`. We then have `fn(_#0t) <: fn(&'0 int)`. This
418-
* can be made true by unifying `_#0t` with `&'0 int`. In the
417+
* variable `'1`. We then have `fn(_#0t) <: fn(&'1 int)`. This
418+
* can be made true by unifying `_#0t` with `&'1 int`. In the
419419
* process, we create a fresh variable for the skolemized
420-
* region, `'$0`, and hence we have that `_#0t == &'$0
421-
* int`. However, because `'$0` was created during the sub
420+
* region, `'$2`, and hence we have that `_#0t == &'$2
421+
* int`. However, because `'$2` was created during the sub
422422
* computation, if we're not careful we will erroneously
423423
* assume it is one of the transient region variables
424424
* representing a lub/glb internally. Not good.
@@ -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
}

0 commit comments

Comments
 (0)