diff --git a/distr/flecs.c b/distr/flecs.c index 2d52d92b8..47a680f7c 100644 --- a/distr/flecs.c +++ b/distr/flecs.c @@ -71407,6 +71407,7 @@ bool flecs_query_idsright( } } +next: do { cur = op_ctx->cur = op_ctx->cur->first.next; } while (cur && !cur->cache.tables.count); /* Skip empty ids */ @@ -71415,6 +71416,12 @@ bool flecs_query_idsright( return false; } + if (cur->id == ecs_pair(EcsChildOf, 0)) { + /* Skip the special (ChildOf, 0) entry for root entities, as 0 is + * not a valid target and could be matched by (ChildOf, *) */ + goto next; + } + flecs_query_set_vars(op, cur->id, ctx); if (op->field_index != -1) { diff --git a/src/query/engine/eval.c b/src/query/engine/eval.c index b104d3c26..63500bfc6 100644 --- a/src/query/engine/eval.c +++ b/src/query/engine/eval.c @@ -627,6 +627,7 @@ bool flecs_query_idsright( } } +next: do { cur = op_ctx->cur = op_ctx->cur->first.next; } while (cur && !cur->cache.tables.count); /* Skip empty ids */ @@ -635,6 +636,12 @@ bool flecs_query_idsright( return false; } + if (cur->id == ecs_pair(EcsChildOf, 0)) { + /* Skip the special (ChildOf, 0) entry for root entities, as 0 is + * not a valid target and could be matched by (ChildOf, *) */ + goto next; + } + flecs_query_set_vars(op, cur->id, ctx); if (op->field_index != -1) { diff --git a/test/query/project.json b/test/query/project.json index 5ad705e19..e22242339 100644 --- a/test/query/project.json +++ b/test/query/project.json @@ -559,6 +559,8 @@ "2_any_src", "2_any_src_w_pair", "1_any_src_w_pair_tgt_var", + "1_any_src_w_pair_tgt_var_2", + "1_any_src_w_pair_tgt_var_childof", "1_any_src_w_pair_rel_var", "1_any_src_w_pair_tgt_this", "1_any_src_w_pair_rel_this", diff --git a/test/query/src/Basic.c b/test/query/src/Basic.c index 270c59dd5..f66be4f76 100644 --- a/test/query/src/Basic.c +++ b/test/query/src/Basic.c @@ -3702,6 +3702,107 @@ void Basic_1_any_src_w_pair_tgt_var(void) { ecs_fini(world); } +void Basic_1_any_src_w_pair_tgt_var_2(void) { + ecs_world_t *world = ecs_mini(); + + ECS_TAG(world, Rel); + ECS_TAG(world, Foo); + + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + + ecs_entity_t tgt_a = ecs_new(world); + ecs_entity_t tgt_b = ecs_new(world); + + ecs_add_pair(world, e1, Rel, tgt_a); + ecs_add_pair(world, e2, Rel, tgt_b); + ecs_add_pair(world, e3, Rel, tgt_b); + ecs_add(world, e3, Foo); + + ecs_query_t *q = ecs_query(world, { + .expr = "Rel(_, $x)", + .cache_kind = cache_kind + }); + + test_assert(q != NULL); + + int x_var = ecs_query_find_var(q, "x"); + test_assert(x_var != -1); + + ecs_iter_t it = ecs_query_iter(world, q); + test_bool(true, ecs_query_next(&it)); + test_int(0, it.count); + test_uint(ecs_pair(Rel, tgt_b), ecs_field_id(&it, 0)); + test_uint(tgt_b, ecs_iter_get_var(&it, x_var)); + + test_bool(true, ecs_query_next(&it)); + test_int(0, it.count); + test_uint(ecs_pair(Rel, tgt_a), ecs_field_id(&it, 0)); + test_uint(tgt_a, ecs_iter_get_var(&it, x_var)); + + test_bool(false, ecs_query_next(&it)); + + ecs_query_fini(q); + + ecs_fini(world); +} + +void Basic_1_any_src_w_pair_tgt_var_childof(void) { + ecs_world_t *world = ecs_mini(); + + ECS_TAG(world, Rel); + ECS_TAG(world, Foo); + + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + + ecs_entity_t tgt_a = ecs_new(world); + ecs_entity_t tgt_b = ecs_new(world); + + ecs_add_pair(world, e1, Rel, tgt_a); + ecs_add_pair(world, e2, Rel, tgt_b); + ecs_add_pair(world, e3, Rel, tgt_b); + ecs_add(world, e3, Foo); + + ecs_query_t *q = ecs_query(world, { + .expr = "ChildOf(_, $x)", + .cache_kind = cache_kind + }); + + test_assert(q != NULL); + + int x_var = ecs_query_find_var(q, "x"); + test_assert(x_var != -1); + + ecs_iter_t it = ecs_query_iter(world, q); + test_bool(true, ecs_query_next(&it)); + test_int(0, it.count); + test_uint(ecs_pair(EcsChildOf, EcsFlecs), ecs_field_id(&it, 0)); + test_uint(EcsFlecs, ecs_iter_get_var(&it, x_var)); + test_uint(EcsWildcard, ecs_field_src(&it, 0)); + + test_bool(true, ecs_query_next(&it)); + ecs_entity_t internals = ecs_lookup(world, "flecs.core.internals"); + test_int(0, it.count); + test_uint(ecs_pair(EcsChildOf, internals), ecs_field_id(&it, 0)); + test_uint(internals, ecs_iter_get_var(&it, x_var)); + test_uint(EcsWildcard, ecs_field_src(&it, 0)); + + test_bool(true, ecs_query_next(&it)); + test_int(0, it.count); + test_uint(ecs_pair(EcsChildOf, EcsFlecsCore), ecs_field_id(&it, 0)); + test_uint(EcsFlecsCore, ecs_iter_get_var(&it, x_var)); + test_uint(EcsWildcard, ecs_field_src(&it, 0)); + + test_bool(false, ecs_query_next(&it)); + + ecs_query_fini(q); + + ecs_fini(world); +} + void Basic_1_any_src_w_pair_rel_var(void) { ecs_world_t *world = ecs_mini(); diff --git a/test/query/src/Variables.c b/test/query/src/Variables.c index 4fbe05f0b..3b899fea0 100644 --- a/test/query/src/Variables.c +++ b/test/query/src/Variables.c @@ -11560,4 +11560,3 @@ void Variables_second_invalid_var_name_and_id(void) { ecs_fini(world); } - diff --git a/test/query/src/main.c b/test/query/src/main.c index ab8b8a69c..f5cb9544d 100644 --- a/test/query/src/main.c +++ b/test/query/src/main.c @@ -542,6 +542,8 @@ void Basic_1_any_src_w_pair(void); void Basic_2_any_src(void); void Basic_2_any_src_w_pair(void); void Basic_1_any_src_w_pair_tgt_var(void); +void Basic_1_any_src_w_pair_tgt_var_2(void); +void Basic_1_any_src_w_pair_tgt_var_childof(void); void Basic_1_any_src_w_pair_rel_var(void); void Basic_1_any_src_w_pair_tgt_this(void); void Basic_1_any_src_w_pair_rel_this(void); @@ -4260,6 +4262,14 @@ bake_test_case Basic_testcases[] = { "1_any_src_w_pair_tgt_var", Basic_1_any_src_w_pair_tgt_var }, + { + "1_any_src_w_pair_tgt_var_2", + Basic_1_any_src_w_pair_tgt_var_2 + }, + { + "1_any_src_w_pair_tgt_var_childof", + Basic_1_any_src_w_pair_tgt_var_childof + }, { "1_any_src_w_pair_rel_var", Basic_1_any_src_w_pair_rel_var @@ -10626,7 +10636,7 @@ static bake_test_suite suites[] = { "Basic", Basic_setup, NULL, - 234, + 236, Basic_testcases, 1, Basic_params