naga/proc/overloads/
list.rs

1//! An [`OverloadSet`] represented as a vector of rules.
2//!
3//! [`OverloadSet`]: crate::proc::overloads::OverloadSet
4
5use crate::common::{DiagnosticDebug, ForDebug, ForDebugWithTypes};
6use crate::ir;
7use crate::proc::overloads::one_bits_iter::OneBitsIter;
8use crate::proc::overloads::Rule;
9use crate::proc::{GlobalCtx, TypeResolution};
10
11use alloc::rc::Rc;
12use alloc::vec::Vec;
13use core::fmt;
14
15/// A simple list of overloads.
16///
17/// Note that this type is not quite as general as it looks, in that
18/// the implementation of `most_preferred` doesn't work for arbitrary
19/// lists of overloads. See the documentation for [`List::rules`] for
20/// details.
21#[derive(Clone)]
22pub(in crate::proc::overloads) struct List {
23    /// A bitmask of which elements of `rules` are included in the set.
24    members: u64,
25
26    /// A list of type rules that are members of the set.
27    ///
28    /// These must be listed in order such that every rule in the list
29    /// is always more preferred than all subsequent rules in the
30    /// list. If there is no such arrangement of rules, then you
31    /// cannot use `List` to represent the overload set.
32    rules: Rc<Vec<Rule>>,
33}
34
35impl List {
36    pub(in crate::proc::overloads) fn from_rules(rules: Vec<Rule>) -> List {
37        List {
38            members: len_to_full_mask(rules.len()),
39            rules: Rc::new(rules),
40        }
41    }
42
43    fn members(&self) -> impl Iterator<Item = (u64, &Rule)> {
44        OneBitsIter::new(self.members).map(|mask| {
45            let index = mask.trailing_zeros() as usize;
46            (mask, &self.rules[index])
47        })
48    }
49
50    fn filter<F>(&self, mut pred: F) -> List
51    where
52        F: FnMut(&Rule) -> bool,
53    {
54        let mut filtered_members = 0;
55        for (mask, rule) in self.members() {
56            if pred(rule) {
57                filtered_members |= mask;
58            }
59        }
60
61        List {
62            members: filtered_members,
63            rules: self.rules.clone(),
64        }
65    }
66}
67
68impl crate::proc::overloads::OverloadSet for List {
69    fn is_empty(&self) -> bool {
70        self.members == 0
71    }
72
73    fn min_arguments(&self) -> usize {
74        self.members()
75            .fold(None, |best, (_, rule)| {
76                // This is different from `max_arguments` because
77                // `<Option as PartialOrd>` doesn't work the way we'd like.
78                let len = rule.arguments.len();
79                Some(match best {
80                    Some(best) => core::cmp::max(best, len),
81                    None => len,
82                })
83            })
84            .unwrap()
85    }
86
87    fn max_arguments(&self) -> usize {
88        self.members()
89            .fold(None, |n, (_, rule)| {
90                core::cmp::max(n, Some(rule.arguments.len()))
91            })
92            .unwrap()
93    }
94
95    fn arg(&self, i: usize, arg_ty: &ir::TypeInner, types: &crate::UniqueArena<ir::Type>) -> Self {
96        log::debug!("arg {i} of type {:?}", arg_ty.for_debug(types));
97        self.filter(|rule| {
98            if log::log_enabled!(log::Level::Debug) {
99                log::debug!("    considering rule {:?}", rule.for_debug(types));
100                match rule.arguments.get(i) {
101                    Some(rule_ty) => {
102                        let rule_ty = rule_ty.inner_with(types);
103                        if arg_ty.non_struct_equivalent(rule_ty, types) {
104                            log::debug!("    types are equivalent");
105                        } else {
106                            match arg_ty.automatically_converts_to(rule_ty, types) {
107                                Some((from, to)) => {
108                                    log::debug!(
109                                        "    converts automatically from {:?} to {:?}",
110                                        from.for_debug(),
111                                        to.for_debug()
112                                    );
113                                }
114                                None => {
115                                    log::debug!("    no conversion possible");
116                                }
117                            }
118                        }
119                    }
120                    None => {
121                        log::debug!("    argument index {i} out of bounds");
122                    }
123                }
124            }
125            rule.arguments.get(i).is_some_and(|rule_ty| {
126                let rule_ty = rule_ty.inner_with(types);
127                arg_ty.non_struct_equivalent(rule_ty, types)
128                    || arg_ty.automatically_converts_to(rule_ty, types).is_some()
129            })
130        })
131    }
132
133    fn concrete_only(self, types: &crate::UniqueArena<ir::Type>) -> Self {
134        self.filter(|rule| {
135            rule.arguments
136                .iter()
137                .all(|arg_ty| !arg_ty.inner_with(types).is_abstract(types))
138        })
139    }
140
141    fn most_preferred(&self) -> Rule {
142        // As documented for `Self::rules`, whatever rule is first is
143        // the most preferred. `OverloadSet` documents this method to
144        // panic if the set is empty.
145        let (_, rule) = self.members().next().unwrap();
146        rule.clone()
147    }
148
149    fn overload_list(&self, _gctx: &GlobalCtx<'_>) -> Vec<Rule> {
150        self.members().map(|(_, rule)| rule.clone()).collect()
151    }
152
153    fn allowed_args(&self, i: usize, _gctx: &GlobalCtx<'_>) -> Vec<TypeResolution> {
154        self.members()
155            .map(|(_, rule)| rule.arguments[i].clone())
156            .collect()
157    }
158
159    fn for_debug(&self, types: &crate::UniqueArena<ir::Type>) -> impl fmt::Debug {
160        DiagnosticDebug((self, types))
161    }
162}
163
164const fn len_to_full_mask(n: usize) -> u64 {
165    if n >= 64 {
166        panic!("List::rules can only hold up to 63 rules");
167    }
168
169    (1_u64 << n) - 1
170}
171
172impl ForDebugWithTypes for &List {}
173
174impl fmt::Debug for DiagnosticDebug<(&List, &crate::UniqueArena<ir::Type>)> {
175    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176        let (list, types) = self.0;
177
178        f.debug_list()
179            .entries(list.members().map(|(_mask, rule)| rule.for_debug(types)))
180            .finish()
181    }
182}