Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/daScript/ast/compilation_errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ namespace das
, exceeds_new_argument = 30509 // 1 site(s)
, exceeds_structure = 30510 // 1 site(s)
, exceeds_tuple_index = 30511 // 1 site(s)
, exceeds_type = 30512 // 2 site(s)
, exceeds_type = 30512 // 3 site(s)
, exceeds_type_alias = 30513 // 1 site(s)
, exceeds_typeinfo_sizeof = 30514 // 1 site(s)
, exceeds_constant_range = 30515 // 1 site(s)
Expand Down
7 changes: 7 additions & 0 deletions include/daScript/simulate/REVIEW.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ C++ half never opens the daslib checklist on its own.
- **A diff that changes `KeyHash` (`runtime_table.h`) or `WrapsBuiltinValue` (`cast.h`) states
in its own PR description which key types change hash value.**

- **A `cvt_*` inline in `aot.h` takes and returns `vec4f`, and none of them is overloaded.**
`vec4f` is the SIMD register; the `vec2`/`vec3`/`vec4` types are structs of scalars, so a
concrete return spills the lanes through `v_extract_*` and the next conversion reloads them.
Overloading is what forced that once: every flavor converts from `vec4f`, so an overload set
fed a `vec4f` result is ambiguous - the emitter writes `cvt_pass(cvt_uint3(..))` for
`x |> uint3 |> int3`. One name per conversion, `vec4f` throughout, keeps both.

