naga/proc/overloads/
rule.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/*! Type rules.

An implementation of [`OverloadSet`] represents a set of type rules, each of
which has a list of types for its arguments, and a conclusion about the
type of the expression as a whole.

This module defines the [`Rule`] type, representing a type rule from an
[`OverloadSet`], and the [`Conclusion`] type, a specialized enum for
representing a type rule's conclusion.

[`OverloadSet`]: crate::proc::overloads::OverloadSet

*/

use crate::common::{DiagnosticDebug, ForDebugWithTypes};
use crate::ir;
use crate::proc::overloads::constructor_set::ConstructorSize;
use crate::proc::TypeResolution;
use crate::UniqueArena;

use alloc::vec::Vec;
use core::fmt;
use core::result::Result;

/// A single type rule.
#[derive(Clone)]
pub struct Rule {
    pub arguments: Vec<TypeResolution>,
    pub conclusion: Conclusion,
}

/// The result type of a [`Rule`].
///
/// A `Conclusion` value represents the return type of some operation
/// in the builtin function database.
///
/// This is very similar to [`TypeInner`], except that it represents
/// predeclared types using [`PredeclaredType`], so that overload
/// resolution can delegate registering predeclared types to its users.
///
/// [`TypeInner`]: ir::TypeInner
/// [`PredeclaredType`]: ir::PredeclaredType
#[derive(Clone, Debug)]
pub enum Conclusion {
    /// A type that can be entirely characterized by a [`TypeInner`] value.
    ///
    /// [`TypeInner`]: ir::TypeInner
    Value(ir::TypeInner),

    /// A type that should be registered in the module's
    /// [`SpecialTypes::predeclared_types`] table.
    ///
    /// This is used for operations like [`Frexp`] and [`Modf`].
    ///
    /// [`SpecialTypes::predeclared_types`]: ir::SpecialTypes::predeclared_types
    /// [`Frexp`]: crate::ir::MathFunction::Frexp
    /// [`Modf`]: crate::ir::MathFunction::Modf
    Predeclared(ir::PredeclaredType),
}

impl Conclusion {
    pub fn for_frexp_modf(
        function: ir::MathFunction,
        size: ConstructorSize,
        scalar: ir::Scalar,
    ) -> Self {
        use ir::MathFunction as Mf;
        use ir::PredeclaredType as Pt;

        let size = match size {
            ConstructorSize::Scalar => None,
            ConstructorSize::Vector(size) => Some(size),
            ConstructorSize::Matrix { .. } => {
                unreachable!("FrexpModf only supports scalars and vectors");
            }
        };

        let predeclared = match function {
            Mf::Frexp => Pt::FrexpResult { size, scalar },
            Mf::Modf => Pt::ModfResult { size, scalar },
            _ => {
                unreachable!("FrexpModf only supports Frexp and Modf");
            }
        };

        Conclusion::Predeclared(predeclared)
    }

    pub fn into_resolution(
        self,
        special_types: &ir::SpecialTypes,
    ) -> Result<TypeResolution, MissingSpecialType> {
        match self {
            Conclusion::Value(inner) => Ok(TypeResolution::Value(inner)),
            Conclusion::Predeclared(predeclared) => {
                let handle = *special_types
                    .predeclared_types
                    .get(&predeclared)
                    .ok_or(MissingSpecialType)?;
                Ok(TypeResolution::Handle(handle))
            }
        }
    }
}

#[derive(Debug, thiserror::Error)]
#[error("Special type is not registered within the module")]
pub struct MissingSpecialType;

impl ForDebugWithTypes for &Rule {}

impl fmt::Debug for DiagnosticDebug<(&Rule, &UniqueArena<ir::Type>)> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let (rule, arena) = self.0;
        f.write_str("(")?;
        for (i, argument) in rule.arguments.iter().enumerate() {
            if i > 0 {
                f.write_str(", ")?;
            }
            write!(f, "{:?}", argument.for_debug(arena))?;
        }
        write!(f, ") -> {:?}", rule.conclusion.for_debug(arena))
    }
}

impl ForDebugWithTypes for &Conclusion {}

impl fmt::Debug for DiagnosticDebug<(&Conclusion, &UniqueArena<ir::Type>)> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let (conclusion, ctx) = self.0;

        #[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))]
        {
            use crate::common::wgsl::TypeContext;
            ctx.write_type_conclusion(conclusion, f)?;
        }

        #[cfg(not(any(feature = "wgsl-in", feature = "wgsl-out")))]
        {
            let _ = ctx;
            write!(f, "{conclusion:?}")?;
        }

        Ok(())
    }
}