@@ -38,7 +38,7 @@ impl Summary {
38
38
namespaced_features : bool ,
39
39
) -> CargoResult < Summary > {
40
40
for dep in dependencies. iter ( ) {
41
- if features. get ( & * dep. name ( ) ) . is_some ( ) {
41
+ if !namespaced_features && features. get ( & * dep. name ( ) ) . is_some ( ) {
42
42
bail ! (
43
43
"Features and dependencies cannot have the \
44
44
same name: `{}`",
@@ -52,7 +52,7 @@ impl Summary {
52
52
)
53
53
}
54
54
}
55
- let feature_map = build_feature_map ( features, & dependencies) ?;
55
+ let feature_map = build_feature_map ( features, & dependencies, namespaced_features ) ?;
56
56
Ok ( Summary {
57
57
inner : Rc :: new ( Inner {
58
58
package_id : pkg_id,
@@ -137,6 +137,7 @@ impl PartialEq for Summary {
137
137
fn build_feature_map (
138
138
features : BTreeMap < String , Vec < String > > ,
139
139
dependencies : & [ Dependency ] ,
140
+ namespaced : bool ,
140
141
) -> CargoResult < FeatureMap > {
141
142
use self :: FeatureValue :: * ;
142
143
let dep_map: HashMap < _ , _ > = dependencies
@@ -146,52 +147,169 @@ fn build_feature_map(
146
147
147
148
let mut map = BTreeMap :: new ( ) ;
148
149
for ( feature, list) in features. iter ( ) {
150
+ // If namespaced features is active and the key is the same as that of an
151
+ // optional dependency, that dependency must be included in the values.
152
+ // Thus, if a `feature` is found that has the same name as a dependency, we
153
+ // (a) bail out if the dependency is non-optional, and (b) we track if the
154
+ // feature requirements include the dependency `crate:feature` in the list.
155
+ // This is done with the `dependency_found` variable, which can only be
156
+ // false if features are namespaced and the current feature key is the same
157
+ // as the name of an optional dependency. If so, it gets set to true during
158
+ // iteration over the list if the dependency is found in the list.
159
+ let mut dependency_found = if namespaced {
160
+ match dep_map. get ( feature. as_str ( ) ) {
161
+ Some ( ref dep_data) => {
162
+ if !dep_data. is_optional ( ) {
163
+ bail ! (
164
+ "Feature `{}` includes the dependency of the same name, but this is \
165
+ left implicit in the features included by this feature.\n \
166
+ Additionally, the dependency must be marked as optional to be \
167
+ included in the feature definition.\n \
168
+ Consider adding `crate:{}` to this feature's requirements \
169
+ and marking the dependency as `optional = true`",
170
+ feature,
171
+ feature
172
+ )
173
+ } else {
174
+ false
175
+ }
176
+ }
177
+ None => true ,
178
+ }
179
+ } else {
180
+ true
181
+ } ;
182
+
149
183
let mut values = vec ! [ ] ;
150
184
for dep in list {
151
- let val = FeatureValue :: build ( InternedString :: new ( dep ) , |fs| features . contains_key ( fs ) ) ;
152
- if let & Feature ( _ ) = & val {
153
- values . push ( val ) ;
154
- continue ;
155
- }
185
+ let val = FeatureValue :: build (
186
+ InternedString :: new ( dep ) ,
187
+ |fs| features . contains_key ( fs ) ,
188
+ namespaced ,
189
+ ) ;
156
190
157
191
// Find data for the referenced dependency...
158
192
let dep_data = {
159
193
match val {
160
- Feature ( _) => None ,
161
- Crate ( ref dep_name) | CrateFeature ( ref dep_name, _) => {
194
+ Feature ( ref dep_name) | Crate ( ref dep_name) | CrateFeature ( ref dep_name, _) => {
162
195
dep_map. get ( dep_name. as_str ( ) )
163
196
}
164
197
}
165
198
} ;
199
+ let is_optional_dep = dep_data. map_or ( false , |d| d. is_optional ( ) ) ;
200
+ if let FeatureValue :: Crate ( ref dep_name) = val {
201
+ // If we have a dependency value, check if this is the dependency named
202
+ // the same as the feature that we were looking for.
203
+ if !dependency_found && feature == dep_name. as_str ( ) {
204
+ dependency_found = true ;
205
+ }
206
+ }
166
207
167
- match ( & val, dep_data) {
168
- ( & Crate ( ref dep) , Some ( d) ) => {
169
- if !d. is_optional ( ) {
170
- bail ! (
171
- "Feature `{}` depends on `{}` which is not an \
172
- optional dependency.\n Consider adding \
173
- `optional = true` to the dependency",
174
- feature,
175
- dep
176
- )
208
+ match ( & val, dep_data. is_some ( ) , is_optional_dep) {
209
+ // The value is a feature. If features are namespaced, this just means
210
+ // it's not prefixed with `crate:`, so we have to check whether the
211
+ // feature actually exist. If the feature is not defined *and* an optional
212
+ // dependency of the same name exists, the feature is defined implicitly
213
+ // here by adding it to the feature map, pointing to the dependency.
214
+ // If features are not namespaced, it's been validated as a feature already
215
+ // while instantiating the `FeatureValue` in `FeatureValue::build()`, so
216
+ // we don't have to do so here.
217
+ ( & Feature ( feat) , _, true ) => {
218
+ if namespaced && !features. contains_key ( & * feat) {
219
+ map. insert ( feat. to_string ( ) , vec ! [ FeatureValue :: Crate ( feat) ] ) ;
177
220
}
178
221
}
179
- ( & CrateFeature ( ref dep_name, _) , None ) => bail ! (
222
+ // If features are namespaced and the value is not defined as a feature
223
+ // and there is no optional dependency of the same name, error out.
224
+ // If features are not namespaced, there must be an existing feature
225
+ // here (checked by `FeatureValue::build()`), so it will always be defined.
226
+ ( & Feature ( feat) , dep_exists, false ) => {
227
+ if namespaced && !features. contains_key ( & * feat) {
228
+ if dep_exists {
229
+ bail ! (
230
+ "Feature `{}` includes `{}` which is not defined as a feature.\n \
231
+ A non-optional dependency of the same name is defined; consider \
232
+ adding `optional = true` to its definition",
233
+ feature,
234
+ feat
235
+ )
236
+ } else {
237
+ bail ! (
238
+ "Feature `{}` includes `{}` which is not defined as a feature" ,
239
+ feature,
240
+ feat
241
+ )
242
+ }
243
+ }
244
+ }
245
+ // The value is a dependency. If features are namespaced, it is explicitly
246
+ // tagged as such (`crate:value`). If features are not namespaced, any value
247
+ // not recognized as a feature is pegged as a `Crate`. Here we handle the case
248
+ // where the dependency exists but is non-optional. It branches on namespaced
249
+ // just to provide the correct string for the crate dependency in the error.
250
+ ( & Crate ( ref dep) , true , false ) => if namespaced {
251
+ bail ! (
252
+ "Feature `{}` includes `crate:{}` which is not an \
253
+ optional dependency.\n Consider adding \
254
+ `optional = true` to the dependency",
255
+ feature,
256
+ dep
257
+ )
258
+ } else {
259
+ bail ! (
260
+ "Feature `{}` depends on `{}` which is not an \
261
+ optional dependency.\n Consider adding \
262
+ `optional = true` to the dependency",
263
+ feature,
264
+ dep
265
+ )
266
+ } ,
267
+ // If namespaced, the value was tagged as a dependency; if not namespaced,
268
+ // this could be anything not defined as a feature. This handles the case
269
+ // where no such dependency is actually defined; again, the branch on
270
+ // namespaced here is just to provide the correct string in the error.
271
+ ( & Crate ( ref dep) , false , _) => if namespaced {
272
+ bail ! (
273
+ "Feature `{}` includes `crate:{}` which is not a known \
274
+ dependency",
275
+ feature,
276
+ dep
277
+ )
278
+ } else {
279
+ bail ! (
280
+ "Feature `{}` includes `{}` which is neither a dependency nor \
281
+ another feature",
282
+ feature,
283
+ dep
284
+ )
285
+ } ,
286
+ ( & Crate ( _) , true , true ) => { }
287
+ // If the value is a feature for one of the dependencies, bail out if no such
288
+ // dependency is actually defined in the manifest.
289
+ ( & CrateFeature ( ref dep, _) , false , _) => bail ! (
180
290
"Feature `{}` requires a feature of `{}` which is not a \
181
291
dependency",
182
292
feature,
183
- dep_name
184
- ) ,
185
- ( & Crate ( ref dep) , None ) => bail ! (
186
- "Feature `{}` includes `{}` which is neither \
187
- a dependency nor another feature",
188
- feature,
189
293
dep
190
294
) ,
191
- ( & CrateFeature ( _, _) , Some ( _ ) ) | ( & Feature ( _ ) , _) => { }
295
+ ( & CrateFeature ( _, _) , true , _) => { }
192
296
}
193
297
values. push ( val) ;
194
298
}
299
+
300
+ if !dependency_found {
301
+ // If we have not found the dependency of the same-named feature, we should
302
+ // bail here.
303
+ bail ! (
304
+ "Feature `{}` includes the optional dependency of the \
305
+ same name, but this is left implicit in the features \
306
+ included by this feature.\n Consider adding \
307
+ `crate:{}` to this feature's requirements.",
308
+ feature,
309
+ feature
310
+ )
311
+ }
312
+
195
313
map. insert ( feature. clone ( ) , values) ;
196
314
}
197
315
Ok ( map)
@@ -212,30 +330,42 @@ pub enum FeatureValue {
212
330
}
213
331
214
332
impl FeatureValue {
215
- fn build < T > ( feature : InternedString , is_feature : T ) -> FeatureValue
333
+ fn build < T > ( feature : InternedString , is_feature : T , namespaced : bool ) -> FeatureValue
216
334
where
217
335
T : Fn ( & str ) -> bool ,
218
336
{
219
- match feature. find ( '/' ) {
220
- Some ( pos) => {
337
+ match ( feature. find ( '/' ) , namespaced ) {
338
+ ( Some ( pos) , _ ) => {
221
339
let ( dep, dep_feat) = feature. split_at ( pos) ;
222
340
let dep_feat = & dep_feat[ 1 ..] ;
223
341
FeatureValue :: CrateFeature ( InternedString :: new ( dep) , InternedString :: new ( dep_feat) )
224
342
}
225
- None if is_feature ( & feature) => FeatureValue :: Feature ( feature) ,
226
- None => FeatureValue :: Crate ( feature) ,
343
+ ( None , true ) if feature. starts_with ( "crate:" ) => {
344
+ FeatureValue :: Crate ( InternedString :: new ( & feature[ 6 ..] ) )
345
+ }
346
+ ( None , true ) => FeatureValue :: Feature ( feature) ,
347
+ ( None , false ) if is_feature ( & feature) => FeatureValue :: Feature ( feature) ,
348
+ ( None , false ) => FeatureValue :: Crate ( feature) ,
227
349
}
228
350
}
229
351
230
352
pub fn new ( feature : InternedString , s : & Summary ) -> FeatureValue {
231
- Self :: build ( feature, |fs| s. features ( ) . contains_key ( fs) )
353
+ Self :: build (
354
+ feature,
355
+ |fs| s. features ( ) . contains_key ( fs) ,
356
+ s. namespaced_features ( ) ,
357
+ )
232
358
}
233
359
234
- pub fn to_string ( & self ) -> String {
360
+ pub fn to_string ( & self , s : & Summary ) -> String {
235
361
use self :: FeatureValue :: * ;
236
362
match * self {
237
363
Feature ( ref f) => f. to_string ( ) ,
238
- Crate ( ref c) => c. to_string ( ) ,
364
+ Crate ( ref c) => if s. namespaced_features ( ) {
365
+ format ! ( "crate:{}" , & c)
366
+ } else {
367
+ c. to_string ( )
368
+ } ,
239
369
CrateFeature ( ref c, ref f) => [ c. as_ref ( ) , f. as_ref ( ) ] . join ( "/" ) ,
240
370
}
241
371
}
0 commit comments