]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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 | use super::{ | |
12 | FulfillmentError, | |
13 | FulfillmentErrorCode, | |
14 | MismatchedProjectionTypes, | |
15 | ObligationCauseCode, | |
16 | OutputTypeParameterMismatch, | |
17 | PredicateObligation, | |
18 | SelectionError, | |
19 | }; | |
20 | ||
21 | use middle::infer::InferCtxt; | |
22 | use middle::ty::{self, AsPredicate, ReferencesError, ToPolyTraitRef}; | |
23 | use syntax::codemap::Span; | |
24 | use util::ppaux::{Repr, UserString}; | |
25 | ||
26 | pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, | |
27 | errors: &Vec<FulfillmentError<'tcx>>) { | |
28 | for error in errors.iter() { | |
29 | report_fulfillment_error(infcx, error); | |
30 | } | |
31 | } | |
32 | ||
33 | fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, | |
34 | error: &FulfillmentError<'tcx>) { | |
35 | match error.code { | |
36 | FulfillmentErrorCode::CodeSelectionError(ref e) => { | |
37 | report_selection_error(infcx, &error.obligation, e); | |
38 | } | |
39 | FulfillmentErrorCode::CodeProjectionError(ref e) => { | |
40 | report_projection_error(infcx, &error.obligation, e); | |
41 | } | |
42 | FulfillmentErrorCode::CodeAmbiguity => { | |
43 | maybe_report_ambiguity(infcx, &error.obligation); | |
44 | } | |
45 | } | |
46 | } | |
47 | ||
48 | pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, | |
49 | obligation: &PredicateObligation<'tcx>, | |
50 | error: &MismatchedProjectionTypes<'tcx>) | |
51 | { | |
52 | let predicate = | |
53 | infcx.resolve_type_vars_if_possible(&obligation.predicate); | |
54 | if !predicate.references_error() { | |
55 | infcx.tcx.sess.span_err( | |
56 | obligation.cause.span, | |
57 | format!( | |
58 | "type mismatch resolving `{}`: {}", | |
59 | predicate.user_string(infcx.tcx), | |
60 | ty::type_err_to_str(infcx.tcx, &error.err)).as_slice()); | |
61 | note_obligation_cause(infcx, obligation); | |
62 | } | |
63 | } | |
64 | ||
65 | pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, | |
66 | obligation: &PredicateObligation<'tcx>, | |
67 | error: &SelectionError<'tcx>) | |
68 | { | |
69 | match *error { | |
70 | SelectionError::Overflow => { | |
71 | // We could track the stack here more precisely if we wanted, I imagine. | |
72 | let predicate = | |
73 | infcx.resolve_type_vars_if_possible(&obligation.predicate); | |
74 | infcx.tcx.sess.span_err( | |
75 | obligation.cause.span, | |
76 | format!( | |
77 | "overflow evaluating the requirement `{}`", | |
78 | predicate.user_string(infcx.tcx)).as_slice()); | |
79 | ||
80 | suggest_new_overflow_limit(infcx.tcx, obligation.cause.span); | |
81 | ||
82 | note_obligation_cause(infcx, obligation); | |
83 | } | |
84 | SelectionError::Unimplemented => { | |
85 | match obligation.predicate { | |
86 | ty::Predicate::Trait(ref trait_predicate) => { | |
87 | let trait_predicate = | |
88 | infcx.resolve_type_vars_if_possible(trait_predicate); | |
89 | if !trait_predicate.references_error() { | |
90 | let trait_ref = trait_predicate.to_poly_trait_ref(); | |
91 | infcx.tcx.sess.span_err( | |
92 | obligation.cause.span, | |
93 | format!( | |
94 | "the trait `{}` is not implemented for the type `{}`", | |
95 | trait_ref.user_string(infcx.tcx), | |
96 | trait_ref.self_ty().user_string(infcx.tcx)).as_slice()); | |
97 | } | |
98 | } | |
99 | ||
100 | ty::Predicate::Equate(ref predicate) => { | |
101 | let predicate = infcx.resolve_type_vars_if_possible(predicate); | |
102 | let err = infcx.equality_predicate(obligation.cause.span, | |
103 | &predicate).unwrap_err(); | |
104 | infcx.tcx.sess.span_err( | |
105 | obligation.cause.span, | |
106 | format!( | |
107 | "the requirement `{}` is not satisfied (`{}`)", | |
108 | predicate.user_string(infcx.tcx), | |
109 | ty::type_err_to_str(infcx.tcx, &err)).as_slice()); | |
110 | } | |
111 | ||
112 | ty::Predicate::RegionOutlives(ref predicate) => { | |
113 | let predicate = infcx.resolve_type_vars_if_possible(predicate); | |
114 | let err = infcx.region_outlives_predicate(obligation.cause.span, | |
115 | &predicate).unwrap_err(); | |
116 | infcx.tcx.sess.span_err( | |
117 | obligation.cause.span, | |
118 | format!( | |
119 | "the requirement `{}` is not satisfied (`{}`)", | |
120 | predicate.user_string(infcx.tcx), | |
121 | ty::type_err_to_str(infcx.tcx, &err)).as_slice()); | |
122 | } | |
123 | ||
124 | ty::Predicate::Projection(..) | | |
125 | ty::Predicate::TypeOutlives(..) => { | |
126 | let predicate = | |
127 | infcx.resolve_type_vars_if_possible(&obligation.predicate); | |
128 | infcx.tcx.sess.span_err( | |
129 | obligation.cause.span, | |
130 | format!( | |
131 | "the requirement `{}` is not satisfied", | |
132 | predicate.user_string(infcx.tcx)).as_slice()); | |
133 | } | |
134 | } | |
135 | } | |
136 | OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => { | |
137 | let expected_trait_ref = infcx.resolve_type_vars_if_possible(&*expected_trait_ref); | |
138 | let actual_trait_ref = infcx.resolve_type_vars_if_possible(&*actual_trait_ref); | |
139 | if !ty::type_is_error(actual_trait_ref.self_ty()) { | |
140 | infcx.tcx.sess.span_err( | |
141 | obligation.cause.span, | |
142 | format!( | |
143 | "type mismatch: the type `{}` implements the trait `{}`, \ | |
144 | but the trait `{}` is required ({})", | |
145 | expected_trait_ref.self_ty().user_string(infcx.tcx), | |
146 | expected_trait_ref.user_string(infcx.tcx), | |
147 | actual_trait_ref.user_string(infcx.tcx), | |
148 | ty::type_err_to_str(infcx.tcx, e)).as_slice()); | |
149 | note_obligation_cause(infcx, obligation); | |
150 | } | |
151 | } | |
152 | } | |
153 | } | |
154 | ||
155 | pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, | |
156 | obligation: &PredicateObligation<'tcx>) { | |
157 | // Unable to successfully determine, probably means | |
158 | // insufficient type information, but could mean | |
159 | // ambiguous impls. The latter *ought* to be a | |
160 | // coherence violation, so we don't report it here. | |
161 | ||
162 | let predicate = infcx.resolve_type_vars_if_possible(&obligation.predicate); | |
163 | ||
164 | debug!("maybe_report_ambiguity(predicate={}, obligation={})", | |
165 | predicate.repr(infcx.tcx), | |
166 | obligation.repr(infcx.tcx)); | |
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( | |
212 | obligation.cause.span, | |
213 | format!( | |
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), | |
218 | self_ty.user_string(infcx.tcx)).as_slice()); | |
219 | } | |
220 | } | |
221 | ||
222 | _ => { | |
223 | if !infcx.tcx.sess.has_errors() { | |
224 | infcx.tcx.sess.span_err( | |
225 | obligation.cause.span, | |
226 | format!( | |
227 | "type annotations required: cannot resolve `{}`", | |
228 | predicate.user_string(infcx.tcx)).as_slice()); | |
229 | note_obligation_cause(infcx, obligation); | |
230 | } | |
231 | } | |
232 | } | |
233 | } | |
234 | ||
235 | fn note_obligation_cause<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, | |
236 | obligation: &PredicateObligation<'tcx>) | |
237 | { | |
238 | note_obligation_cause_code(infcx, | |
239 | &obligation.predicate, | |
240 | obligation.cause.span, | |
241 | &obligation.cause.code); | |
242 | } | |
243 | ||
244 | fn note_obligation_cause_code<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, | |
245 | _predicate: &ty::Predicate<'tcx>, | |
246 | cause_span: Span, | |
247 | cause_code: &ObligationCauseCode<'tcx>) | |
248 | { | |
249 | let tcx = infcx.tcx; | |
250 | match *cause_code { | |
251 | ObligationCauseCode::MiscObligation => { } | |
252 | ObligationCauseCode::ItemObligation(item_def_id) => { | |
253 | let item_name = ty::item_path_str(tcx, item_def_id); | |
254 | tcx.sess.span_note( | |
255 | cause_span, | |
256 | format!("required by `{}`", item_name).as_slice()); | |
257 | } | |
258 | ObligationCauseCode::ObjectCastObligation(object_ty) => { | |
259 | tcx.sess.span_note( | |
260 | cause_span, | |
261 | format!( | |
262 | "required for the cast to the object type `{}`", | |
263 | infcx.ty_to_string(object_ty)).as_slice()); | |
264 | } | |
265 | ObligationCauseCode::RepeatVec => { | |
266 | tcx.sess.span_note( | |
267 | cause_span, | |
268 | "the `Copy` trait is required because the \ | |
269 | repeated element will be copied"); | |
270 | } | |
271 | ObligationCauseCode::VariableType(_) => { | |
272 | tcx.sess.span_note( | |
273 | cause_span, | |
274 | "all local variables must have a statically known size"); | |
275 | } | |
276 | ObligationCauseCode::ReturnType => { | |
277 | tcx.sess.span_note( | |
278 | cause_span, | |
279 | "the return type of a function must have a \ | |
280 | statically known size"); | |
281 | } | |
282 | ObligationCauseCode::AssignmentLhsSized => { | |
283 | tcx.sess.span_note( | |
284 | cause_span, | |
285 | "the left-hand-side of an assignment must have a statically known size"); | |
286 | } | |
287 | ObligationCauseCode::StructInitializerSized => { | |
288 | tcx.sess.span_note( | |
289 | cause_span, | |
290 | "structs must have a statically known size to be initialized"); | |
291 | } | |
292 | ObligationCauseCode::ClosureCapture(var_id, closure_span, builtin_bound) => { | |
293 | let def_id = tcx.lang_items.from_builtin_kind(builtin_bound).unwrap(); | |
294 | let trait_name = ty::item_path_str(tcx, def_id); | |
295 | let name = ty::local_var_name_str(tcx, var_id); | |
296 | span_note!(tcx.sess, closure_span, | |
297 | "the closure that captures `{}` requires that all captured variables \ | |
298 | implement the trait `{}`", | |
299 | name, | |
300 | trait_name); | |
301 | } | |
302 | ObligationCauseCode::FieldSized => { | |
303 | span_note!(tcx.sess, cause_span, | |
304 | "only the last field of a struct or enum variant \ | |
305 | may have a dynamically sized type") | |
306 | } | |
307 | ObligationCauseCode::ObjectSized => { | |
308 | span_note!(tcx.sess, cause_span, | |
309 | "only sized types can be made into objects"); | |
310 | } | |
311 | ObligationCauseCode::SharedStatic => { | |
312 | span_note!(tcx.sess, cause_span, | |
313 | "shared static variables must have a type that implements `Sync`"); | |
314 | } | |
315 | ObligationCauseCode::BuiltinDerivedObligation(ref data) => { | |
316 | let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref); | |
317 | span_note!(tcx.sess, cause_span, | |
318 | "required because it appears within the type `{}`", | |
319 | parent_trait_ref.0.self_ty().user_string(infcx.tcx)); | |
320 | let parent_predicate = parent_trait_ref.as_predicate(); | |
321 | note_obligation_cause_code(infcx, &parent_predicate, cause_span, &*data.parent_code); | |
322 | } | |
323 | ObligationCauseCode::ImplDerivedObligation(ref data) => { | |
324 | let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref); | |
325 | span_note!(tcx.sess, cause_span, | |
326 | "required because of the requirements on the impl of `{}` for `{}`", | |
327 | parent_trait_ref.user_string(infcx.tcx), | |
328 | parent_trait_ref.0.self_ty().user_string(infcx.tcx)); | |
329 | let parent_predicate = parent_trait_ref.as_predicate(); | |
330 | note_obligation_cause_code(infcx, &parent_predicate, cause_span, &*data.parent_code); | |
331 | } | |
332 | } | |
333 | } | |
334 | ||
335 | pub fn suggest_new_overflow_limit(tcx: &ty::ctxt, span: Span) { | |
336 | let current_limit = tcx.sess.recursion_limit.get(); | |
337 | let suggested_limit = current_limit * 2; | |
338 | tcx.sess.span_note( | |
339 | span, | |
340 | &format!( | |
341 | "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", | |
342 | suggested_limit)[]); | |
343 | } |