# Conversions and promotions

C3 differs in some crucial respects when it comes to number conversions and promotions. These are the rules for C3:

- float to int conversions require a cast
- int to float conversions do not require a cast
- bool to float converts to 0.0 / 1.0
- widening float conversions do
*not*require a cast - narrowing conversions require a cast(*)
- widening conversions do
*not*require a cast - signed <-> unsigned conversions do not require a cast.
- In conditionals float to bool
*do not*require a cast, any non zero float value considered true - Implicit conversion to bool only occurs in conditionals or when the value is enclosed in
`()`

e.g.`bool x = (1.0)`

or`if (1.0) { ... }`

C3 uses two's complement arithmetic for all integer math.

## Target type

The left hand side of an assignment, or the parameter type in a call is known as the *target type* the target type is used for implicit widening and inferring struct initialization.

## Implicit promotion

Like C, C3 uses implicit promotion of integer and floating point variables:

- For any floating point type with a bit width smaller than 32 bits, widen to
`float`

. E.g.`half -> float`

- After 1, for any floating point type with a bit width smaller than the
*target type*widen to the target type. - For an integer type smaller than the
*minimum arithmetic width*, promote the value to a signed integer of the*minimum arithmetic width*(this usually corresponds to a c int). E.g.`ushort -> int`

- After 3, for an integer type smaller than the
*target type*, promote the value to an integer of the the same bit width. E.g.`ulong = int + int -> ulong = long + long`

## Maximum type

The *maximum type* is a concept used when unifying two or more types. The algorithm follows:

- First perform implicit promotion.
- If both types are the same, the maximum type is this type.
- If one type is a floating point type, and the other is an integer type, the maximum type is the floating point type. E.g.
`int + float -> float`

. - If both types are floating point types, the maximum type is the widest floating point type. E.g.
`float + double -> double`

. - If both types are integer types with the same signedness, the maximum type is the widest integer type of the two. E.g.
`uint + ulong -> ulong`

. - If both types are integer types with different signedness, the maximum type is a signed integer with the same bit width as the maximum integer type.
`ulong + int -> long`

- If at least one side is a struct or a pointer to a struct with an
`inline`

directive on a member, check recursively check if the type of the inline member can be used to find a maximum type (see below under sub struct conversions) - All other cases are errors.

## Substruct conversions

Substructs may be used in place of its parent structs in many cases. The rule is as follows:

- A substruct pointer may implicitly convert to a parent struct.
- A substruct
*value*may be implicitly assigned to a variable with the parent struct type, This will*truncate*the value, copying only the parent part of the substruct. However, a substruct value cannot be assigned its parent struct. - Substruct subarrays, vararrays and arrays
*can not*be cast (implicitly or explicitly) to an array of the parent struct type.

## Pointer conversions

Pointer conversion between types usually need explicit casts. The exception is `void *`

which any type may implicitly convert *to* or *from*. Conversion rules from and to arrays are detailed under arrays

## Implicit narrowing

Implicit narrowing is only allowed for floating point values and integer types. The following must hold:

- To narrow to a floating point type, all sub expressions must be integers or a floating point as narrow or more narrow than the target type.
- To narrow to an integer type, all sub expressions must be integers and as narrow or narrower than the target type, ignoring signedness.

```
half h = 12.0;
float f = 13.0;
double d = 22.0;
char x = 1;
short y = -3;
int z = 0xFFFFF;
ulong w = -0xFFFFFFF;
x = x + x; // => calculated as x = (char)((int)(x) + (int)(x));
x = y + x; // => error
w = x + y; // => calculated as w = (ulong)((long)(x) + (long)(x));
h = x * h; // => calculated as h = (half)((float)(x) * (float)(h));
h = f + x; // => error
d = f * h; // => calculated as d = (double)(f) * (double)(h);
```

## Binary conversions

### 1. Multiplication, division, remainder, subtraction / addition with both operands being numbers

These operations are only valid for integer and float types.

- Resolve the operands, left to right, pushing down the target type.
- Find the maximum type of the two operands.
- Promote both operands to the resulting type.
- The resulting type of the expression is the resulting type.

### 2. Addition with left side being a pointer

