1use crate::common::{DiagnosticDebug, ForDebugWithTypes};
12use crate::ir;
13use crate::proc::overloads::constructor_set::{ConstructorSet, ConstructorSize};
14use crate::proc::overloads::rule::{Conclusion, Rule};
15use crate::proc::overloads::scalar_set::ScalarSet;
16use crate::proc::overloads::OverloadSet;
17use crate::proc::{GlobalCtx, TypeResolution};
18use crate::UniqueArena;
19
20use alloc::vec::Vec;
21use core::fmt;
22
23#[derive(Clone)]
50pub(in crate::proc::overloads) struct Regular {
51 pub arity: usize,
53
54 pub constructors: ConstructorSet,
56
57 pub scalars: ScalarSet,
59
60 pub conclude: ConclusionRule,
63}
64
65impl Regular {
66 pub(in crate::proc::overloads) const EMPTY: Regular = Regular {
67 arity: 0,
68 constructors: ConstructorSet::empty(),
69 scalars: ScalarSet::empty(),
70 conclude: ConclusionRule::ArgumentType,
71 };
72
73 fn members(&self) -> impl Iterator<Item = (ConstructorSize, ir::Scalar)> {
84 let scalars = self.scalars;
85 self.constructors.members().flat_map(move |constructor| {
86 let size = constructor.size();
87 scalars
91 .members()
92 .map(move |singleton| (size, singleton.most_general_scalar()))
93 })
94 }
95
96 fn rules(&self) -> impl Iterator<Item = Rule> {
97 let arity = self.arity;
98 let conclude = self.conclude;
99 self.members()
100 .map(move |(size, scalar)| make_rule(arity, size, scalar, conclude))
101 }
102}
103
104impl OverloadSet for Regular {
105 fn is_empty(&self) -> bool {
106 self.constructors.is_empty() || self.scalars.is_empty()
107 }
108
109 fn min_arguments(&self) -> usize {
110 assert!(!self.is_empty());
111 self.arity
112 }
113
114 fn max_arguments(&self) -> usize {
115 assert!(!self.is_empty());
116 self.arity
117 }
118
119 fn arg(&self, i: usize, ty: &ir::TypeInner, types: &UniqueArena<ir::Type>) -> Self {
120 if i >= self.arity {
121 return Self::EMPTY;
122 }
123
124 let constructor = ConstructorSet::singleton(ty);
125
126 let scalars = match ty.scalar_for_conversions(types) {
127 Some(ty_scalar) => ScalarSet::convertible_from(ty_scalar),
128 None => ScalarSet::empty(),
129 };
130
131 Self {
132 arity: self.arity,
133
134 constructors: self.constructors & constructor,
136
137 scalars: self.scalars & scalars,
140
141 conclude: self.conclude,
142 }
143 }
144
145 fn concrete_only(self, _types: &UniqueArena<ir::Type>) -> Self {
146 Self {
147 scalars: self.scalars & ScalarSet::CONCRETE,
148 ..self
149 }
150 }
151
152 fn most_preferred(&self) -> Rule {
153 assert!(!self.is_empty());
154
155 assert!(self.constructors.is_singleton());
159
160 let size = self.constructors.size();
161 let scalar = self.scalars.most_general_scalar();
162 make_rule(self.arity, size, scalar, self.conclude)
163 }
164
165 fn overload_list(&self, _gctx: &GlobalCtx<'_>) -> Vec<Rule> {
166 self.rules().collect()
167 }
168
169 fn allowed_args(&self, i: usize, _gctx: &GlobalCtx<'_>) -> Vec<TypeResolution> {
170 if i >= self.arity {
171 return Vec::new();
172 }
173 self.members()
174 .map(|(size, scalar)| TypeResolution::Value(size.to_inner(scalar)))
175 .collect()
176 }
177
178 fn for_debug(&self, types: &UniqueArena<ir::Type>) -> impl fmt::Debug {
179 DiagnosticDebug((self, types))
180 }
181}
182
183fn make_rule(
190 arity: usize,
191 size: ConstructorSize,
192 scalar: ir::Scalar,
193 conclusion_rule: ConclusionRule,
194) -> Rule {
195 let inner = size.to_inner(scalar);
196 let arg = TypeResolution::Value(inner.clone());
197 Rule {
198 arguments: core::iter::repeat(arg.clone()).take(arity).collect(),
199 conclusion: conclusion_rule.conclude(size, scalar),
200 }
201}
202
203#[derive(Clone, Copy, Debug)]
205#[repr(u8)]
206pub(in crate::proc::overloads) enum ConclusionRule {
207 ArgumentType,
208 Scalar,
209 Frexp,
210 Modf,
211 U32,
212 Vec2F,
213 Vec4F,
214 Vec4I,
215 Vec4U,
216}
217
218impl ConclusionRule {
219 fn conclude(self, size: ConstructorSize, scalar: ir::Scalar) -> Conclusion {
220 match self {
221 Self::ArgumentType => Conclusion::Value(size.to_inner(scalar)),
222 Self::Scalar => Conclusion::Value(ir::TypeInner::Scalar(scalar)),
223 Self::Frexp => Conclusion::for_frexp_modf(ir::MathFunction::Frexp, size, scalar),
224 Self::Modf => Conclusion::for_frexp_modf(ir::MathFunction::Modf, size, scalar),
225 Self::U32 => Conclusion::Value(ir::TypeInner::Scalar(ir::Scalar::U32)),
226 Self::Vec2F => Conclusion::Value(ir::TypeInner::Vector {
227 size: ir::VectorSize::Bi,
228 scalar: ir::Scalar::F32,
229 }),
230 Self::Vec4F => Conclusion::Value(ir::TypeInner::Vector {
231 size: ir::VectorSize::Quad,
232 scalar: ir::Scalar::F32,
233 }),
234 Self::Vec4I => Conclusion::Value(ir::TypeInner::Vector {
235 size: ir::VectorSize::Quad,
236 scalar: ir::Scalar::I32,
237 }),
238 Self::Vec4U => Conclusion::Value(ir::TypeInner::Vector {
239 size: ir::VectorSize::Quad,
240 scalar: ir::Scalar::U32,
241 }),
242 }
243 }
244}
245
246impl fmt::Debug for DiagnosticDebug<(&Regular, &UniqueArena<ir::Type>)> {
247 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248 let (regular, types) = self.0;
249 let rules: Vec<Rule> = regular.rules().collect();
250 f.debug_struct("List")
251 .field("rules", &rules.for_debug(types))
252 .field("conclude", ®ular.conclude)
253 .finish()
254 }
255}
256
257impl ForDebugWithTypes for &Regular {}
258
259impl fmt::Debug for DiagnosticDebug<(&[Rule], &UniqueArena<ir::Type>)> {
260 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
261 let (rules, types) = self.0;
262 f.debug_list()
263 .entries(rules.iter().map(|rule| rule.for_debug(types)))
264 .finish()
265 }
266}
267
268impl ForDebugWithTypes for &[Rule] {}
269
270macro_rules! regular {
291 ( $arity:literal , $( $constr:ident )|* of $( $scalar:ident )|*) => {
293 {
294 use $crate::proc::overloads;
295 use overloads::constructor_set::constructor_set;
296 use overloads::regular::{Regular, ConclusionRule};
297 use overloads::scalar_set::scalar_set;
298 Regular {
299 arity: $arity,
300 constructors: constructor_set!( $( $constr )|* ),
301 scalars: scalar_set!( $( $scalar )|* ),
302 conclude: ConclusionRule::ArgumentType,
303 }
304 }
305 };
306
307 ( $arity:literal , $( $constr:ident )|* of $( $scalar:ident )|* -> $conclude:ident) => {
309 {
310 use $crate::proc::overloads;
311 use overloads::constructor_set::constructor_set;
312 use overloads::regular::{Regular, ConclusionRule};
313 use overloads::scalar_set::scalar_set;
314 Regular {
315 arity: $arity,
316 constructors:constructor_set!( $( $constr )|* ),
317 scalars: scalar_set!( $( $scalar )|* ),
318 conclude: ConclusionRule::$conclude,
319 }
320 }
321 };
322}
323
324pub(in crate::proc::overloads) use regular;
325
326#[cfg(test)]
327mod test {
328 use super::*;
329 use crate::ir;
330
331 const fn scalar(scalar: ir::Scalar) -> ir::TypeInner {
332 ir::TypeInner::Scalar(scalar)
333 }
334
335 const fn vec2(scalar: ir::Scalar) -> ir::TypeInner {
336 ir::TypeInner::Vector {
337 scalar,
338 size: ir::VectorSize::Bi,
339 }
340 }
341
342 const fn vec3(scalar: ir::Scalar) -> ir::TypeInner {
343 ir::TypeInner::Vector {
344 scalar,
345 size: ir::VectorSize::Tri,
346 }
347 }
348
349 #[track_caller]
352 fn check_return_type(set: &Regular, expected: &ir::TypeInner, arena: &UniqueArena<ir::Type>) {
353 assert!(!set.is_empty());
354
355 let special_types = ir::SpecialTypes::default();
356
357 let preferred = set.most_preferred();
358 let conclusion = preferred.conclusion;
359 let resolution = conclusion
360 .into_resolution(&special_types)
361 .expect("special types should have been pre-registered");
362 let inner = resolution.inner_with(arena);
363
364 assert!(
365 inner.equivalent(expected, arena),
366 "Expected {:?}, got {:?}",
367 expected.for_debug(arena),
368 inner.for_debug(arena),
369 );
370 }
371
372 #[test]
373 fn unary_vec_or_scalar_numeric_scalar() {
374 let arena = UniqueArena::default();
375
376 let builtin = regular!(1, SCALAR of NUMERIC);
377
378 let ok = builtin.arg(0, &scalar(ir::Scalar::U32), &arena);
379 check_return_type(&ok, &scalar(ir::Scalar::U32), &arena);
380
381 let err = builtin.arg(0, &scalar(ir::Scalar::BOOL), &arena);
382 assert!(err.is_empty());
383 }
384
385 #[test]
386 fn unary_vec_or_scalar_numeric_vector() {
387 let arena = UniqueArena::default();
388
389 let builtin = regular!(1, VECN|SCALAR of NUMERIC);
390
391 let ok = builtin.arg(0, &vec3(ir::Scalar::F64), &arena);
392 check_return_type(&ok, &vec3(ir::Scalar::F64), &arena);
393
394 let err = builtin.arg(0, &vec3(ir::Scalar::BOOL), &arena);
395 assert!(err.is_empty());
396 }
397
398 #[test]
399 fn unary_vec_or_scalar_numeric_matrix() {
400 let arena = UniqueArena::default();
401
402 let builtin = regular!(1, VECN|SCALAR of NUMERIC);
403
404 let err = builtin.arg(
405 0,
406 &ir::TypeInner::Matrix {
407 columns: ir::VectorSize::Tri,
408 rows: ir::VectorSize::Tri,
409 scalar: ir::Scalar::F32,
410 },
411 &arena,
412 );
413 assert!(err.is_empty());
414 }
415
416 #[test]
417 #[rustfmt::skip]
418 fn binary_vec_or_scalar_numeric_scalar() {
419 let arena = UniqueArena::default();
420
421 let builtin = regular!(2, VECN|SCALAR of NUMERIC);
422
423 let ok = builtin
424 .arg(0, &scalar(ir::Scalar::F32), &arena)
425 .arg(1, &scalar(ir::Scalar::F32), &arena);
426 check_return_type(&ok, &scalar(ir::Scalar::F32), &arena);
427
428 let ok = builtin
429 .arg(0, &scalar(ir::Scalar::ABSTRACT_FLOAT), &arena)
430 .arg(1, &scalar(ir::Scalar::F32), &arena);
431 check_return_type(&ok, &scalar(ir::Scalar::F32), &arena);
432
433 let ok = builtin
434 .arg(0, &scalar(ir::Scalar::F32), &arena)
435 .arg(1, &scalar(ir::Scalar::ABSTRACT_INT), &arena);
436 check_return_type(&ok, &scalar(ir::Scalar::F32), &arena);
437
438 let ok = builtin
439 .arg(0, &scalar(ir::Scalar::U32), &arena)
440 .arg(1, &scalar(ir::Scalar::U32), &arena);
441 check_return_type(&ok, &scalar(ir::Scalar::U32), &arena);
442
443 let ok = builtin
444 .arg(0, &scalar(ir::Scalar::U32), &arena)
445 .arg(1, &scalar(ir::Scalar::ABSTRACT_INT), &arena);
446 check_return_type(&ok, &scalar(ir::Scalar::U32), &arena);
447
448 let ok = builtin
449 .arg(0, &scalar(ir::Scalar::ABSTRACT_INT), &arena)
450 .arg(1, &scalar(ir::Scalar::U32), &arena);
451 check_return_type(&ok, &scalar(ir::Scalar::U32), &arena);
452
453 let err = builtin
455 .arg(0, &scalar(ir::Scalar::BOOL), &arena)
456 .arg(1, &scalar(ir::Scalar::BOOL), &arena);
457 assert!(err.is_empty());
458
459 let err = builtin
461 .arg(0, &scalar(ir::Scalar::F32), &arena)
462 .arg(1, &scalar(ir::Scalar::F64), &arena);
463 assert!(err.is_empty());
464
465 let err = builtin
467 .arg(0, &scalar(ir::Scalar::F32), &arena)
468 .arg(1, &vec2(ir::Scalar::F32), &arena);
469 assert!(err.is_empty());
470
471 let err = builtin
473 .arg(0, &vec2(ir::Scalar::F32), &arena)
474 .arg(1, &vec3(ir::Scalar::F32), &arena);
475 assert!(err.is_empty());
476 }
477
478 #[test]
479 #[rustfmt::skip]
480 fn binary_vec_or_scalar_numeric_vector() {
481 let arena = UniqueArena::default();
482
483 let builtin = regular!(2, VECN|SCALAR of NUMERIC);
484
485 let ok = builtin
486 .arg(0, &vec3(ir::Scalar::F32), &arena)
487 .arg(1, &vec3(ir::Scalar::F32), &arena);
488 check_return_type(&ok, &vec3(ir::Scalar::F32), &arena);
489
490 let err = builtin
492 .arg(0, &vec2(ir::Scalar::F32), &arena)
493 .arg(1, &vec3(ir::Scalar::F32), &arena);
494 assert!(err.is_empty());
495
496 let err = builtin
498 .arg(0, &vec3(ir::Scalar::F32), &arena)
499 .arg(1, &vec3(ir::Scalar::F64), &arena);
500 assert!(err.is_empty());
501
502 let err = builtin
504 .arg(0, &scalar(ir::Scalar::F32), &arena)
505 .arg(1, &vec3(ir::Scalar::F32), &arena);
506 assert!(err.is_empty());
507 }
508
509 #[test]
510 #[rustfmt::skip]
511 fn binary_vec_or_scalar_numeric_vector_abstract() {
512 let arena = UniqueArena::default();
513
514 let builtin = regular!(2, VECN|SCALAR of NUMERIC);
515
516 let ok = builtin
517 .arg(0, &vec2(ir::Scalar::ABSTRACT_INT), &arena)
518 .arg(1, &vec2(ir::Scalar::U32), &arena);
519 check_return_type(&ok, &vec2(ir::Scalar::U32), &arena);
520
521 let ok = builtin
522 .arg(0, &vec3(ir::Scalar::ABSTRACT_INT), &arena)
523 .arg(1, &vec3(ir::Scalar::F32), &arena);
524 check_return_type(&ok, &vec3(ir::Scalar::F32), &arena);
525
526 let ok = builtin
527 .arg(0, &scalar(ir::Scalar::ABSTRACT_FLOAT), &arena)
528 .arg(1, &scalar(ir::Scalar::F32), &arena);
529 check_return_type(&ok, &scalar(ir::Scalar::F32), &arena);
530
531 let err = builtin
532 .arg(0, &scalar(ir::Scalar::ABSTRACT_FLOAT), &arena)
533 .arg(1, &scalar(ir::Scalar::U32), &arena);
534 assert!(err.is_empty());
535
536 let err = builtin
537 .arg(0, &scalar(ir::Scalar::I32), &arena)
538 .arg(1, &scalar(ir::Scalar::U32), &arena);
539 assert!(err.is_empty());
540 }
541}