librashader_naga/front/wgsl/lower/
conversion.rs1use crate::{Handle, Span};
4
5impl<'source, 'temp, 'out> super::ExpressionContext<'source, 'temp, 'out> {
6 pub fn try_automatic_conversions(
19 &mut self,
20 expr: Handle<crate::Expression>,
21 goal_ty: &crate::proc::TypeResolution,
22 goal_span: Span,
23 ) -> Result<Handle<crate::Expression>, super::Error<'source>> {
24 let expr_span = self.get_expression_span(expr);
25 let expr_resolution = super::resolve!(self, expr);
28 let types = &self.module.types;
29 let expr_inner = expr_resolution.inner_with(types);
30 let goal_inner = goal_ty.inner_with(types);
31
32 if expr_inner.equivalent(goal_inner, types) {
34 return Ok(expr);
35 }
36
37 let (_expr_scalar, goal_scalar) =
38 match expr_inner.automatically_converts_to(goal_inner, types) {
39 Some(scalars) => scalars,
40 None => {
41 let gctx = &self.module.to_ctx();
42 let source_type = expr_resolution.to_wgsl(gctx);
43 let dest_type = goal_ty.to_wgsl(gctx);
44
45 return Err(super::Error::AutoConversion {
46 dest_span: goal_span,
47 dest_type,
48 source_span: expr_span,
49 source_type,
50 });
51 }
52 };
53
54 let converted = if let crate::TypeInner::Array { .. } = *goal_inner {
55 let span = self.get_expression_span(expr);
56 self.as_const_evaluator()
57 .cast_array(expr, goal_scalar, span)
58 .map_err(|err| super::Error::ConstantEvaluatorError(err, span))?
59 } else {
60 let cast = crate::Expression::As {
61 expr,
62 kind: goal_scalar.kind,
63 convert: Some(goal_scalar.width),
64 };
65 self.append_expression(cast, expr_span)?
66 };
67
68 Ok(converted)
69 }
70
71 pub fn try_automatic_conversions_slice(
73 &mut self,
74 exprs: &mut [Handle<crate::Expression>],
75 goal_ty: &crate::proc::TypeResolution,
76 goal_span: Span,
77 ) -> Result<(), super::Error<'source>> {
78 for expr in exprs.iter_mut() {
79 *expr = self.try_automatic_conversions(*expr, goal_ty, goal_span)?;
80 }
81
82 Ok(())
83 }
84
85 pub fn try_automatic_conversions_for_vector(
94 &mut self,
95 exprs: &mut [Handle<crate::Expression>],
96 goal_scalar: crate::Scalar,
97 goal_span: Span,
98 ) -> Result<(), super::Error<'source>> {
99 use crate::proc::TypeResolution as Tr;
100 use crate::TypeInner as Ti;
101 let goal_scalar_res = Tr::Value(Ti::Scalar(goal_scalar));
102
103 for (i, expr) in exprs.iter_mut().enumerate() {
104 let expr_resolution = super::resolve!(self, *expr);
107 let types = &self.module.types;
108 let expr_inner = expr_resolution.inner_with(types);
109
110 match *expr_inner {
111 Ti::Scalar(_) => {
112 *expr = self.try_automatic_conversions(*expr, &goal_scalar_res, goal_span)?;
113 }
114 Ti::Vector { size, scalar: _ } => {
115 let goal_vector_res = Tr::Value(Ti::Vector {
116 size,
117 scalar: goal_scalar,
118 });
119 *expr = self.try_automatic_conversions(*expr, &goal_vector_res, goal_span)?;
120 }
121 _ => {
122 let span = self.get_expression_span(*expr);
123 return Err(super::Error::InvalidConstructorComponentType(
124 span, i as i32,
125 ));
126 }
127 }
128 }
129
130 Ok(())
131 }
132
133 pub fn convert_slice_to_common_scalar(
144 &mut self,
145 exprs: &mut [Handle<crate::Expression>],
146 goal: crate::Scalar,
147 ) -> Result<(), super::Error<'source>> {
148 for expr in exprs.iter_mut() {
149 let inner = super::resolve_inner!(self, *expr);
150 if inner.scalar() != Some(goal) {
153 let cast = crate::Expression::As {
154 expr: *expr,
155 kind: goal.kind,
156 convert: Some(goal.width),
157 };
158 let expr_span = self.get_expression_span(*expr);
159 *expr = self.append_expression(cast, expr_span)?;
160 }
161 }
162
163 Ok(())
164 }
165
166 pub fn concretize(
170 &mut self,
171 mut expr: Handle<crate::Expression>,
172 ) -> Result<Handle<crate::Expression>, super::Error<'source>> {
173 let inner = super::resolve_inner!(self, expr);
174 if let Some(scalar) = inner.automatically_convertible_scalar(&self.module.types) {
175 let concretized = scalar.concretize();
176 if concretized != scalar {
177 let span = self.get_expression_span(expr);
178 expr = self
179 .as_const_evaluator()
180 .cast_array(expr, concretized, span)
181 .map_err(|err| super::Error::ConstantEvaluatorError(err, span))?;
182 }
183 }
184
185 Ok(expr)
186 }
187}
188
189impl crate::TypeInner {
190 fn automatically_converts_to(
204 &self,
205 goal: &Self,
206 types: &crate::UniqueArena<crate::Type>,
207 ) -> Option<(crate::Scalar, crate::Scalar)> {
208 use crate::ScalarKind as Sk;
209 use crate::TypeInner as Ti;
210
211 let expr_scalar;
217 let goal_scalar;
218 match (self, goal) {
219 (&Ti::Scalar(expr), &Ti::Scalar(goal)) => {
220 expr_scalar = expr;
221 goal_scalar = goal;
222 }
223 (
224 &Ti::Vector {
225 size: expr_size,
226 scalar: expr,
227 },
228 &Ti::Vector {
229 size: goal_size,
230 scalar: goal,
231 },
232 ) if expr_size == goal_size => {
233 expr_scalar = expr;
234 goal_scalar = goal;
235 }
236 (
237 &Ti::Matrix {
238 rows: expr_rows,
239 columns: expr_columns,
240 scalar: expr,
241 },
242 &Ti::Matrix {
243 rows: goal_rows,
244 columns: goal_columns,
245 scalar: goal,
246 },
247 ) if expr_rows == goal_rows && expr_columns == goal_columns => {
248 expr_scalar = expr;
249 goal_scalar = goal;
250 }
251 (
252 &Ti::Array {
253 base: expr_base,
254 size: expr_size,
255 stride: _,
256 },
257 &Ti::Array {
258 base: goal_base,
259 size: goal_size,
260 stride: _,
261 },
262 ) if expr_size == goal_size => {
263 return types[expr_base]
264 .inner
265 .automatically_converts_to(&types[goal_base].inner, types);
266 }
267 _ => return None,
268 }
269
270 match (expr_scalar.kind, goal_scalar.kind) {
271 (Sk::AbstractFloat, Sk::Float) => {}
272 (Sk::AbstractInt, Sk::Sint | Sk::Uint | Sk::AbstractFloat | Sk::Float) => {}
273 _ => return None,
274 }
275
276 log::trace!(" okay: expr {expr_scalar:?}, goal {goal_scalar:?}");
277 Some((expr_scalar, goal_scalar))
278 }
279
280 fn automatically_convertible_scalar(
281 &self,
282 types: &crate::UniqueArena<crate::Type>,
283 ) -> Option<crate::Scalar> {
284 use crate::TypeInner as Ti;
285 match *self {
286 Ti::Scalar(scalar) | Ti::Vector { scalar, .. } | Ti::Matrix { scalar, .. } => {
287 Some(scalar)
288 }
289 Ti::Array { base, .. } => types[base].inner.automatically_convertible_scalar(types),
290 Ti::Atomic(_)
291 | Ti::Pointer { .. }
292 | Ti::ValuePointer { .. }
293 | Ti::Struct { .. }
294 | Ti::Image { .. }
295 | Ti::Sampler { .. }
296 | Ti::AccelerationStructure
297 | Ti::RayQuery
298 | Ti::BindingArray { .. } => None,
299 }
300 }
301}
302
303impl crate::Scalar {
304 pub const fn automatic_conversion_combine(self, other: Self) -> Option<crate::Scalar> {
311 use crate::ScalarKind as Sk;
312
313 match (self.kind, other.kind) {
314 (Sk::AbstractFloat, Sk::AbstractFloat)
316 | (Sk::AbstractInt, Sk::AbstractInt)
317 | (Sk::Sint, Sk::Sint)
318 | (Sk::Uint, Sk::Uint)
319 | (Sk::Float, Sk::Float)
320 | (Sk::Bool, Sk::Bool) => {
321 if self.width == other.width {
322 Some(self)
324 } else {
325 None
329 }
330 }
331
332 (Sk::AbstractFloat, Sk::AbstractInt) => Some(self),
334 (Sk::AbstractInt, Sk::AbstractFloat) => Some(other),
335
336 (Sk::AbstractFloat, Sk::Float) => Some(other),
338 (Sk::Float, Sk::AbstractFloat) => Some(self),
339
340 (Sk::AbstractInt, Sk::Uint | Sk::Sint | Sk::Float) => Some(other),
342 (Sk::Uint | Sk::Sint | Sk::Float, Sk::AbstractInt) => Some(self),
343
344 (Sk::AbstractFloat, Sk::Uint | Sk::Sint) | (Sk::Uint | Sk::Sint, Sk::AbstractFloat) => {
346 None
347 }
348
349 (Sk::Bool, _) | (_, Sk::Bool) => None,
351
352 (Sk::Sint | Sk::Uint | Sk::Float, Sk::Sint | Sk::Uint | Sk::Float) => None,
354 }
355 }
356
357 const fn concretize(self) -> Self {
358 use crate::ScalarKind as Sk;
359 match self.kind {
360 Sk::Sint | Sk::Uint | Sk::Float | Sk::Bool => self,
361 Sk::AbstractInt => Self::I32,
362 Sk::AbstractFloat => Self::F32,
363 }
364 }
365}