From e6c2fb0287355c74d38789b8ebc51bbc5927fd22 Mon Sep 17 00:00:00 2001
From: Botond Baranyi <botond.baranyi@ericsson.com>
Date: Tue, 12 May 2020 16:57:06 +0200
Subject: [PATCH] Implemented object-oriented features - stage 6.1 (bug 552011)

Change-Id: Ief2350ee8c8a5d979e8c1efc7e564d691a91fba7
Signed-off-by: Botond Baranyi <botond.baranyi@ericsson.com>
---
 compiler2/Setting.cc                          |  58 +++++++
 compiler2/Setting.hh                          |  17 +-
 compiler2/Type.cc                             | 145 +++++++++++-------
 compiler2/Type_codegen.cc                     |   1 +
 compiler2/Value.cc                            |   7 +
 compiler2/ttcn3/AST_ttcn3.cc                  |  49 +++---
 compiler2/ttcn3/Ttcnstuff.cc                  | 129 +++++++++++++---
 compiler2/ttcn3/Ttcnstuff.hh                  |   7 +-
 compiler2/ttcn3/compiler.l                    |  12 ++
 compiler2/ttcn3/compiler.y                    |  12 +-
 core/OOP.hh                                   |  24 +--
 .../Semantic_Analyser/oop/oop_SE.ttcn         |  90 +++++++++--
 regression_test/oop/oop.ttcn                  |  89 +++++++++++
 13 files changed, 517 insertions(+), 123 deletions(-)

diff --git a/compiler2/Setting.cc b/compiler2/Setting.cc
index 3e57713fe..4ecad25e2 100644
--- a/compiler2/Setting.cc
+++ b/compiler2/Setting.cc
@@ -39,6 +39,7 @@
 #include "ttcn3/profiler.h"
 #include "ttcn3/Attributes.hh"
 #include "ttcn3/Ttcnstuff.hh"
+#include "ttcn3/Statement.hh"
 
 namespace Common {
 
@@ -676,6 +677,9 @@ namespace Common {
     case Type::T_ALTSTEP:
       typetype_name = "altstep";
       break;
+    case Type::T_CLASS:
+      typetype_name = "class";
+      break;
     default:
       FATAL_ERROR("Scope::chk_runs_on_clause()");
       typetype_name = 0;
@@ -727,6 +731,33 @@ namespace Common {
     }
   }
   
+  void Scope::chk_mtc_clause(Type* p_type, const Location& p_loc)
+  {
+    // component type of the referred definition
+    Type* refd_comptype = p_type->get_class_type_body()->get_MtcType();
+    // definitions without 'mtc' can be called from anywhere
+    if (refd_comptype == NULL) {
+      return;
+    }
+    if (get_statementblock_scope()->get_my_def() == NULL) { // in control part
+      p_loc.error("Cannot create value of class type `%s', which has an `mtc' "
+        "clause, in the control part.", p_type->get_typename().c_str());
+      return;
+    }
+    Type* t_comptype = get_mtc_system_comptype(false);
+    if (t_comptype != NULL) {
+      if (!refd_comptype->is_compatible_component_by_port(t_comptype)) {
+        // the 'mtc' clause of the referred definition is not compatible
+        // with that of the current scope (i.e. the referring definition)
+        p_loc.error("Mtc clause mismatch: A definition that runs on component "
+          "type `%s' cannot create a value of class type `%s', which has `mtc' "
+          "component type `%s'",
+          t_comptype->get_typename().c_str(), p_type->get_typename().c_str(),
+          refd_comptype->get_typename().c_str());
+      }
+    }
+  }
+  
   void Scope::chk_system_clause(Assignment *p_ass, const Location& p_loc,
     const char *p_what, bool in_control_part)
   {
@@ -751,6 +782,33 @@ namespace Common {
       }
     }
   }
+  
+  void Scope::chk_system_clause(Type* p_type, const Location& p_loc)
+  {
+    // component type of the referred definition
+    Type* refd_comptype = p_type->get_class_type_body()->get_SystemType();
+    // definitions without 'system' can be called from anywhere
+    if (refd_comptype == NULL) {
+      return;
+    }
+    if (get_statementblock_scope()->get_my_def() == NULL) { // in control part
+      p_loc.error("Cannot create value of class type `%s', which has a `system' "
+        "clause, in the control part.", p_type->get_typename().c_str());
+      return;
+    }
+    Type* t_comptype = get_mtc_system_comptype(true);
+    if (t_comptype != NULL) {
+      if (!refd_comptype->is_compatible_component_by_port(t_comptype)) {
+        // the 'system' clause of the referred definition is not compatible
+        // with that of the current scope (i.e. the referring definition)
+        p_loc.error("System clause mismatch: A definition that runs on component "
+          "type `%s' cannot create a value of class type `%s', which has `system' "
+          "component type `%s'",
+          t_comptype->get_typename().c_str(), p_type->get_typename().c_str(),
+          refd_comptype->get_typename().c_str());
+      }
+    }
+  }
 
   // =================================
   // ===== Reference
diff --git a/compiler2/Setting.hh b/compiler2/Setting.hh
index 0f5ab426d..ca3103316 100644
--- a/compiler2/Setting.hh
+++ b/compiler2/Setting.hh
@@ -634,10 +634,11 @@ public:
      * "activate". */
     void chk_runs_on_clause(Assignment *p_ass, const Location& p_loc,
       const char *p_what);
-    /** Checks the 'runs on' clause of type \a p_fat that the values of it can
-     * be called from this scope unit. Type \a p_fat shall be of type function
-     * or altstep. Parameters \a p_loc and \a p_what are used in error messages.
-     * \a p_what contains "call" or "activate". */
+    /** Checks the 'runs on' clause of type \a p_fat that values of it can
+     * be called/created from this scope unit.
+     * Type \a p_fat shall be of function, altstep or class type.
+     * Parameters \a p_loc and \a p_what are used in error messages.
+     * \a p_what contains "call", "activate" or "create". */
     void chk_runs_on_clause(Type *p_fat, const Location& p_loc,
       const char *p_what);
     /** Checks the 'mtc' clause of definition \a p_ass that it can
@@ -646,12 +647,20 @@ public:
      * "activate". */
     void chk_mtc_clause(Assignment *p_ass, const Location& p_loc,
       const char *p_what, bool in_control_part);
+    /** Checks the 'mtc' clause of type \a p_type that values of it can
+     * be created from this scope unit. Type \a p_type shall be of class type.
+     * Parameters \a p_loc is used in error messages. */
+    void chk_mtc_clause(Type* p_type, const Location& p_loc);
     /** Checks the 'system' clause of definition \a p_ass that it can
      * be called from this scope unit. Parameters \a p_loc and \a
      * p_what are used in error messages. \a p_what contains "call" or
      * "activate". */
     void chk_system_clause(Assignment *p_ass, const Location& p_loc,
       const char *p_what, bool in_control_part);
