Skip to content

Commit b7c6e31

Browse files
committed
Make projected types select out of the trait bounds.
1 parent de806bc commit b7c6e31

File tree

13 files changed

+321
-164
lines changed

13 files changed

+321
-164
lines changed

src/librustc/middle/check_static.rs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ use middle::infer;
3131
use middle::traits;
3232
use middle::mem_categorization as mc;
3333
use middle::expr_use_visitor as euv;
34-
use util::common::ErrorReported;
3534
use util::nodemap::NodeSet;
3635

3736
use syntax::ast;
@@ -120,19 +119,14 @@ impl<'a, 'tcx> CheckStaticVisitor<'a, 'tcx> {
120119
let ty = ty::node_id_to_type(self.tcx, e.id);
121120
let infcx = infer::new_infer_ctxt(self.tcx);
122121
let mut fulfill_cx = traits::FulfillmentContext::new();
123-
match traits::poly_trait_ref_for_builtin_bound(self.tcx, ty::BoundSync, ty) {
124-
Ok(trait_ref) => {
125-
let cause = traits::ObligationCause::new(e.span, e.id, traits::SharedStatic);
126-
fulfill_cx.register_trait_ref(self.tcx, trait_ref, cause);
127-
let env = ty::empty_parameter_environment();
128-
match fulfill_cx.select_all_or_error(&infcx, &env, self.tcx) {
129-
Ok(()) => { },
130-
Err(ref errors) => {
131-
traits::report_fulfillment_errors(&infcx, errors);
132-
}
133-
}
122+
let cause = traits::ObligationCause::new(e.span, e.id, traits::SharedStatic);
123+
fulfill_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause);
124+
let env = ty::empty_parameter_environment();
125+
match fulfill_cx.select_all_or_error(&infcx, &env, self.tcx) {
126+
Ok(()) => { },
127+
Err(ref errors) => {
128+
traits::report_fulfillment_errors(&infcx, errors);
134129
}
135-
Err(ErrorReported) => { }
136130
}
137131
}
138132
}

src/librustc/middle/subst.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,10 @@ impl<T> VecPerParamSpace<T> {
412412
self.content.as_slice()
413413
}
414414

415+
pub fn to_vec(self) -> Vec<T> {
416+
self.content
417+
}
418+
415419
pub fn all_vecs<P>(&self, mut pred: P) -> bool where
416420
P: FnMut(&[T]) -> bool,
417421
{

src/librustc/middle/traits/fulfill.rs

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -119,43 +119,43 @@ impl<'tcx> FulfillmentContext<'tcx> {
119119
ty: ty_var
120120
});
121121
let obligation = Obligation::new(cause, projection.as_predicate());
122-
self.register_predicate(infcx.tcx, obligation);
122+
self.register_predicate(infcx, obligation);
123123
ty_var
124124
}
125125

