11
11
use middle:: infer;
12
12
use middle:: traits;
13
13
use middle:: ty:: { mod} ;
14
- use middle:: subst:: { mod, Subst } ;
14
+ use middle:: subst:: { mod, Subst , VecPerParamSpace } ;
15
15
use util:: ppaux:: { mod, Repr } ;
16
16
17
17
use syntax:: ast;
18
18
use syntax:: codemap:: { Span } ;
19
19
use syntax:: parse:: token;
20
20
21
+ use super :: assoc;
22
+
21
23
/// Checks that a method from an impl conforms to the signature of
22
24
/// the same method as declared in the trait.
23
25
///
@@ -42,6 +44,7 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
42
44
impl_trait_ref. repr( tcx) ) ;
43
45
44
46
let infcx = infer:: new_infer_ctxt ( tcx) ;
47
+ let mut fulfillment_cx = traits:: FulfillmentContext :: new ( ) ;
45
48
46
49
let trait_to_impl_substs = & impl_trait_ref. substs ;
47
50
@@ -174,10 +177,11 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
174
177
175
178
// Create a parameter environment that represents the implementation's
176
179
// method.
177
- let impl_env = ty:: ParameterEnvironment :: for_item ( tcx, impl_m. def_id . node ) ;
180
+ let impl_param_env =
181
+ ty:: ParameterEnvironment :: for_item ( tcx, impl_m. def_id . node ) ;
178
182
179
183
// Create mapping from impl to skolemized.
180
- let impl_to_skol_substs = & impl_env . free_substs ;
184
+ let impl_to_skol_substs = & impl_param_env . free_substs ;
181
185
182
186
// Create mapping from trait to skolemized.
183
187
let trait_to_skol_substs =
@@ -188,77 +192,145 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
188
192
debug ! ( "compare_impl_method: trait_to_skol_substs={}" ,
189
193
trait_to_skol_substs. repr( tcx) ) ;
190
194
191
- // Construct trait parameter environment and then shift it into the skolemized viewpoint.
192
- let trait_param_env =
193
- ty:: construct_parameter_environment ( tcx,
194
- & trait_m. generics ,
195
- impl_m_body_id) ;
196
- let trait_param_env =
197
- trait_param_env. subst ( tcx, & trait_to_skol_substs) ;
198
- debug ! ( "compare_impl_method: trait_param_env={}" ,
199
- trait_param_env. repr( tcx) ) ;
200
-
201
- // Create a fresh fulfillment context.
202
- let mut fulfill_cx = traits:: FulfillmentContext :: new ( ) ;
203
-
204
195
// Create obligations for each predicate declared by the impl
205
196
// definition in the context of the trait's parameter
206
197
// environment. We can't just use `impl_env.caller_bounds`,
207
198
// however, because we want to replace all late-bound regions with
208
199
// region variables.
209
200
let impl_bounds =
210
201
impl_m. generics . to_bounds ( tcx, impl_to_skol_substs) ;
202
+
211
203
let ( impl_bounds, _) =
212
204
infcx. replace_late_bound_regions_with_fresh_var (
213
205
impl_m_span,
214
206
infer:: HigherRankedType ,
215
- & ty:: Binder ( impl_bounds) ) ; // TODO I think this is right?
207
+ & ty:: Binder ( impl_bounds) ) ;
216
208
debug ! ( "compare_impl_method: impl_bounds={}" ,
217
209
impl_bounds. repr( tcx) ) ;
218
- for predicate in impl_bounds. predicates . into_iter ( ) {
219
- fulfill_cx. register_predicate (
220
- tcx,
221
- traits:: Obligation :: new ( traits:: ObligationCause :: dummy ( ) ,
222
- predicate) ) ;
223
- }
224
210
225
- // Check that all obligations are satisfied by the implementation's
226
- // version.
227
- match fulfill_cx. select_all_or_error ( & infcx, & trait_param_env, tcx) {
228
- Err ( ref errors) => { traits:: report_fulfillment_errors ( & infcx, errors) }
229
- Ok ( _) => { }
211
+ let mut selcx = traits:: SelectionContext :: new ( & infcx, & impl_param_env, tcx) ;
212
+
213
+ // Normalize the associated types in the impl_bounds.
214
+ let traits:: Normalized { value : impl_bounds, .. } =
215
+ traits:: normalize ( & mut selcx, traits:: ObligationCause :: dummy ( ) , & impl_bounds) ;
216
+
217
+ // Normalize the associated types in the trait_boubnds.
218
+ let trait_bounds = trait_m. generics . to_bounds ( tcx, & trait_to_skol_substs) ;
219
+ let traits:: Normalized { value : trait_bounds, .. } =
220
+ traits:: normalize ( & mut selcx, traits:: ObligationCause :: dummy ( ) , & trait_bounds) ;
221
+
222
+ // Obtain the predicate split predicate sets for each.
223
+ let trait_pred = trait_bounds. predicates . split ( ) ;
224
+ let impl_pred = impl_bounds. predicates . split ( ) ;
225
+
226
+ // This is the only tricky bit of the new way we check implementation methods
227
+ // We need to build a set of predicates where only the FnSpace bounds
228
+ // are from the trait and we assume all other bounds from the implementation
229
+ // to be previously satisfied.
230
+ //
231
+ // We then register the obligations from the impl_m and check to see
232
+ // if all constraints hold.
233
+ let hybrid_preds = VecPerParamSpace :: new (
234
+ impl_pred. types ,
235
+ impl_pred. selfs ,
236
+ trait_pred. fns
237
+ ) ;
238
+
239
+ // Construct trait parameter environment and then shift it into the skolemized viewpoint.
240
+ let mut trait_param_env = impl_param_env. clone ( ) ;
241
+ // The key step here is to update the caller_bounds's predicates to be
242
+ // the new hybrid bounds we computed.
243
+ trait_param_env. caller_bounds . predicates = hybrid_preds;
244
+
245
+ debug ! ( "compare_impl_method: trait_bounds={}" ,
246
+ trait_param_env. caller_bounds. repr( tcx) ) ;
247
+
248
+ for predicate in impl_pred. fns . into_iter ( ) {
249
+ fulfillment_cx. register_predicate_obligation (
250
+ & infcx,
251
+ traits:: Obligation :: new ( traits:: ObligationCause :: dummy ( ) , predicate) ) ;
230
252
}
231
253
232
254
// Compute skolemized form of impl and trait method tys.
233
- let impl_fty = ty:: mk_bare_fn ( tcx, None , impl_m. fty . clone ( ) ) ;
255
+ let impl_fty = ty:: mk_bare_fn ( tcx, None , tcx . mk_bare_fn ( impl_m. fty . clone ( ) ) ) ;
234
256
let impl_fty = impl_fty. subst ( tcx, impl_to_skol_substs) ;
235
- let trait_fty = ty:: mk_bare_fn ( tcx, None , trait_m. fty . clone ( ) ) ;
257
+ let trait_fty = ty:: mk_bare_fn ( tcx, None , tcx . mk_bare_fn ( trait_m. fty . clone ( ) ) ) ;
236
258
let trait_fty = trait_fty. subst ( tcx, & trait_to_skol_substs) ;
237
259
238
- // Check the impl method type IM is a subtype of the trait method
239
- // type TM. To see why this makes sense, think of a vtable. The
240
- // expected type of the function pointers in the vtable is the
241
- // type TM of the trait method. The actual type will be the type
242
- // IM of the impl method. Because we know that IM <: TM, that
243
- // means that anywhere a TM is expected, a IM will do instead. In
244
- // other words, anyone expecting to call a method with the type
245
- // from the trait, can safely call a method with the type from the
246
- // impl instead.
247
- debug ! ( "checking trait method for compatibility: impl ty {}, trait ty {}" ,
248
- impl_fty. repr( tcx) ,
249
- trait_fty. repr( tcx) ) ;
250
- match infer:: mk_subty ( & infcx, false , infer:: MethodCompatCheck ( impl_m_span) ,
251
- impl_fty, trait_fty) {
252
- Ok ( ( ) ) => { }
253
- Err ( ref terr) => {
254
- span_err ! ( tcx. sess, impl_m_span, E0053 ,
255
- "method `{}` has an incompatible type for trait: {}" ,
256
- token:: get_name( trait_m. name) ,
257
- ty:: type_err_to_str( tcx, terr) ) ;
258
- ty:: note_and_explain_type_err ( tcx, terr) ;
260
+ let err = infcx. try ( |snapshot| {
261
+ let origin = infer:: MethodCompatCheck ( impl_m_span) ;
262
+
263
+ let ( impl_sig, _) =
264
+ infcx. replace_late_bound_regions_with_fresh_var ( impl_m_span,
265
+ infer:: HigherRankedType ,
266
+ & impl_m. fty . sig ) ;
267
+
268
+ let impl_sig =
269
+ impl_sig. subst ( tcx, impl_to_skol_substs) ;
270
+ let impl_sig =
271
+ assoc:: normalize_associated_types_in ( & infcx,
272
+ & impl_param_env,
273
+ infcx. tcx ,
274
+ & mut fulfillment_cx,
275
+ impl_m_span,
276
+ impl_m_body_id,
277
+ & impl_sig) ;
278
+ let impl_fty =
279
+ ty:: mk_bare_fn ( tcx,
280
+ None ,
281
+ tcx. mk_bare_fn ( ty:: BareFnTy {
282
+ unsafety : impl_m. fty . unsafety ,
283
+ abi : impl_m. fty . abi ,
284
+ sig : ty:: Binder ( impl_sig) } ) ) ;
285
+ debug ! ( "compare_impl_method: impl_fty={}" ,
286
+ impl_fty. repr( tcx) ) ;
287
+
288
+ let ( trait_sig, skol_map) =
289
+ infcx. skolemize_late_bound_regions ( & trait_m. fty . sig , snapshot) ;
290
+ let trait_sig =
291
+ trait_sig. subst ( tcx, & trait_to_skol_substs) ;
292
+ let trait_sig =
293
+ assoc:: normalize_associated_types_in ( & infcx,
294
+ & impl_param_env,
295
+ infcx. tcx ,
296
+ & mut fulfillment_cx,
297
+ impl_m_span,
298
+ impl_m_body_id,
299
+ & trait_sig) ;
300
+ let trait_fty =
301
+ ty:: mk_bare_fn ( tcx,
302
+ None ,
303
+ tcx. mk_bare_fn ( ty:: BareFnTy {
304
+ unsafety : trait_m. fty . unsafety ,
305
+ abi : trait_m. fty . abi ,
306
+ sig : ty:: Binder ( trait_sig) } ) ) ;
307
+
308
+ debug ! ( "compare_impl_method: trait_fty={}" , trait_fty. repr( tcx) ) ;
309
+ try!( infer:: mk_subty ( & infcx, false , origin, impl_fty, trait_fty) ) ;
310
+ infcx. leak_check ( & skol_map, snapshot)
311
+ } ) ;
312
+
313
+ match err {
314
+ Ok ( ( ) ) => { }
315
+ Err ( terr) => {
316
+ debug ! ( "checking trait method for compatibility: impl ty {}, trait ty {}" ,
317
+ impl_fty. repr( tcx) ,
318
+ trait_fty. repr( tcx) ) ;
319
+ span_err ! ( tcx. sess, impl_m_span, E0053 ,
320
+ "method `{}` has an incompatible type for trait: {}" ,
321
+ token:: get_name( trait_m. name) ,
322
+ ty:: type_err_to_str( tcx, & terr) ) ;
323
+ return ;
259
324
}
260
325
}
261
326
327
+ // Check that all obligations are satisfied by the implementation's
328
+ // version.
329
+ match fulfillment_cx. select_all_or_error ( & infcx, & trait_param_env, tcx) {
330
+ Err ( ref errors) => { traits:: report_fulfillment_errors ( & infcx, errors) }
331
+ Ok ( _) => { }
332
+ }
333
+
262
334
// Finally, resolve all regions. This catches wily misuses of lifetime
263
335
// parameters.
264
336
infcx. resolve_regions_and_report_errors ( impl_m_body_id) ;
0 commit comments