+    /** Checks the 'system' clause of type \a p_type that values of it can
+     * be created from this scope unit. Type \a p_type shall be of class type.
+     * Parameters \a p_loc is used in error messages. */
+    void chk_system_clause(Type* p_type, const Location& p_loc);
   };
 
   /**
diff --git a/compiler2/Type.cc b/compiler2/Type.cc
index 928aea26a..ffeee7778 100644
--- a/compiler2/Type.cc
+++ b/compiler2/Type.cc
@@ -53,6 +53,7 @@
 #include "ttcn3/Templatestuff.hh"
 #include "ttcn3/RawAST.hh"
 #include "ttcn3/JsonAST.hh"
+#include "ttcn3/Statement.hh"
 
 #include "../common/static_check.h"
 #include "PredefFunc.hh"
@@ -227,6 +228,7 @@ namespace Common {
     case T_VERDICT:
     case T_COMPONENT:
     case T_DEFAULT:
+    case T_CLASS: // for the built-in class 'object'
       break; // we have a pool type
     default:
       return 0; // no pool type for you!
@@ -867,6 +869,9 @@ namespace Common {
     case T_ADDRESS:
       u.address = 0;
       break;
+    case T_CLASS:
+      u.class_ = new Ttcn::ClassTypeBody();
+      break;
     default:
       FATAL_ERROR("Type::Type()");
     } // switch
@@ -1776,66 +1781,91 @@ namespace Common {
           return 0;
         }
         Ttcn::ClassTypeBody* class_ = t->get_class_type_body();
+        bool base_toString = false;
         if (!class_->has_local_ass_withId(id)) {
-          ref->error("Reference to non-existent method `%s' in class type `%s'",
-            id.get_dispname().c_str(), t->get_typename().c_str());
-          return 0;
-        }
-        Assignment* ass = class_->get_local_ass_byId(id);
-        if (!class_->chk_visibility(ass, ref, subrefs->get_my_scope())) {
-          // the method is not visible (the error has already been reported)
-          return 0;
-        }
-        switch (ass->get_asstype()) {
-        case Assignment::A_VAR:
-        case Assignment::A_VAR_TEMPLATE:
-        case Assignment::A_CONST:
-        case Assignment::A_TEMPLATE:
-          ref->error("Invalid reference to member `%s' in class type `%s', "
-            "reference to a method was expected instead",
-            id.get_dispname().c_str(), t->get_typename().c_str());
-          return 0;
-        case Assignment::A_FUNCTION:
-        case Assignment::A_EXT_FUNCTION:
-          if (i != nof_refs - 1 || last_method == NULL) {
-            ref->error("Invalid reference to method `%s' with no return type in "
-              "class type `%s'",
+          if (id.get_name() == string("toString")) {
+            // the 'toString' method is not in the AST, but it is inherited by
+            // every class from the 'object' class
+            base_toString = true;
+            if (!ref->parameters_checked()) {
+              Ttcn::FormalParList fp_list; // empty formal parameter list
+              Ttcn::ParsedActualParameters* parsed_pars = ref->get_parsed_pars();
+              Ttcn::ActualParList* ap_list = new Ttcn::ActualParList;
+              bool is_erroneous = fp_list.fold_named_and_chk(parsed_pars, ap_list);
+              if (is_erroneous) {
+                delete ap_list;
+                return 0;
+              }
+              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);
+            }
+            t = get_pooltype(T_USTR);
+            // todo: set *last_method
+          }
+          else {
+            ref->error("Reference to non-existent method `%s' in class type `%s'",
               id.get_dispname().c_str(), t->get_typename().c_str());
             return 0;
           }
-          // a method with no return value can still be valid (e.g. if it's
-          // in a statement)
-          // proceed as normal and return null at the end
-        case Assignment::A_FUNCTION_RVAL:
-        case Assignment::A_FUNCTION_RTEMP:
-        case Assignment::A_EXT_FUNCTION_RVAL:
-        case Assignment::A_EXT_FUNCTION_RTEMP: {
-          Ttcn::Def_Function_Base* def_func =
-            dynamic_cast<Ttcn::Def_Function_Base*>(ass);
-          if (def_func == NULL) {
-            FATAL_ERROR("Type::get_field_type");
+        }
+        if (!base_toString) {
+          Assignment* ass = class_->get_local_ass_byId(id);
+          if (!class_->chk_visibility(ass, ref, subrefs->get_my_scope())) {
+            // the method is not visible (the error has already been reported)
+            return 0;
           }
-          t = def_func->get_return_type();
-          if (!ref->parameters_checked()) {
-            Ttcn::FormalParList* fp_list = ass->get_FormalParList();
-            Ttcn::ParsedActualParameters* parsed_pars = ref->get_parsed_pars();
-            Ttcn::ActualParList* ap_list = new Ttcn::ActualParList;
-            bool is_erroneous = fp_list->fold_named_and_chk(parsed_pars, ap_list);
-            if (is_erroneous) {
-              delete ap_list;
+          switch (ass->get_asstype()) {
+          case Assignment::A_VAR:
+          case Assignment::A_VAR_TEMPLATE:
+          case Assignment::A_CONST:
+          case Assignment::A_TEMPLATE:
+            ref->error("Invalid reference to member `%s' in class type `%s', "
+              "reference to a method was expected instead",
+              id.get_dispname().c_str(), t->get_typename().c_str());
+            return 0;
+          case Assignment::A_FUNCTION:
+          case Assignment::A_EXT_FUNCTION:
+            if (i != nof_refs - 1 || last_method == NULL) {
+              ref->error("Invalid reference to method `%s' with no return type in "
+                "class type `%s'",
+                id.get_dispname().c_str(), t->get_typename().c_str());
               return 0;
             }
-            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);
-          }
-          if (last_method != NULL) {
-            *last_method = ass;
+            // a method with no return value can still be valid (e.g. if it's
+            // in a statement)
+            // proceed as normal and return null at the end
+          case Assignment::A_FUNCTION_RVAL:
+          case Assignment::A_FUNCTION_RTEMP:
+          case Assignment::A_EXT_FUNCTION_RVAL:
+          case Assignment::A_EXT_FUNCTION_RTEMP: {
+            Ttcn::Def_Function_Base* def_func =
+              dynamic_cast<Ttcn::Def_Function_Base*>(ass);
+            if (def_func == NULL) {
+              FATAL_ERROR("Type::get_field_type");
+            }
+            t = def_func->get_return_type();
+            if (!ref->parameters_checked()) {
+              Ttcn::FormalParList* fp_list = ass->get_FormalParList();
+              Ttcn::ParsedActualParameters* parsed_pars = ref->get_parsed_pars();
+              Ttcn::ActualParList* ap_list = new Ttcn::ActualParList;
+              bool is_erroneous = fp_list->fold_named_and_chk(parsed_pars, ap_list);
+              if (is_erroneous) {
+                delete ap_list;
+                return 0;
+              }
+              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);
+            }
+            if (last_method != NULL) {
+              *last_method = ass;
+            }
+            break; }
+          default:
+            FATAL_ERROR("Type::get_field_type - %s shouldn't be in a class",
+              ass->get_assname());
           }
-          break; }
-        default:
-          FATAL_ERROR("Type::get_field_type - %s shouldn't be in a class",
-            ass->get_assname());
         }
         break; }
       case Ttcn::FieldOrArrayRef::ARRAY_REF: {
@@ -6224,6 +6254,8 @@ namespace Common {
     case T_ALTSTEP:
     case T_TESTCASE:
       return u.fatref.runs_on.type;
+    case T_CLASS:
+      return u.class_->get_RunsOnType();
     default:
       FATAL_ERROR("Type::get_fat_runs_on_type()");
       return 0;
@@ -7542,6 +7574,9 @@ namespace Common {
       return string("COMPONENT");
     case T_DEFAULT:
       return string("DEFAULT");
+    case T_CLASS:
+      return t->u.class_->is_built_in() ? string("OBJECT_REF<OBJECT>") :
+        string("OBJECT_REF<") + t->get_genname_own(p_scope) + string(">");
     case T_ARRAY:
       if (!t->u.array.in_typedef)
         return t->u.array.dimension->get_value_type(t->u.array.element_type,
@@ -7634,6 +7669,11 @@ namespace Common {
     const char* tn = get_typename_builtin(t->typetype);
     if (tn != 0) return string(tn);
     switch (t->typetype) {
+    case T_CLASS:
+      if (t->u.class_->is_built_in()) {
+        return string("object");
+      }
+      // else fall through
     case T_COMPONENT:
     case T_SIGNATURE:
     case T_CHOICE_A:
@@ -7651,7 +7691,6 @@ namespace Common {
     case T_FUNCTION:
     case T_ALTSTEP:
     case T_TESTCASE:
-    case T_CLASS:
       return t->get_fullname();
     case T_ARRAY: {
       string dimensions(t->u.array.dimension->get_stringRepr());
diff --git a/compiler2/Type_codegen.cc b/compiler2/Type_codegen.cc
index 7ef873ec3..9f4e9659f 100644
--- a/compiler2/Type_codegen.cc
+++ b/compiler2/Type_codegen.cc
@@ -257,6 +257,7 @@ void Type::generate_code_typedescriptor(output_struct *target)
   switch (get_type_refd_last()->typetype) {
   case T_PORT:
   case T_SIGNATURE:
+  case T_CLASS:
     // do not generate any type descriptor for these non-data types
     return;
   case T_ARRAY:
diff --git a/compiler2/Value.cc b/compiler2/Value.cc
index 2cee16d5b..6204546b2 100644
--- a/compiler2/Value.cc
+++ b/compiler2/Value.cc
@@ -2200,6 +2200,7 @@ namespace Common {
       if(u.expr.v3) u.expr.v3->set_fullname(p_fullname+".<operand3>");
       break;
     case OPTYPE_UNDEF_CREATE: // r1 t_list2 b4
+    case OPTYPE_CLASS_CREATE: // r1 t_list2 b4
       u.expr.r1->set_fullname(p_fullname+".<operand1>");
       u.expr.t_list2->set_fullname(p_fullname+".<parameterlist>");
       break;
@@ -8216,6 +8217,9 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
           u.expr.ap_list2 = parlist;
         }
         chk_expr_dynamic_part(exp_val, true);
+        my_scope->chk_runs_on_clause(t, *this, "create");
+        my_scope->chk_mtc_clause(t, *this);
+        my_scope->chk_system_clause(t, *this);
       }
       if (u.expr.v_optype != OPTYPE_COMP_CREATE) {
         break;
@@ -13029,6 +13033,9 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
         FATAL_ERROR("Value::generate_code_init()");
       }
       break;
+    case V_TTCN3_NULL:
+      str = mputprintf(str, "%s = NULL_VALUE;\n", name);
+      break;
     case V_NOTUSED:
       // unbound value, don't generate anything
       break;
diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc
index 1a4481507..3a464bf8a 100644
--- a/compiler2/ttcn3/AST_ttcn3.cc
+++ b/compiler2/ttcn3/AST_ttcn3.cc
@@ -482,12 +482,19 @@ namespace Ttcn {
           Free(prev_expr);
         }
         const Identifier& id = *ref->get_id();
-        Common::Assignment* ass = class_->get_local_ass_byId(id);
+        // 'ass' is null if the 'toString' method from the 'object' class is called
+        Common::Assignment* ass = class_->has_local_ass_withId(id) ?
+          class_->get_local_ass_byId(id) : NULL;
         expr->expr = mputprintf(expr->expr, "->%s(", id.get_name().c_str());
-        ref->get_actual_par_list()->generate_code_noalias(expr, ass->get_FormalParList());
+        FormalParList* fp_list = ass != NULL ? ass->get_FormalParList() :
+          new FormalParList; // the formal parameter list of 'toString' is empty
+        ref->get_actual_par_list()->generate_code_noalias(expr, fp_list);
+        if (ass == NULL) {
+          delete fp_list;
+        }
         expr->expr = mputc(expr->expr, ')');
-        Def_Function_Base* def_func = dynamic_cast<Def_Function_Base*>(ass);
-        type = def_func->get_return_type();
+        type = ass != NULL ? ass->get_Type() :
+          Common::Type::get_pooltype(Common::Type::T_USTR);
         if (const_ref && i < n_refs - 1 &&
             refs[i + 1]->get_type() != FieldOrArrayRef::FUNCTION_REF) {
           // the next subreference is a field name or array index, have to
@@ -1055,15 +1062,17 @@ namespace Ttcn {
         expr->expr = mputstr(expr->expr, "this->");
       }
       else { // no 'id' means it's just a 'this' reference
-        expr->expr = mputprintf(expr->expr, "OBJECT_REF<%s>(this)",
+        expr->expr = mputprintf(expr->expr, "%s(this)",
           ass->get_Type()->get_genname_value(my_scope).c_str());
         return;
       }
     }
     else if (reftype == REF_SUPER) {
+      Common::Type* base_type = my_scope->get_scope_class()->get_base_type()->
+        get_type_refd_last();
       expr->expr = mputprintf(expr->expr, "%s::",
-        my_scope->get_scope_class()->get_base_type()->
-        get_genname_value(my_scope).c_str());
+        base_type->get_class_type_body()->is_built_in() ? "OBJECT" :
+        base_type->get_genname_own(my_scope).c_str());
     }
     string const_prefix; // empty by default
     if (gen_const_prefix) {
@@ -1146,12 +1155,8 @@ namespace Ttcn {
     } else {
       // don't convert to const object if the first subreference is a method call
       if (t_subrefs->get_ref(0)->get_type() != FieldOrArrayRef::FUNCTION_REF) {
-        string type_str = refd_gov->get_genname_value(get_my_scope());
-        if (refd_gov->get_type_refd_last()->get_typetype() == Common::Type::T_CLASS) {
-          type_str = string("OBJECT_REF<") + type_str + string(">");
-        }
         this_expr.expr = mputprintf(this_expr.expr, "const_cast< const %s&>(",
-          type_str.c_str());
+          refd_gov->get_genname_value(get_my_scope()).c_str());
       }
     }
     if (parlist != NULL) {
@@ -3688,6 +3693,11 @@ namespace Ttcn {
                 continue;
               }
               field_name = tref->get_id()->get_ttcnname();
+              if (oop_features && field_name == string("object")) {
+                ea.error("Class type `object' cannot be added to the anytype");
+                delete t;
+                continue;
+              }
             }
             else {
               // Can't happen here
@@ -3888,7 +3898,7 @@ namespace Ttcn {
       break;
     case Type::T_CLASS:
       error("Constant cannot be defined for class type `%s'",
-        t->get_fullname().c_str());
+        t->get_typename().c_str());
       break;
     default:
       value_under_check = true;
@@ -4078,7 +4088,7 @@ namespace Ttcn {
       break;
     case Type::T_CLASS:
       error("External constant cannot be defined for class type `%s'",
-        t->get_fullname().c_str());
+        t->get_typename().c_str());
       break;
     default:
       break;
@@ -4204,7 +4214,7 @@ namespace Ttcn {
       break;
     case Type::T_CLASS:
       error("Type of module parameter cannot be or embed class type `%s'",
-        t->get_fullname().c_str());
+        t->get_typename().c_str());
       break;
     case Type::T_FUNCTION:
     case Type::T_ALTSTEP:
@@ -4384,7 +4394,7 @@ namespace Ttcn {
       break;
     case Type::T_CLASS:
       error("Type of template module parameter cannot be class type `%s'",
-        t->get_fullname().c_str());
+        t->get_typename().c_str());
       break;
     default:
       if (IMPLICIT_OMIT == has_implicit_omit_attr()) {
@@ -4605,7 +4615,7 @@ namespace Ttcn {
     }
     else if (t->get_typetype() == Type::T_CLASS) {
       error("Template cannot be defined for class type `%s'",
-        t->get_fullname().c_str());
+        t->get_typename().c_str());
     }
     chk_modified();
     chk_recursive_derivation();
@@ -5285,9 +5295,6 @@ namespace Ttcn {
     const string& t_genname = get_genname();
     const char *genname_str = t_genname.c_str();
     string type_name = type->get_genname_value(my_scope);
-    if (type->get_type_refd_last()->get_typetype() == Common::Type::T_CLASS) {
-      type_name = string("OBJECT_REF<") + type_name + string(">");
-    }
     if (initial_value && initial_value->has_single_expr()) {
       // the initial value can be represented by a single C++ expression
       // the object is initialized by the constructor
@@ -5396,7 +5403,7 @@ namespace Ttcn {
     }
     else if (t->get_typetype() == Type::T_CLASS) {
       error("Template variable cannot be defined for class type `%s'",
-        t->get_fullname().c_str());
+        t->get_typename().c_str());
     }
 
     if (initial_value) {
diff --git a/compiler2/ttcn3/Ttcnstuff.cc b/compiler2/ttcn3/Ttcnstuff.cc
index 9a2e25891..f588d5bc0 100644
--- a/compiler2/ttcn3/Ttcnstuff.cc
+++ b/compiler2/ttcn3/Ttcnstuff.cc
@@ -2982,23 +2982,37 @@ namespace Ttcn {
   // =================================
   
   ClassTypeBody::ClassTypeBody(Common::Identifier* p_class_id, boolean p_external, boolean p_final,
-                               boolean p_abstract, Common::Type* p_base_type, Reference* p_runs_on_ref,
-                               Reference* p_mtc_ref, Reference* p_system_ref,
+                               boolean p_abstract, Common::Type* p_base_type,
+                               Reference* p_runs_on_ref, Reference* p_mtc_ref, Reference* p_system_ref,
                                Definitions* p_members, StatementBlock* p_finally_block)
-  : Scope(), Location(), class_id(p_class_id), my_def(NULL), external(p_external), final(p_final), abstract(p_abstract),
-    base_type(p_base_type), runs_on_ref(p_runs_on_ref), runs_on_type(NULL),
-    mtc_ref(p_mtc_ref), mtc_type(NULL), system_ref(p_system_ref), system_type(NULL),
+  : Scope(), Location(), class_id(p_class_id), my_def(NULL), external(p_external), final(p_final),
+    abstract(p_abstract), built_in(FALSE), base_type(p_base_type),
+    runs_on_ref(p_runs_on_ref), runs_on_type(NULL), mtc_ref(p_mtc_ref),
+    mtc_type(NULL), system_ref(p_system_ref), system_type(NULL),
     members(p_members), finally_block(p_finally_block), constructor(NULL), checked(false),
     default_constructor(false)
   {
+    // constructor for user-defined classes
     if (members == NULL) {
       FATAL_ERROR("ClassTypeBody::ClassTypeBody");
     }
   }
   
+  ClassTypeBody::ClassTypeBody()
+  : Scope(), Location(), class_id(NULL), my_def(NULL), external(FALSE), final(FALSE),
+    abstract(TRUE), built_in(TRUE), base_type(NULL),
+    runs_on_ref(NULL), runs_on_type(NULL), mtc_ref(NULL),
+    mtc_type(NULL), system_ref(NULL), system_type(NULL),
+    members(NULL), finally_block(NULL), constructor(NULL), checked(false),
+    default_constructor(false)
+  {
+    // constructor for the built-in class 'object'
+  }
+  
   ClassTypeBody::ClassTypeBody(const ClassTypeBody& p)
   {
-    class_id = p.class_id->clone();
+    built_in = p.built_in;
+    class_id = p.class_id != NULL ? p.class_id->clone() : NULL;
     my_def = p.my_def;
     external = p.external;
     final = p.final;
@@ -3007,7 +3021,7 @@ namespace Ttcn {
     runs_on_ref = p.runs_on_ref != NULL ? p.runs_on_ref->clone() : NULL;
     mtc_ref = p.mtc_ref != NULL ? p.mtc_ref->clone() : NULL;
     system_ref = p.system_ref != NULL ? p.system_ref->clone() : NULL;
-    members = p.members->clone();
+    members = p.members != NULL ? p.members->clone() : NULL;
     finally_block = p.finally_block != NULL ? p.finally_block->clone() : NULL;
     default_constructor = p.default_constructor;
     constructor = default_constructor ? p.constructor->clone() : p.constructor;
@@ -3021,6 +3035,9 @@ namespace Ttcn {
   
   ClassTypeBody::~ClassTypeBody()
   {
+    if (built_in) {
+      return;
+    }
     delete base_type;
     delete finally_block;
     delete members;
@@ -3034,6 +3051,9 @@ namespace Ttcn {
   
   void ClassTypeBody::set_fullname(const string& p_fullname)
   {
+    if (built_in) {
+      return;
+    }
     Common::Scope::set_fullname(p_fullname);
     if (base_type != NULL) {
       base_type->set_fullname(p_fullname + ".<superclass>");
@@ -3055,6 +3075,9 @@ namespace Ttcn {
   
   void ClassTypeBody::set_my_scope(Scope* p_scope)
   {
+    if (built_in) {
+      return;
+    }
     set_parent_scope(p_scope);
     if (base_type != NULL) {
       base_type->set_my_scope(p_scope);
@@ -3076,6 +3099,10 @@ namespace Ttcn {
   
   void ClassTypeBody::dump(unsigned level) const
   {
+    if (built_in) {
+      DEBUG(level, "Built-in class 'object'");
+      return;
+    }
     DEBUG(level, "Modifiers:%s%s%s", external ? "external " : "",
       final ? " @final " : "", abstract ? " @abstract" : "");
     DEBUG(level, "Base class: %s", base_type != NULL ?
@@ -3132,7 +3159,7 @@ namespace Ttcn {
   
   bool ClassTypeBody::is_parent_class(const ClassTypeBody* p_class) const
   {
-    if (this == p_class) {
+    if (this == p_class || p_class->built_in) {
       return true;
     }
     if (base_type == NULL) {
@@ -3144,6 +3171,9 @@ namespace Ttcn {
   
   bool ClassTypeBody::has_local_ass_withId(const Identifier& p_id)
   {
+    if (built_in) {
+      return false;
+    }
     chk();
     if (members->has_local_ass_withId(p_id)) {
       return true;
@@ -3159,6 +3189,9 @@ namespace Ttcn {
   
   Common::Assignment* ClassTypeBody::get_local_ass_byId(const Identifier& p_id)
   {
+    if (built_in) {
+      FATAL_ERROR("ClassTypeBody::get_local_ass_byId");
+    }
     chk();
     Common::Assignment* ass = NULL;
     if (members->has_local_ass_withId(p_id)) {
@@ -3175,6 +3208,9 @@ namespace Ttcn {
                                      Common::Location* usage_loc,
                                      Common::Scope* usage_scope)
   {
+    if (built_in) {
+      FATAL_ERROR("ClassTypeBody::chk_visibility");
+    }
     if (ass->get_visibility() == PUBLIC) {
       // it's public, so it doesn't matter where it's accessed from
       return true;
@@ -3204,6 +3240,9 @@ namespace Ttcn {
   
   Common::Assignment* ClassTypeBody::get_ass_bySRef(Common::Ref_simple* p_ref)
   {
+    if (built_in) {
+      return NULL;
+    }
     if (p_ref == NULL || parent_scope == NULL) {
       FATAL_ERROR("ClassTypeBody::get_ass_bySRef()");
     }
@@ -3251,7 +3290,7 @@ namespace Ttcn {
   
   void ClassTypeBody::chk()
   {
-    if (checked) {
+    if (checked || built_in) {
       return;
     }
     checked = true;
@@ -3270,25 +3309,69 @@ namespace Ttcn {
       // TODO: additional checks for the base type
     }
 
+    ClassTypeBody* base_class = base_type != NULL ? 
+      base_type->get_type_refd_last()->get_class_type_body() : NULL;
     if (runs_on_ref != NULL) {
       Error_Context cntxt(runs_on_ref, "In `runs on' clause");
       runs_on_type = runs_on_ref->chk_comptype_ref();
-      // TODO
+      if (base_class != NULL) {
+        Type* base_runs_on_type = base_class->get_RunsOnType();
+        if (base_runs_on_type != NULL &&
+            !base_runs_on_type->is_compatible(runs_on_type, NULL, NULL)) {
+          runs_on_ref->error("The `runs on' component type of the subclass, "
+            "`%s', is not compatible with the `runs on' component type of the "
+            "superclass, `%s'",
+            runs_on_type->get_typename().c_str(),
+            base_runs_on_type->get_typename().c_str());
+        }
+      }
+    }
+    else if (base_class != NULL) {
+      // inherit `runs on' component from the superclass
+      runs_on_type = base_class->get_RunsOnType();
     }
+    
     if (mtc_ref != NULL) {
       Error_Context cntxt(mtc_ref, "In `mtc' clause");
       mtc_type = mtc_ref->chk_comptype_ref();
-      // TODO
+      if (base_class != NULL) {
+        Type* base_mtc_type = base_class->get_MtcType();
+        if (base_mtc_type != NULL &&
+            !base_mtc_type->is_compatible(mtc_type, NULL, NULL)) {
+          mtc_ref->error("The `mtc' component type of the subclass, `%s', is not "
+            "compatible with the `mtc' component type of the superclass, `%s'",
+            mtc_type->get_typename().c_str(),
+            base_mtc_type->get_typename().c_str());
+        }
+      }
     }
+    else if (base_class != NULL) {
+      // inherit `mtc' component from the superclass
+      mtc_type = base_class->get_MtcType();
+    }
+    
     if (system_ref != NULL) {
       Error_Context cntxt(system_ref, "In `system' clause");
       system_type = system_ref->chk_comptype_ref();
-      // TODO
+      if (base_class != NULL) {
+        Type* base_system_type = base_class->get_SystemType();
+        if (base_system_type != NULL &&
+            !base_system_type->is_compatible(system_type, NULL, NULL)) {
+          system_ref->error("The `system' component type of the subclass, `%s', is "
+            "not compatible with the `system' component type of the superclass, `%s'",
+            system_type->get_typename().c_str(),
+            base_system_type->get_typename().c_str());
+        }
+      }
+    }
+    else if (base_class != NULL) {
+      // inherit `system' component from the superclass
+      system_type = base_class->get_SystemType();
     }
 
     members->chk_uniq();
     members->chk();
-    
+
     for (size_t i = 0; i < members->get_nof_asss(); ++i) {
       Common::Assignment* ass = members->get_ass_byIndex(i);
       if (ass->get_asstype() == Common::Assignment::A_CONSTRUCTOR) {
@@ -3305,9 +3388,7 @@ namespace Ttcn {
       // create a default constructor
       Reference* base_call = NULL;
       FormalParList* fp_list = NULL;
-      if (base_type != NULL) {
-        ClassTypeBody* base_class = base_type->get_type_refd_last()->
-          get_class_type_body();
+      if (base_class != NULL) {
         Def_Constructor* base_constructor = base_class->get_constructor();
         if (base_constructor != NULL) {
           FormalParList* base_fp_list = base_constructor->get_FormalParList();
@@ -3374,6 +3455,9 @@ namespace Ttcn {
   
   void ClassTypeBody::chk_recursions(ReferenceChain& refch)
   {
+    if (built_in) {
+      return;
+    }
     if (base_type != NULL) {
       base_type->chk_recursions(refch);
     }
@@ -3381,8 +3465,12 @@ namespace Ttcn {
     for (size_t i = 0; i < members->get_nof_asss(); ++i) {
       Common::Assignment* def = members->get_ass_byIndex(i);
       switch (def->get_asstype()) {
-      case Common::Assignment::A_CONST:
       case Common::Assignment::A_VAR:
+        if (def->get_Type()->get_type_refd_last()->get_typetype() == Common::Type::T_CLASS) {
+          break;
+        }
+        // else fall through
+      case Common::Assignment::A_CONST:
       case Common::Assignment::A_TEMPLATE:
       case Common::Assignment::A_VAR_TEMPLATE:
         def->get_Type()->chk_recursions(refch);
@@ -3395,11 +3483,14 @@ namespace Ttcn {
   
   void ClassTypeBody::generate_code(output_struct* target)
   {
+    if (built_in) {
+      return;
+    }
     target->header.class_decls = mputprintf(target->header.class_decls,
       "class %s;\n", class_id->get_name().c_str());
     if (!external) {
       string base_type_name = base_type != NULL ?
-        base_type->get_genname_value(this) : string("OBJECT");
+        base_type->get_type_refd_last()->get_genname_own(this) : string("OBJECT");
       
       target->header.class_defs = mputprintf(target->header.class_defs,
         "class %s : public %s {\n",
@@ -3505,7 +3596,7 @@ namespace Ttcn {
       if (base_type != NULL) {
         target->source.methods = mputprintf(target->source.methods,
           "%s::log();\n",
-          base_type->get_genname_value(this).c_str());
+          base_type_name.c_str());
         first_logged = true;
       }
       for (size_t i = 0; i < members->get_nof_asss(); ++i) {
diff --git a/compiler2/ttcn3/Ttcnstuff.hh b/compiler2/ttcn3/Ttcnstuff.hh
index 9ad4794da..d6a7669c0 100644
--- a/compiler2/ttcn3/Ttcnstuff.hh
+++ b/compiler2/ttcn3/Ttcnstuff.hh
@@ -760,6 +760,7 @@ class ClassTypeBody : public Common::Scope, public Common::Location {
   boolean external;
   boolean final;
   boolean abstract;
+  boolean built_in;
   Common::Type* base_type;
   Reference* runs_on_ref;
   Type* runs_on_type;
@@ -777,9 +778,10 @@ class ClassTypeBody : public Common::Scope, public Common::Location {
   
 public:
   ClassTypeBody(Common::Identifier* p_class_id, boolean p_external, boolean p_final,
-    boolean p_abstract, Common::Type* p_base_type, Ttcn::Reference* p_runs_on_ref,
-    Reference* p_mtc_ref, Reference* p_system_ref,
+    boolean p_abstract, Common::Type* p_base_type,
+    Ttcn::Reference* p_runs_on_ref, Reference* p_mtc_ref, Reference* p_system_ref,
     Definitions* p_members, StatementBlock* p_finally_block);
+  ClassTypeBody();
   ClassTypeBody(const ClassTypeBody& p);
   ClassTypeBody* clone() const;
   virtual ~ClassTypeBody();
@@ -795,6 +797,7 @@ public:
   Common::Identifier* get_id() const { return class_id; }
   Def_Constructor* get_constructor();
   Common::Type* get_base_type() const { return base_type; }
+  boolean is_built_in() const { return built_in; }
   
   Type* get_RunsOnType();
   Type* get_MtcType();
diff --git a/compiler2/ttcn3/compiler.l b/compiler2/ttcn3/compiler.l
index f18436ce9..cc5de153a 100644
--- a/compiler2/ttcn3/compiler.l
+++ b/compiler2/ttcn3/compiler.l
@@ -606,6 +606,18 @@ super {
     RETURN_LVAL(IDentifier);
   }
 }
+object {
+  if (oop_features) {
+    RETURN(ObjectKeyword);
+  }
+  else {
+    Location loc(infile, yylloc);
+    loc.warning("Keyword 'object' is treated as an identifier. Activate "
+      "compiler option '-k' to use object-oriented features.");
+    yylval.id = new Identifier(Identifier::ID_TTCN, string(yyleng, yytext));
+    RETURN_LVAL(IDentifier);
+  }
+}
 
   /* modifier keywords */
 