126-
pub fn register_builtin_bound(&mut self,
127-
tcx: &ty::ctxt<'tcx>,
128-
ty: Ty<'tcx>,
129-
builtin_bound: ty::BuiltinBound,
130-
cause: ObligationCause<'tcx>)
126+
pub fn register_builtin_bound<'a>(&mut self,
127+
infcx: &InferCtxt<'a,'tcx>,
128+
ty: Ty<'tcx>,
129+
builtin_bound: ty::BuiltinBound,
130+
cause: ObligationCause<'tcx>)
131131
{
132-
match predicate_for_builtin_bound(tcx, cause, builtin_bound, 0, ty) {
132+
match predicate_for_builtin_bound(infcx.tcx, cause, builtin_bound, 0, ty) {
133133
Ok(predicate) => {
134-
self.register_predicate(tcx, predicate);
134+
self.register_predicate(infcx, predicate);
135135
}
136136
Err(ErrorReported) => { }
137137
}
138138
}
139139

140-
pub fn register_region_obligation(&mut self,
141-
tcx: &ty::ctxt<'tcx>,
142-
t_a: Ty<'tcx>,
143-
r_b: ty::Region,
144-
cause: ObligationCause<'tcx>)
140+
pub fn register_region_obligation<'a>(&mut self,
141+
infcx: &InferCtxt<'a,'tcx>,
142+
t_a: Ty<'tcx>,
143+
r_b: ty::Region,
144+
cause: ObligationCause<'tcx>)
145145
{
146-
register_region_obligation(tcx, t_a, r_b, cause, &mut self.region_obligations);
146+
register_region_obligation(infcx.tcx, t_a, r_b, cause, &mut self.region_obligations);
147147
}
148148

149149
pub fn register_predicate<'a>(&mut self,
150-
tcx: &ty::ctxt<'tcx>,
150+
infcx: &InferCtxt<'a,'tcx>,
151151
obligation: PredicateObligation<'tcx>)
152152
{
153153
if !self.duplicate_set.insert(obligation.predicate.clone()) {
154-
debug!("register_predicate({}) -- already seen, skip", obligation.repr(tcx));
154+
debug!("register_predicate({}) -- already seen, skip", obligation.repr(infcx.tcx));
155155
return;
156156
}
157157

158-
debug!("register_predicate({})", obligation.repr(tcx));
158+
debug!("register_predicate({})", obligation.repr(infcx.tcx));
159159
self.predicates.push(obligation);
160160
}
161161

@@ -230,7 +230,6 @@ impl<'tcx> FulfillmentContext<'tcx> {
230230
self.predicates.len(),
231231
only_new_obligations);
232232

233-
let tcx = selcx.tcx();
234233
let mut errors = Vec::new();
235234

236235
loop {
@@ -279,7 +278,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
279278
// Now go through all the successful ones,
280279
// registering any nested obligations for the future.
281280
for new_obligation in new_obligations.into_iter() {
282-
self.register_predicate(tcx, new_obligation);
281+
self.register_predicate(selcx.infcx(), new_obligation);
283282
}
284283
}
285284

@@ -469,17 +468,22 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
469468
CodeProjectionError(e)));
470469
true
471470
}
472-
Err(project::ProjectionError::TraitSelectionError(e)) => {
473-
// Extract just the `T : Trait` from `<T as
474-
// Trait>::Name == U`, so that when we report an
475-
// error to the user, it says something like "`T :
476-
// Trait` not satisfied".5D
471+
Err(project::ProjectionError::TraitSelectionError(_)) => {
472+
// There was an error matching `T : Trait` (which
473+
// is a pre-requisite for `<T as Trait>::Name`
474+
// being valid). We could just report the error
475+
// now, but that tends to lead to double error
476+
// reports for the user (one for the obligation `T
477+
// : Trait`, typically incurred somewhere else,
478+
// and one from here). Instead, we'll create the
479+
// `T : Trait` obligation and add THAT as a
480+
// requirement. This will (eventually) trigger the
481+
// same error, but it will also wind up flagged as
482+
// a duplicate if another requirement that `T :
483+
// Trait` arises from somewhere else.
477484
let trait_predicate = data.to_poly_trait_ref();
478485
let trait_obligation = obligation.with(trait_predicate.as_predicate());
479-
errors.push(
480-
FulfillmentError::new(
481-
trait_obligation,
482-
CodeSelectionError(e)));
486+
new_obligations.push(trait_obligation);
483487
true
484488
}
485489
}

src/librustc/middle/traits/mod.rs

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ pub use self::util::elaborate_predicates;
3737
pub use self::util::trait_ref_for_builtin_bound;
3838
pub use self::util::supertraits;
3939
pub use self::util::Supertraits;
40-
pub use self::util::search_trait_and_supertraits_from_bound;
4140
pub use self::util::transitive_bounds;
4241

4342
mod coherence;
@@ -189,10 +188,10 @@ pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>;
189188
///
190189
/// // Case B: Vtable must be provided by caller. This applies when
191190
/// // type is a type parameter.
192-
/// param.clone(); // VtableParam(Oblig_1)
191+
/// param.clone(); // VtableParam
193192
///
194193
/// // Case C: A mix of cases A and B.
195-
/// mixed.clone(); // Vtable(Impl_1, [VtableParam(Oblig_1)])
194+
/// mixed.clone(); // Vtable(Impl_1, [VtableParam])
196195
/// }
197196
/// ```
198197
///
@@ -206,7 +205,7 @@ pub enum Vtable<'tcx, N> {
206205

