naga/proc/overloads/
rule.rs

1/*! Type rules.
2
3An implementation of [`OverloadSet`] represents a set of type rules, each of
4which has a list of types for its arguments, and a conclusion about the
5type of the expression as a whole.
6
7This module defines the [`Rule`] type, representing a type rule from an
8[`OverloadSet`], and the [`Conclusion`] type, a specialized enum for
9representing a type rule's conclusion.
10
11[`OverloadSet`]: crate::proc::overloads::OverloadSet
12
13*/
14
15use crate::common::{DiagnosticDebug, ForDebugWithTypes};
16use crate::ir;
17use crate::proc::overloads::constructor_set::ConstructorSize;
18use crate::proc::TypeResolution;
19use crate::UniqueArena;
20
21use alloc::vec::Vec;
22use core::fmt;
23use core::result::Result;
24
25/// A single type rule.
26#[derive(Clone)]
27pub struct Rule {
28    pub arguments: Vec<TypeResolution>,
29    pub conclusion: Conclusion,
30}
31
32/// The result type of a [`Rule`].
33///
34/// A `Conclusion` value represents the return type of some operation
35/// in the builtin function database.
36///
37/// This is very similar to [`TypeInner`], except that it represents
38/// predeclared types using [`PredeclaredType`], so that overload
39/// resolution can delegate registering predeclared types to its users.
40///
41/// [`TypeInner`]: ir::TypeInner
42/// [`PredeclaredType`]: ir::PredeclaredType
43#[derive(Clone, Debug)]
44pub enum Conclusion {
45    /// A type that can be entirely characterized by a [`TypeInner`] value.
46    ///
47    /// [`TypeInner`]: ir::TypeInner
48    Value(ir::TypeInner),
49
50    /// A type that should be registered in the module's
51    /// [`SpecialTypes::predeclared_types`] table.
52    ///
53    /// This is used for operations like [`Frexp`] and [`Modf`].
54    ///
55    /// [`SpecialTypes::predeclared_types`]: ir::SpecialTypes::predeclared_types
56    /// [`Frexp`]: crate::ir::MathFunction::Frexp
57    /// [`Modf`]: crate::ir::MathFunction::Modf
58    Predeclared(ir::PredeclaredType),
59}
60
61impl Conclusion {
62    pub fn for_frexp_modf(
63        function: ir::MathFunction,
64        size: ConstructorSize,
65        scalar: ir::Scalar,
66    ) -> Self {
67        use ir::MathFunction as Mf;
68        use ir::PredeclaredType as Pt;
69
70        let size = match size {
71            ConstructorSize::Scalar => None,
72            ConstructorSize::Vector(size) => Some(size),
73            ConstructorSize::Matrix { .. } => {
74                unreachable!("FrexpModf only supports scalars and vectors");
75            }
76        };
77
78        let predeclared = match function {
79            Mf::Frexp => Pt::FrexpResult { size, scalar },
80            Mf::Modf => Pt::ModfResult { size, scalar },
81            _ => {
82                unreachable!("FrexpModf only supports Frexp and Modf");
83            }
84        };
85
86        Conclusion::Predeclared(predeclared)
87    }
88
89    pub fn into_resolution(
90        self,
91        special_types: &ir::SpecialTypes,
92    ) -> Result<TypeResolution, MissingSpecialType> {
93        match self {
94            Conclusion::Value(inner) => Ok(TypeResolution::Value(inner)),
95            Conclusion::Predeclared(predeclared) => {
96                let handle = *special_types
97                    .predeclared_types
98                    .get(&predeclared)
99                    .ok_or(MissingSpecialType)?;
100                Ok(TypeResolution::Handle(handle))
101            }
102        }
103    }
104}
105
106#[derive(Debug, thiserror::Error)]
107#[error("Special type is not registered within the module")]
108pub struct MissingSpecialType;
109
110impl ForDebugWithTypes for &Rule {}
111
112impl fmt::Debug for DiagnosticDebug<(&Rule, &UniqueArena<ir::Type>)> {
113    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114        let (rule, arena) = self.0;
115        f.write_str("(")?;
116        for (i, argument) in rule.arguments.iter().enumerate() {
117            if i > 0 {
118                f.write_str(", ")?;
119            }
120            write!(f, "{:?}", argument.for_debug(arena))?;
121        }
122        write!(f, ") -> {:?}", rule.conclusion.for_debug(arena))
123    }
124}
125
126impl ForDebugWithTypes for &Conclusion {}
127
128impl fmt::Debug for DiagnosticDebug<(&Conclusion, &UniqueArena<ir::Type>)> {
129    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130        let (conclusion, ctx) = self.0;
131
132        #[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))]
133        {
134            use crate::common::wgsl::TypeContext;
135            ctx.write_type_conclusion(conclusion, f)?;
136        }
137
138        #[cfg(not(any(feature = "wgsl-in", feature = "wgsl-out")))]
139        {
140            let _ = ctx;
141            write!(f, "{conclusion:?}")?;
142        }
143
144        Ok(())
145    }
146}