- **A diff that makes the hot path cost more per evaluated expression in the build the repo
ships is a defect.** The hot path is a `SimNode::eval*` method, any helper such a method
calls on every evaluation, the dispatchers `Context::callOrFastcall` /
Expand Down
7 changes: 1 addition & 6 deletions include/daScript/simulate/aot.h
Original file line number Diff line number Diff line change
Expand Up @@ -4517,12 +4517,7 @@ namespace das {
__forceinline vec4f cvt_uint3 ( float3 f ) { return v_cast_vec4f(v_cvt_vec4i(f)); }
__forceinline vec4f cvt_uint4 ( float4 f ) { return v_cast_vec4f(v_cvt_vec4i(f)); }

__forceinline vec4f cvt_pass ( int2 i ) { return i; }
__forceinline vec4f cvt_pass ( int3 i ) { return i; }
__forceinline vec4f cvt_pass ( int4 i ) { return i; }
__forceinline vec4f cvt_pass ( uint2 i ) { return i; }
__forceinline vec4f cvt_pass ( uint3 i ) { return i; }
__forceinline vec4f cvt_pass ( uint4 i ) { return i; }
__forceinline vec4f cvt_pass ( vec4f i ) { return i; }

__forceinline int32_t class_rtti_size ( void * ptr ) {
auto pti = (TypeInfo **)ptr;
Expand Down
10 changes: 9 additions & 1 deletion src/ast/ast_infer_type_function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,15 @@ namespace das {
}
padded.push_back(newArg);
}
for (int ai = p; ai != k; ++ai) {
const auto & argType = winner->arguments[ai]->type;
if (!argType->isAutoOrAlias()) continue;
AliasMap aliases;
OptionsMap options;
if (!isMatchingArgument(winner, argType, padded[ai - p]->type, useGenerics, true, &aliases, &options)) {
return false;
}
}
for (int ai = k - 1; ai >= p; --ai) {
expr->arguments.insert(expr->arguments.begin() + p, padded[ai - p]);
types.insert(types.begin() + p, padded[ai - p]->type);
Expand Down Expand Up @@ -1908,7 +1917,6 @@ namespace das {
if (!anyFailed)
break;
if (totalAliases == aliases.size()) {
DAS_ASSERTF(0, "we should not be here. function matched arguments!");
break;
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/ast/ast_lint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1109,6 +1109,10 @@ namespace das {
program->error("[init] is disabled in the options or CodeOfPolicies", "", "",
fn->at, CompilationError::cant_function);
}
if ( !fn->result->isAutoOrAlias() && fn->result->getSizeOf64()>0x7fffffff ) {
program->error("function result of '" + fn->name + "' is too big", "", "",
fn->at, CompilationError::exceeds_type);
}
}
virtual FunctionPtr visit ( Function * fn ) override {
// Derived class ctor: every CFG path must call super(...) exactly once,
Expand Down
2 changes: 2 additions & 0 deletions src/ast/ast_typedecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3476,6 +3476,8 @@ namespace das
uint64_t TypeDecl::getCountOf64() const {
uint64_t size = 1;
for ( const TypeDecl * t = this; t && t->baseType==Type::tFixedArray; t = t->firstType ) {
// dimAuto (-1) and dimConst (-2) are valid unresolved dims, not counts; uint64_t wraps them
if ( t->fixedDim<=0 ) return 0;
size *= uint64_t(t->fixedDim);
}
return size;
Expand Down
13 changes: 13 additions & 0 deletions tests/language/failed_generic_default_type_mismatch.das
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// A piped call pads a default in for the parameter it shifts across, and lookup admits the
// candidate on that default's existence alone. When the parameter type is concrete the
// candidate is still instanced, so the argument-matching loop gives up without progress and
// the instanced function names the real mistake - which is why that exit falls through.
options gen2
expect 30161, 30341

def generic_with_mismatched_default(r : string <- 1, v) => 0

[export]
def main {
generic_with_mismatched_default(){}
}
12 changes: 12 additions & 0 deletions tests/language/failed_generic_unknown_arg_type.das
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// A generic whose first argument is an unresolved type expression with a default value. The
// call matches at lookup; the alias map then stops growing with that argument still
// unmatched, and the instancing after the loop used to read types the loop never produced.
options gen2
expect 30341

def generic_with_unknown_arg_type(r : l() <- 1, v) => 0

[export]
def call_generic_with_unknown_arg_type {
generic_with_unknown_arg_type(){}
}
9 changes: 9 additions & 0 deletions tests/language/failed_pointer_math_unsized_pointee.das
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Pointer arithmetic whose pointee carries a dimension the parser already rejected. The
// dimension is negative, so the element count wrapped and the size read as 2^64-48.
options gen2
expect 30109, 30239

[export]
def pointer_math_on_unsized_pointee {
var x = new class<block[]>() - 0
}
13 changes: 13 additions & 0 deletions tests/language/failed_result_type_by_ref_too_big.das
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// The oversized result on its own, with no other error to stop compilation first: this one
// reaches Program::simulate, where the debug-info walk sizes the result and asserts.
options gen2
expect 30512

[export]
def result_too_big_by_ref(p : int[2000000000]?) : int[2000000000]& {
unsafe { return *p }
}

[export]
def main {
}
13 changes: 13 additions & 0 deletions tests/language/failed_result_type_too_big.das
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// An oversized function result. The size gate covered locals, arguments, structures and
// aliases but not the result, so the type reached the debug-info walk and asserted there.
options gen2
expect 30512

// the reported shape - the make-value on the path is diagnosed as well. the crash itself is
// in failed_result_type_by_ref_too_big.das, where no earlier error stops the walk
[export]
def result_too_big => <- tuple<int[2000000000]>(uninitialized)

[export]
def main {
}
21 changes: 21 additions & 0 deletions tests/language/vec_constructors.das
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ require dastest/testing_boost public
// and type conversions between vector types.
// VEC_SEP is a built-in constant (default ",") used in vector printing.

// globals, so the constant folder leaves the conversion chains below to codegen
var g_f2 = float2(1, 2)
var g_f3 = float3(1, 2, 3)
var g_f4 = float4(1, 2, 3, 4)
var g_i3 = int3(1, 2, 3)

def test_vec2(tt : T?; a : auto(vec2) -const -&; isRange = false) {
let f2_0 = vec2()
let f2_x = vec2(1.0, 2.0)
Expand Down Expand Up @@ -117,4 +123,19 @@ def test_vec_constructors(t : T?) {
t |> equal(uint3(float3(1, 2, 3)), uint3(1u, 2u, 3u))
t |> equal(uint4(float4(1, 2, 3, 4)), uint4(1u, 2u, 3u, 4u))
}
t |> run("chained type conversions") @(t : T?) {
// AOT writes these as cvt_pass(cvt_uint3(..)), which resolves only while each cvt_
// answers in its vector type - a vec4f argument matches every cvt_pass overload
t |> equal(g_f2 |> uint2 |> int2, int2(1, 2))
t |> equal(g_f3 |> uint3 |> int3, int3(1, 2, 3))
t |> equal(g_f4 |> uint4 |> int4, int4(1, 2, 3, 4))
t |> equal(g_f2 |> int2 |> uint2, uint2(1u, 2u))
t |> equal(g_f3 |> int3 |> uint3, uint3(1u, 2u, 3u))
t |> equal(g_f4 |> int4 |> uint4, uint4(1u, 2u, 3u, 4u))
t |> equal(g_i3 |> float3 |> int3, int3(1, 2, 3))
t |> equal(g_i3 |> uint3 |> float3, float3(1, 2, 3))
// three links: cvt_pass(cvt_pass(cvt_uint3(..))), so a cvt_pass feeds a cvt_pass
t |> equal(g_f3 |> uint3 |> int3 |> uint3, uint3(1u, 2u, 3u))
t |> equal(g_f2 |> int2 |> uint2 |> int2, int2(1, 2))
}
}
Loading