]>
Commit | Line | Data |
---|---|---|
85aaf69f SL |
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 | ||
d9579d0f | 11 | //! Give useful errors and suggestions to users when an item can't be |
85aaf69f SL |
12 | //! found or is otherwise invalid. |
13 | ||
14 | use CrateCtxt; | |
15 | ||
16 | use astconv::AstConv; | |
54a0048b SL |
17 | use check::{self, FnCtxt, UnresolvedTypeAction, autoderef}; |
18 | use rustc::hir::map as hir_map; | |
19 | use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TypeFoldable}; | |
7453a54e | 20 | use middle::cstore::{self, CrateStore}; |
54a0048b SL |
21 | use hir::def::Def; |
22 | use hir::def_id::DefId; | |
62682a34 | 23 | use middle::lang_items::FnOnceTraitLangItem; |
54a0048b SL |
24 | use rustc::ty::subst::Substs; |
25 | use rustc::ty::LvaluePreference; | |
26 | use rustc::traits::{Obligation, SelectionContext}; | |
b039eaaf | 27 | use util::nodemap::{FnvHashSet}; |
85aaf69f | 28 | |
54a0048b | 29 | |
e9174d1e | 30 | use syntax::ast; |
85aaf69f | 31 | use syntax::codemap::Span; |
9cc50fc6 | 32 | use syntax::errors::DiagnosticBuilder; |
54a0048b SL |
33 | use rustc::hir::print as pprust; |
34 | use rustc::hir; | |
35 | use rustc::hir::Expr_; | |
85aaf69f SL |
36 | |
37 | use std::cell; | |
38 | use std::cmp::Ordering; | |
39 | ||
62682a34 | 40 | use super::{MethodError, NoMatchData, CandidateSource, impl_item, trait_item}; |
d9579d0f | 41 | use super::probe::Mode; |
85aaf69f | 42 | |
54a0048b SL |
43 | fn is_fn_ty<'a, 'tcx>(ty: &Ty<'tcx>, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> bool { |
44 | let cx = fcx.tcx(); | |
45 | match ty.sty { | |
46 | // Not all of these (e.g. unsafe fns) implement FnOnce | |
47 | // so we look for these beforehand | |
48 | ty::TyClosure(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) => true, | |
49 | // If it's not a simple function, look for things which implement FnOnce | |
50 | _ => { | |
51 | if let Ok(fn_once_trait_did) = | |
52 | cx.lang_items.require(FnOnceTraitLangItem) { | |
53 | let infcx = fcx.infcx(); | |
54 | let (_, _, opt_is_fn) = autoderef(fcx, | |
55 | span, | |
56 | ty, | |
57 | || None, | |
58 | UnresolvedTypeAction::Ignore, | |
59 | LvaluePreference::NoPreference, | |
60 | |ty, _| { | |
61 | infcx.probe(|_| { | |
62 | let fn_once_substs = | |
63 | Substs::new_trait(vec![infcx.next_ty_var()], | |
64 | Vec::new(), | |
65 | ty); | |
66 | let trait_ref = | |
67 | ty::TraitRef::new(fn_once_trait_did, | |
68 | cx.mk_substs(fn_once_substs)); | |
69 | let poly_trait_ref = trait_ref.to_poly_trait_ref(); | |
70 | let obligation = Obligation::misc(span, | |
71 | fcx.body_id, | |
72 | poly_trait_ref | |
73 | .to_predicate()); | |
74 | let mut selcx = SelectionContext::new(infcx); | |
75 | ||
76 | if selcx.evaluate_obligation(&obligation) { | |
77 | Some(()) | |
78 | } else { | |
79 | None | |
80 | } | |
81 | }) | |
82 | }); | |
83 | ||
84 | opt_is_fn.is_some() | |
85 | } else { | |
86 | false | |
87 | } | |
88 | } | |
89 | } | |
90 | } | |
91 | ||
85aaf69f SL |
92 | pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, |
93 | span: Span, | |
94 | rcvr_ty: Ty<'tcx>, | |
d9579d0f | 95 | item_name: ast::Name, |
e9174d1e | 96 | rcvr_expr: Option<&hir::Expr>, |
62682a34 | 97 | error: MethodError<'tcx>) |
85aaf69f SL |
98 | { |
99 | // avoid suggestions when we don't know what's going on. | |
c1a9b12d | 100 | if rcvr_ty.references_error() { |
85aaf69f SL |
101 | return |
102 | } | |
103 | ||
104 | match error { | |
62682a34 SL |
105 | MethodError::NoMatch(NoMatchData { static_candidates: static_sources, |
106 | unsatisfied_predicates, | |
107 | out_of_scope_traits, | |
54a0048b | 108 | mode, .. }) => { |
85aaf69f | 109 | let cx = fcx.tcx(); |
85aaf69f | 110 | |
9cc50fc6 | 111 | let mut err = fcx.type_error_struct( |
85aaf69f SL |
112 | span, |
113 | |actual| { | |
d9579d0f AL |
114 | format!("no {} named `{}` found for type `{}` \ |
115 | in the current scope", | |
116 | if mode == Mode::MethodCall { "method" } | |
117 | else { "associated item" }, | |
62682a34 | 118 | item_name, |
d9579d0f | 119 | actual) |
85aaf69f SL |
120 | }, |
121 | rcvr_ty, | |
122 | None); | |
123 | ||
d9579d0f | 124 | // If the item has the name of a field, give a help note |
e9174d1e SL |
125 | if let (&ty::TyStruct(def, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) { |
126 | if let Some(field) = def.struct_variant().find_field_named(item_name) { | |
62682a34 SL |
127 | let expr_string = match cx.sess.codemap().span_to_snippet(expr.span) { |
128 | Ok(expr_string) => expr_string, | |
129 | _ => "s".into() // Default to a generic placeholder for the | |
130 | // expression when we can't generate a string | |
131 | // snippet | |
132 | }; | |
133 | ||
54a0048b | 134 | let field_ty = field.ty(cx, substs); |
62682a34 | 135 | |
54a0048b SL |
136 | if is_fn_ty(&field_ty, &fcx, span) { |
137 | err.span_note(span, | |
138 | &format!("use `({0}.{1})(...)` if you meant to call \ | |
139 | the function stored in the `{1}` field", | |
140 | expr_string, item_name)); | |
141 | } else { | |
142 | err.span_note(span, &format!("did you mean to write `{0}.{1}`?", | |
143 | expr_string, item_name)); | |
9cc50fc6 | 144 | } |
54a0048b SL |
145 | } |
146 | } | |
62682a34 | 147 | |
54a0048b SL |
148 | if is_fn_ty(&rcvr_ty, &fcx, span) { |
149 | macro_rules! report_function { | |
150 | ($span:expr, $name:expr) => { | |
151 | err.fileline_note( | |
152 | $span, | |
153 | &format!("{} is a function, perhaps you wish to call it", | |
154 | $name)); | |
155 | } | |
156 | } | |
92a42be0 | 157 | |
54a0048b SL |
158 | if let Some(expr) = rcvr_expr { |
159 | if let Ok (expr_string) = cx.sess.codemap().span_to_snippet(expr.span) { | |
160 | report_function!(expr.span, expr_string); | |
161 | err.span_suggestion(expr.span, | |
162 | "try calling the base function:", | |
163 | format!("{}()", | |
164 | expr_string)); | |
165 | } | |
166 | else if let Expr_::ExprPath(_, path) = expr.node.clone() { | |
167 | if let Some(segment) = path.segments.last() { | |
168 | report_function!(expr.span, segment.identifier.name); | |
62682a34 SL |
169 | } |
170 | } | |
c34b1796 | 171 | } |
85aaf69f SL |
172 | } |
173 | ||
9346a6ac | 174 | if !static_sources.is_empty() { |
9cc50fc6 | 175 | err.fileline_note( |
85aaf69f | 176 | span, |
54a0048b SL |
177 | "found the following associated functions; to be used as \ |
178 | methods, functions must have a `self` parameter"); | |
85aaf69f | 179 | |
9cc50fc6 | 180 | report_candidates(fcx, &mut err, span, item_name, static_sources); |
85aaf69f SL |
181 | } |
182 | ||
62682a34 SL |
183 | if !unsatisfied_predicates.is_empty() { |
184 | let bound_list = unsatisfied_predicates.iter() | |
185 | .map(|p| format!("`{} : {}`", | |
186 | p.self_ty(), | |
187 | p)) | |
188 | .collect::<Vec<_>>() | |
c1a9b12d | 189 | .join(", "); |
9cc50fc6 | 190 | err.fileline_note( |
62682a34 SL |
191 | span, |
192 | &format!("the method `{}` exists but the \ | |
193 | following trait bounds were not satisfied: {}", | |
194 | item_name, | |
195 | bound_list)); | |
196 | } | |
197 | ||
9cc50fc6 SL |
198 | suggest_traits_to_import(fcx, &mut err, span, rcvr_ty, item_name, |
199 | rcvr_expr, out_of_scope_traits); | |
200 | err.emit(); | |
85aaf69f SL |
201 | } |
202 | ||
203 | MethodError::Ambiguity(sources) => { | |
9cc50fc6 SL |
204 | let mut err = struct_span_err!(fcx.sess(), span, E0034, |
205 | "multiple applicable items in scope"); | |
85aaf69f | 206 | |
9cc50fc6 SL |
207 | report_candidates(fcx, &mut err, span, item_name, sources); |
208 | err.emit(); | |
85aaf69f SL |
209 | } |
210 | ||
211 | MethodError::ClosureAmbiguity(trait_def_id) => { | |
c34b1796 AL |
212 | let msg = format!("the `{}` method from the `{}` trait cannot be explicitly \ |
213 | invoked on this closure as we have not yet inferred what \ | |
214 | kind of closure it is", | |
62682a34 | 215 | item_name, |
c1a9b12d | 216 | fcx.tcx().item_path_str(trait_def_id)); |
c34b1796 AL |
217 | let msg = if let Some(callee) = rcvr_expr { |
218 | format!("{}; use overloaded call notation instead (e.g., `{}()`)", | |
219 | msg, pprust::expr_to_string(callee)) | |
220 | } else { | |
221 | msg | |
222 | }; | |
223 | fcx.sess().span_err(span, &msg); | |
85aaf69f | 224 | } |
54a0048b SL |
225 | |
226 | MethodError::PrivateMatch(def) => { | |
227 | let msg = format!("{} `{}` is private", def.kind_name(), item_name); | |
228 | fcx.tcx().sess.span_err(span, &msg); | |
229 | } | |
85aaf69f SL |
230 | } |
231 | ||
232 | fn report_candidates(fcx: &FnCtxt, | |
9cc50fc6 | 233 | err: &mut DiagnosticBuilder, |
85aaf69f | 234 | span: Span, |
d9579d0f | 235 | item_name: ast::Name, |
85aaf69f SL |
236 | mut sources: Vec<CandidateSource>) { |
237 | sources.sort(); | |
238 | sources.dedup(); | |
239 | ||
240 | for (idx, source) in sources.iter().enumerate() { | |
241 | match *source { | |
242 | CandidateSource::ImplSource(impl_did) => { | |
d9579d0f AL |
243 | // Provide the best span we can. Use the item, if local to crate, else |
244 | // the impl, if local to crate (item may be defaulted), else the call site. | |
b039eaaf SL |
245 | let item = impl_item(fcx.tcx(), impl_did, item_name) |
246 | .or_else(|| { | |
247 | trait_item( | |
248 | fcx.tcx(), | |
249 | fcx.tcx().impl_trait_ref(impl_did).unwrap().def_id, | |
250 | item_name | |
251 | ) | |
252 | }).unwrap(); | |
85aaf69f | 253 | let impl_span = fcx.tcx().map.def_id_span(impl_did, span); |
d9579d0f | 254 | let item_span = fcx.tcx().map.def_id_span(item.def_id(), impl_span); |
85aaf69f SL |
255 | |
256 | let impl_ty = check::impl_self_ty(fcx, span, impl_did).ty; | |
257 | ||
c1a9b12d | 258 | let insertion = match fcx.tcx().impl_trait_ref(impl_did) { |
85aaf69f | 259 | None => format!(""), |
c1a9b12d SL |
260 | Some(trait_ref) => { |
261 | format!(" of the trait `{}`", | |
262 | fcx.tcx().item_path_str(trait_ref.def_id)) | |
263 | } | |
85aaf69f SL |
264 | }; |
265 | ||
9cc50fc6 | 266 | span_note!(err, item_span, |
85aaf69f SL |
267 | "candidate #{} is defined in an impl{} for the type `{}`", |
268 | idx + 1, | |
269 | insertion, | |
62682a34 | 270 | impl_ty); |
85aaf69f SL |
271 | } |
272 | CandidateSource::TraitSource(trait_did) => { | |
c1a9b12d | 273 | let item = trait_item(fcx.tcx(), trait_did, item_name).unwrap(); |
d9579d0f | 274 | let item_span = fcx.tcx().map.def_id_span(item.def_id(), span); |
9cc50fc6 | 275 | span_note!(err, item_span, |
85aaf69f SL |
276 | "candidate #{} is defined in the trait `{}`", |
277 | idx + 1, | |
c1a9b12d | 278 | fcx.tcx().item_path_str(trait_did)); |
85aaf69f SL |
279 | } |
280 | } | |
281 | } | |
282 | } | |
283 | } | |
284 | ||
285 | ||
286 | pub type AllTraitsVec = Vec<TraitInfo>; | |
287 | ||
288 | fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, | |
9cc50fc6 | 289 | err: &mut DiagnosticBuilder, |
85aaf69f SL |
290 | span: Span, |
291 | rcvr_ty: Ty<'tcx>, | |
d9579d0f | 292 | item_name: ast::Name, |
e9174d1e SL |
293 | rcvr_expr: Option<&hir::Expr>, |
294 | valid_out_of_scope_traits: Vec<DefId>) | |
85aaf69f SL |
295 | { |
296 | let tcx = fcx.tcx(); | |
85aaf69f SL |
297 | |
298 | if !valid_out_of_scope_traits.is_empty() { | |
299 | let mut candidates = valid_out_of_scope_traits; | |
300 | candidates.sort(); | |
301 | candidates.dedup(); | |
302 | let msg = format!( | |
d9579d0f | 303 | "items from traits can only be used if the trait is in scope; \ |
85aaf69f SL |
304 | the following {traits_are} implemented but not in scope, \ |
305 | perhaps add a `use` for {one_of_them}:", | |
306 | traits_are = if candidates.len() == 1 {"trait is"} else {"traits are"}, | |
307 | one_of_them = if candidates.len() == 1 {"it"} else {"one of them"}); | |
308 | ||
9cc50fc6 | 309 | err.fileline_help(span, &msg[..]); |
85aaf69f SL |
310 | |
311 | for (i, trait_did) in candidates.iter().enumerate() { | |
9cc50fc6 | 312 | err.fileline_help(span, |
7453a54e | 313 | &format!("candidate #{}: `use {}`", |
9cc50fc6 SL |
314 | i + 1, |
315 | fcx.tcx().item_path_str(*trait_did))); | |
85aaf69f SL |
316 | } |
317 | return | |
318 | } | |
319 | ||
c34b1796 | 320 | let type_is_local = type_derefs_to_local(fcx, span, rcvr_ty, rcvr_expr); |
85aaf69f SL |
321 | |
322 | // there's no implemented traits, so lets suggest some traits to | |
d9579d0f | 323 | // implement, by finding ones that have the item name, and are |
85aaf69f SL |
324 | // legal to implement. |
325 | let mut candidates = all_traits(fcx.ccx) | |
326 | .filter(|info| { | |
327 | // we approximate the coherence rules to only suggest | |
328 | // traits that are legal to implement by requiring that | |
329 | // either the type or trait is local. Multidispatch means | |
330 | // this isn't perfect (that is, there are cases when | |
331 | // implementing a trait would be legal but is rejected | |
332 | // here). | |
e9174d1e | 333 | (type_is_local || info.def_id.is_local()) |
d9579d0f | 334 | && trait_item(tcx, info.def_id, item_name).is_some() |
85aaf69f SL |
335 | }) |
336 | .collect::<Vec<_>>(); | |
337 | ||
9346a6ac | 338 | if !candidates.is_empty() { |
85aaf69f SL |
339 | // sort from most relevant to least relevant |
340 | candidates.sort_by(|a, b| a.cmp(b).reverse()); | |
341 | candidates.dedup(); | |
342 | ||
343 | // FIXME #21673 this help message could be tuned to the case | |
344 | // of a type parameter: suggest adding a trait bound rather | |
345 | // than implementing. | |
346 | let msg = format!( | |
d9579d0f AL |
347 | "items from traits can only be used if the trait is implemented and in scope; \ |
348 | the following {traits_define} an item `{name}`, \ | |
85aaf69f SL |
349 | perhaps you need to implement {one_of_them}:", |
350 | traits_define = if candidates.len() == 1 {"trait defines"} else {"traits define"}, | |
351 | one_of_them = if candidates.len() == 1 {"it"} else {"one of them"}, | |
62682a34 | 352 | name = item_name); |
85aaf69f | 353 | |
9cc50fc6 | 354 | err.fileline_help(span, &msg[..]); |
85aaf69f SL |
355 | |
356 | for (i, trait_info) in candidates.iter().enumerate() { | |
9cc50fc6 | 357 | err.fileline_help(span, |
7453a54e | 358 | &format!("candidate #{}: `{}`", |
9cc50fc6 SL |
359 | i + 1, |
360 | fcx.tcx().item_path_str(trait_info.def_id))); | |
85aaf69f SL |
361 | } |
362 | } | |
363 | } | |
364 | ||
365 | /// Checks whether there is a local type somewhere in the chain of | |
366 | /// autoderefs of `rcvr_ty`. | |
367 | fn type_derefs_to_local<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, | |
368 | span: Span, | |
c34b1796 | 369 | rcvr_ty: Ty<'tcx>, |
e9174d1e | 370 | rcvr_expr: Option<&hir::Expr>) -> bool { |
c34b1796 AL |
371 | fn is_local(ty: Ty) -> bool { |
372 | match ty.sty { | |
e9174d1e | 373 | ty::TyEnum(def, _) | ty::TyStruct(def, _) => def.did.is_local(), |
85aaf69f | 374 | |
e9174d1e | 375 | ty::TyTrait(ref tr) => tr.principal_def_id().is_local(), |
85aaf69f | 376 | |
62682a34 | 377 | ty::TyParam(_) => true, |
85aaf69f | 378 | |
85aaf69f SL |
379 | // everything else (primitive types etc.) is effectively |
380 | // non-local (there are "edge" cases, e.g. (LocalType,), but | |
381 | // the noise from these sort of types is usually just really | |
382 | // annoying, rather than any sort of help). | |
383 | _ => false | |
c34b1796 AL |
384 | } |
385 | } | |
386 | ||
387 | // This occurs for UFCS desugaring of `T::method`, where there is no | |
388 | // receiver expression for the method call, and thus no autoderef. | |
389 | if rcvr_expr.is_none() { | |
390 | return is_local(fcx.resolve_type_vars_if_possible(rcvr_ty)); | |
391 | } | |
392 | ||
54a0048b | 393 | check::autoderef(fcx, span, rcvr_ty, || None, |
e9174d1e | 394 | check::UnresolvedTypeAction::Ignore, ty::NoPreference, |
c34b1796 AL |
395 | |ty, _| { |
396 | if is_local(ty) { | |
397 | Some(()) | |
85aaf69f SL |
398 | } else { |
399 | None | |
400 | } | |
c34b1796 | 401 | }).2.is_some() |
85aaf69f SL |
402 | } |
403 | ||
c34b1796 | 404 | #[derive(Copy, Clone)] |
85aaf69f | 405 | pub struct TraitInfo { |
e9174d1e | 406 | pub def_id: DefId, |
85aaf69f SL |
407 | } |
408 | ||
409 | impl TraitInfo { | |
e9174d1e | 410 | fn new(def_id: DefId) -> TraitInfo { |
85aaf69f SL |
411 | TraitInfo { |
412 | def_id: def_id, | |
413 | } | |
414 | } | |
415 | } | |
416 | impl PartialEq for TraitInfo { | |
417 | fn eq(&self, other: &TraitInfo) -> bool { | |
418 | self.cmp(other) == Ordering::Equal | |
419 | } | |
420 | } | |
421 | impl Eq for TraitInfo {} | |
422 | impl PartialOrd for TraitInfo { | |
423 | fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> { Some(self.cmp(other)) } | |
424 | } | |
425 | impl Ord for TraitInfo { | |
426 | fn cmp(&self, other: &TraitInfo) -> Ordering { | |
b039eaaf SL |
427 | // local crates are more important than remote ones (local: |
428 | // cnum == 0), and otherwise we throw in the defid for totality | |
85aaf69f | 429 | |
b039eaaf SL |
430 | let lhs = (other.def_id.krate, other.def_id); |
431 | let rhs = (self.def_id.krate, self.def_id); | |
85aaf69f SL |
432 | lhs.cmp(&rhs) |
433 | } | |
434 | } | |
435 | ||
436 | /// Retrieve all traits in this crate and any dependent crates. | |
437 | pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> { | |
438 | if ccx.all_traits.borrow().is_none() { | |
54a0048b | 439 | use rustc::hir::intravisit; |
85aaf69f SL |
440 | |
441 | let mut traits = vec![]; | |
442 | ||
443 | // Crate-local: | |
444 | // | |
445 | // meh. | |
b039eaaf SL |
446 | struct Visitor<'a, 'tcx:'a> { |
447 | map: &'a hir_map::Map<'tcx>, | |
85aaf69f SL |
448 | traits: &'a mut AllTraitsVec, |
449 | } | |
92a42be0 | 450 | impl<'v, 'a, 'tcx> intravisit::Visitor<'v> for Visitor<'a, 'tcx> { |
e9174d1e | 451 | fn visit_item(&mut self, i: &'v hir::Item) { |
85aaf69f | 452 | match i.node { |
e9174d1e | 453 | hir::ItemTrait(..) => { |
b039eaaf SL |
454 | let def_id = self.map.local_def_id(i.id); |
455 | self.traits.push(TraitInfo::new(def_id)); | |
85aaf69f SL |
456 | } |
457 | _ => {} | |
458 | } | |
85aaf69f SL |
459 | } |
460 | } | |
92a42be0 | 461 | ccx.tcx.map.krate().visit_all_items(&mut Visitor { |
b039eaaf | 462 | map: &ccx.tcx.map, |
85aaf69f | 463 | traits: &mut traits |
92a42be0 | 464 | }); |
85aaf69f SL |
465 | |
466 | // Cross-crate: | |
b039eaaf | 467 | let mut external_mods = FnvHashSet(); |
85aaf69f | 468 | fn handle_external_def(traits: &mut AllTraitsVec, |
b039eaaf | 469 | external_mods: &mut FnvHashSet<DefId>, |
85aaf69f | 470 | ccx: &CrateCtxt, |
92a42be0 SL |
471 | cstore: &for<'a> cstore::CrateStore<'a>, |
472 | dl: cstore::DefLike) { | |
85aaf69f | 473 | match dl { |
7453a54e | 474 | cstore::DlDef(Def::Trait(did)) => { |
85aaf69f SL |
475 | traits.push(TraitInfo::new(did)); |
476 | } | |
7453a54e | 477 | cstore::DlDef(Def::Mod(did)) => { |
b039eaaf SL |
478 | if !external_mods.insert(did) { |
479 | return; | |
480 | } | |
92a42be0 | 481 | for child in cstore.item_children(did) { |
b039eaaf | 482 | handle_external_def(traits, external_mods, |
92a42be0 SL |
483 | ccx, cstore, child.def) |
484 | } | |
85aaf69f SL |
485 | } |
486 | _ => {} | |
487 | } | |
488 | } | |
92a42be0 SL |
489 | let cstore = &*ccx.tcx.sess.cstore; |
490 | ||
491 | for cnum in ccx.tcx.sess.cstore.crates() { | |
492 | for child in cstore.crate_top_level_items(cnum) { | |
493 | handle_external_def(&mut traits, &mut external_mods, | |
494 | ccx, cstore, child.def) | |
495 | } | |
496 | } | |
85aaf69f SL |
497 | |
498 | *ccx.all_traits.borrow_mut() = Some(traits); | |
499 | } | |
500 | ||
501 | let borrow = ccx.all_traits.borrow(); | |
502 | assert!(borrow.is_some()); | |
503 | AllTraits { | |
504 | borrow: borrow, | |
505 | idx: 0 | |
506 | } | |
507 | } | |
508 | ||
509 | pub struct AllTraits<'a> { | |
bd371182 | 510 | borrow: cell::Ref<'a, Option<AllTraitsVec>>, |
85aaf69f SL |
511 | idx: usize |
512 | } | |
513 | ||
514 | impl<'a> Iterator for AllTraits<'a> { | |
515 | type Item = TraitInfo; | |
516 | ||
517 | fn next(&mut self) -> Option<TraitInfo> { | |
518 | let AllTraits { ref borrow, ref mut idx } = *self; | |
519 | // ugh. | |
520 | borrow.as_ref().unwrap().get(*idx).map(|info| { | |
521 | *idx += 1; | |
522 | *info | |
523 | }) | |
524 | } | |
525 | } |