@@ -293,7 +293,7 @@ void ungrounded_parameter_checker::report_unused_parameter(const report::span& s
293
293
bool flag_self_ungrounded = false ;
294
294
295
295
// start checking
296
- for (const auto & i : func->ordered_parameter_list ) {
296
+ for (const auto & i : func->ordered_parameter_list ) {
297
297
// if variable is not a parameter or already used, do not report
298
298
if (!record.count (i) || record.at (i)) {
299
299
continue ;
@@ -315,25 +315,27 @@ void ungrounded_parameter_checker::report_unused_parameter(const report::span& s
315
315
if (is_native_type (type) && !record_is_set_flag.at (i)) {
316
316
ungrounded_params += ungrounded_params.length ()? " , " :" " ;
317
317
ungrounded_params += i;
318
- } else if (i!= " self" ) {
318
+ } else if (i != " self" ) {
319
319
unused_params += unused_params.length ()? " , " :" " ;
320
320
unused_params += i;
321
321
} else {
322
+ // unused self, mark it as ungrounded
323
+ // so self constraint will be generated to protect this parameter
322
324
flag_self_ungrounded = true ;
323
325
}
324
326
}
325
327
326
328
// unused warning report
327
329
if (unused_params.length ()) {
328
330
err->warn (stmt_loc,
329
- " unused parameter \" " + unused_params + " \" in this branch."
331
+ " \" " + unused_params + " \" is unused in this branch."
330
332
);
331
333
}
332
334
333
335
// ungrounded error report
334
336
if (ungrounded_params.length ()) {
335
337
err->err (stmt_loc,
336
- " ungrounded parameter \" " + ungrounded_params + " \" in this branch."
338
+ " \" " + ungrounded_params + " \" is ungrounded in this branch."
337
339
);
338
340
}
339
341
@@ -381,6 +383,11 @@ bool ungrounded_parameter_checker::check_directly_call_identifier(expr* node) {
381
383
!= ast_class::ac_identifier) {
382
384
return false ;
383
385
}
386
+ // schema instance getting primary key equals to directly using this instance
387
+ // e.g. `a.id` in fact equals to `a` itself, so we see this as direct call id
388
+ if (is_schema_get_primary_key (real)) {
389
+ return true ;
390
+ }
384
391
if (!real->get_call_chain ().empty ()) {
385
392
return false ;
386
393
}
@@ -646,11 +653,13 @@ bool ungrounded_parameter_checker::visit_call_head(call_head* node) {
646
653
}
647
654
648
655
bool ungrounded_parameter_checker::is_schema_get_primary_key (call_root* node) {
649
- if (node->get_call_head ()->get_first_expression ()->get_ast_class ()!=ast_class::ac_identifier) {
656
+ auto head = node->get_call_head ();
657
+ // should call a variable
658
+ if (head->get_first_expression ()->get_ast_class () != ast_class::ac_identifier) {
650
659
return false ;
651
660
}
652
661
653
- const auto & head_type = node-> get_call_head () ->get_resolve ();
662
+ const auto & head_type = head ->get_resolve ();
654
663
// head type should not be global symbol or data-set type
655
664
if (head_type.is_global || head_type.type .is_set ) {
656
665
return false ;
@@ -663,16 +672,19 @@ bool ungrounded_parameter_checker::is_schema_get_primary_key(call_root* node) {
663
672
if (node->get_call_chain ().size ()<1 ) {
664
673
return false ;
665
674
}
675
+
676
+ // get type full path name
666
677
const auto name = head_type.type .full_path_name_without_set ();
667
678
const auto index = ctx->global .get_index (name);
668
- if (index == global_symbol_table::npos) {
679
+ if (index == global_symbol_table::npos) {
669
680
return false ;
670
681
}
671
- if (ctx->global .get_kind (index )!= symbol_kind::schema) {
682
+ if (ctx->global .get_kind (index ) != symbol_kind::schema) {
672
683
return false ;
673
684
}
685
+
674
686
const auto & sc = ctx->global .get_schema (index );
675
- if (node->get_call_chain ()[0 ]->get_call_type ()!= call_expr::type::get_field ||
687
+ if (node->get_call_chain ()[0 ]->get_call_type () != call_expr::type::get_field ||
676
688
node->get_call_chain ()[0 ]->has_func_call ()) {
677
689
return false ;
678
690
}
@@ -682,7 +694,20 @@ bool ungrounded_parameter_checker::is_schema_get_primary_key(call_root* node) {
682
694
}
683
695
684
696
bool ungrounded_parameter_checker::visit_call_root (call_root* node) {
697
+ // we see schema get primary key as call schema itself
698
+ // because in generated souffle:
699
+ // schema.primary_key = schema
700
+ // if schema is not grounded, the primary key is not grounded too
701
+ // but we add type constraint for each schema, so mark this as grounded
702
+ // except this call is:
703
+ // self.primary_key
704
+ // self is not always constraint, if marked as grounded
705
+ // self will be ungrounded in generated souffle
685
706
if (is_schema_get_primary_key (node)) {
707
+ auto first = node->get_call_head ()->get_first_expression ();
708
+ if (reinterpret_cast <identifier*>(first)->get_name () != " self" ) {
709
+ node->get_call_head ()->accept (this );
710
+ }
686
711
return true ;
687
712
}
688
713
for (auto i : node->get_call_chain ()) {
0 commit comments