Unhandled edge cases for cast/assignment to vector type
Cast/assignment to vector has some unhandled edge cases:
float[<4>] a;
a = true; // Permitted, but shouldn't be
a = "1234"; // I get this casts char[4] to float[<4>], but can this specific case be prevented for the String type?
// Casting from pointer
a = (void*)1; // No proper error emitted
a = null; // No proper error emitted
a = &foo; // Casting from function pointer, no proper error emitted
Yeah, looks bad.
Should be fixed now.
Thanks. I think the implicit scalar broadcast cast should be explicit instead. This should better signify intent to actually do a broadcast, and prevent accidentally assigning or passing a scalar where a vector is expected.
That would break things like
int[<3>] x = foo();
int[<3>] y = x * 3 + 1;
// int[<3>] y = x * (int[<3>])3 + (int[<3>])1;
It should break this, scaling is the only operator that makes sense mathematically ("ah yes, let me add 1 to a vector"). I'd rather it be x + (int[<3>])1.
I think this is fine in GLSL though?
True, but it's important to note that for GLSL the implicit cast is only legal for operators, meaning you can't assign or pass a scalar to a vector (see https://registry.khronos.org/OpenGL/specs/gl/GLSLangSpec.4.60.pdf Section 5.9). If that were also the case in C3 I'd have no problem with the implicit broadcasting.
If we think about how casts work:
- First we have the normal casts, for example between binary sub expression.
- Then we have the assign expression, here there is some inference and more leeway.
- Finally we have the most generous casts, which is during initialization.
So this is problematic in reversing how "generous" the rules are in the particular case of scalar -> vector conversion. This special case will also likely affect how one would write macros.
For example we would have 1 not being assignable (so $assignable(1, int[<2>]) would fail) to int[<2>] but it would be possible to multiply the scalar with the expression? So that is my concern.
For what it's worth, HLSL always does the scalar conversion: https://microsoft.github.io/hlsl-specs/specs/hlsl.pdf
I'm still on the fence about this, except for one thing that bothers me the most. I found a solution that works for me though: I added a specific check to my fork which prevents implicit casting function arguments from scalar to vector types. The reason being that type awareness of parameters on the caller side is typically very low. So at least I have a way to enforce this in my codebase.
If you just want it explicit for parameters, then that's something I could consider. I think the conversions in expressions is important, but conversion passing it as arguments.. that's a different thing.
The original issue looks fixed.
As for the changes to implicit scalar->vector casting, I feel pretty good about them. They strike a good middle ground between convenience and explicitness.