diff --git a/compiler2/Value.cc b/compiler2/Value.cc index 3d69ee615fb8a64b99db4fe20c98e026c3eda2d6..2e2d933d83f76927ef570ed989ed89a76a736637 100644 --- a/compiler2/Value.cc +++ b/compiler2/Value.cc @@ -8477,22 +8477,16 @@ void Value::chk_expr_operand_execute_refd(Value *v1, } erroneous = true; } - else if (u.expr.v_optype == OPTYPE_CLASS_CASTING) { + else if (u.expr.v_optype == OPTYPE_CLASS_CASTING && !erroneous) { Ttcn::ClassTypeBody* new_class = type_last->get_class_type_body(); - if (new_class->is_abstract()) { - u.expr.type->error("Cannot cast to abstract class type `%s'", + Ttcn::ClassTypeBody* old_class = ref_type_last->get_class_type_body(); + if (!new_class->is_parent_class(old_class) && + !old_class->is_parent_class(new_class)) { + u.expr.type->error("Cannot cast an object of class type `%s' " + "to class type `%s'", + ref_type_last->get_typename().c_str(), u.expr.type->get_typename().c_str()); } - if (!erroneous) { - Ttcn::ClassTypeBody* old_class = ref_type_last->get_class_type_body(); - if (!new_class->is_parent_class(old_class) && - !old_class->is_parent_class(new_class)) { - u.expr.type->error("Cannot cast an object of class type `%s' " - "to class type `%s'", - ref_type_last->get_typename().c_str(), - u.expr.type->get_typename().c_str()); - } - } } } if (erroneous) { @@ -14138,6 +14132,8 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Code::free_expr(&ref_expr); break; } case OPTYPE_CLASS_CASTING: { + Ttcn::ClassTypeBody* exp_class = u.expr.type->get_type_refd_last()-> + get_class_type_body(); expression_struct_t ref_expr; Code::init_expr(&ref_expr); u.expr.r2->generate_code(&ref_expr); @@ -14146,7 +14142,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1, } expr->expr = mputprintf(expr->expr, "%s.cast_to<%s>()", - ref_expr.expr, + ref_expr.expr, exp_class->is_built_in() ? "OBJECT" : u.expr.type->get_type_refd_last()->get_genname_own(my_scope).c_str()); if (ref_expr.postamble != NULL) { expr->postamble = mputstr(expr->postamble, ref_expr.postamble); diff --git a/compiler2/ttcn3/compiler.y b/compiler2/ttcn3/compiler.y index 3a818e72f092a566cd600d8bbbc335eae26e5256..9f5c4a18adab05472fbfe0710f7c47bb98a8fc53 100644 --- a/compiler2/ttcn3/compiler.y +++ b/compiler2/ttcn3/compiler.y @@ -10257,6 +10257,13 @@ ClassCastingOp: $$ = new Value(Value::OPTYPE_CLASS_CASTING, $3, $1); $$->set_location(infile, @$); } +| VariableRef ClassCastingSymbol ObjectKeyword + { + Type* type = new Type(Type::T_CLASS); + type->set_location(infile, @3); + $$ = new Value(Value::OPTYPE_CLASS_CASTING, type, $1); + $$->set_location(infile, @$); + } | VariableRef ClassCastingSymbol '(' VariableRef ')' { $$ = new Value(Value::OPTYPE_CLASS_CASTING_REF, $4, $1); diff --git a/function_test/Semantic_Analyser/oop/oop_SE.ttcn b/function_test/Semantic_Analyser/oop/oop_SE.ttcn index 4eade8c7ea95a3f7daf1c71766feceb70ecd6fda..cfd560a454f85f23419d3e94e493a203e14d3b60 100644 --- a/function_test/Semantic_Analyser/oop/oop_SE.ttcn +++ b/function_test/Semantic_Analyser/oop/oop_SE.ttcn @@ -506,7 +506,7 @@ function f_casting() { //^In function definition// var C35 x1 := C36.create; var C36 x2 := x1 => C36; var C0 x3 := x1 => C0; //^In variable definition// //^In the second operand of operation `=>'// //Cannot cast an object of class type `@oop_SE.C35' to class type `@oop_SE.C0'// - var C35 x4 := x2 => (x1); //^In variable definition// //^In the second operand of operation `=>'// //Cannot cast to abstract class type `@oop_SE.C35'// + var C35 x4 := x2 => (x1); var C36 x5 := c => C36; //^In variable definition// //^In the first operand of operation `=>'// //Reference to a variable or value parameter was expected instead of constant `@oop_SE.c'// var Rec x6 := x1 => Rec; //^In variable definition// //^In the second operand of operation `=>'// //Class type was expected// var integer x7 := x1 => (x6); //^In variable definition// //^In the second operand of operation `=>'// //Class type was expected// diff --git a/regression_test/oop/oop.ttcn b/regression_test/oop/oop.ttcn index 0c088dcba7bbba1aaa40832ee98ec2ba8c598a25..e48e24ee81950e594f9c40a4db0dada92a333d65 100644 --- a/regression_test/oop/oop.ttcn +++ b/regression_test/oop/oop.ttcn @@ -390,8 +390,8 @@ testcase tc_references() runs on CT { type class Node { - var integer data; - var Node next; + public var integer data; + public var Node next; } function f_test(in Node p1, inout Node p2, out Node p3, @@ -435,8 +435,8 @@ testcase tc_function_pars_and_retval() runs on CT { } type class Node2 { - var object data; - var Node2 next; + public var object data; + public var Node2 next; } type class Something { @@ -624,10 +624,10 @@ testcase tc_casting() runs on CT { var object v_obj := Node.create(3, null); var BaseClass v_null := null; var Node v_null2 := null; + var object v_con := ConcreteClass.create; var BaseClass v_base := v_sub => BaseClass; - var BaseClass v_base2 := v_sub; - if (log2str(v_base) != log2str(v_base2)) { + if (log2str(v_base) != log2str(v_sub)) { setverdict(fail, "#1: ", v_base); } var FinalClass v_final2 := v_final => FinalClass; @@ -642,24 +642,36 @@ testcase tc_casting() runs on CT { if (log2str(v_sub2) != log2str(v_sub)) { setverdict(fail, "#4: ", v_sub2); } + var object v_obj2 := v_sub => object; + if (log2str(v_obj2) != log2str(v_sub)) { + setverdict(fail, "#5: ", v_obj2); + } + var AbstractClass v_abs := v_con => AbstractClass; + if (log2str(v_abs) != log2str(v_con)) { + setverdict(fail, "#6: ", v_abs); + } @try { var SubClass v_bad := v_null => SubClass; - setverdict(fail, "#5: Error expected"); + setverdict(fail, "#7: Error expected"); } @catch(msg) { if (not match(msg, pattern "*Casting a null reference")) { - setverdict(fail, "#5: Invalid error: ", msg); + setverdict(fail, "#7: Invalid error: ", msg); } } @try { var FinalClass v_bad2 := v_sub => FinalClass; - setverdict(fail, "#6: Error expected"); + setverdict(fail, "#8: Error expected"); } @catch(msg) { if (not match(msg, pattern "*Invalid casting to class type `FinalClass'")) { - setverdict(fail, "#6: Invalid error: ", msg); + setverdict(fail, "#8: Invalid error: ", msg); } } + /*var integer v_int := (v_obj => Node).data; + if (v_int != 3) { + setverdict(fail, "#9: ", v_int); + }*/ setverdict(pass); }