Skip to content

Commit 7d4f487

Browse files
committed
auto merge of #20374 : nikomatsakis/rust/assoc-types, r=nikomatsakis
These mostly derive from problems that @japaric encountered. r? @pcwalton
2 parents 10d99a9 + 004a567 commit 7d4f487

23 files changed

+886
-430
lines changed

src/librustc/metadata/encoder.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1402,6 +1402,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
14021402
}
14031403
ty::TypeTraitItem(associated_type) => {
14041404
encode_name(rbml_w, associated_type.name);
1405+
encode_def_id(rbml_w, associated_type.def_id);
14051406

14061407
let elem = ast_map::PathName(associated_type.name);
14071408
encode_path(rbml_w,

src/librustc/middle/traits/error_reporting.rs

+69-63
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,7 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
7777
"overflow evaluating the requirement `{}`",
7878
predicate.user_string(infcx.tcx)).as_slice());
7979

80-
let current_limit = infcx.tcx.sess.recursion_limit.get();
81-
let suggested_limit = current_limit * 2;
82-
infcx.tcx.sess.span_note(
83-
obligation.cause.span,
84-
format!(
85-
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
86-
suggested_limit)[]);
80+
suggest_new_overflow_limit(infcx, obligation.cause.span);
8781

8882
note_obligation_cause(infcx, obligation);
8983
}
@@ -165,73 +159,76 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
165159
// ambiguous impls. The latter *ought* to be a
166160
// coherence violation, so we don't report it here.
167161

168-
let trait_ref = match obligation.predicate {
169-
ty::Predicate::Trait(ref trait_predicate) => {
170-
infcx.resolve_type_vars_if_possible(
171-
&trait_predicate.to_poly_trait_ref())
172-
}
173-
_ => {
174-
infcx.tcx.sess.span_bug(
175-
obligation.cause.span,
176-
format!("ambiguity from something other than a trait: {}",
177-
obligation.predicate.repr(infcx.tcx)).as_slice());
178-
}
179-
};
180-
181-
let self_ty = trait_ref.self_ty();
162+
let predicate = infcx.resolve_type_vars_if_possible(&obligation.predicate);
182163

