Преглед на файлове

[java/cs] String cast will now call haxe.lang.Runtime.toString() instead of doing _ + "", in order to correctly handle null cases. Fixed Issue #941

Caue Waneck преди 13 години
родител
ревизия
9bd631db95
променени са 5 файла, в които са добавени 19 реда и са изтрити 6 реда
  1. 5 1
      gencommon.ml
  2. 1 3
      gencs.ml
  3. 1 2
      genjava.ml
  4. 6 0
      std/cs/_std/haxe/lang/Runtime.hx
  5. 6 0
      std/java/_std/haxe/lang/Runtime.hx

+ 5 - 1
gencommon.ml

@@ -164,6 +164,8 @@ let debug_mode = ref false
 let trace s = if !debug_mode then print_endline s else ()
 let timer name = if !debug_mode then Common.timer name else fun () -> ()
 
+let is_string t = match follow t with | TInst({ cl_path = ([], "String") }, []) -> true | _ -> false
+
 (* helper function for creating Anon types of class / enum modules *)
 
 let anon_of_classtype cl =
@@ -1883,7 +1885,6 @@ struct
   let priority_as_synf = 100.0 (*solve_deps name [DBefore ExpressionUnwrap.priority]*)
   
   let abstract_implementation gen (should_change:texpr->bool) (equals_handler:texpr->texpr->texpr) (dyn_plus_handler:texpr->texpr->texpr->texpr) (compare_handler:texpr->texpr->texpr) =
-    let is_string t = match follow t with | TInst({ cl_path = ([], "String") }, []) -> true | _ -> false in
     
     let get_etype_one e =
       match follow e.etype with
@@ -4545,6 +4546,9 @@ struct
         | TBinop ( (Ast.OpAssign as op),e1,e2)
         | TBinop ( (Ast.OpAssignOp _ as op),e1,e2) ->
           { e with eexpr = TBinop(op, Type.map_expr run e1, handle (run e2) e1.etype e2.etype) }
+        (* this is an exception so we can avoid infinite loop on Std.String and haxe.lang.Runtime.toString(). It also takes off unnecessary casts to string *)
+        | TBinop ( Ast.OpAdd, ( { eexpr = TCast(e1, _) } as e1c), e2 ) when is_string e1c.etype && is_string e2.etype ->
+          { e with eexpr = TBinop( Ast.OpAdd, run e1, run e2 ) }
         | TField(ef, f) ->
           handle_type_parameter gen None e (run ef) f [] impossible_tparam_is_dynamic
         | TArrayDecl el ->

+ 1 - 3
gencs.ml

@@ -297,9 +297,7 @@ struct
           
           if needs_cast then mk_cast e.etype ret else ret
         | TCast(expr, _) when is_string e.etype ->
-          (*{ e with eexpr = TCall( { expr with eexpr = TField(expr, "ToString"); etype = TFun([], basic.tstring) }, [] ) }*)
-          mk_paren { e with eexpr = TBinop(Ast.OpAdd, run expr, { e with eexpr = TConst(TString("")) }) }
-        
+          { e with eexpr = TCall( mk_static_field_access_infer runtime_cl "toString" expr.epos [], [expr] ) }
         | TBinop( (Ast.OpNotEq as op), e1, e2)
         | TBinop( (Ast.OpEq as op), e1, e2) when is_string e1.etype || is_string e2.etype ->
           let mk_ret e = match op with | Ast.OpNotEq -> { e with eexpr = TUnop(Ast.Not, Ast.Prefix, e) } | _ -> e in

+ 1 - 2
genjava.ml

@@ -557,8 +557,7 @@ struct
           in
           if need_second_cast then { e with eexpr = TCast(mk_cast (follow e.etype) (run expr), c) }  else Type.map_expr run e*)
         | TCast(expr, _) when is_string e.etype ->
-          (*{ e with eexpr = TCall( { expr with eexpr = TField(expr, "ToString"); etype = TFun([], basic.tstring) }, [] ) }*)
-          mk_paren { e with eexpr = TBinop(Ast.OpAdd, run expr, { e with eexpr = TConst(TString("")) }) }
+          { e with eexpr = TCall( mk_static_field_access_infer runtime_cl "toString" expr.epos [], [expr] ) }
           
         | TSwitch(cond, ecases, edefault) when is_string cond.etype ->
           (*let change_string_switch gen eswitch e1 ecases edefault =*)

+ 6 - 0
std/cs/_std/haxe/lang/Runtime.hx

@@ -413,6 +413,12 @@ package haxe.lang;
 		return null;
 	}
 	
+	public static function toString(obj:Dynamic):String
+	{
+		if (obj == null) 
+			return null;
+		return obj + "";
+	}
 }
 
 @:native("haxe.lang.EmptyObject") private enum EmptyObject

+ 6 - 0
std/java/_std/haxe/lang/Runtime.hx

@@ -540,6 +540,12 @@ package haxe.lang;
 		return null;
 	}
 	
+	public static function toString(obj:Dynamic):String
+	{
+		if (obj == null) 
+			return null;
+		return obj + "";
+	}
 }
 
 @:native("haxe.lang.EmptyObject") private enum EmptyObject