- Resolve the left hand operand pushing down the target type.
- Resolve the right hand operand pushing down iptrdiff as the target type.
- If the rhs is not an integer, this is an error.
- If the rhs has a bit width that exceeds iptrdiff, this is an error.
- The result of the expression is the lhs type.

### 3. Subtraction with lhs pointer and rhs integer

- Resolve the left hand operand pushing down the target type.
- Resolve the right hand operand pushing down iptrdiff as the target type.
- If the right hand type has a bit width that exceeds iptrdiff, this is an error.
- The result of the expression is the left hand type.

### 4. Subtraction with both sides pointers

- Resolve the operands, left to right.
- If the either side is a
`void *`

, it is cast to the other type. - If the types of the sides are different, this is an error.
- The result of the expression is iptrdiff.
- If this result exceeds the target width, this is an error.

### 6. Bit operations `^`

`&`

`|`

These operations are only valid for integers and booleans.

- Resolve the operands, left to right, pushing down the target type.
- Find the maximum type of the two operands.
- Promote both operands to the resulting type.
- The result of the expression is the resulting type.

### 6. Shift operations `<<`

`>>`

These operations are only valid for integers.

- Resolve the left operand pushing down the target type.
- Resolve the right operand
*without pushing down*a target type. - In safe mode, insert a trap to ensure that rhs >= 0 and rhs < bit width of the left hand side.
- The result of the expression is the lhs type.

### 7. Assignment operations `+=`

`-=`

`*=`

`*=`

`/=`

`%=`

`^=`

`|=`

`&=`

- Resolve the type of the left operand.
- Resolve the right operand pushing down the lhs type as target type
- The result of the expression is the lhs type.

### 8. Assignment shift `>>=`

`<<=`

- Resolve both operands
- In safe mode, insert a trap to ensure that rhs >= 0 and rhs < bit width of the left hand side.
- The result of the expression is the lhs type.

### 9. `&&`

and `||`

- Resolve both operands.
- Insert bool cast of both operands.
- The type is bool.

### 10. `<=`

`==`

`>=`

`!=`

- Resolve the operands, left to right.
- Find the maximum type of the two operands.
- Promote both operands to the resulting type.
- The type is bool.

## Unary conversions

### 1. Bit negate

- Resolve the inner operand, pushing down the target type.
- If the inner type is not an integer this is an error.
- The type is the inner type.

### 2. Boolean not

- Resolve the inner operand.
- The type is bool.

### 3. Negation

- Resolve the inner operand, pushing down the target type.
- If the type inner type is not a number this is an error.
- If the inner type is an unsigned integer, cast it to the same signed type.
- The type is the type of the result from (3)

### 4. `&`

and `&&`

- Resolve the inner operand.
- The type is a pointer to the type of the inner operand.

### 5. `*`

- Resolve the inner operand.
- If the operand is not a pointer, or is a
`void *`

pointer, this is an error. - The type is the pointee of the inner operand's type.

Dereferencing 0 is implementation defined.

### 6. `++`

and `--`

- Resolve the inner operand.
- If the type is not a number, this is an error.
- The type is the same as the inner operand.

## Base expressions

### 1. Typed identifiers

- The type is that of the declaration.
- If the width of the type is less than that of the target type, widen to the target type.
- If the width of the type is greater than that of the target type, it is an error.

### 2. Constants and literals

- If it is untyped, the type is that of the smallest type that the constant can fit in.
- If the width of the type is less than that of the target type, widen to the target type.
- If the width of the type is greater than that of the target type, it is an error.

## Ternary and return type conversions

In some cases an expression may have more than one branch and those branches have different types. A simple example is the ternary expressions. To resolve this, C3 does *return type conversion*. In essence this involves trying to implicitly cast each of the branches to the expected *return type*.

C3 resolves the type in this manner:

- Is there an expected return type? Proceed error checking with the expected return type as the
*target type* - Is there no expected return type? Find the maximum type of all results and promote all results to the value.

```
int a = foo();
short b = bar();
// This is using return type conversion:
long c = baz() ? a : b;
// The above will compile to:
long c = baz() ? (long)(a) : (long)(c);
char d = foobar();
// This is using maximum type because the ternary
// is inside of an addition.
baz() ? a : b;
// The above will compile to:
baz() ? a : (int)(b);
```