diff --git a/compiler2/ttcn3/compiler.y b/compiler2/ttcn3/compiler.y
index e4e0c01a4..bc7557559 100644
--- a/compiler2/ttcn3/compiler.y
+++ b/compiler2/ttcn3/compiler.y
@@ -738,6 +738,7 @@ static const string anyname("anytype");
 %token NowKeyword
 %token NowaitKeyword
 %token NullKeyword
+%token ObjectKeyword
 %token ObjectIdentifierKeyword
 %token OctetStringKeyword
 %token OfKeyword
@@ -1948,7 +1949,7 @@ optDecodedModifier
 %left '*' '/' ModKeyword RemKeyword
 %left UnarySign
 
-%expect 75
+%expect 76
 
 %start GrammarRoot
 
@@ -1996,9 +1997,9 @@ non-standard language extension.
 
 6.) 1 Conflict due to pattern concatenation
 
-7.) 29 conflicts in one state
+7.) 30 conflicts in one state
 In the DecodedContentMatch rule a SingleExpression encased in round brackets is
-followed by an in-line template. For 29 tokens (after the ')' ) the parser cannot
+followed by an in-line template. For 30 tokens (after the ')' ) the parser cannot
 decide whether the token is the beginning of the in-line template (shift) or
 the brackets are only part of the SingleExpression itself and the conflicting
 token is the next segment in the expression (reduce).
