Document TypeResolution and TypeInner::ValuePointer.

This commit is contained in:
Jim Blandy
2021-09-13 22:34:10 -07:00
committed by Dzmitry Malyshau
parent 807accd7de
commit c03427b154
2 changed files with 107 additions and 0 deletions

View File

@@ -579,7 +579,13 @@ pub enum TypeInner {
base: Handle<Type>,
class: StorageClass,
},
/// Pointer to a value.
///
/// A `ValuePointer` type is equivalent to a `Pointer` to a `Scalar` or `Vector`.
/// This is for use in [`TypeResolution::Value`] variants.
///
/// [`TypeResolution::Value`]: proc::TypeResolution::Value
ValuePointer {
size: Option<VectorSize>,
kind: ScalarKind,

View File

@@ -2,11 +2,97 @@ use crate::arena::{Arena, Handle};
use thiserror::Error;
/// The result of computing an expression's type.
///
/// This is the type returned by [`ResolveContext::resolve`] to represent the type
/// it ascribes to some expression.
///
/// You might expect such a function to simply return a `Handle<Type>`. However,
/// we want type resolution to be a read-only process, and that would limit the
/// possible results to types already present in the expression's associated
/// `Arena<Type>`. Naga IR does have certain expressions whose types are not
/// certain to be present.
///
/// So instead, type resolution returns a `TypeResolution` enum: either a
/// [`Handle`], referencing some type in the arena, or a [`Value`], holding a
/// free-floating [`TypeInner`]. This extends the range to cover anything that
/// can be represented with a `TypeInner` referring to the existing arena.
///
/// What sorts of expressions can have types not available in the arena?
///
/// - An [`Access`] or [`AccessIndex`] expression applied to a [`Vector`] or
/// [`Matrix`] must have a [`Scalar`] or [`Vector`] type. But since `Vector`
/// and `Matrix` represent their element and column types implicitly, not
/// via a handle, there may not be a suitable type in the expression's
/// associated arena. Instead, resolving such an expression returns a
/// `TypeResolution::Value(TypeInner::X { ... })`, where `X` is `Scalar` or
/// `Vector`.
///
/// - Similarly, the type of an [`Access`] or [`AccessIndex`] expression
/// applied to a *pointer to* a vector or matrix must produce a *pointer to*
/// a scalar or vector type. These cannot be represented with a
/// [`TypeInner::Pointer`], since the `Pointer`'s `base` must point into the
/// arena, and as before, we cannot assume that a suitable scalar or vector
/// type is there. So we take things one step further and provide
/// [`TypeInner::ValuePointer`], specifically for the case of pointers to
/// scalars or vectors. This type fits in a `TypeInner` and is exactly
/// equivalent to a `Pointer` to a `Vector` or `Scalar`.
///
/// So, for example, the type of an `Access` expression applied to a value of type:
///
/// ```ignore
/// TypeInner::Matrix { columns, rows, width }
/// ```
///
/// might be:
///
/// ```ignore
/// TypeResolution::Value(TypeInner::Vector {
/// size: rows,
/// kind: ScalarKind::Float,
/// width,
/// })
/// ```
///
/// and the type of an access to a pointer of storage class `class` to such a
/// matrix might be:
///
/// ```ignore
/// TypeResolution::Value(TypeInner::ValuePointer {
/// size: Some(rows),
/// kind: ScalarKind::Float,
/// width,
/// class
/// })
/// ```
///
/// [`Handle`]: TypeResolution::Handle
/// [`Value`]: TypeResolution::Value
///
/// [`Access`]: crate::Expression::Access
/// [`AccessIndex`]: crate::Expression::AccessIndex
///
/// [`TypeInner`]: crate::TypeInner
/// [`Matrix`]: crate::TypeInner::Matrix
/// [`Pointer`]: crate::TypeInner::Pointer
/// [`Scalar`]: crate::TypeInner::Scalar
/// [`ValuePointer`]: crate::TypeInner::ValuePointer
/// [`Vector`]: crate::TypeInner::Vector
///
/// [`TypeInner::Pointer`]: crate::TypeInner::Pointer
/// [`TypeInner::ValuePointer`]: crate::TypeInner::ValuePointer
#[derive(Debug, PartialEq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
pub enum TypeResolution {
/// A type stored in the associated arena.
Handle(Handle<crate::Type>),
/// A free-floating [`TypeInner`], representing a type that may not be
/// available in the associated arena. However, the `TypeInner` itself may
/// contain `Handle<Type>` values referring to types from the arena.
///
/// [`TypeInner`]: crate::TypeInner
Value(crate::TypeInner),
}
@@ -119,6 +205,21 @@ pub struct ResolveContext<'a> {
}
impl<'a> ResolveContext<'a> {
/// Determine the type of `expr`.
///
/// The `past` argument must be a closure that can resolve the types of any
/// expressions that `expr` refers to. These can be gathered by caching the
/// results of prior calls to `resolve`, perhaps as done by the
/// [`front::Typifier`] utility type.
///
/// Type resolution is a read-only process: this method takes `self` by
/// shared reference. However, this means that we cannot add anything to
/// `self.types` that we might need to describe `expr`. To work around this,
/// this method returns a [`TypeResolution`], rather than simply returning a
/// `Handle<Type>`; see the documentation for [`TypeResolution`] for
/// details.
///
/// [`front::Typifier`]: crate::front::Typifier
pub fn resolve(
&self,
expr: &crate::Expression,