From a685eb2e9e9d36e03c9ba415d1c1a40cf245dc1e Mon Sep 17 00:00:00 2001
From: Botond Baranyi <botond.baranyi@ericsson.com>
Date: Wed, 18 Nov 2020 17:04:14 +0100
Subject: [PATCH] When checking whether a reference can be generated as a
 single expression, the subreferences are taken into account, too (bug 563718)

Signed-off-by: Botond Baranyi <botond.baranyi@ericsson.com>
Change-Id: I383875aa8802d050a9cd4bd3cd75a88e7c2342a4
---
 compiler2/Type.cc            |  4 ++--
 compiler2/ttcn3/AST_ttcn3.cc | 26 ++++++++++++++++++++++++--
 compiler2/ttcn3/AST_ttcn3.hh |  8 ++++++--
 regression_test/oop/oop.ttcn | 12 ++++++++++--
 4 files changed, 42 insertions(+), 8 deletions(-)

diff --git a/compiler2/Type.cc b/compiler2/Type.cc
index be2d4838c..ca1ccb5d6 100644
--- a/compiler2/Type.cc
+++ b/compiler2/Type.cc
@@ -1817,7 +1817,7 @@ namespace Common {
               }
               ap_list->set_fullname(parsed_pars->get_fullname());
               ap_list->set_my_scope(parsed_pars->get_my_scope());
-              ref->set_actual_par_list(ap_list);
+              ref->set_parameter_list(ap_list, NULL);
             }
             t = get_pooltype(T_USTR);
             // todo: set *last_method
@@ -1876,7 +1876,7 @@ namespace Common {
               }
               ap_list->set_fullname(parsed_pars->get_fullname());
               ap_list->set_my_scope(parsed_pars->get_my_scope());
-              ref->set_actual_par_list(ap_list);
+              ref->set_parameter_list(ap_list, fp_list);
             }
             if (last_method != NULL) {
               *last_method = ass;
diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc
index 1e8c2fdcf..0291a21a0 100644
--- a/compiler2/ttcn3/AST_ttcn3.cc
+++ b/compiler2/ttcn3/AST_ttcn3.cc
@@ -236,14 +236,23 @@ namespace Ttcn {
     return u.ff.ap_list;
   }
   
-  void FieldOrArrayRef::set_actual_par_list(ActualParList* p_ap_list)
+  FormalParList* FieldOrArrayRef::get_formal_par_list() const
+  {
+    if (ref_type != FUNCTION_REF || !u.ff.checked) {
+      FATAL_ERROR("FieldOrArrayRef::get_formal_par_list()");
+    }
+    return u.ff.fp_list;
+  }
+  
+  void FieldOrArrayRef::set_parameter_list(ActualParList* p_ap_list, FormalParList* p_fp_list)
   {
     if (ref_type != FUNCTION_REF || u.ff.checked) {
-      FATAL_ERROR("FieldOrArrayRef::set_actual_par_list()");
+      FATAL_ERROR("FieldOrArrayRef::set_parameter_list()");
     }
     u.ff.checked = true;
     delete u.ff.parsed_pars;
     u.ff.ap_list = p_ap_list;
+    u.ff.fp_list = p_fp_list;
   }
 
   void FieldOrArrayRef::append_stringRepr(string& str) const
@@ -1080,6 +1089,19 @@ namespace Ttcn {
         }
       }
     }
+    for (size_t i = 0; i < subrefs.get_nof_refs(); ++i) {
+      FieldOrArrayRef* subref = subrefs.get_ref(i);
+      if (subref->get_type() == FieldOrArrayRef::FUNCTION_REF) {
+        ActualParList* ap_list = subref->get_actual_par_list();
+        FormalParList* fp_list = subref->get_formal_par_list();
+        for (size_t j = 0; j < ap_list->get_nof_pars(); ++j) {
+          if (!ap_list->get_par(j)->has_single_expr(
+              fp_list != NULL ? fp_list->get_fp_byIndex(i) : NULL)) {
+            return false;
+          }
+        }
+      }
+    }
     return true;
   }
   
diff --git a/compiler2/ttcn3/AST_ttcn3.hh b/compiler2/ttcn3/AST_ttcn3.hh
index 1ba3bdd15..2730f9048 100644
--- a/compiler2/ttcn3/AST_ttcn3.hh
+++ b/compiler2/ttcn3/AST_ttcn3.hh
@@ -205,7 +205,10 @@ namespace Ttcn {
         bool checked;
         union {
           ParsedActualParameters* parsed_pars; ///< parsed function parameters, used by FUNCTION_REF
-          ActualParList* ap_list; ///< actual parameter list (after semantic analysis), used by FUNCTION_REF
+          struct {
+            ActualParList* ap_list; ///< actual parameter list (after semantic analysis), used by FUNCTION_REF
+            FormalParList* fp_list; ///< formal parameter list (after semantic analysis, not owned), used by FUNCTION_REF
+          };
         };
       } ff; ///< field or function
       Value *arp; ///< value of the index, used by ARRAY_REF
@@ -230,8 +233,9 @@ namespace Ttcn {
     Value* get_val() const;
     ParsedActualParameters* get_parsed_pars() const;
     ActualParList* get_actual_par_list() const;
+    FormalParList* get_formal_par_list() const;
     bool parameters_checked() const;
-    void set_actual_par_list(ActualParList* p_ap_list);
+    void set_parameter_list(ActualParList* p_ap_list, FormalParList* p_fp_list);
     /** Appends the string representation of the sub-reference to \a str. */
     void append_stringRepr(string& str) const;
     /** Sets the first letter in the name of the field to lowercase if it's an
diff --git a/regression_test/oop/oop.ttcn b/regression_test/oop/oop.ttcn
index c6a9290d7..3a731723c 100644
--- a/regression_test/oop/oop.ttcn
+++ b/regression_test/oop/oop.ttcn
@@ -470,6 +470,12 @@ function f_test_in(Node p1, Node2 p2) {
   p2.f(p1.get_next());
 }
 
+type class InParTester {
+  public function test(object x) return boolean {
+    return x of Node;
+  }
+}
+
 testcase tc_function_pars_in() runs on CT {
   var Node n1 := Node.create(1, Node.create(2, null));
   var Node2 n2 := Node2.create(null, null);
@@ -477,9 +483,11 @@ testcase tc_function_pars_in() runs on CT {
   if (log2str(n2.get_data()) != log2str(n1.get_next())) {
     setverdict(fail, "Expected: ", n1.get_next(), ", got: ", n2.get_data());
   }
-  else {
-    setverdict(pass);
+  var InParTester t := InParTester.create;
+  if (not t.test(n1.get_next())) {
+    setverdict(fail, "InParTester failed");
   }
+  setverdict(pass);
 }
 
 type class Something {
-- 
GitLab