@@ -8229,6 +8230,11 @@ Type: // 450
     $$ = new Type($1);
     $$->set_location(infile, @$);
   }
+| ObjectKeyword
+  {
+    $$ = new Type(Type::T_CLASS);
+    $$->set_location(infile, @$);
+  }
 | AnyTypeKeyword /* a predefined type with special treatment */
   {
     anytype_access = true;
diff --git a/core/OOP.hh b/core/OOP.hh
index a3ddd55e0..f5a03e74c 100644
--- a/core/OOP.hh
+++ b/core/OOP.hh
@@ -38,9 +38,12 @@ public:
     --ref_count;
     return ref_count == 0;
   }
-  void log() const {
+  virtual void log() const {
     TTCN_Logger::log_event_str("object: { }");
   }
+  virtual UNIVERSAL_CHARSTRING toString() {
+    return UNIVERSAL_CHARSTRING("Object");
+  }
 };
 
 // OBJECT_REF
@@ -55,15 +58,6 @@ class OBJECT_REF {
 private:
   T* ptr; // NULL if it's a null reference
   
-  void clean_up() {
-    if (ptr != NULL) {
-      if (ptr->remove_ref()) {
-        delete ptr;
-      }
-      ptr = NULL;
-    }
-  }
-  
 public:
   OBJECT_REF(): ptr(NULL) {} // constructor with no parameters
 
@@ -79,12 +73,22 @@ public:
     }
   }
   
