Skip to content

Commit 57aaa9b

Browse files
committed
Make supertrait references work in object types too.
1 parent 7ee5863 commit 57aaa9b

File tree

2 files changed

+71
-12
lines changed

2 files changed

+71
-12
lines changed

src/librustc_typeck/astconv.rs

+44-12
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,8 @@ fn ast_path_to_trait_ref<'a,'tcx>(
627627
}
628628
Some(ref mut v) => {
629629
for binding in assoc_bindings.iter() {
630-
match ast_type_binding_to_projection_predicate(this, trait_ref.clone(), binding) {
630+
match ast_type_binding_to_projection_predicate(this, trait_ref.clone(),
631+
self_ty, binding) {
631632
Ok(pp) => { v.push(pp); }
632633
Err(ErrorReported) => { }
633634
}
@@ -640,10 +641,13 @@ fn ast_path_to_trait_ref<'a,'tcx>(
640641

641642
fn ast_type_binding_to_projection_predicate<'tcx>(
642643
this: &AstConv<'tcx>,
643-
trait_ref: Rc<ty::TraitRef<'tcx>>,
644+
mut trait_ref: Rc<ty::TraitRef<'tcx>>,
645+
self_ty: Option<Ty<'tcx>>,
644646
binding: &ConvertedBinding<'tcx>)
645647
-> Result<ty::ProjectionPredicate<'tcx>, ErrorReported>
646648
{
649+
let tcx = this.tcx();
650+
647651
// Given something like `U : SomeTrait<T=X>`, we want to produce a
648652
// predicate like `<U as SomeTrait>::T = X`. This is somewhat
649653
// subtle in the event that `T` is defined in a supertrait of
@@ -671,39 +675,67 @@ fn ast_type_binding_to_projection_predicate<'tcx>(
671675
});
672676
}
673677

674-
// Otherwise, we have to walk through the supertraits to find those that do.
675-
let mut candidates: Vec<_> =
676-
traits::supertraits(this.tcx(), trait_ref.to_poly_trait_ref())
678+
// Otherwise, we have to walk through the supertraits to find
679+
// those that do. This is complicated by the fact that, for an
680+
// object type, the `Self` type is not present in the
681+
// substitutions (after all, it's being constructed right now),
682+
// but the `supertraits` iterator really wants one. To handle
683+
// this, we currently insert a dummy type and then remove it
684+
// later. Yuck.
685+
686+
let dummy_self_ty = ty::mk_infer(tcx, ty::FreshTy(0));
687+
if self_ty.is_none() { // if converting for an object type
688+
let mut dummy_substs = trait_ref.substs.clone();
689+
assert!(dummy_substs.self_ty().is_none());
690+
dummy_substs.types.push(SelfSpace, dummy_self_ty);
691+
trait_ref = Rc::new(ty::TraitRef::new(trait_ref.def_id,
692+
tcx.mk_substs(dummy_substs)));
693+
}
694+
695+
let mut candidates: Vec<ty::PolyTraitRef> =
696+
traits::supertraits(tcx, trait_ref.to_poly_trait_ref())
677697
.filter(|r| trait_defines_associated_type_named(this, r.def_id(), binding.item_name))
678698
.collect();
679699

700+
// If converting for an object type, then remove the dummy-ty from `Self` now.
701+
// Yuckety yuck.
702+
if self_ty.is_none() {
703+
for candidate in candidates.iter_mut() {
704+
let mut dummy_substs = candidate.0.substs.clone();
705+
assert!(dummy_substs.self_ty() == Some(dummy_self_ty));
706+
dummy_substs.types.pop(SelfSpace);
707+
*candidate = ty::Binder(Rc::new(ty::TraitRef::new(candidate.def_id(),
708+
tcx.mk_substs(dummy_substs))));
709+
}
710+
}
711+
680712
if candidates.len() > 1 {
681-
this.tcx().sess.span_err(
713+
tcx.sess.span_err(
682714
binding.span,
683715
format!("ambiguous associated type: `{}` defined in multiple supertraits `{}`",
684716
token::get_name(binding.item_name),
685-
candidates.user_string(this.tcx())).as_slice());
717+
candidates.user_string(tcx)).as_slice());
686718
return Err(ErrorReported);
687719
}
688720

689721
let candidate = match candidates.pop() {
690722
Some(c) => c,
691723
None => {
692-
this.tcx().sess.span_err(
724+
tcx.sess.span_err(
693725
binding.span,
694726
format!("no associated type `{}` defined in `{}`",
695727
token::get_name(binding.item_name),
696-
trait_ref.user_string(this.tcx())).as_slice());
728+
trait_ref.user_string(tcx)).as_slice());
697729
return Err(ErrorReported);
698730
}
699731
};
700732

701-
if ty::binds_late_bound_regions(this.tcx(), &candidate) {
702-
this.tcx().sess.span_err(
733+
if ty::binds_late_bound_regions(tcx, &candidate) {
734+
tcx.sess.span_err(
703735
binding.span,
704736
format!("associated type `{}` defined in higher-ranked supertrait `{}`",
705737
token::get_name(binding.item_name),
706-
candidate.user_string(this.tcx())).as_slice());
738+
candidate.user_string(tcx)).as_slice());
707739
return Err(ErrorReported);
708740
}
709741

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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+
fn pairwise_sub(mut t: Box<DoubleEndedIterator<Item=int>>) -> int {
12+
let mut result = 0;
13+
loop {
14+
let front = t.next();
15+
let back = t.next_back();
16+
match (front, back) {
17+
(Some(f), Some(b)) => { result += b - f; }
18+
_ => { return result; }
19+
}
20+
}
21+
}
22+
23+
fn main() {
24+
let v = vec!(1, 2, 3, 4, 5, 6);
25+
let r = pairwise_sub(box v.into_iter());
26+
assert_eq!(r, 9);
27+
}

0 commit comments

Comments
 (0)