@@ -25,7 +25,7 @@ use middle::def_id::DefId;
25
25
use middle:: infer:: { self , InferCtxt , TypeOrigin } ;
26
26
use middle:: region;
27
27
use middle:: subst:: { Subst , Substs } ;
28
- use middle:: traits:: { self , ProjectionMode } ;
28
+ use middle:: traits:: ProjectionMode ;
29
29
use middle:: ty;
30
30
use syntax:: codemap:: DUMMY_SP ;
31
31
@@ -41,45 +41,43 @@ pub struct Overlap<'a, 'tcx: 'a> {
41
41
/// Given a subst for the requested impl, translate it to a subst
42
42
/// appropriate for the actual item definition (whether it be in that impl,
43
43
/// a parent impl, or the trait).
44
- //
45
- // When we have selected one impl, but are actually using item definitions from
46
- // a parent impl providing a default, we need a way to translate between the
47
- // type parameters of the two impls. Here the `source_impl` is the one we've
48
- // selected, and `source_substs` is a substitution of its generics (and
49
- // possibly some relevant `FnSpace` variables as well). And `target_node` is
50
- // the impl/trait we're actually going to get the definition from. The resulting
51
- // substitution will map from `target_node`'s generics to `source_impl`'s
52
- // generics as instantiated by `source_subst`.
53
- //
54
- // For example, consider the following scenario:
55
- //
56
- // ```rust
57
- // trait Foo { ... }
58
- // impl<T, U> Foo for (T, U) { ... } // target impl
59
- // impl<V> Foo for (V, V) { ... } // source impl
60
- // ```
61
- //
62
- // Suppose we have selected "source impl" with `V` instantiated with `u32`.
63
- // This function will produce a substitution with `T` and `U` both mapping to `u32`.
64
- //
65
- // Where clauses add some trickiness here, because they can be used to "define"
66
- // an argument indirectly:
67
- //
68
- // ```rust
69
- // impl<'a, I, T: 'a> Iterator for Cloned<I>
70
- // where I: Iterator<Item=&'a T>, T: Clone
71
- // ```
72
- //
73
- // In a case like this, the substitution for `T` is determined indirectly,
74
- // through associated type projection. We deal with such cases by using
75
- // *fulfillment* to relate the two impls, requiring that all projections are
76
- // resolved.
44
+ /// When we have selected one impl, but are actually using item definitions from
45
+ /// a parent impl providing a default, we need a way to translate between the
46
+ /// type parameters of the two impls. Here the `source_impl` is the one we've
47
+ /// selected, and `source_substs` is a substitution of its generics (and
48
+ /// possibly some relevant `FnSpace` variables as well). And `target_node` is
49
+ /// the impl/trait we're actually going to get the definition from. The resulting
50
+ /// substitution will map from `target_node`'s generics to `source_impl`'s
51
+ /// generics as instantiated by `source_subst`.
52
+ ///
53
+ /// For example, consider the following scenario:
54
+ ///
55
+ /// ```rust
56
+ /// trait Foo { ... }
57
+ /// impl<T, U> Foo for (T, U) { ... } // target impl
58
+ /// impl<V> Foo for (V, V) { ... } // source impl
59
+ /// ```
60
+ ///
61
+ /// Suppose we have selected "source impl" with `V` instantiated with `u32`.
62
+ /// This function will produce a substitution with `T` and `U` both mapping to `u32`.
63
+ ///
64
+ /// Where clauses add some trickiness here, because they can be used to "define"
65
+ /// an argument indirectly:
66
+ ///
67
+ /// ```rust
68
+ /// impl<'a, I, T: 'a> Iterator for Cloned<I>
69
+ /// where I: Iterator<Item=&'a T>, T: Clone
70
+ /// ```
71
+ ///
72
+ /// In a case like this, the substitution for `T` is determined indirectly,
73
+ /// through associated type projection. We deal with such cases by using
74
+ /// *fulfillment* to relate the two impls, requiring that all projections are
75
+ /// resolved.
77
76
pub fn translate_substs < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
78
77
source_impl : DefId ,
79
78
source_substs : Substs < ' tcx > ,
80
79
target_node : specialization_graph:: Node )
81
- -> Substs < ' tcx >
82
- {
80
+ -> Substs < ' tcx > {
83
81
let source_trait_ref = infcx. tcx
84
82
. impl_trait_ref ( source_impl)
85
83
. unwrap ( )
@@ -116,29 +114,16 @@ pub fn translate_substs<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
116
114
target_substs. with_method_from_subst ( & source_substs)
117
115
}
118
116
119
-
120
- fn skolemizing_subst_for_impl < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
121
- impl_def_id : DefId )
122
- -> Substs < ' tcx >
123
- {
124
- let impl_generics = infcx. tcx . lookup_item_type ( impl_def_id) . generics ;
125
-
126
- let types = impl_generics. types . map ( |def| infcx. tcx . mk_param_from_def ( def) ) ;
127
-
128
- // TODO: figure out what we actually want here
129
- let regions = impl_generics. regions . map ( |_| ty:: Region :: ReStatic ) ;
130
- // |d| infcx.next_region_var(infer::RegionVariableOrigin::EarlyBoundRegion(span, d.name)));
131
-
132
- Substs :: new ( types, regions)
133
- }
134
-
135
117
/// Is impl1 a specialization of impl2?
136
118
///
137
119
/// Specialization is determined by the sets of types to which the impls apply;
138
120
/// impl1 specializes impl2 if it applies to a subset of the types impl2 applies
139
121
/// to.
140
122
pub fn specializes ( tcx : & ty:: ctxt , impl1_def_id : DefId , impl2_def_id : DefId ) -> bool {
141
- if !tcx. sess . features . borrow ( ) . specialization {
123
+ // The feature gate should prevent introducing new specializations, but not
124
+ // taking advantage of upstream ones.
125
+ if !tcx. sess . features . borrow ( ) . specialization &&
126
+ ( impl1_def_id. is_local ( ) || impl2_def_id. is_local ( ) ) {
142
127
return false ;
143
128
}
144
129
@@ -156,33 +141,24 @@ pub fn specializes(tcx: &ty::ctxt, impl1_def_id: DefId, impl2_def_id: DefId) ->
156
141
157
142
// Currently we do not allow e.g. a negative impl to specialize a positive one
158
143
if tcx. trait_impl_polarity ( impl1_def_id) != tcx. trait_impl_polarity ( impl2_def_id) {
159
- return false
144
+ return false ;
160
145
}
161
146
162
147
let mut infcx = infer:: normalizing_infer_ctxt ( tcx, & tcx. tables , ProjectionMode :: Topmost ) ;
163
148
164
- // Skiolemize impl1: we want to prove that "for all types matched by impl1,
165
- // those types are also matched by impl2".
166
- let impl1_substs = skolemizing_subst_for_impl ( & infcx, impl1_def_id) ;
167
- let ( impl1_trait_ref, impl1_obligations) = {
168
- let selcx = & mut SelectionContext :: new ( & infcx) ;
169
- impl_trait_ref_and_oblig ( selcx, impl1_def_id, & impl1_substs)
170
- } ;
149
+ // create a parameter environment corresponding to a (skolemized) instantiation of impl1
150
+ let scheme = tcx. lookup_item_type ( impl1_def_id) ;
151
+ let predicates = tcx. lookup_predicates ( impl1_def_id) ;
152
+ let penv = tcx. construct_parameter_environment ( DUMMY_SP ,
153
+ & scheme. generics ,
154
+ & predicates,
155
+ region:: DUMMY_CODE_EXTENT ) ;
156
+ let impl1_trait_ref = tcx. impl_trait_ref ( impl1_def_id)
157
+ . unwrap ( )
158
+ . subst ( tcx, & penv. free_substs ) ;
171
159
172
- // Add impl1's obligations as assumptions to the environment.
173
- let impl1_predicates: Vec < _ > = impl1_obligations. iter ( )
174
- . cloned ( )
175
- . map ( |oblig| oblig. predicate )
176
- . collect ( ) ;
177
- infcx. parameter_environment = ty:: ParameterEnvironment {
178
- tcx : tcx,
179
- free_substs : impl1_substs,
180
- implicit_region_bound : ty:: ReEmpty , // TODO: is this OK?
181
- caller_bounds : impl1_predicates,
182
- selection_cache : traits:: SelectionCache :: new ( ) ,
183
- evaluation_cache : traits:: EvaluationCache :: new ( ) ,
184
- free_id_outlive : region:: DUMMY_CODE_EXTENT , // TODO: is this OK?
185
- } ;
160
+ // Install the parameter environment, which means we take the predicates of impl1 as assumptions:
161
+ infcx. parameter_environment = penv;
186
162
187
163
// Attempt to prove that impl2 applies, given all of the above.
188
164
fulfill_implication ( & infcx, impl1_trait_ref, impl2_def_id) . is_ok ( )
@@ -196,9 +172,8 @@ pub fn specializes(tcx: &ty::ctxt, impl1_def_id: DefId, impl2_def_id: DefId) ->
196
172
fn fulfill_implication < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
197
173
source_trait_ref : ty:: TraitRef < ' tcx > ,
198
174
target_impl : DefId )
199
- -> Result < Substs < ' tcx > , ( ) >
200
- {
201
- infcx. probe ( |_| {
175
+ -> Result < Substs < ' tcx > , ( ) > {
176
+ infcx. commit_if_ok ( |_| {
202
177
let selcx = & mut SelectionContext :: new ( & infcx) ;
203
178
let target_substs = fresh_type_vars_for_impl ( & infcx, DUMMY_SP , target_impl) ;
204
179
let ( target_trait_ref, obligations) = impl_trait_ref_and_oblig ( selcx,
@@ -227,23 +202,20 @@ fn fulfill_implication<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
227
202
228
203
if let Err ( errors) = infer:: drain_fulfillment_cx ( & infcx, & mut fulfill_cx, & ( ) ) {
229
204
// no dice!
230
- debug ! ( "fulfill_implication: for impls on {:?} and {:?}, could not fulfill: {:?} \
231
- given {:?}",
205
+ debug ! ( "fulfill_implication: for impls on {:?} and {:?}, could not fulfill: {:?} given \
206
+ {:?}",
232
207
source_trait_ref,
233
208
target_trait_ref,
234
209
errors,
235
210
infcx. parameter_environment. caller_bounds) ;
236
211
Err ( ( ) )
237
212
} else {
238
- debug ! ( "fulfill_implication: an impl for {:?} specializes {:?} (`where` clauses \
239
- elided)",
213
+ debug ! ( "fulfill_implication: an impl for {:?} specializes {:?} (`where` clauses elided)" ,
240
214
source_trait_ref,
241
215
target_trait_ref) ;
242
216
243
217
// Now resolve the *substitution* we built for the target earlier, replacing
244
218
// the inference variables inside with whatever we got from fulfillment.
245
-
246
- // TODO: should this use `fully_resolve` instead?
247
219
Ok ( infcx. resolve_type_vars_if_possible ( & target_substs) )
248
220
}
249
221
} )
0 commit comments