+  void clean_up() {
+    if (ptr != NULL) {
+      if (ptr->remove_ref()) {
+        delete ptr;
+      }
+      ptr = NULL;
+    }
+  }
+  
   ~OBJECT_REF() {
     clean_up();
   }
   
   OBJECT_REF& operator=(null_type) { // assignment operator for null reference
     clean_up();
+    return *this;
   }
   
   OBJECT_REF& operator=(const OBJECT_REF<T>& p_other) { // assignment operator for actual reference
diff --git a/function_test/Semantic_Analyser/oop/oop_SE.ttcn b/function_test/Semantic_Analyser/oop/oop_SE.ttcn
index b7d6129fe..b2213a0ff 100644
--- a/function_test/Semantic_Analyser/oop/oop_SE.ttcn
+++ b/function_test/Semantic_Analyser/oop/oop_SE.ttcn
@@ -124,32 +124,44 @@ type class C8 extends C7 { //^In type definition// //While checking embedded rec
 
 type class C9 extends C8 {} //^In type definition// //^In superclass definition//
 
-external const C0 ec_obj; //^In external constant definition// //External constant cannot be defined for class type `@oop_SE.C0'//
-modulepar C0 mp_obj; //^In module parameter definition// //Type of module parameter cannot be or embed class type `@oop_SE.C0'//
-modulepar template C0 mpt_obj; //^In template module parameter definition// //Type of template module parameter cannot be class type `@oop_SE.C0'//
+external const C0 ec_c0; //^In external constant definition// //External constant cannot be defined for class type `@oop_SE.C0'//
+external const object ec_obj; //^In external constant definition// //External constant cannot be defined for class type `object'//
+modulepar C0 mp_c0; //^In module parameter definition// //Type of module parameter cannot be or embed class type `@oop_SE.C0'//
+modulepar object mp_obj; //^In module parameter definition// //Type of module parameter cannot be or embed class type `object'//
+modulepar template C0 mpt_c0; //^In template module parameter definition// //Type of template module parameter cannot be class type `@oop_SE.C0'//
+modulepar template object mpt_obj; //^In template module parameter definition// //Type of template module parameter cannot be class type `object'//
 
 function f_defs() { //^In function definition//
-  const C0 c_obj := null; //^In constant definition// //Constant cannot be defined for class type `@oop_SE.C0'//
-  var C0 v_obj;
-  template C0 t_obj := *; //^In template definition// //Template cannot be defined for class type `@oop_SE.C0'//
-  var template C0 vt_obj; //^In template variable definition// //Template variable cannot be defined for class type `@oop_SE.C0'//
+  const C0 c_c0 := null; //^In constant definition// //Constant cannot be defined for class type `@oop_SE.C0'//
+  const object c_obj := null; //^In constant definition// //Constant cannot be defined for class type `object'//
+  var C0 v_c0;
+  var object v_obj;
+  template C0 t_c0 := *; //^In template definition// //Template cannot be defined for class type `@oop_SE.C0'//
+  template object t_obj := *; //^In template definition// //Template cannot be defined for class type `object'//
+  var template C0 vt_c0; //^In template variable definition// //Template variable cannot be defined for class type `@oop_SE.C0'//
+  var template object vt_obj; //^In template variable definition// //Template variable cannot be defined for class type `object'//
 }
 
 
 type record RecClass { //^In type definition//
-  C0 x //^In record field// //Class type `@oop_SE.C0' cannot be embedded into another type//
+  C0 x, //^In record field// //Class type `@oop_SE.C0' cannot be embedded into another type//
+  object y //^In record field// //Class type `object' cannot be embedded into another type//
 }
 
 type set SetClass { //^In type definition//
-  C0 x //^In set field// //Class type `@oop_SE.C0' cannot be embedded into another type//
+  C0 x, //^In set field// //Class type `@oop_SE.C0' cannot be embedded into another type//
+  object y //^In set field// //Class type `object' cannot be embedded into another type//
 }
 
 type record of C0 RecOfClass; //^In type definition// //^In embedded type of record of// //Class type `@oop_SE.C0' cannot be embedded into another type//
+type record of object RecOfObject; //^In type definition// //^In embedded type of record of// //Class type `object' cannot be embedded into another type//
 
 type set of C0 SetOfClass; //^In type definition// //^In embedded type of set of// //Class type `@oop_SE.C0' cannot be embedded into another type//
+type set of object SetOfObject; //^In type definition// //^In embedded type of set of// //Class type `object' cannot be embedded into another type//
 
 type union UniClass { //^In type definition//
-  C0 x //^In union field// //Class type `@oop_SE.C0' cannot be embedded into another type//
+  C0 x, //^In union field// //Class type `@oop_SE.C0' cannot be embedded into another type//
+  object y //^In union field// //Class type `object' cannot be embedded into another type//
 }
 
 function f_embedded_types() { //^In function definition//
@@ -191,11 +203,25 @@ type component CT_RunsOn {
 type component CT_Mtc {
   var integer cv_mtc;
   const integer cc_mtc := 1;
+  port Port pt;
 }
 
 type component CT_System {
   var integer cv_system;
   const integer cc_system := 2;
+  port Port pt;
+}
+
+type component CT_RunsOn2 extends CT_RunsOn {
+  var template integer cvt_runs_on := *;
+}
+
+type component CT_Mtc2 extends CT_Mtc {
+  var template integer cvt_mtc := ?;
+}
+
+type component CT_System2 extends CT_System {
+  var template integer cvt_system := omit;
 }
 
 type class C10 runs on CT_RunsOn mtc CT_Mtc system CT_System { //^In type definition//
@@ -210,8 +236,50 @@ type class C10 runs on CT_RunsOn mtc CT_Mtc system CT_System { //^In type defini
   }
 }
 
+type class C11 extends C10 { //^In type definition//
+  public function f_inherited_comp_visibility(in integer p1 := cc_runs_on, //^In function definition// //^In formal parameter list//
+                                              in integer p2 := cc_mtc,
+                                              in integer p3 := cc_system,
+                                              in integer p4 := cc_comp) { //^In parameter// //^In default value// //There is no local or imported definition with name `cc_comp'//
+    log(cv_runs_on);
+    log(cv_mtc);
+    log(cv_system);
+    log(cv_comp); //^In log statement// //There is no local or imported definition with name `cv_comp'//
+  }
+}
+
+type class C12 extends C10 runs on CT_RunsOn mtc CT_Mtc system CT_System { }
+
+type class C13 extends C11 //^In type definition//
+  runs on Comp //^In `runs on' clause// //The `runs on' component type of the subclass, `@oop_SE.Comp', is not compatible with the `runs on' component type of the superclass, `@oop_SE.CT_RunsOn'//
+  mtc Comp //^In `mtc' clause// //The `mtc' component type of the subclass, `@oop_SE.Comp', is not compatible with the `mtc' component type of the superclass, `@oop_SE.CT_Mtc'//
+  system Comp //^In `system' clause// //The `system' component type of the subclass, `@oop_SE.Comp', is not compatible with the `system' component type of the superclass, `@oop_SE.CT_System'//
+  { }
+
+type class C14 extends C11
+  runs on CT_RunsOn2
+  mtc CT_Mtc2
+  system CT_System2
+  { }
+
+function f_good_comp_usage() runs on CT_RunsOn mtc CT_Mtc system CT_System {
+  var C11 x := C11.create;
+}
+
+function f_bad_comp_usage() runs on Comp mtc Comp system Comp { //^In function definition//
+  var C11 x := C11.create; //^In variable definition// //Runs on clause mismatch: A definition that runs on component type `@oop_SE.Comp' cannot create a value of class type `@oop_SE.C11', which runs on `@oop_SE.CT_RunsOn'// //Mtc clause mismatch: A definition that runs on component type `@oop_SE.Comp' cannot create a value of class type `@oop_SE.C11', which has `mtc' component type `@oop_SE.CT_Mtc'// //System clause mismatch: A definition that runs on component type `@oop_SE.Comp' cannot create a value of class type `@oop_SE.C11', which has `system' component type `@oop_SE.CT_System'//
+}
+
+function f_no_comp_usage() { //^In function definition//
+  var C11 x := C11.create; //^In variable definition// //A definition without `runs on' clause cannot create a value of class type `@oop_SE.C11', which runs on component type `@oop_SE.CT_RunsOn'//
+}
+
+
+control { //^In control part//
+  var C11 x := C11.create; //^In variable definition// //A definition without `runs on' clause cannot create a value of class type `@oop_SE.C11', which runs on component type `@oop_SE.CT_RunsOn'// //Cannot create value of class type `@oop_SE.C11', which has an `mtc' clause, in the control part.// //Cannot create value of class type `@oop_SE.C11', which has a `system' clause, in the control part.//
+}
 
 }
 with {
-  extension "anytype C0" //^In anytype field// //Class type `@oop_SE.C0' cannot be embedded into another type//
+  extension "anytype C0, object" //^In anytype field// //Class type `@oop_SE.C0' cannot be embedded into another type// //Class type `object' cannot be added to the anytype//
 }
diff --git a/regression_test/oop/oop.ttcn b/regression_test/oop/oop.ttcn
index f8213cc6e..dbef29742 100644
--- a/regression_test/oop/oop.ttcn
+++ b/regression_test/oop/oop.ttcn
@@ -357,6 +357,93 @@ testcase tc_references() runs on CT {
 }
 
 
+type class Node {
+  var integer data;
+  var Node next;
+}
+
+function f_test(in Node p1, inout Node p2, out Node p3,
+                in charstring p1_str, in charstring p2_str) return Node {
+  if (log2str(p1) != p1_str) {
+    setverdict(fail, "Invalid 'in' parameter value at start: ", p1, ", expected: ", p1_str);
+  }
+  if (log2str(p2) != p2_str) {
+    setverdict(fail, "Invalid 'inout' parameter value at start: ", p2, ", expected: ", p2_str);
+  }
+  if (p3 != null) {
+    setverdict(fail, "Invalid 'out' parameter value at start: ", p3, ", expected: null");
+  }
+  var Node tmp := p2;
+  p3 := p1;
+  p1 := null;
+  p2 := null;
+  return tmp;
+}
+
+testcase tc_function_pars_and_retval() runs on CT {
+  var Node x := Node.create(1, Node.create(2, Node.create(3, null)));
+  var Node y := Node.create(0, null);
+  var Node z := Node.create(-1, null);
+  var charstring x_str := log2str(x);
+  var charstring y_str := log2str(y);
+  var Node res := f_test(x, y, z, x_str, y_str);
+  if (log2str(x) != x_str) {
+    setverdict(fail, "Invalid 'in' parameter value at end: ", x, ", expected: ", x_str);
+  }
+  if (y != null) {
+    setverdict(fail, "Invalid 'inout' parameter value at end: ", y, ", expected: null");
+  }
+  if (log2str(z) != x_str) {
+    setverdict(fail, "Invalid 'out' parameter value at end: ", z, ", expected: ", x_str);
+  }
+  if (log2str(res) != y_str) {
+    setverdict(fail, "Invalid return value: ", res, ", expected: ", y_str);
+  }
+  setverdict(pass);
+}
+
+type class Node2 {
+  var object data;
+  var Node2 next;
+}
+
+type class Something {
+  public function toString() return universal charstring {
+    return "Something";
+  }
+}
+
+testcase tc_object() runs on CT {
+  var object v_obj := Node.create(3, null);
+  var Node v_node := Node.create(3, null);
+  if (log2str(v_obj) != log2str(v_node)) {
+    setverdict(fail, "v_obj: ", v_obj, ", v_node: ", v_node);
+  }
+  if (v_obj.toString() != "Object") {
+    setverdict(fail, "v_obj.toString(): ", v_obj.toString());
+  }
+  if (v_obj.toString() != v_node.toString()) {
+    setverdict(fail, "v_obj.toString(): ", v_obj.toString(), ", v_node.toString(): ", v_node.toString());
+  }
+  var object v_obj2 := Something.create;
+  var Something v_smthn := Something.create;
+  if (v_obj2.toString() != "Something") {
+    setverdict(fail, "v_obj2.toString(): ", v_obj2.toString());
+  }
+  if (v_obj2.toString() != v_smthn.toString()) {
+    setverdict(fail, "v_obj2.toString(): ", v_obj2.toString(), ", v_smthn.toString(): ", v_smthn.toString());
+  }
+  if (v_obj2.toString()[3] != "e") {
+    setverdict(fail, "v_obj2.toString()[3]: ", v_obj2.toString()[3]);
+  }
+  var Node2 v_node2 := Node2.create(Something.create, Node2.create(Node.create(1, null), null));
+  if (log2str(v_node2) != "Node2: { data := Something: {  }, next := Node2: { data := Node: { data := 1, next := null }, next := null } }") {
+    setverdict(fail, "v_node2: ", v_node2);
+  }
+  setverdict(pass);
+}
+
+
 control {
   execute(tc_members_and_methods());
   execute(tc_logging());
@@ -364,6 +451,8 @@ control {
   execute(tc_null());
   execute(tc_this());
   execute(tc_references());
+  execute(tc_function_pars_and_retval());
+  execute(tc_object());
 }
 
 }
-- 
GitLab