Allow for implicit int conversion to larger type

This commit is contained in:
nub31
2025-09-08 22:09:25 +02:00
parent f332856dd7
commit 9c9578f526
4 changed files with 86 additions and 39 deletions

View File

@@ -1,37 +1,13 @@
// c // c
extern func puts(text: cstring) extern func puts(text: cstring)
interface Printable
{
func print()
func test()
}
struct Human : Printable
{
name: cstring
age: u32
func print()
{
puts(this.name)
}
func test()
{
puts("test")
}
}
func main(args: []cstring): i64 func main(args: []cstring): i64
{ {
let x = struct Human { let x: i32 = 23
name = "Oliver" test(x)
age = 23
}
x.print()
x.test()
return 0 return 0
} }
func test(test: u8)
{
}

View File

@@ -600,6 +600,8 @@ public class QBEGenerator
FuncCallNode funcCall => EmitFuncCall(funcCall), FuncCallNode funcCall => EmitFuncCall(funcCall),
InterfaceFuncCallNode interfaceFuncCall => EmitInterfaceFuncCall(interfaceFuncCall), InterfaceFuncCallNode interfaceFuncCall => EmitInterfaceFuncCall(interfaceFuncCall),
InterfaceInitializerNode interfaceInitializer => EmitInterfaceInitializer(interfaceInitializer), InterfaceInitializerNode interfaceInitializer => EmitInterfaceInitializer(interfaceInitializer),
ConvertIntNode convertInt => EmitConvertInt(convertInt),
ConvertFloatNode convertFloat => EmitConvertFloat(convertFloat),
ExternFuncIdentNode externFuncIdent => EmitExternFuncIdent(externFuncIdent), ExternFuncIdentNode externFuncIdent => EmitExternFuncIdent(externFuncIdent),
LocalFuncIdentNode localFuncIdent => EmitLocalFuncIdent(localFuncIdent), LocalFuncIdentNode localFuncIdent => EmitLocalFuncIdent(localFuncIdent),
VariableIdentNode variableIdent => EmitVariableIdent(variableIdent), VariableIdentNode variableIdent => EmitVariableIdent(variableIdent),
@@ -1118,6 +1120,59 @@ public class QBEGenerator
return destination; return destination;
} }
private string EmitConvertInt(ConvertIntNode convertInt)
{
var value = EmitExpression(convertInt.Value);
if (convertInt.ValueType == convertInt.TargetType || convertInt.ValueType.Width > convertInt.TargetType.Width)
{
return value;
}
var method = convertInt.ValueType.Signed switch
{
true => convertInt.ValueType.Width switch
{
8 => "extsb",
16 => "extsh",
32 => "extsw",
_ => throw new ArgumentOutOfRangeException()
},
false => convertInt.ValueType.Width switch
{
8 => "extub",
16 => "extuh",
32 => "extuw",
_ => throw new ArgumentOutOfRangeException()
}
};
var result = TmpName();
_writer.Indented($"{result} {QBEAssign(convertInt.TargetType)} {method} {value}");
return result;
}
private string EmitConvertFloat(ConvertFloatNode convertFloat)
{
var value = EmitExpression(convertFloat.Value);
if (convertFloat.ValueType == convertFloat.TargetType)
{
return value;
}
var method = convertFloat.ValueType.Width switch
{
32 => "exts",
64 => "truncd",
_ => throw new ArgumentOutOfRangeException()
};
var result = TmpName();
_writer.Indented($"{result} {QBEAssign(convertFloat.TargetType)} {method} {value}");
return result;
}
private string EmitFuncCall(FuncCallNode funcCall) private string EmitFuncCall(FuncCallNode funcCall)
{ {
var funcPointer = EmitExpression(funcCall.Expression); var funcPointer = EmitExpression(funcCall.Expression);

View File

@@ -60,3 +60,7 @@ public record StructInitializerNode(StructTypeNode StructType, Dictionary<string
public record DereferenceNode(TypeNode Type, ExpressionNode Expression) : RValueExpressionNode(Type); public record DereferenceNode(TypeNode Type, ExpressionNode Expression) : RValueExpressionNode(Type);
public record InterfaceInitializerNode(TypeNode Type, InterfaceTypeNode InterfaceType, StructTypeNode StructType, ExpressionNode Implementation) : LValueExpressionNode(Type); public record InterfaceInitializerNode(TypeNode Type, InterfaceTypeNode InterfaceType, StructTypeNode StructType, ExpressionNode Implementation) : LValueExpressionNode(Type);
public record ConvertIntNode(TypeNode Type, ExpressionNode Value, IntTypeNode TargetType, IntTypeNode ValueType) : RValueExpressionNode(Type);
public record ConvertFloatNode(TypeNode Type, ExpressionNode Value, FloatTypeNode TargetType, FloatTypeNode ValueType) : RValueExpressionNode(Type);

View File

@@ -296,13 +296,25 @@ public sealed class TypeChecker
private ExpressionNode CheckConversion(TypeNode targetType, ExpressionNode expression) private ExpressionNode CheckConversion(TypeNode targetType, ExpressionNode expression)
{ {
// todo(nub): Add conversions for primitive types such as i32 -> i64 etc. if (expression.Type is StructTypeNode structType && targetType is InterfaceTypeNode interfaceType)
switch (expression.Type)
{ {
case StructTypeNode structType when targetType is InterfaceTypeNode interfaceType: return new InterfaceInitializerNode(interfaceType, interfaceType, structType, expression);
{ }
return new InterfaceInitializerNode(interfaceType, interfaceType, structType, expression);
} if (expression.Type is IntTypeNode sourceIntType && targetType is IntTypeNode targetIntType)
{
// if ((sourceIntType.Width < targetIntType.Width) || (sourceIntType.Width == targetIntType.Width && sourceIntType.Signed != targetIntType.Signed))
// {
return new ConvertIntNode(targetIntType, expression, targetIntType, sourceIntType);
// }
}
if (expression.Type is FloatTypeNode sourceFloatType && targetType is FloatTypeNode targetFloatType)
{
// if (sourceFloatType.Width < targetFloatType.Width)
// {
return new ConvertFloatNode(targetFloatType, expression, targetFloatType, sourceFloatType);
// }
} }
throw new TypeCheckerException(Diagnostic.Error($"Cannot convert {expression.Type} to {targetType}").Build()); throw new TypeCheckerException(Diagnostic.Error($"Cannot convert {expression.Type} to {targetType}").Build());