183-
debug!("maybe_report_ambiguity(trait_ref={}, self_ty={}, obligation={})",
184-
trait_ref.repr(infcx.tcx),
185-
self_ty.repr(infcx.tcx),
164+
debug!("maybe_report_ambiguity(predicate={}, obligation={})",
165+
predicate.repr(infcx.tcx),
186166
obligation.repr(infcx.tcx));
187-
let all_types = &trait_ref.substs().types;
188-
if all_types.iter().any(|&t| ty::type_is_error(t)) {
189-
} else if all_types.iter().any(|&t| ty::type_needs_infer(t)) {
190-
// This is kind of a hack: it frequently happens that some earlier
191-
// error prevents types from being fully inferred, and then we get
192-
// a bunch of uninteresting errors saying something like "<generic
193-
// #0> doesn't implement Sized". It may even be true that we
194-
// could just skip over all checks where the self-ty is an
195-
// inference variable, but I was afraid that there might be an
196-
// inference variable created, registered as an obligation, and
197-
// then never forced by writeback, and hence by skipping here we'd
198-
// be ignoring the fact that we don't KNOW the type works
199-
// out. Though even that would probably be harmless, given that
200-
// we're only talking about builtin traits, which are known to be
201-
// inhabited. But in any case I just threw in this check for
202-
// has_errors() to be sure that compilation isn't happening
203-
// anyway. In that case, why inundate the user.
204-
if !infcx.tcx.sess.has_errors() {
205-
if infcx.tcx.lang_items.sized_trait()
206-
.map_or(false, |sized_id| sized_id == trait_ref.def_id()) {
207-
infcx.tcx.sess.span_err(
167+
168+
match predicate {
169+
ty::Predicate::Trait(ref data) => {
170+
let trait_ref = data.to_poly_trait_ref();
171+
let self_ty = trait_ref.self_ty();
172+
let all_types = &trait_ref.substs().types;
173+
if all_types.iter().any(|&t| ty::type_is_error(t)) {
174+
} else if all_types.iter().any(|&t| ty::type_needs_infer(t)) {
175+
// This is kind of a hack: it frequently happens that some earlier
176+
// error prevents types from being fully inferred, and then we get
177+
// a bunch of uninteresting errors saying something like "<generic
178+
// #0> doesn't implement Sized". It may even be true that we
179+
// could just skip over all checks where the self-ty is an
180+
// inference variable, but I was afraid that there might be an
181+
// inference variable created, registered as an obligation, and
182+
// then never forced by writeback, and hence by skipping here we'd
183+
// be ignoring the fact that we don't KNOW the type works
184+
// out. Though even that would probably be harmless, given that
185+
// we're only talking about builtin traits, which are known to be
186+
// inhabited. But in any case I just threw in this check for
187+
// has_errors() to be sure that compilation isn't happening
188+
// anyway. In that case, why inundate the user.
189+
if !infcx.tcx.sess.has_errors() {
190+
if
191+
infcx.tcx.lang_items.sized_trait()
192+
.map_or(false, |sized_id| sized_id == trait_ref.def_id())
193+
{
194+
infcx.tcx.sess.span_err(
195+
obligation.cause.span,
196+
format!(
197+
"unable to infer enough type information about `{}`; \
198+
type annotations required",
199+
self_ty.user_string(infcx.tcx)).as_slice());
200+
} else {
201+
infcx.tcx.sess.span_err(
202+
obligation.cause.span,
203+
format!(
204+
"type annotations required: cannot resolve `{}`",
205+
predicate.user_string(infcx.tcx)).as_slice());
206+
note_obligation_cause(infcx, obligation);
207+
}
208+
}
209+
} else if !infcx.tcx.sess.has_errors() {
210+
// Ambiguity. Coherence should have reported an error.
211+
infcx.tcx.sess.span_bug(
208212
obligation.cause.span,
209213
format!(
210-
"unable to infer enough type information about `{}`; type annotations \
211-
required",
214+
"coherence failed to report ambiguity: \
215+
cannot locate the impl of the trait `{}` for \
216+
the type `{}`",
217+
trait_ref.user_string(infcx.tcx),
212218
self_ty.user_string(infcx.tcx)).as_slice());
213-
} else {
219+
}
220+
}
221+
222+
_ => {
223+
if !infcx.tcx.sess.has_errors() {
214224
infcx.tcx.sess.span_err(
215225
obligation.cause.span,
216226
format!(
217-
"unable to infer enough type information to \
218-
locate the impl of the trait `{}` for \
219-
the type `{}`; type annotations required",
220-
trait_ref.user_string(infcx.tcx),
221-
self_ty.user_string(infcx.tcx)).as_slice());
227+
"type annotations required: cannot resolve `{}`",
228+
predicate.user_string(infcx.tcx)).as_slice());
222229
note_obligation_cause(infcx, obligation);
223230
}
224231
}
225-
} else if !infcx.tcx.sess.has_errors() {
226-
// Ambiguity. Coherence should have reported an error.
227-
infcx.tcx.sess.span_bug(
228-
obligation.cause.span,
229-
format!(
230-
"coherence failed to report ambiguity: \
231-
cannot locate the impl of the trait `{}` for \
232-
the type `{}`",
233-
trait_ref.user_string(infcx.tcx),
234-
self_ty.user_string(infcx.tcx)).as_slice());
235232
}
236233
}
237234

@@ -335,3 +332,12 @@ fn note_obligation_cause_code<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
335332
}
336333
}
337334

335+
pub fn suggest_new_overflow_limit(infcx: &InferCtxt, span: Span) {
336+
let current_limit = infcx.tcx.sess.recursion_limit.get();
337+
let suggested_limit = current_limit * 2;
338+
infcx.tcx.sess.span_note(
339+
span,
340+
format!(
341+
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
342+
suggested_limit)[]);
343+
}

src/librustc/middle/traits/fulfill.rs

