浏览代码

[cpp] Enum Type Checking (#11444)

* Give enums a unique class ID

* Add more type check scaffolding

* Add test

* Use Int32.zero
Aidan Lee 1 年之前
父节点
当前提交
4a175dfdb4
共有 2 个文件被更改,包括 45 次插入3 次删除
  1. 23 3
      src/generators/gencpp.ml
  2. 22 0
      tests/unit/src/unit/issues/Issue11442.hx

+ 23 - 3
src/generators/gencpp.ml

@@ -3442,7 +3442,7 @@ let cpp_class_hash interface =
 let rec is_constant_zero expr =
   match expr.cppexpr with
   | CppFloat x when (float_of_string x) = 0.0 -> true
-  | CppInt i when i = Int32.of_int 0 -> true
+  | CppInt i when i = Int32.zero -> true
   | CppCastScalar(expr,_) -> is_constant_zero(expr)
   | _ -> false
 ;;
@@ -5238,6 +5238,9 @@ let generate_enum_files baseCtx enum_def super_deps meta =
    let ctx = file_context baseCtx cpp_file debug false in
    let strq = strq ctx.ctx_common in
 
+   let classId = try Hashtbl.find baseCtx.ctx_type_ids (class_text enum_def.e_path) with Not_found -> Int32.zero in
+   let classIdTxt = Printf.sprintf "0x%08lx" classId in
+
    if (debug>1) then
       print_endline ("Found enum definition:" ^ (join_class_path  class_path "::" ));
 
@@ -5279,6 +5282,10 @@ let generate_enum_files baseCtx enum_def super_deps meta =
 
    output_cpp ("HX_DEFINE_CREATE_ENUM(" ^ class_name ^ ")\n\n");
 
+   output_cpp ("bool " ^ class_name ^ "::_hx_isInstanceOf(int inClassId) {\n");
+   output_cpp ("\treturn inClassId == (int)0x00000001 || inClassId == ::hx::EnumBase_obj::_hx_ClassId || inClassId == _hx_ClassId;\n");
+   output_cpp ("}\n");
+
    output_cpp ("int " ^ class_name ^ "::__FindIndex(::String inName)\n{\n");
    PMap.iter (fun _ constructor ->
       let name = constructor.ef_name in
@@ -5390,13 +5397,15 @@ let generate_enum_files baseCtx enum_def super_deps meta =
    output_h ("{\n\ttypedef " ^ super ^ " super;\n");
    output_h ("\t\ttypedef " ^ class_name ^ " OBJ_;\n");
    output_h "\n\tpublic:\n";
+   output_h ("\t\tenum { _hx_ClassId = " ^ classIdTxt ^ " };\n\n");
    output_h ("\t\t" ^ class_name ^ "() {};\n");
    output_h ("\t\tHX_DO_ENUM_RTTI;\n");
    output_h ("\t\tstatic void __boot();\n");
    output_h ("\t\tstatic void __register();\n");
    output_h ("\t\tstatic bool __GetStatic(const ::String &inName, Dynamic &outValue, ::hx::PropertyAccess inCallProp);\n");
    output_h ("\t\t::String GetEnumName( ) const { return " ^ (strq (join_class_path class_path "."))  ^ "; }\n" );
-   output_h ("\t\t::String __ToString() const { return " ^ (strq (just_class_name ^ ".") )^ " + _hx_tag; }\n\n");
+   output_h ("\t\t::String __ToString() const { return " ^ (strq (just_class_name ^ ".") )^ " + _hx_tag; }\n");
+   output_h ("\t\tbool _hx_isInstanceOf(int inClassId);\n\n");
 
 
    PMap.iter (fun _ constructor ->
@@ -5761,7 +5770,7 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta
       then 0 else 1 in
    let scriptable = inScriptable && not class_def.cl_private in
 
-   let classId = try Hashtbl.find baseCtx.ctx_type_ids (class_text class_def.cl_path) with Not_found -> Int32.of_int 0 in
+   let classId = try Hashtbl.find baseCtx.ctx_type_ids (class_text class_def.cl_path) with Not_found -> Int32.zero in
    let classIdTxt = Printf.sprintf "0x%08lx" classId in
 
    (* Config *)
@@ -8564,6 +8573,17 @@ let generate_source ctx =
          if (is_internal) then
             (if (debug>1) then print_endline (" internal enum " ^ name ))
          else begin
+            let rec makeId enum_name seed =
+               let id = gen_hash32 seed enum_name in
+               (* reserve first 100 ids for runtime *)
+               if id < Int32.of_int 100 || Hashtbl.mem existingIds id then
+                  makeId enum_name (seed+100)
+               else begin
+                  Hashtbl.add existingIds id true;
+                  Hashtbl.add ctx.ctx_type_ids enum_name id;
+               end in
+            makeId name 0;
+
             let meta = Texpr.build_metadata common_ctx.basic object_def in
             if (enum_def.e_extern) then
                (if (debug>1) then print_endline ("external enum " ^ name ));

+ 22 - 0
tests/unit/src/unit/issues/Issue11442.hx

@@ -0,0 +1,22 @@
+package unit.issues;
+
+import utest.Assert;
+
+enum Dummy {
+	DummyCtor;
+}
+
+class Issue11442 extends Test {
+    function test() {
+        f(Std.isOfType(DummyCtor, haxe.ds.Option));
+        t(Std.isOfType(DummyCtor, Dummy));
+
+        try {
+            throw DummyCtor;
+        } catch(e:haxe.ds.Option<Dynamic>) {
+            Assert.fail("wrong catch");
+        } catch(e:Dummy) {
+            Assert.pass("correct catch");
+        }
+    }
+}