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(())
}
}