+26-109
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use middle::infer::{mod, InferCtxt};
11+
use middle::infer::{InferCtxt};
1212
use middle::mem_categorization::Typer;
13-
use middle::ty::{mod, AsPredicate, RegionEscape, Ty, ToPolyTraitRef};
13+
use middle::ty::{mod, RegionEscape, Ty};
1414
use std::collections::HashSet;
1515
use std::collections::hash_map::Entry::{Occupied, Vacant};
1616
use std::default::Default;
@@ -23,7 +23,6 @@ use super::CodeAmbiguity;
2323
use super::CodeProjectionError;
2424
use super::CodeSelectionError;
2525
use super::FulfillmentError;
26-
use super::Obligation;
2726
use super::ObligationCause;
2827
use super::PredicateObligation;
2928
use super::project;
@@ -110,6 +109,8 @@ impl<'tcx> FulfillmentContext<'tcx> {
110109
/// `projection_ty` again.
111110
pub fn normalize_projection_type<'a>(&mut self,
112111
infcx: &InferCtxt<'a,'tcx>,
112+
param_env: &ty::ParameterEnvironment<'tcx>,
113+
typer: &Typer<'tcx>,
113114
projection_ty: ty::ProjectionTy<'tcx>,
114115
cause: ObligationCause<'tcx>)
115116
-> Ty<'tcx>
@@ -121,18 +122,16 @@ impl<'tcx> FulfillmentContext<'tcx> {
121122

122123
// FIXME(#20304) -- cache
123124

124-
let ty_var = infcx.next_ty_var();
125-
let projection =
126-
ty::Binder(ty::ProjectionPredicate {
127-
projection_ty: projection_ty,
128-
ty: ty_var
129-
});
130-
let obligation = Obligation::new(cause, projection.as_predicate());
131-
self.register_predicate(infcx, obligation);
125+
let mut selcx = SelectionContext::new(infcx, param_env, typer);
126+
let normalized = project::normalize_projection_type(&mut selcx, projection_ty, cause, 0);
127+
128+
for obligation in normalized.obligations.into_iter() {
129+
self.register_predicate_obligation(infcx, obligation);
130+
}
132131

133-
debug!("normalize_associated_type: result={}", ty_var.repr(infcx.tcx));
132+
debug!("normalize_associated_type: result={}", normalized.value.repr(infcx.tcx));
134133

135-
ty_var
134+
normalized.value
136135
}
137136

138137
pub fn register_builtin_bound<'a>(&mut self,
@@ -143,7 +142,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
143142
{
144143
match predicate_for_builtin_bound(infcx.tcx, cause, builtin_bound, 0, ty) {
145144
Ok(predicate) => {
146-
self.register_predicate(infcx, predicate);
145+
self.register_predicate_obligation(infcx, predicate);
147146
}
148147
Err(ErrorReported) => { }
149148
}
@@ -158,10 +157,14 @@ impl<'tcx> FulfillmentContext<'tcx> {
158157
register_region_obligation(infcx.tcx, t_a, r_b, cause, &mut self.region_obligations);
159158
}
160159

161-
pub fn register_predicate<'a>(&mut self,
162-
infcx: &InferCtxt<'a,'tcx>,
163-
obligation: PredicateObligation<'tcx>)
160+
pub fn register_predicate_obligation<'a>(&mut self,
161+
infcx: &InferCtxt<'a,'tcx>,
162+
obligation: PredicateObligation<'tcx>)
164163
{
164+
// this helps to reduce duplicate errors, as well as making
165+
// debug output much nicer to read and so on.
166+
let obligation = infcx.resolve_type_vars_if_possible(&obligation);
167+
165168
if !self.duplicate_set.insert(obligation.predicate.clone()) {
166169
debug!("register_predicate({}) -- already seen, skip", obligation.repr(infcx.tcx));
167170
return;
@@ -290,7 +293,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
290293
// Now go through all the successful ones,
291294
// registering any nested obligations for the future.
292295
for new_obligation in new_obligations.into_iter() {
293-
self.register_predicate(selcx.infcx(), new_obligation);
296+
self.register_predicate_obligation(selcx.infcx(), new_obligation);
294297
}
295298
}
296299

@@ -398,104 +401,18 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
398401
project_obligation.repr(tcx),
399402
result.repr(tcx));
400403
match result {
401-
Ok(()) => {
404+
Ok(Some(obligations)) => {
405+
new_obligations.extend(obligations.into_iter());
402406
true
403407
}
404-
Err(project::ProjectionError::TooManyCandidates) => {
405-
// Without more type information, we can't say much.
408+
Ok(None) => {
406409
false
407410
}
408-
Err(project::ProjectionError::NoCandidate) => {
409-
// This means that we have a type like `<T as
410-
// Trait>::name = U` but we couldn't find any more
411-
// information. This could just be that we're in a
412-
// function like:
413-
//
414-
// fn foo<T:Trait>(...)
415-
//
416-
// in which case this is not an error. But it
417-
// might also mean we're in a situation where we
418-
// don't actually know that `T : Trait` holds,
419-
// which would be weird (e.g., if `T` was not a
420-
// parameter type but a normal type, like `int`).
421-
//
422-
// So what we do is to (1) add a requirement that
423-
// `T : Trait` (just in case) and (2) try to unify
424-
// `U` with `<T as Trait>::name`.
425-
426-
if !ty::binds_late_bound_regions(selcx.tcx(), data) {
427-
// Check that `T : Trait` holds.
428-
let trait_ref = data.to_poly_trait_ref();
429-
new_obligations.push(obligation.with(trait_ref.as_predicate()));
430-
431-
// Fallback to `<T as Trait>::name`. If this
432-
// fails, then the output must be at least
433-
// somewhat constrained, and we cannot verify
434-
// that constraint, so yield an error.
435-
let ty_projection = ty::mk_projection(tcx,
436-
trait_ref.0.clone(),
437-
data.0.projection_ty.item_name);
438-
439-
debug!("process_predicate: falling back to projection {}",
440-
ty_projection.repr(selcx.tcx()));
441-
442-
match infer::mk_eqty(selcx.infcx(),
443-
true,
444-
infer::EquatePredicate(obligation.cause.span),
445-
ty_projection,
446-
data.0.ty) {
447-
Ok(()) => { }
448-
Err(_) => {
449-
debug!("process_predicate: fallback failed to unify; error");
450-
errors.push(
451-
FulfillmentError::new(
452-
obligation.clone(),
453-
CodeSelectionError(Unimplemented)));
454-
}
455-
}
456-
457-
true
458-
} else {
459-
// If we have something like
460-
//
461-
// for<'a> <T<'a> as Trait>::name == &'a int
462-
//
463-
// there is no "canonical form" for us to
464-
// make, so just report the lack of candidates
465-
// as an error.
466-
467-
debug!("process_predicate: can't fallback, higher-ranked");
468-
errors.push(
469-
FulfillmentError::new(
470-
obligation.clone(),
471-
CodeSelectionError(Unimplemented)));
472-
473-
true
474-
}
475-
}
476-
Err(project::ProjectionError::MismatchedTypes(e)) => {
411+
Err(err) => {
477412
errors.push(
478413
FulfillmentError::new(
479414
obligation.clone(),
480-
CodeProjectionError(e)));
481-
true
482-
}
483-
Err(project::ProjectionError::TraitSelectionError(_)) => {
484-
// There was an error matching `T : Trait` (which
485-
// is a pre-requisite for `<T as Trait>::Name`
486-
// being valid). We could just report the error
487-
// now, but that tends to lead to double error
488-
// reports for the user (one for the obligation `T
489-
// : Trait`, typically incurred somewhere else,
490-
// and one from here). Instead, we'll create the
491-
// `T : Trait` obligation and add THAT as a
492-
// requirement. This will (eventually) trigger the
493-
// same error, but it will also wind up flagged as
494-
// a duplicate if another requirement that `T :
495-
// Trait` arises from somewhere else.
496-
let trait_predicate = data.to_poly_trait_ref();
497-
let trait_obligation = obligation.with(trait_predicate.as_predicate());
498-
new_obligations.push(trait_obligation);
415+
CodeProjectionError(err)));
499416
true
500417
}
501418
}

src/librustc/middle/traits/mod.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ use util::ppaux::Repr;
2727
pub use self::error_reporting::report_fulfillment_errors;
2828
pub use self::fulfill::{FulfillmentContext, RegionObligation};
2929
pub use self::project::MismatchedProjectionTypes;
30-
pub use self::project::project_type;
31-
pub use self::project::ProjectionResult;
30+
pub use self::project::normalize;
31+
pub use self::project::Normalized;
3232
pub use self::select::SelectionContext;
3333
pub use self::select::SelectionCache;
3434
pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
@@ -320,6 +320,16 @@ impl<'tcx,O> Obligation<'tcx,O> {
320320
predicate: trait_ref }
321321
}
322322

323+
fn with_depth(cause: ObligationCause<'tcx>,
324+
recursion_depth: uint,
325+
trait_ref: O)
326+
-> Obligation<'tcx, O>
327+
{
328+
Obligation { cause: cause,
329+
recursion_depth: recursion_depth,
330+
predicate: trait_ref }
331+
}
332+
323333
pub fn misc(span: Span, body_id: ast::NodeId, trait_ref: O) -> Obligation<'tcx, O> {
324334
Obligation::new(ObligationCause::misc(span, body_id), trait_ref)
325335
}

0 commit comments

Comments
 (0)