1use crate::front::wgsl::error::{
4 AutoConversionError, AutoConversionLeafScalarError, ConcretizationFailedError,
5};
6use crate::{Handle, Span};
7
8impl<'source, 'temp, 'out> super::ExpressionContext<'source, 'temp, 'out> {
9 pub fn try_automatic_conversions(
22 &mut self,
23 expr: Handle<crate::Expression>,
24 goal_ty: &crate::proc::TypeResolution,
25 goal_span: Span,
26 ) -> Result<Handle<crate::Expression>, super::Error<'source>> {
27 let expr_span = self.get_expression_span(expr);
28 let expr_resolution = super::resolve!(self, expr);
31 let types = &self.module.types;
32 let expr_inner = expr_resolution.inner_with(types);
33 let goal_inner = goal_ty.inner_with(types);
34
35 if expr_inner.equivalent(goal_inner, types) {
37 return Ok(expr);
38 }
39
40 let (_expr_scalar, goal_scalar) =
41 match expr_inner.automatically_converts_to(goal_inner, types) {
42 Some(scalars) => scalars,
43 None => {
44 let gctx = &self.module.to_ctx();
45 let source_type = expr_resolution.to_wgsl(gctx).into();
46 let dest_type = goal_ty.to_wgsl(gctx).into();
47
48 return Err(super::Error::AutoConversion(Box::new(
49 AutoConversionError {
50 dest_span: goal_span,
51 dest_type,
52 source_span: expr_span,
53 source_type,
54 },
55 )));
56 }
57 };
58
59 self.convert_leaf_scalar(expr, expr_span, goal_scalar)
60 }
61
62 pub fn try_automatic_conversion_for_leaf_scalar(
75 &mut self,
76 expr: Handle<crate::Expression>,
77 goal_scalar: crate::Scalar,
78 goal_span: Span,
79 ) -> Result<Handle<crate::Expression>, super::Error<'source>> {
80 let expr_span = self.get_expression_span(expr);
81 let expr_resolution = super::resolve!(self, expr);
82 let types = &self.module.types;
83 let expr_inner = expr_resolution.inner_with(types);
84
85 let make_error = || {
86 let gctx = &self.module.to_ctx();
87 let source_type = expr_resolution.to_wgsl(gctx).into();
88 super::Error::AutoConversionLeafScalar(Box::new(AutoConversionLeafScalarError {
89 dest_span: goal_span,
90 dest_scalar: goal_scalar.to_wgsl().into(),
91 source_span: expr_span,
92 source_type,
93 }))
94 };
95
96 let expr_scalar = match expr_inner.scalar() {
97 Some(scalar) => scalar,
98 None => return Err(make_error()),
99 };
100
101 if expr_scalar == goal_scalar {
102 return Ok(expr);
103 }
104
105 if !expr_scalar.automatically_converts_to(goal_scalar) {
106 return Err(make_error());
107 }
108
109 assert!(expr_scalar.is_abstract());
110
111 self.convert_leaf_scalar(expr, expr_span, goal_scalar)
112 }
113
114 fn convert_leaf_scalar(
115 &mut self,
116 expr: Handle<crate::Expression>,
117 expr_span: Span,
118 goal_scalar: crate::Scalar,
119 ) -> Result<Handle<crate::Expression>, super::Error<'source>> {
120 let expr_inner = super::resolve_inner!(self, expr);
121 if let crate::TypeInner::Array { .. } = *expr_inner {
122 self.as_const_evaluator()
123 .cast_array(expr, goal_scalar, expr_span)
124 .map_err(|err| super::Error::ConstantEvaluatorError(err.into(), expr_span))
125 } else {
126 let cast = crate::Expression::As {
127 expr,
128 kind: goal_scalar.kind,
129 convert: Some(goal_scalar.width),
130 };
131 self.append_expression(cast, expr_span)
132 }
133 }
134
135 pub fn try_automatic_conversions_slice(
137 &mut self,
138 exprs: &mut [Handle<crate::Expression>],
139 goal_ty: &crate::proc::TypeResolution,
140 goal_span: Span,
141 ) -> Result<(), super::Error<'source>> {
142 for expr in exprs.iter_mut() {
143 *expr = self.try_automatic_conversions(*expr, goal_ty, goal_span)?;
144 }
145
146 Ok(())
147 }
148
149 pub fn try_automatic_conversions_for_vector(
158 &mut self,
159 exprs: &mut [Handle<crate::Expression>],
160 goal_scalar: crate::Scalar,
161 goal_span: Span,
162 ) -> Result<(), super::Error<'source>> {
163 use crate::proc::TypeResolution as Tr;
164 use crate::TypeInner as Ti;
165 let goal_scalar_res = Tr::Value(Ti::Scalar(goal_scalar));
166
167 for (i, expr) in exprs.iter_mut().enumerate() {
168 let expr_resolution = super::resolve!(self, *expr);
171 let types = &self.module.types;
172 let expr_inner = expr_resolution.inner_with(types);
173
174 match *expr_inner {
175 Ti::Scalar(_) => {
176 *expr = self.try_automatic_conversions(*expr, &goal_scalar_res, goal_span)?;
177 }
178 Ti::Vector { size, scalar: _ } => {
179 let goal_vector_res = Tr::Value(Ti::Vector {
180 size,
181 scalar: goal_scalar,
182 });
183 *expr = self.try_automatic_conversions(*expr, &goal_vector_res, goal_span)?;
184 }
185 _ => {
186 let span = self.get_expression_span(*expr);
187 return Err(super::Error::InvalidConstructorComponentType(
188 span, i as i32,
189 ));
190 }
191 }
192 }
193
194 Ok(())
195 }
196
197 pub fn convert_to_leaf_scalar(
199 &mut self,
200 expr: &mut Handle<crate::Expression>,
201 goal: crate::Scalar,
202 ) -> Result<(), super::Error<'source>> {
203 let inner = super::resolve_inner!(self, *expr);
204 if inner.scalar() != Some(goal) {
207 let cast = crate::Expression::As {
208 expr: *expr,
209 kind: goal.kind,
210 convert: Some(goal.width),
211 };
212 let expr_span = self.get_expression_span(*expr);
213 *expr = self.append_expression(cast, expr_span)?;
214 }
215
216 Ok(())
217 }
218
219 pub fn convert_slice_to_common_leaf_scalar(
230 &mut self,
231 exprs: &mut [Handle<crate::Expression>],
232 goal: crate::Scalar,
233 ) -> Result<(), super::Error<'source>> {
234 for expr in exprs.iter_mut() {
235 self.convert_to_leaf_scalar(expr, goal)?;
236 }
237
238 Ok(())
239 }
240
241 pub fn concretize(
245 &mut self,
246 mut expr: Handle<crate::Expression>,
247 ) -> Result<Handle<crate::Expression>, super::Error<'source>> {
248 let inner = super::resolve_inner!(self, expr);
249 if let Some(scalar) = inner.automatically_convertible_scalar(&self.module.types) {
250 let concretized = scalar.concretize();
251 if concretized != scalar {
252 assert!(scalar.is_abstract());
253 let expr_span = self.get_expression_span(expr);
254 expr = self
255 .as_const_evaluator()
256 .cast_array(expr, concretized, expr_span)
257 .map_err(|err| {
258 let expr_type = &self.typifier()[expr];
262 super::Error::ConcretizationFailed(Box::new(ConcretizationFailedError {
263 expr_span,
264 expr_type: expr_type.to_wgsl(&self.module.to_ctx()).into(),
265 scalar: concretized.to_wgsl().into(),
266 inner: err,
267 }))
268 })?;
269 }
270 }
271
272 Ok(expr)
273 }
274
275 pub fn automatic_conversion_consensus<'handle, I>(
293 &self,
294 components: I,
295 ) -> Result<crate::Scalar, usize>
296 where
297 I: IntoIterator<Item = &'handle Handle<crate::Expression>>,
298 I::IntoIter: Clone, {
300 let types = &self.module.types;
301 let mut inners = components
302 .into_iter()
303 .map(|&c| self.typifier()[c].inner_with(types));
304 log::debug!(
305 "wgsl automatic_conversion_consensus: {:?}",
306 inners
307 .clone()
308 .map(|inner| inner.to_wgsl(&self.module.to_ctx()))
309 .collect::<Vec<String>>()
310 );
311 let mut best = inners.next().unwrap().scalar().ok_or(0_usize)?;
312 for (inner, i) in inners.zip(1..) {
313 let scalar = inner.scalar().ok_or(i)?;
314 match best.automatic_conversion_combine(scalar) {
315 Some(new_best) => {
316 best = new_best;
317 }
318 None => return Err(i),
319 }
320 }
321
322 log::debug!(" consensus: {:?}", best.to_wgsl());
323 Ok(best)
324 }
325}
326
327impl crate::TypeInner {
328 fn automatically_converts_to(
342 &self,
343 goal: &Self,
344 types: &crate::UniqueArena<crate::Type>,
345 ) -> Option<(crate::Scalar, crate::Scalar)> {
346 use crate::ScalarKind as Sk;
347 use crate::TypeInner as Ti;
348
349 let expr_scalar;
355 let goal_scalar;
356 match (self, goal) {
357 (&Ti::Scalar(expr), &Ti::Scalar(goal)) => {
358 expr_scalar = expr;
359 goal_scalar = goal;
360 }
361 (
362 &Ti::Vector {
363 size: expr_size,
364 scalar: expr,
365 },
366 &Ti::Vector {
367 size: goal_size,
368 scalar: goal,
369 },
370 ) if expr_size == goal_size => {
371 expr_scalar = expr;
372 goal_scalar = goal;
373 }
374 (
375 &Ti::Matrix {
376 rows: expr_rows,
377 columns: expr_columns,
378 scalar: expr,
379 },
380 &Ti::Matrix {
381 rows: goal_rows,
382 columns: goal_columns,
383 scalar: goal,
384 },
385 ) if expr_rows == goal_rows && expr_columns == goal_columns => {
386 expr_scalar = expr;
387 goal_scalar = goal;
388 }
389 (
390 &Ti::Array {
391 base: expr_base,
392 size: expr_size,
393 stride: _,
394 },
395 &Ti::Array {
396 base: goal_base,
397 size: goal_size,
398 stride: _,
399 },
400 ) if expr_size == goal_size => {
401 return types[expr_base]
402 .inner
403 .automatically_converts_to(&types[goal_base].inner, types);
404 }
405 _ => return None,
406 }
407
408 match (expr_scalar.kind, goal_scalar.kind) {
409 (Sk::AbstractFloat, Sk::Float) => {}
410 (Sk::AbstractInt, Sk::Sint | Sk::Uint | Sk::AbstractFloat | Sk::Float) => {}
411 _ => return None,
412 }
413
414 log::trace!(" okay: expr {expr_scalar:?}, goal {goal_scalar:?}");
415 Some((expr_scalar, goal_scalar))
416 }
417
418 fn automatically_convertible_scalar(
419 &self,
420 types: &crate::UniqueArena<crate::Type>,
421 ) -> Option<crate::Scalar> {
422 use crate::TypeInner as Ti;
423 match *self {
424 Ti::Scalar(scalar) | Ti::Vector { scalar, .. } | Ti::Matrix { scalar, .. } => {
425 Some(scalar)
426 }
427 Ti::Array { base, .. } => types[base].inner.automatically_convertible_scalar(types),
428 Ti::Atomic(_)
429 | Ti::Pointer { .. }
430 | Ti::ValuePointer { .. }
431 | Ti::Struct { .. }
432 | Ti::Image { .. }
433 | Ti::Sampler { .. }
434 | Ti::AccelerationStructure
435 | Ti::RayQuery
436 | Ti::BindingArray { .. } => None,
437 }
438 }
439}
440
441impl crate::Scalar {
442 pub const fn automatic_conversion_combine(self, other: Self) -> Option<crate::Scalar> {
449 use crate::ScalarKind as Sk;
450
451 match (self.kind, other.kind) {
452 (Sk::AbstractFloat, Sk::AbstractFloat)
454 | (Sk::AbstractInt, Sk::AbstractInt)
455 | (Sk::Sint, Sk::Sint)
456 | (Sk::Uint, Sk::Uint)
457 | (Sk::Float, Sk::Float)
458 | (Sk::Bool, Sk::Bool) => {
459 if self.width == other.width {
460 Some(self)
462 } else {
463 None
467 }
468 }
469
470 (Sk::AbstractFloat, Sk::AbstractInt) => Some(self),
472 (Sk::AbstractInt, Sk::AbstractFloat) => Some(other),
473
474 (Sk::AbstractFloat, Sk::Float) => Some(other),
476 (Sk::Float, Sk::AbstractFloat) => Some(self),
477
478 (Sk::AbstractInt, Sk::Uint | Sk::Sint | Sk::Float) => Some(other),
480 (Sk::Uint | Sk::Sint | Sk::Float, Sk::AbstractInt) => Some(self),
481
482 (Sk::AbstractFloat, Sk::Uint | Sk::Sint) | (Sk::Uint | Sk::Sint, Sk::AbstractFloat) => {
484 None
485 }
486
487 (Sk::Bool, _) | (_, Sk::Bool) => None,
489
490 (Sk::Sint | Sk::Uint | Sk::Float, Sk::Sint | Sk::Uint | Sk::Float) => None,
492 }
493 }
494
495 pub fn automatically_converts_to(self, goal: Self) -> bool {
497 self.automatic_conversion_combine(goal) == Some(goal)
498 }
499
500 const fn concretize(self) -> Self {
501 use crate::ScalarKind as Sk;
502 match self.kind {
503 Sk::Sint | Sk::Uint | Sk::Float | Sk::Bool => self,
504 Sk::AbstractInt => Self::I32,
505 Sk::AbstractFloat => Self::F32,
506 }
507 }
508}