1 //! Determining which types for which we cannot emit `#[derive(Trait)]`.
2
3 use std::fmt;
4
5 use super::{generate_dependencies, ConstrainResult, MonotoneFramework};
6 use crate::ir::analysis::has_vtable::HasVtable;
7 use crate::ir::comp::CompKind;
8 use crate::ir::context::{BindgenContext, ItemId};
9 use crate::ir::derive::CanDerive;
10 use crate::ir::function::FunctionSig;
11 use crate::ir::item::{IsOpaque, Item};
12 use crate::ir::template::TemplateParameters;
13 use crate::ir::traversal::{EdgeKind, Trace};
14 use crate::ir::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
15 use crate::ir::ty::{Type, TypeKind};
16 use crate::{Entry, HashMap, HashSet};
17
18 /// Which trait to consider when doing the `CannotDerive` analysis.
19 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
20 pub enum DeriveTrait {
21 /// The `Copy` trait.
22 Copy,
23 /// The `Debug` trait.
24 Debug,
25 /// The `Default` trait.
26 Default,
27 /// The `Hash` trait.
28 Hash,
29 /// The `PartialEq` and `PartialOrd` traits.
30 PartialEqOrPartialOrd,
31 }
32
33 /// An analysis that finds for each IR item whether a trait cannot be derived.
34 ///
35 /// We use the monotone constraint function `cannot_derive`, defined as follows
36 /// for type T:
37 ///
38 /// * If T is Opaque and the layout of the type is known, get this layout as an
39 /// opaquetype and check whether it can derive using trivial checks.
40 ///
41 /// * If T is Array, a trait cannot be derived if the array is incomplete,
42 /// if the length of the array is larger than the limit (unless the trait
43 /// allows it), or the trait cannot be derived for the type of data the array
44 /// contains.
45 ///
46 /// * If T is Vector, a trait cannot be derived if the trait cannot be derived
47 /// for the type of data the vector contains.
48 ///
49 /// * If T is a type alias, a templated alias or an indirection to another type,
50 /// the trait cannot be derived if the trait cannot be derived for type T
51 /// refers to.
52 ///
53 /// * If T is a compound type, the trait cannot be derived if the trait cannot
54 /// be derived for any of its base members or fields.
55 ///
56 /// * If T is an instantiation of an abstract template definition, the trait
57 /// cannot be derived if any of the template arguments or template definition
58 /// cannot derive the trait.
59 ///
60 /// * For all other (simple) types, compiler and standard library limitations
61 /// dictate whether the trait is implemented.
62 #[derive(Debug, Clone)]
63 pub struct CannotDerive<'ctx> {
64 ctx: &'ctx BindgenContext,
65
66 derive_trait: DeriveTrait,
67
68 // The incremental result of this analysis's computation.
69 // Contains information whether particular item can derive `derive_trait`
70 can_derive: HashMap<ItemId, CanDerive>,
71
72 // Dependencies saying that if a key ItemId has been inserted into the
73 // `cannot_derive_partialeq_or_partialord` set, then each of the ids
74 // in Vec<ItemId> need to be considered again.
75 //
76 // This is a subset of the natural IR graph with reversed edges, where we
77 // only include the edges from the IR graph that can affect whether a type
78 // can derive `derive_trait`.
79 dependencies: HashMap<ItemId, Vec<ItemId>>,
80 }
81
82 type EdgePredicate = fn(EdgeKind) -> bool;
83
consider_edge_default(kind: EdgeKind) -> bool84 fn consider_edge_default(kind: EdgeKind) -> bool {
85 match kind {
86 // These are the only edges that can affect whether a type can derive
87 EdgeKind::BaseMember |
88 EdgeKind::Field |
89 EdgeKind::TypeReference |
90 EdgeKind::VarType |
91 EdgeKind::TemplateArgument |
92 EdgeKind::TemplateDeclaration |
93 EdgeKind::TemplateParameterDefinition => true,
94
95 EdgeKind::Constructor |
96 EdgeKind::Destructor |
97 EdgeKind::FunctionReturn |
98 EdgeKind::FunctionParameter |
99 EdgeKind::InnerType |
100 EdgeKind::InnerVar |
101 EdgeKind::Method |
102 EdgeKind::Generic => false,
103 }
104 }
105
106 impl<'ctx> CannotDerive<'ctx> {
insert<Id: Into<ItemId>>( &mut self, id: Id, can_derive: CanDerive, ) -> ConstrainResult107 fn insert<Id: Into<ItemId>>(
108 &mut self,
109 id: Id,
110 can_derive: CanDerive,
111 ) -> ConstrainResult {
112 let id = id.into();
113 trace!(
114 "inserting {:?} can_derive<{}>={:?}",
115 id,
116 self.derive_trait,
117 can_derive
118 );
119
120 if let CanDerive::Yes = can_derive {
121 return ConstrainResult::Same;
122 }
123
124 match self.can_derive.entry(id) {
125 Entry::Occupied(mut entry) => {
126 if *entry.get() < can_derive {
127 entry.insert(can_derive);
128 ConstrainResult::Changed
129 } else {
130 ConstrainResult::Same
131 }
132 }
133 Entry::Vacant(entry) => {
134 entry.insert(can_derive);
135 ConstrainResult::Changed
136 }
137 }
138 }
139
constrain_type(&mut self, item: &Item, ty: &Type) -> CanDerive140 fn constrain_type(&mut self, item: &Item, ty: &Type) -> CanDerive {
141 if !self.ctx.allowlisted_items().contains(&item.id()) {
142 let can_derive = self
143 .ctx
144 .blocklisted_type_implements_trait(item, self.derive_trait);
145 match can_derive {
146 CanDerive::Yes => trace!(
147 " blocklisted type explicitly implements {}",
148 self.derive_trait
149 ),
150 CanDerive::Manually => trace!(
151 " blocklisted type requires manual implementation of {}",
152 self.derive_trait
153 ),
154 CanDerive::No => trace!(
155 " cannot derive {} for blocklisted type",
156 self.derive_trait
157 ),
158 }
159 return can_derive;
160 }
161
162 if self.derive_trait.not_by_name(self.ctx, &item) {
163 trace!(
164 " cannot derive {} for explicitly excluded type",
165 self.derive_trait
166 );
167 return CanDerive::No;
168 }
169
170 trace!("ty: {:?}", ty);
171 if item.is_opaque(self.ctx, &()) {
172 if !self.derive_trait.can_derive_union() &&
173 ty.is_union() &&
174 self.ctx.options().rust_features().untagged_union
175 {
176 trace!(
177 " cannot derive {} for Rust unions",
178 self.derive_trait
179 );
180 return CanDerive::No;
181 }
182
183 let layout_can_derive =
184 ty.layout(self.ctx).map_or(CanDerive::Yes, |l| {
185 l.opaque().array_size_within_derive_limit(self.ctx)
186 });
187
188 match layout_can_derive {
189 CanDerive::Yes => {
190 trace!(
191 " we can trivially derive {} for the layout",
192 self.derive_trait
193 );
194 }
195 _ => {
196 trace!(
197 " we cannot derive {} for the layout",
198 self.derive_trait
199 );
200 }
201 };
202 return layout_can_derive;
203 }
204
205 match *ty.kind() {
206 // Handle the simple cases. These can derive traits without further
207 // information.
208 TypeKind::Void |
209 TypeKind::NullPtr |
210 TypeKind::Int(..) |
211 TypeKind::Complex(..) |
212 TypeKind::Float(..) |
213 TypeKind::Enum(..) |
214 TypeKind::TypeParam |
215 TypeKind::UnresolvedTypeRef(..) |
216 TypeKind::Reference(..) |
217 TypeKind::ObjCInterface(..) |
218 TypeKind::ObjCId |
219 TypeKind::ObjCSel => {
220 return self.derive_trait.can_derive_simple(ty.kind());
221 }
222 TypeKind::Pointer(inner) => {
223 let inner_type =
224 self.ctx.resolve_type(inner).canonical_type(self.ctx);
225 if let TypeKind::Function(ref sig) = *inner_type.kind() {
226 return self.derive_trait.can_derive_fnptr(sig);
227 } else {
228 return self.derive_trait.can_derive_pointer();
229 }
230 }
231 TypeKind::Function(ref sig) => {
232 return self.derive_trait.can_derive_fnptr(sig)
233 }
234
235 // Complex cases need more information
236 TypeKind::Array(t, len) => {
237 let inner_type =
238 self.can_derive.get(&t.into()).cloned().unwrap_or_default();
239 if inner_type != CanDerive::Yes {
240 trace!(
241 " arrays of T for which we cannot derive {} \
242 also cannot derive {}",
243 self.derive_trait,
244 self.derive_trait
245 );
246 return CanDerive::No;
247 }
248
249 if len == 0 && !self.derive_trait.can_derive_incomplete_array()
250 {
251 trace!(
252 " cannot derive {} for incomplete arrays",
253 self.derive_trait
254 );
255 return CanDerive::No;
256 }
257
258 if self.derive_trait.can_derive_large_array() {
259 trace!(" array can derive {}", self.derive_trait);
260 return CanDerive::Yes;
261 }
262
263 if len > RUST_DERIVE_IN_ARRAY_LIMIT {
264 trace!(
265 " array is too large to derive {}, but it may be implemented", self.derive_trait
266 );
267 return CanDerive::Manually;
268 }
269 trace!(
270 " array is small enough to derive {}",
271 self.derive_trait
272 );
273 return CanDerive::Yes;
274 }
275 TypeKind::Vector(t, len) => {
276 let inner_type =
277 self.can_derive.get(&t.into()).cloned().unwrap_or_default();
278 if inner_type != CanDerive::Yes {
279 trace!(
280 " vectors of T for which we cannot derive {} \
281 also cannot derive {}",
282 self.derive_trait,
283 self.derive_trait
284 );
285 return CanDerive::No;
286 }
287 assert_ne!(len, 0, "vectors cannot have zero length");
288 return self.derive_trait.can_derive_vector();
289 }
290
291 TypeKind::Comp(ref info) => {
292 assert!(
293 !info.has_non_type_template_params(),
294 "The early ty.is_opaque check should have handled this case"
295 );
296
297 if !self.derive_trait.can_derive_compound_forward_decl() &&
298 info.is_forward_declaration()
299 {
300 trace!(
301 " cannot derive {} for forward decls",
302 self.derive_trait
303 );
304 return CanDerive::No;
305 }
306
307 // NOTE: Take into account that while unions in C and C++ are copied by
308 // default, the may have an explicit destructor in C++, so we can't
309 // defer this check just for the union case.
310 if !self.derive_trait.can_derive_compound_with_destructor() &&
311 self.ctx.lookup_has_destructor(
312 item.id().expect_type_id(self.ctx),
313 )
314 {
315 trace!(
316 " comp has destructor which cannot derive {}",
317 self.derive_trait
318 );
319 return CanDerive::No;
320 }
321
322 if info.kind() == CompKind::Union {
323 if self.derive_trait.can_derive_union() {
324 if self.ctx.options().rust_features().untagged_union &&
325 // https://github.com/rust-lang/rust/issues/36640
326 (!info.self_template_params(self.ctx).is_empty() ||
327 !item.all_template_params(self.ctx).is_empty())
328 {
329 trace!(
330 " cannot derive {} for Rust union because issue 36640", self.derive_trait
331 );
332 return CanDerive::No;
333 }
334 // fall through to be same as non-union handling
335 } else {
336 if self.ctx.options().rust_features().untagged_union {
337 trace!(
338 " cannot derive {} for Rust unions",
339 self.derive_trait
340 );
341 return CanDerive::No;
342 }
343
344 let layout_can_derive =
345 ty.layout(self.ctx).map_or(CanDerive::Yes, |l| {
346 l.opaque()
347 .array_size_within_derive_limit(self.ctx)
348 });
349 match layout_can_derive {
350 CanDerive::Yes => {
351 trace!(
352 " union layout can trivially derive {}",
353 self.derive_trait
354 );
355 }
356 _ => {
357 trace!(
358 " union layout cannot derive {}",
359 self.derive_trait
360 );
361 }
362 };
363 return layout_can_derive;
364 }
365 }
366
367 if !self.derive_trait.can_derive_compound_with_vtable() &&
368 item.has_vtable(self.ctx)
369 {
370 trace!(
371 " cannot derive {} for comp with vtable",
372 self.derive_trait
373 );
374 return CanDerive::No;
375 }
376
377 // Bitfield units are always represented as arrays of u8, but
378 // they're not traced as arrays, so we need to check here
379 // instead.
380 if !self.derive_trait.can_derive_large_array() &&
381 info.has_too_large_bitfield_unit() &&
382 !item.is_opaque(self.ctx, &())
383 {
384 trace!(
385 " cannot derive {} for comp with too large bitfield unit",
386 self.derive_trait
387 );
388 return CanDerive::No;
389 }
390
391 let pred = self.derive_trait.consider_edge_comp();
392 return self.constrain_join(item, pred);
393 }
394
395 TypeKind::ResolvedTypeRef(..) |
396 TypeKind::TemplateAlias(..) |
397 TypeKind::Alias(..) |
398 TypeKind::BlockPointer(..) => {
399 let pred = self.derive_trait.consider_edge_typeref();
400 return self.constrain_join(item, pred);
401 }
402
403 TypeKind::TemplateInstantiation(..) => {
404 let pred = self.derive_trait.consider_edge_tmpl_inst();
405 return self.constrain_join(item, pred);
406 }
407
408 TypeKind::Opaque => unreachable!(
409 "The early ty.is_opaque check should have handled this case"
410 ),
411 }
412 }
413
constrain_join( &mut self, item: &Item, consider_edge: EdgePredicate, ) -> CanDerive414 fn constrain_join(
415 &mut self,
416 item: &Item,
417 consider_edge: EdgePredicate,
418 ) -> CanDerive {
419 let mut candidate = None;
420
421 item.trace(
422 self.ctx,
423 &mut |sub_id, edge_kind| {
424 // Ignore ourselves, since union with ourself is a
425 // no-op. Ignore edges that aren't relevant to the
426 // analysis.
427 if sub_id == item.id() || !consider_edge(edge_kind) {
428 return;
429 }
430
431 let can_derive = self.can_derive
432 .get(&sub_id)
433 .cloned()
434 .unwrap_or_default();
435
436 match can_derive {
437 CanDerive::Yes => trace!(" member {:?} can derive {}", sub_id, self.derive_trait),
438 CanDerive::Manually => trace!(" member {:?} cannot derive {}, but it may be implemented", sub_id, self.derive_trait),
439 CanDerive::No => trace!(" member {:?} cannot derive {}", sub_id, self.derive_trait),
440 }
441
442 *candidate.get_or_insert(CanDerive::Yes) |= can_derive;
443 },
444 &(),
445 );
446
447 if candidate.is_none() {
448 trace!(
449 " can derive {} because there are no members",
450 self.derive_trait
451 );
452 }
453 candidate.unwrap_or_default()
454 }
455 }
456
457 impl DeriveTrait {
not_by_name(&self, ctx: &BindgenContext, item: &Item) -> bool458 fn not_by_name(&self, ctx: &BindgenContext, item: &Item) -> bool {
459 match self {
460 DeriveTrait::Copy => ctx.no_copy_by_name(item),
461 DeriveTrait::Debug => ctx.no_debug_by_name(item),
462 DeriveTrait::Default => ctx.no_default_by_name(item),
463 DeriveTrait::Hash => ctx.no_hash_by_name(item),
464 DeriveTrait::PartialEqOrPartialOrd => {
465 ctx.no_partialeq_by_name(item)
466 }
467 }
468 }
469
consider_edge_comp(&self) -> EdgePredicate470 fn consider_edge_comp(&self) -> EdgePredicate {
471 match self {
472 DeriveTrait::PartialEqOrPartialOrd => consider_edge_default,
473 _ => |kind| match kind {
474 EdgeKind::BaseMember | EdgeKind::Field => true,
475 _ => false,
476 },
477 }
478 }
479
consider_edge_typeref(&self) -> EdgePredicate480 fn consider_edge_typeref(&self) -> EdgePredicate {
481 match self {
482 DeriveTrait::PartialEqOrPartialOrd => consider_edge_default,
483 _ => |kind| kind == EdgeKind::TypeReference,
484 }
485 }
486
consider_edge_tmpl_inst(&self) -> EdgePredicate487 fn consider_edge_tmpl_inst(&self) -> EdgePredicate {
488 match self {
489 DeriveTrait::PartialEqOrPartialOrd => consider_edge_default,
490 _ => |kind| match kind {
491 EdgeKind::TemplateArgument | EdgeKind::TemplateDeclaration => {
492 true
493 }
494 _ => false,
495 },
496 }
497 }
498
can_derive_large_array(&self) -> bool499 fn can_derive_large_array(&self) -> bool {
500 match self {
501 DeriveTrait::Copy => true,
502 _ => false,
503 }
504 }
505
can_derive_union(&self) -> bool506 fn can_derive_union(&self) -> bool {
507 match self {
508 DeriveTrait::Copy => true,
509 _ => false,
510 }
511 }
512
can_derive_compound_with_destructor(&self) -> bool513 fn can_derive_compound_with_destructor(&self) -> bool {
514 match self {
515 DeriveTrait::Copy => false,
516 _ => true,
517 }
518 }
519
can_derive_compound_with_vtable(&self) -> bool520 fn can_derive_compound_with_vtable(&self) -> bool {
521 match self {
522 DeriveTrait::Default => false,
523 _ => true,
524 }
525 }
526
can_derive_compound_forward_decl(&self) -> bool527 fn can_derive_compound_forward_decl(&self) -> bool {
528 match self {
529 DeriveTrait::Copy | DeriveTrait::Debug => true,
530 _ => false,
531 }
532 }
533
can_derive_incomplete_array(&self) -> bool534 fn can_derive_incomplete_array(&self) -> bool {
535 match self {
536 DeriveTrait::Copy |
537 DeriveTrait::Hash |
538 DeriveTrait::PartialEqOrPartialOrd => false,
539 _ => true,
540 }
541 }
542
can_derive_fnptr(&self, f: &FunctionSig) -> CanDerive543 fn can_derive_fnptr(&self, f: &FunctionSig) -> CanDerive {
544 match (self, f.function_pointers_can_derive()) {
545 (DeriveTrait::Copy, _) | (DeriveTrait::Default, _) | (_, true) => {
546 trace!(" function pointer can derive {}", self);
547 CanDerive::Yes
548 }
549 (DeriveTrait::Debug, false) => {
550 trace!(" function pointer cannot derive {}, but it may be implemented", self);
551 CanDerive::Manually
552 }
553 (_, false) => {
554 trace!(" function pointer cannot derive {}", self);
555 CanDerive::No
556 }
557 }
558 }
559
can_derive_vector(&self) -> CanDerive560 fn can_derive_vector(&self) -> CanDerive {
561 match self {
562 DeriveTrait::PartialEqOrPartialOrd => {
563 // FIXME: vectors always can derive PartialEq, but they should
564 // not derive PartialOrd:
565 // https://github.com/rust-lang-nursery/packed_simd/issues/48
566 trace!(" vectors cannot derive PartialOrd");
567 CanDerive::No
568 }
569 _ => {
570 trace!(" vector can derive {}", self);
571 CanDerive::Yes
572 }
573 }
574 }
575
can_derive_pointer(&self) -> CanDerive576 fn can_derive_pointer(&self) -> CanDerive {
577 match self {
578 DeriveTrait::Default => {
579 trace!(" pointer cannot derive Default");
580 CanDerive::No
581 }
582 _ => {
583 trace!(" pointer can derive {}", self);
584 CanDerive::Yes
585 }
586 }
587 }
588
can_derive_simple(&self, kind: &TypeKind) -> CanDerive589 fn can_derive_simple(&self, kind: &TypeKind) -> CanDerive {
590 match (self, kind) {
591 // === Default ===
592 (DeriveTrait::Default, TypeKind::Void) |
593 (DeriveTrait::Default, TypeKind::NullPtr) |
594 (DeriveTrait::Default, TypeKind::Enum(..)) |
595 (DeriveTrait::Default, TypeKind::Reference(..)) |
596 (DeriveTrait::Default, TypeKind::TypeParam) |
597 (DeriveTrait::Default, TypeKind::ObjCInterface(..)) |
598 (DeriveTrait::Default, TypeKind::ObjCId) |
599 (DeriveTrait::Default, TypeKind::ObjCSel) => {
600 trace!(" types that always cannot derive Default");
601 CanDerive::No
602 }
603 (DeriveTrait::Default, TypeKind::UnresolvedTypeRef(..)) => {
604 unreachable!(
605 "Type with unresolved type ref can't reach derive default"
606 )
607 }
608 // === Hash ===
609 (DeriveTrait::Hash, TypeKind::Float(..)) |
610 (DeriveTrait::Hash, TypeKind::Complex(..)) => {
611 trace!(" float cannot derive Hash");
612 CanDerive::No
613 }
614 // === others ===
615 _ => {
616 trace!(" simple type that can always derive {}", self);
617 CanDerive::Yes
618 }
619 }
620 }
621 }
622
623 impl fmt::Display for DeriveTrait {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result624 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
625 let s = match self {
626 DeriveTrait::Copy => "Copy",
627 DeriveTrait::Debug => "Debug",
628 DeriveTrait::Default => "Default",
629 DeriveTrait::Hash => "Hash",
630 DeriveTrait::PartialEqOrPartialOrd => "PartialEq/PartialOrd",
631 };
632 s.fmt(f)
633 }
634 }
635
636 impl<'ctx> MonotoneFramework for CannotDerive<'ctx> {
637 type Node = ItemId;
638 type Extra = (&'ctx BindgenContext, DeriveTrait);
639 type Output = HashMap<ItemId, CanDerive>;
640
new( (ctx, derive_trait): (&'ctx BindgenContext, DeriveTrait), ) -> CannotDerive<'ctx>641 fn new(
642 (ctx, derive_trait): (&'ctx BindgenContext, DeriveTrait),
643 ) -> CannotDerive<'ctx> {
644 let can_derive = HashMap::default();
645 let dependencies = generate_dependencies(ctx, consider_edge_default);
646
647 CannotDerive {
648 ctx,
649 derive_trait,
650 can_derive,
651 dependencies,
652 }
653 }
654
initial_worklist(&self) -> Vec<ItemId>655 fn initial_worklist(&self) -> Vec<ItemId> {
656 // The transitive closure of all allowlisted items, including explicitly
657 // blocklisted items.
658 self.ctx
659 .allowlisted_items()
660 .iter()
661 .cloned()
662 .flat_map(|i| {
663 let mut reachable = vec![i];
664 i.trace(
665 self.ctx,
666 &mut |s, _| {
667 reachable.push(s);
668 },
669 &(),
670 );
671 reachable
672 })
673 .collect()
674 }
675
constrain(&mut self, id: ItemId) -> ConstrainResult676 fn constrain(&mut self, id: ItemId) -> ConstrainResult {
677 trace!("constrain: {:?}", id);
678
679 if let Some(CanDerive::No) = self.can_derive.get(&id).cloned() {
680 trace!(" already know it cannot derive {}", self.derive_trait);
681 return ConstrainResult::Same;
682 }
683
684 let item = self.ctx.resolve_item(id);
685 let can_derive = match item.as_type() {
686 Some(ty) => {
687 let mut can_derive = self.constrain_type(item, ty);
688 if let CanDerive::Yes = can_derive {
689 if !self.derive_trait.can_derive_large_array() &&
690 ty.layout(self.ctx).map_or(false, |l| {
691 l.align > RUST_DERIVE_IN_ARRAY_LIMIT
692 })
693 {
694 // We have to be conservative: the struct *could* have enough
695 // padding that we emit an array that is longer than
696 // `RUST_DERIVE_IN_ARRAY_LIMIT`. If we moved padding calculations
697 // into the IR and computed them before this analysis, then we could
698 // be precise rather than conservative here.
699 can_derive = CanDerive::Manually;
700 }
701 }
702 can_derive
703 }
704 None => self.constrain_join(item, consider_edge_default),
705 };
706
707 self.insert(id, can_derive)
708 }
709
each_depending_on<F>(&self, id: ItemId, mut f: F) where F: FnMut(ItemId),710 fn each_depending_on<F>(&self, id: ItemId, mut f: F)
711 where
712 F: FnMut(ItemId),
713 {
714 if let Some(edges) = self.dependencies.get(&id) {
715 for item in edges {
716 trace!("enqueue {:?} into worklist", item);
717 f(*item);
718 }
719 }
720 }
721 }
722
723 impl<'ctx> From<CannotDerive<'ctx>> for HashMap<ItemId, CanDerive> {
from(analysis: CannotDerive<'ctx>) -> Self724 fn from(analysis: CannotDerive<'ctx>) -> Self {
725 extra_assert!(analysis
726 .can_derive
727 .values()
728 .all(|v| *v != CanDerive::Yes));
729
730 analysis.can_derive
731 }
732 }
733
734 /// Convert a `HashMap<ItemId, CanDerive>` into a `HashSet<ItemId>`.
735 ///
736 /// Elements that are not `CanDerive::Yes` are kept in the set, so that it
737 /// represents all items that cannot derive.
as_cannot_derive_set( can_derive: HashMap<ItemId, CanDerive>, ) -> HashSet<ItemId>738 pub fn as_cannot_derive_set(
739 can_derive: HashMap<ItemId, CanDerive>,
740 ) -> HashSet<ItemId> {
741 can_derive
742 .into_iter()
743 .filter_map(|(k, v)| if v != CanDerive::Yes { Some(k) } else { None })
744 .collect()
745 }
746