Remove dumbass type constraint crap.

This commit is contained in:
2024-12-29 23:39:57 +01:00
parent 90fb1a035e
commit f13508262b
7 changed files with 65 additions and 341 deletions

View File

@@ -465,6 +465,7 @@ array_access :: (parse_state : *Parse_State, left : *AST_Node) -> *AST_Node {
} }
source_location.end = parse_state.previous; source_location.end = parse_state.previous;
left.source_location = source_location;
return left; return left;
} }

View File

@@ -77,52 +77,10 @@ Type_Variable :: struct {
//@Note(niels): For constant buffers //@Note(niels): For constant buffers
resource_index : u32; resource_index : u32;
uf_parent : Type_Variable_Handle;
source_node : *AST_Node; source_node : *AST_Node;
} }
Type_Variable_Handle :: #type, distinct u32; Type_Variable_Handle :: #type, distinct u32;
Type_Constraint_Handle :: #type, distinct u32;
Type_Constraint_Kind :: enum {
Int_Literal; // [[I]] = int
Float_Literal; // [[F]] = float
Equivalence; // [[X]] = int/float
Equality; // E1 == E2: [[E1]] = [[E2]] && [[E1 == E2]] = bool
Function_Decl; // X(X1, ..., Xn) { return E; }: [[X]] = ([[X1]], ..., [[Xn]]) -> [[E]]
Function_Call; // E(E1, ..., En): [[E]] = ([[E1]], ..., [[En]]) -> [[E(E1, ..., En)]]
}
Type_Constraint :: struct {
kind : Type_Constraint_Kind;
union {
literal : struct {
type_variable : Type_Variable_Handle;
union {
i : int;
f : float;
}
}
equivalence : struct {
lhs : Type_Variable_Handle;
rhs : Type_Variable_Handle;
}
function : struct {
symbol_variable : Type_Variable_Handle;
return_variable : Type_Variable_Handle;
arguments : [16]Type_Variable_Handle;
argument_count : int;
}
}
usage_site : *AST_Node;
binary_operator : Token;
}
Scope_Stack :: struct { Scope_Stack :: struct {
allocator : Allocator; allocator : Allocator;
@@ -199,7 +157,6 @@ Semantic_Checker :: struct {
current_scope : Scope_Handle; current_scope : Scope_Handle;
// type_variables : [..]Type_Variable; // type_variables : [..]Type_Variable;
constraints : [..]Type_Constraint;
current_buffer_index : u32 = 0; current_buffer_index : u32 = 0;
current_sampler_index : u32 = 0; current_sampler_index : u32 = 0;
@@ -708,7 +665,6 @@ add_symbol_to_scope :: (checker : *Semantic_Checker, scope_handle : Scope_Handle
new_type_variable :: (checker : *Semantic_Checker) -> *Type_Variable, Type_Variable_Handle { new_type_variable :: (checker : *Semantic_Checker) -> *Type_Variable, Type_Variable_Handle {
variable : Type_Variable; variable : Type_Variable;
handle := cast(Type_Variable_Handle)checker.result.type_variables.count + 1; handle := cast(Type_Variable_Handle)checker.result.type_variables.count + 1;
variable.uf_parent = handle;
array_add(*checker.result.type_variables, variable); array_add(*checker.result.type_variables, variable);
return h2tv(checker, handle), handle; return h2tv(checker, handle), handle;
@@ -1103,7 +1059,7 @@ declare_function :: (checker : *Semantic_Checker, node : *AST_Node, builtin : bo
return handle; return handle;
} }
create_function_constraint :: (checker : *Semantic_Checker, node : *AST_Node) { create_function :: (checker : *Semantic_Checker, node : *AST_Node) {
name_to_check := get_actual_function_name(node); name_to_check := get_actual_function_name(node);
find_result := find_symbol(checker, name_to_check, checker.current_scope); find_result := find_symbol(checker, name_to_check, checker.current_scope);
@@ -1123,19 +1079,6 @@ create_function_constraint :: (checker : *Semantic_Checker, node : *AST_Node) {
previous_scope := use_scope(checker, variable.scope); previous_scope := use_scope(checker, variable.scope);
constraint : Type_Constraint;
constraint.kind = .Function_Decl;
constraint.function.symbol_variable = function.type_variable;
for i : 0..variable.children.count - 1 {
arg_var := variable.children[i];
if arg_var > 0 {
constraint.function.arguments[constraint.function.argument_count] = arg_var;
constraint.function.argument_count += 1;
}
}
for child : node.children { for child : node.children {
if child.kind == .Block { if child.kind == .Block {
for statement : child.children { for statement : child.children {
@@ -1143,7 +1086,6 @@ create_function_constraint :: (checker : *Semantic_Checker, node : *AST_Node) {
result_var := check_node(checker, statement); result_var := check_node(checker, statement);
if result_var > 0 { if result_var > 0 {
variable.return_type_variable = result_var; variable.return_type_variable = result_var;
constraint.function.return_variable = variable.return_type_variable;
} }
} else { } else {
result_var := check_node(checker, statement); result_var := check_node(checker, statement);
@@ -1160,44 +1102,10 @@ create_function_constraint :: (checker : *Semantic_Checker, node : *AST_Node) {
not_all_control_paths_return_value(checker, node); not_all_control_paths_return_value(checker, node);
} }
array_add(*checker.constraints, constraint);
use_scope(checker, previous_scope); use_scope(checker, previous_scope);
} }
} }
create_literal_constraint :: (checker : *Semantic_Checker, value : int, type_variable : Type_Variable_Handle) {
constraint : Type_Constraint;
constraint.kind = .Int_Literal;
constraint.literal.i = value;
constraint.literal.type_variable = type_variable;
array_add(*checker.constraints, constraint);
}
create_literal_constraint :: (checker : *Semantic_Checker, value : float, type_variable : Type_Variable_Handle) -> Type_Constraint_Handle {
constraint : Type_Constraint;
constraint.kind = .Float_Literal;
constraint.literal.f = value;
constraint.literal.type_variable = type_variable;
array_add(*checker.constraints, constraint);
return cast(Type_Constraint_Handle)checker.constraints.count;
}
create_equivalence_constraint :: (checker : *Semantic_Checker, lhs : Type_Variable_Handle, rhs : Type_Variable_Handle, usage_site : *AST_Node = null) -> Type_Constraint_Handle {
constraint : Type_Constraint;
constraint.kind = .Equivalence;
constraint.equivalence.lhs = lhs;
constraint.equivalence.rhs = rhs;
constraint.usage_site = usage_site;
array_add(*checker.constraints, constraint);
return cast(Type_Constraint_Handle)checker.constraints.count;
}
create_variable :: (checker : *Semantic_Checker, node : *AST_Node, struct_field_parent : *AST_Node = null) -> Type_Variable_Handle { create_variable :: (checker : *Semantic_Checker, node : *AST_Node, struct_field_parent : *AST_Node = null) -> Type_Variable_Handle {
find_result := find_symbol(checker, node.name, checker.current_scope); find_result := find_symbol(checker, node.name, checker.current_scope);
// x : int; // x : int;
@@ -1317,18 +1225,30 @@ create_field :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable
for child : node.children { for child : node.children {
rhs = check_node(checker, child); rhs = check_node(checker, child);
} }
create_equivalence_constraint(checker, handle, rhs, node);
if handle == 0 || rhs == 0 {
return handle;
}
l := h2tv(checker, handle);
r := h2tv(checker, rhs);
assert(l.type != .Unresolved_Expression && r.type != .Unresolved_Expression);
if !types_compatible(checker, handle, rhs) {
type_mismatch(checker, l.source_node, r.source_node, rhs, handle);
return 0;
}
} }
return handle; return handle;
} }
create_call_constraint :: (checker : *Semantic_Checker, node : *AST_Node, type_var : Type_Variable_Handle) { check_call :: (checker : *Semantic_Checker, node : *AST_Node, type_var : Type_Variable_Handle) -> error : bool {
find_result := find_symbol(checker, node.name, checker.current_scope); find_result := find_symbol(checker, node.name, checker.current_scope);
if !find_result { if !find_result {
function_undeclared(checker, node); function_undeclared(checker, node);
return; return true;
} }
overload_found := false; overload_found := false;
@@ -1359,7 +1279,7 @@ create_call_constraint :: (checker : *Semantic_Checker, node : *AST_Node, type_v
} }
if arg_vars.count != arg_count { if arg_vars.count != arg_count {
return; return true;
} }
Type_Mismatch_Data :: struct { Type_Mismatch_Data :: struct {
@@ -1383,6 +1303,9 @@ create_call_constraint :: (checker : *Semantic_Checker, node : *AST_Node, type_v
if node.children.count == 0 && function.children.count == 0 { if node.children.count == 0 && function.children.count == 0 {
overload_found = true; overload_found = true;
}
if overload_found && function.return_type_variable == 0 {
break; break;
} }
@@ -1424,13 +1347,17 @@ create_call_constraint :: (checker : *Semantic_Checker, node : *AST_Node, type_v
for mismatch : mismatches { for mismatch : mismatches {
type_mismatch(checker, mismatch.lhs.node, mismatch.rhs.node, mismatch.rhs.var, mismatch.lhs.var); type_mismatch(checker, mismatch.lhs.node, mismatch.rhs.node, mismatch.rhs.var, mismatch.lhs.var);
} }
return true;
} }
return false;
} }
check_node :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_Handle { check_node :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_Handle {
if node.kind == { if node.kind == {
case .Function; { case .Function; {
create_function_constraint(checker, node); create_function(checker, node);
return 0; return 0;
} }
case. Field; { case. Field; {
@@ -1466,19 +1393,17 @@ check_node :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_H
case .TOKEN_MINUS; #through; case .TOKEN_MINUS; #through;
case .TOKEN_STAR; #through; case .TOKEN_STAR; #through;
case .TOKEN_SLASH; { case .TOKEN_SLASH; {
create_equivalence_constraint(checker, rhs_var, lhs_var, node); if !types_compatible(checker, lhs_var, rhs_var, true) {
type_mismatch(checker, node, node.children[1], lhs_var, rhs_var);
proper_variable, rhs_handle := new_type_variable(checker); return 0;
lhs_type_var := h2tv(checker, lhs_var); }
proper_variable.type = lhs_type_var.type;
proper_variable.typename = lhs_type_var.typename;
proper_variable.source_node = h2tv(checker, lhs_var).source_node;
proper_variable.struct_field_parent = h2tv(checker, lhs_var).struct_field_parent;
create_equivalence_constraint(checker, handle, rhs_handle, node);
} }
case .TOKEN_ASSIGN; { case .TOKEN_ASSIGN; {
create_equivalence_constraint(checker, lhs_var, rhs_var, node);
if !types_compatible(checker, lhs_var, rhs_var, true) {
type_mismatch(checker, node.parent, node.children[1], lhs_var, rhs_var);
return 0;
}
} }
} }
return handle; return handle;
@@ -1494,7 +1419,6 @@ check_node :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_H
type_variable.type = .Int; type_variable.type = .Int;
type_variable.source_node = node; type_variable.source_node = node;
node.type_variable = handle; node.type_variable = handle;
type_constraint := create_literal_constraint(checker, node.integer_value, handle);
return handle; return handle;
} }
@@ -1503,7 +1427,6 @@ check_node :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_H
type_variable.type = .Float; type_variable.type = .Float;
type_variable.source_node = node; type_variable.source_node = node;
node.type_variable = handle; node.type_variable = handle;
type_constraint := create_literal_constraint(checker, node.float_value, handle);
return handle; return handle;
} }
@@ -1516,7 +1439,9 @@ check_node :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_H
type_variable.source_node = node; type_variable.source_node = node;
node.type_variable = handle; node.type_variable = handle;
create_call_constraint(checker, node, handle); if check_call(checker, node, handle) {
return 0;
}
return handle; return handle;
} }
@@ -1555,16 +1480,16 @@ traverse :: (checker : *Semantic_Checker) {
traverse(checker, checker.program_root); traverse(checker, checker.program_root);
} }
find :: (checker : *Semantic_Checker, root_handle : Type_Variable_Handle) -> Type_Variable_Handle { // find :: (checker : *Semantic_Checker, root_handle : Type_Variable_Handle) -> Type_Variable_Handle {
assert(root_handle > 0); // assert(root_handle > 0);
root := h2tv(checker, root_handle); // root := h2tv(checker, root_handle);
if root.uf_parent != root_handle { // // if root.uf_parent != root_handle {
root.uf_parent = find(checker, root.uf_parent); // // root.uf_parent = find(checker, root.uf_parent);
} // // }
return root.uf_parent; // return root.uf_parent;
} // }
Unification_Result :: enum { Unification_Result :: enum {
Unification_Success; Unification_Success;
@@ -1653,78 +1578,6 @@ types_compatible :: (checker : *Semantic_Checker, lhs : Type_Variable_Handle, rh
return false; return false;
} }
union_terms :: (checker : *Semantic_Checker, lhs_handle : Type_Variable_Handle, rhs_handle : Type_Variable_Handle, usage_site : *AST_Node) {
if !types_compatible(checker, lhs_handle, rhs_handle) {
lhs_var := h2tv(checker, lhs_handle);
rhs_var := h2tv(checker, rhs_handle);
if usage_site {
type_mismatch(checker, usage_site, rhs_var.source_node.parent, rhs_handle, lhs_handle);
} else {
type_mismatch(checker, lhs_var.source_node.parent, rhs_var.source_node.parent, rhs_handle, lhs_handle);
}
} else if lhs_handle != rhs_handle {
lhs := h2tv(checker, lhs_handle);
lhs.uf_parent = rhs_handle;
}
}
unify :: (checker : *Semantic_Checker, lhs_handle : Type_Variable_Handle, rhs_handle : Type_Variable_Handle, usage_site : *AST_Node = null) -> Unification_Result {
rep_lhs := find(checker, lhs_handle);
rep_rhs := find(checker, rhs_handle);
if rep_lhs != rep_rhs {
lhs := h2tv(checker, rep_lhs);
rhs := h2tv(checker, rep_rhs);
if !is_proper(lhs) && !is_proper(rhs) {
union_terms(checker, rep_lhs, rep_rhs, usage_site);
} else if !is_proper(lhs) && is_proper(rhs) {
union_terms(checker, rep_lhs, rep_rhs, usage_site);
} else if is_proper(lhs) && !is_proper(rhs) {
union_terms(checker, rep_rhs, rep_lhs, usage_site);
} else if is_proper(lhs) && is_proper(rhs) {
union_terms(checker, rep_lhs, rep_rhs, usage_site);
//@Incomplete(niels): Evaluate sub-terms for functions.
} else {
return .Unification_Failure;
}
}
return .Unification_Success;
}
union_find :: (checker : *Semantic_Checker) -> bool {
for constraint : checker.constraints {
if constraint.kind == {
case .Int_Literal; {
}
case .Float_Literal; {
}
case .Equivalence; {
if !constraint.equivalence.lhs || !constraint.equivalence.rhs {
return false;
}
handle_lhs := find(checker, constraint.equivalence.lhs);
handle_rhs := find(checker, constraint.equivalence.rhs);
unification_result := unify(checker, handle_lhs, handle_rhs, constraint.usage_site);
if unification_result == .Unification_Failure {
return false;
}
}
case .Function_Decl; {
}
}
}
return true;
}
// HLSL_BUILTIN :: #run -> string { // HLSL_BUILTIN :: #run -> string {
// T := #load "hlsl_builtin.jai"; // T := #load "hlsl_builtin.jai";
@@ -1796,24 +1649,6 @@ add_hlsl_builtins :: (checker : *Semantic_Checker) {
type_check :: (checker : *Semantic_Checker, root : *AST_Node) { type_check :: (checker : *Semantic_Checker, root : *AST_Node) {
traverse(checker, root); traverse(checker, root);
// if checker.result.had_error {
// //@Incomplete(niels): handle error...
// return checker.result;
// }
uf_result := union_find(checker);
if !uf_result {
//@Incomplete(niels): handle error...
// return result;
}
for *type_variable : checker.result.type_variables {
if type_variable.type == .Unresolved_Variable {
rep := h2tv(checker, type_variable.uf_parent);
type_variable.type = rep.type;
}
}
} }
check :: (checker : *Semantic_Checker, root : *AST_Node) -> Semantic_Check_Result { check :: (checker : *Semantic_Checker, root : *AST_Node) -> Semantic_Check_Result {
@@ -1821,7 +1656,6 @@ check :: (checker : *Semantic_Checker, root : *AST_Node) -> Semantic_Check_Resul
checker.current_sampler_index = 0; checker.current_sampler_index = 0;
checker.current_texture_index = 0; checker.current_texture_index = 0;
array_reserve(*checker.result.messages, 16); array_reserve(*checker.result.messages, 16);
array_reserve(*checker.constraints, 1024);
add_hlsl_builtins(checker); add_hlsl_builtins(checker);
type_check(checker, root); type_check(checker, root);
@@ -2019,64 +1853,6 @@ pretty_print_scope :: (checker : *Semantic_Checker, scope : *Scope, builder : *S
append(builder, "]\n"); append(builder, "]\n");
} }
pretty_print_constraint :: (checker : *Semantic_Checker, constraint : Type_Constraint, builder : *String_Builder) {
if constraint.kind == {
case .Int_Literal; {
print_to_builder(builder, "[[%]] = int\n", constraint.literal.i);
}
case .Float_Literal; {
print_to_builder(builder, "[[%]] = float\n", constraint.literal.f);
}
case .Equivalence; {
lhs_var := h2tv(checker, constraint.equivalence.lhs);
rhs_var := h2tv(checker, constraint.equivalence.rhs);
append(builder, "[[");
print_type_variable(builder, lhs_var, checker);
append(builder, "]] = ");
if rhs_var.source_node {
append(builder, "[[");
}
print_type_variable(builder, rhs_var, checker);
if rhs_var.source_node {
append(builder, "]]");
}
append(builder, "\n");
}
case .Function_Decl; {
sym := h2tv(checker, constraint.function.symbol_variable);
print_to_builder(builder, "[[%]] =", sym.name);
append(builder, " (");
if constraint.function.argument_count > 0 {
for i : 0..constraint.function.argument_count - 1 {
arg := h2tv(checker, constraint.function.arguments[i]);
print_to_builder(builder, "[[%]]", arg.name);
if i < constraint.function.argument_count - 1 {
append(builder, ", ");
}
}
}
append(builder, ")");
if constraint.function.return_variable > 0 {
return_var := h2tv(checker, constraint.function.return_variable);
append(builder, " -> ");
append(builder, "[[");
print_type_variable(builder, return_var, checker);
append(builder, "]]", );
append(builder, "\n");
} else {
append(builder, " -> unit\n");
}
}
}
}
print_type_variable :: (builder : *String_Builder, variable : Type_Variable, checker : *Semantic_Checker) { print_type_variable :: (builder : *String_Builder, variable : Type_Variable, checker : *Semantic_Checker) {
if variable.builtin { if variable.builtin {
if variable.type != .Function || variable.type != .Struct { if variable.type != .Function || variable.type != .Struct {
@@ -2173,68 +1949,6 @@ pretty_print_symbol_table :: (checker : *Semantic_Checker, allocator : Allocator
return builder_to_string(*builder,, allocator); return builder_to_string(*builder,, allocator);
} }
pretty_print_type_variable :: (checker : *Semantic_Checker, type_variable : *Type_Variable, builder : *String_Builder) {
rep := type_variable.uf_parent;
if type_variable.name.count > 0 {
append(builder, "[[");
print_type_variable(builder, type_variable, checker);
append(builder, "]] = ");
rep_var := h2tv(checker, rep);
if is_proper(type_variable) {
print_to_builder(builder, proper_type_to_string(checker, type_variable, temp));
} else if type_variable.type == .Struct || type_variable.type == .Properties ||
type_variable.type == .CBuffer {
if type_variable.kind == .Declaration {
append(builder, "{");
for 0..type_variable.children.count - 1 {
child_handle := type_variable.children[it];
child := h2tv(checker, child_handle);
print_to_builder(builder, child.name);
append(builder, " : ");
print_to_builder(builder, type_to_string(child));
if it < type_variable.children.count - 1 {
append(builder, ", ");
}
}
append(builder, "}");
} else if type_variable.typename.count > 0 {
print_to_builder(builder, "%", type_variable.typename);
}
} else {
print_from_source_location(builder, rep_var.source_node.source_location);
}
append(builder, "\n");
}
}
pretty_print_type_variables :: (checker : *Semantic_Checker, allocator : Allocator) -> string {
builder : String_Builder;
init_string_builder(*builder,, allocator);
for *type_variable : checker.result.type_variables {
if type_variable.builtin continue;
pretty_print_type_variable(checker, type_variable, *builder);
}
return builder_to_string(*builder,, allocator);
}
pretty_print_type_constraints :: (checker : *Semantic_Checker, allocator : Allocator) -> string {
builder : String_Builder;
init_string_builder(*builder,, allocator);
for *constraint : checker.constraints {
pretty_print_constraint(checker, constraint, *builder);
}
return builder_to_string(*builder,, allocator);
}
#scope_module #scope_module
#import "ncore"; #import "ncore";

View File

@@ -308,10 +308,6 @@ run_semantic_analysis_test :: (file_path : string, root : *AST_Node, output_type
result_text = report_messages(checker.result.messages); result_text = report_messages(checker.result.messages);
} else { } else {
result_text = pretty_print_symbol_table(*checker, temp); result_text = pretty_print_symbol_table(*checker, temp);
constraints := pretty_print_type_constraints(*checker, temp);
type_vars := pretty_print_type_variables(*checker, temp);
// print("Constraints\n%\n", constraints);
// print("Solution\n%\n", type_vars);
} }
if output_type & .StdOut { if output_type & .StdOut {

3
check.bat Normal file
View File

@@ -0,0 +1,3 @@
@echo off
jai first.jai -natvis - check

View File

@@ -16,6 +16,16 @@ build :: () {
options.write_added_strings = true; options.write_added_strings = true;
args := options.compile_time_command_line;
for arg : args {
if arg == {
case "check"; {
options.output_type = .NO_OUTPUT;
}
}
}
new_path: [..] string; new_path: [..] string;
array_add(*new_path, ..options.import_path); array_add(*new_path, ..options.import_path);
array_add(*new_path, "modules"); array_add(*new_path, "modules");

View File

@@ -6,6 +6,6 @@
float float
got: got:
res : float2 = float2(2.0, 2.0); res : float2 = float2(2.0, 2.0)
 

View File

@@ -2,5 +2,5 @@ vertex main :: (pos : float4 @position) -> float4 @position {
res : float2 = float2(2.0, 2.0); res : float2 = float2(2.0, 2.0);
foo : float = 1.0; foo : float = 1.0;
result : float4 = float4(1.0, foo * res, 0.0, 1.0); result : float4 = float4(1.0, foo * res, 0.0, 1.0);
return result; return float4(1,1,1,1);
} }