naga/proc/overloads/
list.rs
1use 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#[derive(Clone)]
22pub(in crate::proc::overloads) struct List {
23 members: u64,
25
26 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 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 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}