207206
/// Successful resolution to an obligation provided by the caller
208207
/// for some type parameter.
209-
VtableParam(VtableParamData<'tcx>),
208+
VtableParam,
210209

211210
/// Successful resolution for a builtin trait.
212211
VtableBuiltin(VtableBuiltinData<N>),
@@ -243,15 +242,6 @@ pub struct VtableBuiltinData<N> {
243242
pub nested: subst::VecPerParamSpace<N>
244243
}
245244

246-
/// A vtable provided as a parameter by the caller. For example, in a
247-
/// function like `fn foo<T:Eq>(...)`, if the `eq()` method is invoked
248-
/// on an instance of `T`, the vtable would be of type `VtableParam`.
249-
#[deriving(PartialEq,Eq,Clone)]
250-
pub struct VtableParamData<'tcx> {
251-
// In the above example, this would `Eq`
252-
pub bound: ty::PolyTraitRef<'tcx>,
253-
}
254-
255245
/// True if neither the trait nor self type is local. Note that `impl_def_id` must refer to an impl
256246
/// of a trait, not an inherent impl.
257247
pub fn is_orphan_impl(tcx: &ty::ctxt,
@@ -302,7 +292,7 @@ pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
302292
// (there shouldn't really be any anyhow).
303293
let cause = ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID);
304294

305-
fulfill_cx.register_builtin_bound(infcx.tcx, ty, bound, cause);
295+
fulfill_cx.register_builtin_bound(infcx, ty, bound, cause);
306296

307297
// Note: we only assume something is `Copy` if we can
308298
// *definitively* show that it implements `Copy`. Otherwise,
@@ -361,7 +351,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
361351
VtableImpl(ref i) => i.iter_nested(),
362352
VtableFnPointer(..) => (&[]).iter(),
363353
VtableUnboxedClosure(..) => (&[]).iter(),
364-
VtableParam(_) => (&[]).iter(),
354+
VtableParam => (&[]).iter(),
365355
VtableBuiltin(ref i) => i.iter_nested(),
366356
}
367357
}
@@ -371,7 +361,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
371361
VtableImpl(ref i) => VtableImpl(i.map_nested(op)),
372362
VtableFnPointer(ref sig) => VtableFnPointer((*sig).clone()),
373363
VtableUnboxedClosure(d, ref s) => VtableUnboxedClosure(d, s.clone()),
374-
VtableParam(ref p) => VtableParam((*p).clone()),
364+
VtableParam => VtableParam,
375365
VtableBuiltin(ref b) => VtableBuiltin(b.map_nested(op)),
376366
}
377367
}
@@ -383,7 +373,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
383373
VtableImpl(i) => VtableImpl(i.map_move_nested(op)),
384374
VtableFnPointer(sig) => VtableFnPointer(sig),
385375
VtableUnboxedClosure(d, s) => VtableUnboxedClosure(d, s),
386-
VtableParam(p) => VtableParam(p),
376+
VtableParam => VtableParam,
387377
VtableBuiltin(no) => VtableBuiltin(no.map_move_nested(op)),
388378
}
389379
}

src/librustc/middle/traits/project.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,12 @@ pub fn project_type<'cx,'tcx>(
128128
&mut candidates);
129129

130130
if candidates.vec.is_empty() {
131-
// TODO This `if` is not necessarily wrong, but it needs an
132-
// explanation, and it should probably be accompanied by a
133-
// similar rule in `select.rs`. Currently it's *needed*
134-
// because the impl-trait-for-trait branch has not landed.
131+
// FIXME(#20297) -- In `select.rs` there is similar logic that
132+
// gives precedence to where-clauses, but it's a bit more
133+
// fine-grained. I was lazy here and just always give
134+
// precedence to where-clauses or other such sources over
135+
// actually dredging through impls. This logic probably should
136+
// be tightened up.
135137

136138
let () = try!(assemble_candidates_from_impls(selcx,
137139
obligation,

0 commit comments

Comments
 (0)