Implicit casts - Practical/practical-sa GitHub Wiki

Implicit Numerical Casts Rules

There four basic rules governing implicit casts by Practical. They are designed to fix the crazyness that is type promotion in C and C++, without disrupting what people can do too much.

No Implicit Value Narrowing

Practical will only implicitly cast variable var of type A to type B if type B can contain all of the possible values that var may contain.

Under normal circumstances, this means that the following implicit conversions are possible:

  • Ua to Ub: iff a<=b.
  • Sa to Sb: iff a<=b.
  • Ua to Sb: iff a<b (a=b is not enough. This is unlike C and C++, whom allow this conversion).
  • Sa to Ub is never allowed, as Ub cannot represent negative values regardless of number of bits.

Value Range Propagation (VRP)

The compiler shall keep track of the possible values each expression may receive. In case of a need for implicit conversion, that conversion may go through despite the table above if the actual value range fits in the destination type, regardless of the source type.

Type Promotion on Operations

Operations Between Same Types are Not Promoted

Under C, any integer operation that is narrower than int is promoted to int. Under Practical, this is not the case. U8+U8=U8.

Binary Operations Between Different Types

Both operands are implicitly casted to the smallest type that is capable of containing both values. For example, assuming no VRP, S8+S16=S16, S8+U16=S32 and S8+U64=Error. In case of an operator that does not return the same type it gets (such as the comparison operators, that return Bool), the types are promoted, the operation performed, and the result is of the right type.

If both a signed and an unsigned type of the same size fits the above description, the unsigned type is preferred.

Expected Type Back Propagation

Whenever an expression is known to need to produce a result of type A, that knowledge is back-propagated to the subexpressions of that expression. The compiler attempts to convert to the desired type at the earliest possible location.

Mandatory Expected Type

This happens where, should the compiler return the wrong value, it will need to be implicitly casted. If mandatory expected type is propagated, it is a compilation error if the sub-expression cannot be implicitly casted to the expected type.

def var : U8 = 1024;

The above is a compilation error (as 1024 cannot be casted to a U8), but the error is located on the literal 1024, and not on the assignment of the definition.

Optional Expected Type

This happens where it is possible that, should a sub-expression return the wrong type, it is still possible that further processing up the parse tree will be able to handle this. This is the case, for example, for the operand of a static cast.

When propagating optional expected type, the compiler attempts to cast each sub-expression to the desired type. If that cast is not possible, however, then the wider type is returned and compilation continues.