diff --git a/compiler2/Type_chk.cc b/compiler2/Type_chk.cc index 8b47f46b54987c7655f263025279ff48bd79113f..dda0e6eb1813175f77f6145266600543dc428220 100644 --- a/compiler2/Type_chk.cc +++ b/compiler2/Type_chk.cc @@ -3731,7 +3731,7 @@ void Type::chk_Fat() Error_Context cntxt2(u.fatref.return_type, "In return type"); u.fatref.return_type->chk(); u.fatref.return_type->chk_as_return_type(!u.fatref.returns_template, - "function type"); + " function type"); if (u.fatref.is_startable && u.fatref.return_type->get_type_refd_last() ->get_typetype() == T_DEFAULT) u.fatref.is_startable = false; @@ -3920,7 +3920,7 @@ void Type::chk_as_return_type(bool as_value, const char* what) Type *t = get_type_refd_last(); switch(t->get_typetype()) { case Type::T_PORT: - error("Port type `%s' cannot be the return type of a %s" + error("Port type `%s' cannot be the return type of a%s" , t->get_fullname().c_str(), what); break; case Type::T_SIGNATURE: @@ -6000,21 +6000,15 @@ void Type::chk_this_value_class(Value* value) switch(v->get_valuetype()) { case Value::V_TTCN3_NULL: break; // OK - case Value::V_REFD: - // TODO - break; case Value::V_EXPR: - switch (v->get_optype()) { - case Value::OPTYPE_CLASS_CREATE: - // TODO - break; - default: - // error + if (v->get_optype() == Value::OPTYPE_CLASS_CREATE) { + // OK break; } - break; + // else fall through default: // error + v->error("class value was expected"); break; } } diff --git a/compiler2/Value.cc b/compiler2/Value.cc index 6204546b29dfc033201d55337563a91883f08cf7..2d8a79be3515a404ec1c9b74598709c84dcc9c61 100644 --- a/compiler2/Value.cc +++ b/compiler2/Value.cc @@ -4063,8 +4063,11 @@ namespace Common { goto error; case Assignment::A_TYPE: if (ass->get_Type()->get_type_refd_last()->get_typetype() == Type::T_CLASS) { - tmp_type = ass->get_Type(); - break; + Ttcn::Reference* ttcn_ref = static_cast<Ttcn::Reference*>(u.ref.ref); + if (ttcn_ref->get_reftype() == Ref_simple::REF_THIS) { + tmp_type = ass->get_Type(); + break; + } } // else fall through default: @@ -8201,8 +8204,12 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case OPTYPE_CLASS_CREATE: { // r1 t_list2 Type* t = chk_expr_operand_undef_create(); if (u.expr.v_optype == OPTYPE_CLASS_CREATE) { - Ttcn::FormalParList* fp_list = t->get_class_type_body()->get_constructor() - ->get_FormalParList(); + Ttcn::ClassTypeBody* class_ = t->get_class_type_body(); + if (class_->is_abstract()) { + error("Cannot create an instance of abstract class type `%s'", + class_->get_my_def()->get_Type()->get_typename().c_str()); + } + Ttcn::FormalParList* fp_list = class_->get_constructor()->get_FormalParList(); Ttcn::ActualParList* parlist = new Ttcn::ActualParList; bool is_erroneous = fp_list->chk_actual_parlist(u.expr.t_list2->get_tis(), parlist); if (is_erroneous) { @@ -9602,8 +9609,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1, break; case Assignment::A_TYPE: if (ass->get_Type()->get_type_refd_last()->get_typetype() == Type::T_CLASS) { - u.ref.refd_last = this; - break; + Ttcn::Reference* ttcn_ref = static_cast<Ttcn::Reference*>(u.ref.ref); + if (ttcn_ref->get_reftype() == Ref_simple::REF_THIS) { + u.ref.refd_last = this; + break; + } } // else fall through default: diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc index 2448f1ba490474ee2d462bf852f710c2ebb7fffe..4ea2bde4f99fa552baf3480f56f93aab0143a3ed 100644 --- a/compiler2/ttcn3/AST_ttcn3.cc +++ b/compiler2/ttcn3/AST_ttcn3.cc @@ -844,7 +844,6 @@ namespace Ttcn { } } else { // params != NULL - FormalParList *fplist = NULL; if (ass->get_asstype() == Common::Assignment::A_TYPE) { Def_Type* def = dynamic_cast<Def_Type*>(ass); if (def == NULL) { @@ -854,14 +853,10 @@ namespace Ttcn { if (type->get_typetype() == Common::Type::T_CLASS) { // if the referred assignment is a class type, then the reference and // its parameters are meant for the constructor instead - fplist = type->get_class_type_body()->get_constructor()-> - get_FormalParList(); + ass = type->get_class_type_body()->get_constructor(); } } - if (fplist == NULL) { - // if it's not a class type, retrieve the formal parameter list normally - fplist = ass->get_FormalParList(); - } + FormalParList* fplist = ass->get_FormalParList(); if (fplist != NULL) { Error_Context cntxt(params, "In actual parameter list of %s", ass->get_description().c_str()); @@ -6769,7 +6764,7 @@ namespace Ttcn { if (return_type) { Error_Context cntxt2(return_type, "In return type"); return_type->chk(); - return_type->chk_as_return_type(asstype == A_FUNCTION_RVAL,"function"); + return_type->chk_as_return_type(asstype == A_FUNCTION_RVAL," function"); } if (w_attrib_path) { @@ -7454,7 +7449,7 @@ namespace Ttcn { Error_Context cntxt2(return_type, "In return type"); return_type->chk(); return_type->chk_as_return_type(asstype == A_EXT_FUNCTION_RVAL, - "external function"); + " external function"); } if (!semantic_check_only) fp_list->set_genname(get_genname()); if (w_attrib_path) { @@ -8031,7 +8026,84 @@ namespace Ttcn { void Def_AbsFunction::chk() { - // TODO + if (checked) { + return; + } + checked = true; + Error_Context cntxt(this, "In abstract function definition `%s'", + id->get_dispname().c_str()); + ClassTypeBody* my_class = my_scope->get_scope_class(); + if (my_class == NULL) { + FATAL_ERROR("Def_AbsFunction::chk"); + } + if (!my_class->is_abstract()) { + error("Concrete class type `%s' cannot have abstract methods", + my_class->get_my_def()->get_Type()->get_typename().c_str()); + } + fp_list->chk(asstype); + if (return_type != NULL) { + Error_Context cntxt2(return_type, "In return type"); + return_type->chk(); + return_type->chk_as_return_type(asstype == A_FUNCTION_RVAL, + "n abstract function"); + } + if (!semantic_check_only) { + fp_list->set_genname(get_genname()); + } + // TODO: with attributes + } + + void Def_AbsFunction::chk_implementation(Common::Assignment* p_ass, Location* p_loc) + { + switch (p_ass->get_asstype()) { + case A_FUNCTION: + case A_FUNCTION_RVAL: + case A_FUNCTION_RTEMP: { + Def_Function* def_func = dynamic_cast<Def_Function*>(p_ass); + if (def_func == NULL) { + // it's an abstract function, which means it hasn't been implemented + p_loc->error("Missing implementation of abstract method `%s'", + get_fullname().c_str()); + } + else { + // check whether they're identical + bool match = true; + if (asstype != p_ass->get_asstype()) { + match = false; + } + else if (return_type != NULL && + !def_func->get_return_type()->is_identical(return_type)) { + match = false; + } + else { + FormalParList* other_fp_list = def_func->get_FormalParList(); + if (other_fp_list->get_nof_fps() != fp_list->get_nof_fps()) { + match = false; + } + else { + for (size_t i = 0; i < fp_list->get_nof_fps(); ++i) { + FormalPar* fp1 = fp_list->get_fp_byIndex(i); + FormalPar* fp2 = other_fp_list->get_fp_byIndex(i); + if (fp1->get_asstype() != fp2->get_asstype() || + !fp1->get_Type()->is_identical(fp2->get_Type()) || + fp1->get_id().get_name() != fp2->get_id().get_name()) { + match = false; + } + } + } + } + if (!match) { + p_ass->error("The prototype of method `%s' is not identical to that " + "of inherited abstract method `%s'", + def_func->get_id().get_dispname().c_str(), get_fullname().c_str()); + } + } + break; } + default: + p_ass->error("%s shadows inherited abstract method `%s'", + p_ass->get_description().c_str(), get_fullname().c_str()); + break; + } } void Def_AbsFunction::generate_code(output_struct* target, bool) @@ -8746,9 +8818,39 @@ namespace Ttcn { fp_list->chk(asstype); + ClassTypeBody* my_class = my_scope->get_scope_class(); + ClassTypeBody* base_class = my_class->get_base_class(); if (base_call != NULL) { - Common::Assignment* base_type_ass = base_call->get_refd_assignment(true); - // TODO + Error_Context cntxt2(this, "In super-constructor call"); + if (base_class == NULL) { + base_call->error("Class type `%s' does not have a superclass", + my_class->get_my_def()->get_Type()->get_typename().c_str()); + } + else { + Common::Assignment* base_call_ass = base_call->get_refd_assignment(true); + if (base_call_ass != NULL) { + if (base_call_ass->get_asstype() != Common::Assignment::A_CONSTRUCTOR) { + base_call->error("Reference to constructor was expected instead of %s", + base_call_ass->get_assname()); + } + else { + ClassTypeBody* base_call_class = base_call_ass->get_my_scope()->get_scope_class(); + if (base_call_class != base_class) { + base_call->error("expected call to constructor of class type `%s', " + "instead of class type `%s'", + my_class->get_base_type()->get_typename().c_str(), + base_call_class->get_my_def()->get_Type()->get_typename().c_str()); + } + } + } + } + } + else if (base_class != NULL) { + Def_Constructor* base_constructor = base_class->get_constructor(); + if (base_constructor != NULL && + !base_constructor->get_FormalParList()->has_only_default_values()) { + error("Missing super-constructor call"); + } } block->chk(); diff --git a/compiler2/ttcn3/AST_ttcn3.hh b/compiler2/ttcn3/AST_ttcn3.hh index 09987327fbce4ae95bb5ee6b652a7ac2ec5c7e53..c7e856fe38fbf6495490f88eb91f0a9a15d330e5 100644 --- a/compiler2/ttcn3/AST_ttcn3.hh +++ b/compiler2/ttcn3/AST_ttcn3.hh @@ -1385,8 +1385,12 @@ namespace Ttcn { Type *get_input_type(); Type *get_output_type(); Type* get_return_type() const { return return_type; } + //virtual Type *get_RunsOnType(); template_restriction_t get_template_restriction() { return template_restriction; } + /** Checks and returns whether the function is startable. + * Reports the appropriate error message(s) if not. */ + //bool chk_startable(Location* caller_location); }; /** @@ -1611,8 +1615,8 @@ namespace Ttcn { virtual ~Def_AbsFunction(); virtual Definition* clone() const; virtual void chk(); + void chk_implementation(Common::Assignment* p_ass, Location* p_loc); virtual void generate_code(output_struct* target, bool clean_up = false); - // TODO }; /** diff --git a/compiler2/ttcn3/Statement.cc b/compiler2/ttcn3/Statement.cc index 37443c049c13ea331605c91acef2803d63fa6a7a..4cc52b8e13bc7d60ef15e824b52d86b7602ab466 100644 --- a/compiler2/ttcn3/Statement.cc +++ b/compiler2/ttcn3/Statement.cc @@ -11512,7 +11512,8 @@ error: Common::Assignment::asstype_t asstype = t_ass->get_asstype(); switch (asstype) { case Common::Assignment::A_TYPE: - if (t_ass->get_Type()->get_typetype() != Common::Type::T_CLASS) { + if (t_ass->get_Type()->get_typetype() != Common::Type::T_CLASS || + ref->get_reftype() != Common::Ref_simple::REF_THIS) { ref->error("Reference to a value, template, timer, port or class object " "was expected instead of %s", t_ass->get_description().c_str()); return; diff --git a/compiler2/ttcn3/Ttcnstuff.cc b/compiler2/ttcn3/Ttcnstuff.cc index 52faefb9850f724a84248748050e6f89dd18b688..69c31a23dc5af6e5573102fa3c9fc34aa77a04c2 100644 --- a/compiler2/ttcn3/Ttcnstuff.cc +++ b/compiler2/ttcn3/Ttcnstuff.cc @@ -2986,7 +2986,7 @@ namespace Ttcn { 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), built_in(FALSE), base_type(p_base_type), + abstract(p_abstract), built_in(FALSE), base_type(p_base_type), base_class(NULL), 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), @@ -3000,7 +3000,7 @@ namespace Ttcn { ClassTypeBody::ClassTypeBody() : Scope(), Location(), class_id(NULL), my_def(NULL), external(FALSE), final(FALSE), - abstract(TRUE), built_in(TRUE), base_type(NULL), + abstract(TRUE), built_in(TRUE), base_type(NULL), base_class(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), @@ -3018,6 +3018,7 @@ namespace Ttcn { final = p.final; abstract = p.abstract; base_type = p.base_type != NULL ? p.base_type->clone() : NULL; + base_class = p.base_class; 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; @@ -3047,6 +3048,7 @@ namespace Ttcn { if (default_constructor) { delete constructor; } + abstract_functions.clear(); } void ClassTypeBody::set_fullname(const string& p_fullname) @@ -3067,7 +3069,7 @@ namespace Ttcn { if (system_ref != NULL) { system_ref->set_fullname(p_fullname + ".<system_type>"); } - members->set_fullname(p_fullname + ".<members>"); + members->set_fullname(p_fullname); if (finally_block != NULL) { finally_block->set_fullname(p_fullname + ".<finally_block>"); } @@ -3133,6 +3135,14 @@ namespace Ttcn { return constructor; } + ClassTypeBody* ClassTypeBody::get_base_class() + { + if (!checked) { + chk(); + } + return base_class; + } + Type* ClassTypeBody::get_RunsOnType() { if (!checked) { @@ -3157,30 +3167,33 @@ namespace Ttcn { return system_type; } - bool ClassTypeBody::is_parent_class(const ClassTypeBody* p_class) const + bool ClassTypeBody::is_parent_class(const ClassTypeBody* p_class) { + if (!checked) { + chk(); + } if (this == p_class || p_class->built_in) { return true; } - if (base_type == NULL) { + if (base_class == NULL) { return false; } - return base_type->get_type_refd_last()->get_class_type_body()-> - is_parent_class(p_class); + return base_class->is_parent_class(p_class); } bool ClassTypeBody::has_local_ass_withId(const Identifier& p_id) { + if (!checked) { + chk(); + } if (built_in) { return false; } - chk(); if (members->has_local_ass_withId(p_id)) { return true; } if (base_type != NULL) { - return base_type->get_type_refd_last()->get_class_type_body()-> - has_local_ass_withId(p_id); + return base_class->has_local_ass_withId(p_id); } else { return false; @@ -3192,14 +3205,15 @@ namespace Ttcn { if (built_in) { FATAL_ERROR("ClassTypeBody::get_local_ass_byId"); } - chk(); + if (!checked) { + chk(); + } Common::Assignment* ass = NULL; if (members->has_local_ass_withId(p_id)) { ass = members->get_local_ass_byId(p_id); } - if (ass == NULL && base_type != NULL) { - ass = base_type->get_type_refd_last()->get_class_type_body()-> - get_local_ass_byId(p_id); + if (ass == NULL && base_class != NULL) { + ass = base_class->get_local_ass_byId(p_id); } return ass; } @@ -3216,8 +3230,8 @@ namespace Ttcn { return true; } - const ClassTypeBody* ref_scope_class = usage_scope->get_scope_class(); - const ClassTypeBody* ass_scope_class = ass->get_my_scope()->get_scope_class(); + ClassTypeBody* ref_scope_class = usage_scope->get_scope_class(); + ClassTypeBody* ass_scope_class = ass->get_my_scope()->get_scope_class(); if (ass_scope_class == NULL) { FATAL_ERROR("ClassTypeBody::chk_visibility()"); } @@ -3258,8 +3272,7 @@ namespace Ttcn { else { // send the reference to the base type, with the reftype changed to 'this' p_ref->set_reftype(Ref_simple::REF_THIS); - Common::Assignment* ass = base_type->get_type_refd_last()-> - get_class_type_body()->get_ass_bySRef(p_ref); + Common::Assignment* ass = base_class->get_ass_bySRef(p_ref); p_ref->set_reftype(Ref_simple::REF_SUPER); return ass; } @@ -3294,7 +3307,10 @@ namespace Ttcn { return; } checked = true; - // TODO: external? final? abstract? + if (final && abstract) { + error("Final classes cannot be abstract"); + } + // TODO: external? if (base_type != NULL) { Error_Context cntxt(base_type, "In superclass definition"); base_type->chk(); @@ -3306,11 +3322,14 @@ namespace Ttcn { delete base_type; base_type = NULL; } - // TODO: additional checks for the base type + else { + base_class = base_type->get_type_refd_last()->get_class_type_body(); + if (base_class->final) { + base_type->error("The superclass cannot be final"); + } + } } - - 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(); @@ -3375,7 +3394,6 @@ namespace Ttcn { for (size_t i = 0; i < members->get_nof_asss(); ++i) { Common::Assignment* ass = members->get_ass_byIndex(i, false); if (ass->get_asstype() == Common::Assignment::A_CONSTRUCTOR) { - // TODO: check for multiple constructors, or is that handled by previous checks? constructor = dynamic_cast<Def_Constructor*>(ass); if (constructor == NULL) { FATAL_ERROR("ClassTypeBody::chk"); @@ -3453,6 +3471,46 @@ namespace Ttcn { if (finally_block != NULL) { finally_block->chk(); } + + if (abstract) { + // create a map of all abstract functions (including inherited ones) + if (base_class != NULL && base_class->abstract) { + for (size_t i = 0; i < base_class->abstract_functions.size(); ++i) { + abstract_functions.add(base_class->abstract_functions.get_nth_key(i), + base_class->abstract_functions.get_nth_elem(i)); + } + } + for (size_t i = 0; i < members->get_nof_asss(); ++i) { + Common::Assignment* ass = members->get_ass_byIndex(i, false); + switch (ass->get_asstype()) { + case Common::Assignment::A_FUNCTION: + case Common::Assignment::A_FUNCTION_RVAL: + case Common::Assignment::A_FUNCTION_RTEMP: { + Def_AbsFunction* def_abs_func = dynamic_cast<Def_AbsFunction*>(ass); + if (def_abs_func != NULL) { + const string& def_name = def_abs_func->get_id().get_name(); + if (abstract_functions.has_key(def_name)) { + // TODO + } + else { + abstract_functions.add(def_name, def_abs_func); + } + } + break; } + default: + break; + } + } + } + + if (!abstract && base_class != NULL && base_class->abstract) { + // all abstract methods from the base class have to be implemented in this class + for (size_t i = 0; i < base_class->abstract_functions.size(); ++i) { + Def_AbsFunction* def_abs_func = base_class->abstract_functions.get_nth_elem(i); + def_abs_func->chk_implementation(get_local_ass_byId(def_abs_func->get_id()), this); + } + } + // todo: name clashes with defs in the base class? } void ClassTypeBody::chk_recursions(ReferenceChain& refch) diff --git a/compiler2/ttcn3/Ttcnstuff.hh b/compiler2/ttcn3/Ttcnstuff.hh index d6a7669c07a6704d8cc4ba6a7fdf7832fcf271c9..7e4c71cf4b1b8c3a46fcf2a85eebc3efca6812f1 100644 --- a/compiler2/ttcn3/Ttcnstuff.hh +++ b/compiler2/ttcn3/Ttcnstuff.hh @@ -756,12 +756,13 @@ public: class ClassTypeBody : public Common::Scope, public Common::Location { Common::Identifier* class_id; // not owned - Definition* my_def; // pointer to the class type definition (not owned) + Def_Type* my_def; // pointer to the class type definition (not owned) boolean external; boolean final; boolean abstract; boolean built_in; Common::Type* base_type; + ClassTypeBody* base_class; // not owned Reference* runs_on_ref; Type* runs_on_type; Reference* mtc_ref; @@ -773,6 +774,7 @@ class ClassTypeBody : public Common::Scope, public Common::Location { /** set during semantic analysis to either a pointer to the constructor in * 'members', or the actual default constructor (if no constructor is defined) */ Def_Constructor* constructor; + map<string, Def_AbsFunction> abstract_functions; bool checked; bool default_constructor; /// true if the class uses a default constructor @@ -786,7 +788,9 @@ public: ClassTypeBody* clone() const; virtual ~ClassTypeBody(); - void set_my_def(Definition* p_def) { my_def = p_def; } + void set_my_def(Def_Type* p_def) { my_def = p_def; } + Def_Type* get_my_def() { return my_def; } + boolean is_abstract() const { return abstract; } void set_fullname(const string& p_fullname); void set_my_scope(Scope* p_scope); @@ -797,13 +801,14 @@ public: Common::Identifier* get_id() const { return class_id; } Def_Constructor* get_constructor(); Common::Type* get_base_type() const { return base_type; } + ClassTypeBody* get_base_class(); boolean is_built_in() const { return built_in; } Type* get_RunsOnType(); Type* get_MtcType(); Type* get_SystemType(); - bool is_parent_class(const ClassTypeBody* p_class) const; + bool is_parent_class(const ClassTypeBody* p_class); bool has_local_ass_withId(const Identifier& p_id); Common::Assignment* get_local_ass_byId(const Identifier& p_id); Common::Assignment* get_ass_bySRef(Common::Ref_simple* p_ref); diff --git a/function_test/Semantic_Analyser/oop/oop_SE.ttcn b/function_test/Semantic_Analyser/oop/oop_SE.ttcn index b2213a0ffae5f8cf324798d4151d10b224056fce..caea0ac18accd844afc4a0815db2d994c585ff74 100644 --- a/function_test/Semantic_Analyser/oop/oop_SE.ttcn +++ b/function_test/Semantic_Analyser/oop/oop_SE.ttcn @@ -275,6 +275,113 @@ function f_no_comp_usage() { //^In function definition// } +type class C15 { + public var integer v; + public function f() { } + public function g() return boolean { return true; } +} + +function f_access_with_class_name() { //^In function definition// + log(C5.v); //^In log statement// //Reference to a value, template, timer, port or class object was expected instead of type `@oop_SE.C5'// + log(C5.g()); //^In log statement// //Reference to a value, template, timer, port or class object was expected instead of type `@oop_SE.C5'// + C5.f(); //Reference to a function or altstep was expected instead of type `@oop_SE.C5', which cannot be invoked// + C5.g(); //Reference to a function or altstep was expected instead of type `@oop_SE.C5', which cannot be invoked// + if (C5.g()) { log(1); } //^In if statement// //Reference to a value was expected instead of type `@oop_SE.C5'// + if (C5.v == 1) { log(2); } //^In if statement// //Reference to a value was expected instead of type `@oop_SE.C5'// + var integer x1 := C5.v + 1; //^In variable definition// //^In the left operand of operation// //Reference to a value was expected instead of type `@oop_SE.C5'// + var boolean x2 := C5.g(); //^In variable definition// //Reference to a value was expected instead of type `@oop_SE.C5'// +} + + +function f_init_values() { //^In function definition// + var integer v_int := 3; + var template integer vt_int := (1..10); + var C4 v1 := 1; //^In variable definition// //class value was expected// + var C4 v2 := v_int; //^In variable definition// //Type mismatch\: a value of type `@oop_SE.C4' was expected instead of `integer'// + var C4 v3 := valueof(vt_int) + v_int; //^In variable definition// //Incompatible value\: `@oop_SE.C4' value was expected// + var C4 v4 := CT_RunsOn.create; //^In variable definition// //Incompatible value\: `@oop_SE.C4' value was expected// + var C4 v5 := C11.create; //^In variable definition// //Incompatible class types\: operation `create' should refer to `@oop_SE.C4' instead of `@oop_SE.C11'// +} + + +type class C16 extends C15 { //^In type definition// + create() : C15(1) { } //Previous definition of `create' is here// + create(in integer p) : C15(p) { } //Duplicate definition with name `create'// +} + +type class C17 { //^In type definition// + create() : C15(1) { } //^In constructor definition// //^In super-constructor call// //Class type `@oop_SE.C17' does not have a superclass// +} + +type class C18 extends C15 { //^In type definition// + create() : C16() { } //^In constructor definition// //^In super-constructor call// //expected call to constructor of class type `@oop_SE.C15', instead of class type `@oop_SE.C16'// +} + +type class C19 extends C15 { //^In type definition// + create() { } //^In constructor definition// //Missing super-constructor call// +} + +type class C20 extends C15 { //^In type definition// + create() : f_embedded_types() { } //^In constructor definition// //^In super-constructor call// //Reference to constructor was expected instead of function// +} + + +type class @final @abstract C21 { } //^In type definition// //Final classes cannot be abstract// + +type class @final C22 { } + +type class C23 extends C22 { } //^In type definition// //^In superclass definition// //The superclass cannot be final// + +type class @abstract C24 { //^In type definition// + public function @abstract f1(in Nonexistent a); //^In abstract function definition// //^In formal parameter list// //^In parameter// //There is no local or imported definition with name `Nonexistent'// + public function @abstract f2() return template Nonexistent; //^In abstract function definition// //^In return type// //There is no local or imported definition with name `Nonexistent'// + public function @abstract f3() return Port; //^In abstract function definition// //^In return type// //Port type `@oop_SE.Port' cannot be the return type of an abstract function// +} + +function f_inst_abstract() { //^In function definition// + var C24 x := C24.create; //^In variable definition// //Cannot create an instance of abstract class type `@oop_SE.C24'// +} + +type class @abstract C25 { + public function @abstract f_abs() return integer; +} + +type class @abstract C26 extends C25 { + public function @abstract f_abs2(inout template integer p); +} + +type class C27 extends C26 { } //^In type definition// //Missing implementation of abstract method `@oop_SE.C25.f_abs'// //Missing implementation of abstract method `@oop_SE.C26.f_abs2'// + +type class C28 extends C25 { //^In type definition// + public var integer f_abs; //variable `@oop_SE.C28.f_abs' shadows inherited abstract method `@oop_SE.C25.f_abs'// +} + +type class C29 extends C26 { //^In type definition// //Missing implementation of abstract method `@oop_SE.C25.f_abs'// + public function f_abs2(inout template integer p) { } +} + +type class C30 extends C26 { + public function f_abs() return integer { return 1; } + public function f_abs2(inout template integer p) { } +} + +type class C31 extends C25 { //^In type definition// + public function f_abs(in template integer p) { } //The prototype of method `f_abs' is not identical to that of inherited abstract method `@oop_SE.C25.f_abs'// +} + +type class C32 extends C25 { //^In type definition// + public function f_abs(inout integer p) { } //The prototype of method `f_abs' is not identical to that of inherited abstract method `@oop_SE.C25.f_abs'// +} + +type class C33 extends C25 { //^In type definition// + public function f_abs(inout template integer q) { } //The prototype of method `f_abs' is not identical to that of inherited abstract method `@oop_SE.C25.f_abs'// +} + +type class C34 extends C25 { //^In type definition// + public function f_abs(inout template integer p) return boolean { return false; } //The prototype of method `f_abs' is not identical to that of inherited abstract method `@oop_SE.C25.f_abs'// +} + + 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.// } diff --git a/regression_test/oop/oop.ttcn b/regression_test/oop/oop.ttcn index 63601f402adac2a579339c4dfbbcccffb78501d6..047ceadb4c1943d864e86aba03e88db72ceecc29 100644 --- a/regression_test/oop/oop.ttcn +++ b/regression_test/oop/oop.ttcn @@ -460,6 +460,17 @@ testcase tc_order() runs on CT { } } +testcase tc_abstract() runs on CT { + var AbstractClass v := ConcreteClass.create; + var integer x := 0; + if (v.f_abs(x) and x == 1) { + setverdict(pass); + } + else { + setverdict(fail); + } +} + control { execute(tc_members_and_methods()); @@ -471,6 +482,7 @@ control { execute(tc_function_pars_and_retval()); execute(tc_object()); execute(tc_order()); + execute(tc_abstract()); } }