Browse Source

Merge branch 'development' of github.com:HaxeFoundation/haxe into hl

Nicolas Cannasse 9 years ago
parent
commit
62f1a6f2ab

+ 2 - 2
.gitignore

@@ -74,5 +74,5 @@ tests/unit/bin/
 tests/*.n
 tests/misc/projects/Issue3756/cpp/
 tests/misc/projects/Issue4070/cpp/
-/tests/unit/unit_hl.hxml
-/*.manifest
+
+/*.manifest

+ 68 - 2
.travis.yml

@@ -37,7 +37,71 @@ matrix:
     # linux #
     #########
     - os: linux
-      env: TEST=hl
+      env: TEST=third-party
+      language: php
+      php: 5.4
+      addons: {apt: {packages: [*apt_cpp, *apt_cs, *apt_python]}}
+    - os: linux
+      env: TEST=macro
+      addons: {apt: {packages: [*apt_cs, *apt_python]}}
+    - os: linux
+      env:
+        - TEST=neko
+        - BINTRAY=1
+    - os: linux
+      env:
+        - TEST=js
+        - SAUCE=1
+      addons: {apt: {packages: *apt_common}, sauce_connect: true}
+    - os: linux
+      env: TEST=php
+      language: php
+      php: 5.4
+    - os: linux
+      env: TEST=cpp
+      addons: {apt: {packages: *apt_cpp}}
+    - os: linux
+      env: TEST=flash9
+      addons: {apt: {packages: *apt_flash}}
+    - os: linux
+      env: TEST=as3
+      addons: {apt: {packages: *apt_flash}}
+    - os: linux
+      env: TEST=java
+    - os: linux
+      env: TEST=cs
+      addons: {apt: {packages: *apt_cs}}
+    - os: linux
+      env: TEST=python
+      addons: {apt: {packages: *apt_python}}
+
+    #######
+    # osx #
+    #######
+    - os: osx
+      env: TEST=third-party
+    - os: osx
+      env: TEST=macro
+    - os: osx
+      env:
+        - TEST=neko
+        - BINTRAY=1
+    - os: osx
+      env: TEST=js
+    - os: osx
+      env: TEST=php
+    - os: osx
+      env: TEST=cpp
+    - os: osx
+      env: TEST=flash9
+    - os: osx
+      env: TEST=as3
+    - os: osx
+      env: TEST=java
+    - os: osx
+      env: TEST=cs
+    - os: osx
+      env: TEST=python
 
 install:
   # Install haxe and neko dependencies
@@ -62,8 +126,10 @@ before_script:
   - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then
     travis_retry brew install mysql &&
     mysql.server start;
+    mysql -u root -e "create user if not exists travis@localhost identified by '';";
     fi
-  - mysql -u root -e "CREATE DATABASE haxe_test;";
+  - mysql -u root -e "CREATE DATABASE haxe_test;"
+  - mysql -u root -e "grant all on haxe_test.* to travis@localhost;"
 
 script:
   - make package_src -s

+ 15 - 6
analyzer.ml

@@ -591,6 +591,11 @@ module Fusion = struct
 							change_num_uses v2 (-1);
 							let e = (f {e1 with eexpr = TUnop(op,Postfix,ev)}) in
 							fuse (e :: acc) el
+						| TLocal v2 when v == v2 ->
+							changed := true;
+							change_num_uses v2 (-1);
+							let e = (f {e1 with eexpr = TUnop(op,Prefix,ev)}) in
+							fuse (e :: acc) el
 						| _ ->
 							raise Exit
 					end
@@ -683,8 +688,8 @@ module BasicBlock = struct
 		bb_kind : block_kind;                 (* The block kind *)
 		mutable bb_closed : bool;             (* Whether or not the block has been closed *)
 		(* elements *)
-		bb_el : texpr DynArray.t;     (* The block expressions *)
-		bb_phi : texpr DynArray.t;    (* SSA-phi expressions *)
+		bb_el : texpr DynArray.t;             (* The block expressions *)
+		bb_phi : texpr DynArray.t;            (* SSA-phi expressions *)
 		(* relations *)
 		mutable bb_outgoing : cfg_edge list;  (* Outgoing edges *)
 		mutable bb_incoming : cfg_edge list;  (* Incoming edges *)
@@ -751,7 +756,7 @@ module Graph = struct
 		mutable g_functions : tfunc_info IntMap.t; (* A map of functions, indexed by their block IDs *)
 		mutable g_nodes : BasicBlock.t IntMap.t;   (* A map of all blocks *)
 		mutable g_cfg_edges : cfg_edge list;       (* A list of all CFG edges *)
-		g_var_infos : var_info DynArray.t; (* A map of variable information *)
+		g_var_infos : var_info DynArray.t;         (* A map of variable information *)
 		mutable g_loops : BasicBlock.t IntMap.t;   (* A map containing loop information *)
 	}
 
@@ -900,6 +905,7 @@ type analyzer_context = {
 	com : Common.context;
 	config : Config.t;
 	graph : Graph.t;
+	temp_var_name : string;
 	mutable entry : BasicBlock.t;
 	mutable has_unbound : bool;
 	mutable loop_counter : int;
@@ -1085,7 +1091,7 @@ module TexprTransformer = struct
 					fl,e
 			in
 			let fl,e = loop [] e in
-			let v = alloc_var "tmp" e.etype in
+			let v = alloc_var ctx.temp_var_name e.etype in
 			begin match ctx.com.platform with
 				| Cpp when sequential && not (Common.defined ctx.com Define.Cppia) -> ()
 				| _ -> v.v_meta <- [Meta.CompilerGenerated,[],e.epos];
@@ -1447,6 +1453,9 @@ module TexprTransformer = struct
 			com = com;
 			config = config;
 			graph = g;
+			(* For CPP we want to use variable names which are "probably" not used by users in order to
+			   avoid problems with the debugger, see https://github.com/HaxeFoundation/hxcpp/issues/365 *)
+			temp_var_name = (match com.platform with Cpp -> "_hx_tmp" | _ -> "tmp");
 			entry = g.g_unreachable;
 			has_unbound = false;
 			loop_counter = 0;
@@ -2229,7 +2238,7 @@ module CodeMotion = DataFlow(struct
 					let v' = if decl then begin
 						v
 					end else begin
-						let v' = alloc_var "tmp" v.v_type in
+						let v' = alloc_var ctx.temp_var_name v.v_type in
 						declare_var ctx.graph v';
 						v'.v_meta <- [Meta.CompilerGenerated,[],p];
 						v'
@@ -2702,8 +2711,8 @@ module Purity = struct
 			taint node
 		| Some e ->
 			try
-				if is_pure c cf then raise Exit;
 				if (Meta.has (Meta.Custom ":impure")) cf.cf_meta then taint_raise node;
+				if is_pure c cf then raise Exit;
 				loop e;
 				node.pn_purity <- Pure;
 			with Exit ->

+ 11 - 0
appveyor.yml

@@ -14,10 +14,16 @@ environment:
         WODI: wodi32
         ADD_REVISION: 1
         OCAMLOPT: ocamlopt.opt
+        MYSQL_PATH: C:\Program Files\MySQL\MySQL Server 5.6
+        MYSQL_USER: root
+        MYSQL_PASSWORD: Password12!
     matrix:
         - TEST: "neko,python,cs,java,macro"
         - TEST: "cpp"
 
+services:
+    - mysql
+
 skip_tags: true
 
 install:
@@ -60,6 +66,11 @@ build_script:
     - cd %APPVEYOR_BUILD_FOLDER%/tests/
     - mkdir "%HAXELIB_ROOT%"
     - haxelib setup "%HAXELIB_ROOT%"
+    # setup mysql for testing
+    - set PATH=%MYSQL_PATH%\bin;%PATH%
+    - mysql --user=%MYSQL_USER% --password=%MYSQL_PASSWORD% -e "create user 'travis'@'localhost';"
+    - mysql --user=%MYSQL_USER% --password=%MYSQL_PASSWORD% -e "create database haxe_test;"
+    - mysql --user=%MYSQL_USER% --password=%MYSQL_PASSWORD% -e "grant all on haxe_test.* to 'travis'@'localhost';"
 
 test_script:
     - cd %APPVEYOR_BUILD_FOLDER%/tests/

+ 7 - 0
filters.ml

@@ -540,6 +540,13 @@ let rename_local_vars ctx e =
 		while PMap.mem (v.v_name ^ string_of_int !count) vars do
 			incr count;
 		done;
+		begin match ctx.com.platform with
+			| Cpp ->
+				if not (Meta.has Meta.RealPath v.v_meta) then
+					v.v_meta <- (Meta.RealPath,[EConst (String v.v_name),e.epos],e.epos) :: v.v_meta
+			| _ ->
+				()
+		end;
 		v.v_name <- v.v_name ^ string_of_int !count;
 	in
 	let declare v p =

+ 36 - 17
gencpp.ml

@@ -60,6 +60,7 @@ let is_internal_class = function
    |  (["cpp"],"Pointer") | (["cpp"],"ConstPointer")
    |  (["cpp"],"RawPointer") | (["cpp"],"RawConstPointer")
    |  (["cpp"],"Function") -> true
+   |  (["cpp"],"VirtualArray") -> true
    |  ([],"Math") | (["haxe";"io"], "Unsigned_char__") -> true
    |  (["cpp"],"Int8") | (["cpp"],"UInt8") | (["cpp"],"Char")
    |  (["cpp"],"Int16") | (["cpp"],"UInt16")
@@ -626,7 +627,8 @@ let rec class_string klass suffix params remap =
    (match klass.cl_path with
    (* Array class *)
    |  ([],"Array") when is_dynamic_array_param (List.hd params) ->
-           "cpp::ArrayBase" ^ suffix (* "Dynamic" *)
+           "cpp::ArrayBase" ^ suffix
+           (* "cpp::VirtualArray" ^ suffix *)
    |  ([],"Array") -> (snd klass.cl_path) ^ suffix ^ "< " ^ (String.concat ","
                (List.map array_element_type params) ) ^ " >"
    (* FastIterator class *)
@@ -1317,6 +1319,7 @@ let find_undeclared_variables_ctx ctx undeclared declarations this_suffix allow_
    find_undeclared_variables undeclared declarations this_suffix allow_this expression
 ;;
 
+let is_virtual_array expr = (type_string expr.etype="cpp::VirtualArray") ;;
 
 let rec is_dynamic_in_cpp ctx expr =
    let expr_type = type_string ( match follow expr.etype with TFun (args,ret) -> ret | _ -> expr.etype) in
@@ -1348,7 +1351,7 @@ let rec is_dynamic_in_cpp ctx expr =
             )
       | TConst TThis when ((not ctx.ctx_real_this_ptr) && ctx.ctx_dynamic_this_ptr) ->
             ctx.ctx_dbgout ("/* dthis */"); true
-      | TArray (obj,index) -> let dyn = is_dynamic_in_cpp ctx obj in
+      | TArray (obj,index) -> let dyn = (is_dynamic_in_cpp ctx obj || is_virtual_array obj) in
             ctx.ctx_dbgout ("/* aidr:" ^ (if dyn then "Dyn" else "Not") ^ " */");
             dyn;
       | TTypeExpr _ -> false
@@ -1399,18 +1402,20 @@ and is_dynamic_member_return_in_cpp ctx field_object field =
    | TTypeExpr t ->
          let full_name = "::" ^ (join_class_path (t_path t) "::" ) ^ "." ^ member in
          ctx.ctx_dbgout ("/*static:"^ full_name^"*/");
-         ( try ( let mem_type = (Hashtbl.find ctx.ctx_class_member_types full_name) in mem_type="Dynamic"||mem_type="cpp::ArrayBase" )
+         ( try ( let mem_type = (Hashtbl.find ctx.ctx_class_member_types full_name) in
+             mem_type="Dynamic" || mem_type="cpp::ArrayBase" || mem_type="cpp::VirtualArray" )
          with Not_found -> true )
    | _ ->
       let tstr = type_string field_object.etype in
       (match tstr with
          (* Internal classes have no dynamic members *)
          | "::String" | "Null" | "::hx::Class" | "::Enum" | "::Math" | "::ArrayAccess" -> false
-         | "Dynamic" | "cpp::ArrayBase" -> ctx.ctx_dbgout "/*D*/"; true
+         | "Dynamic" | "cpp::ArrayBase" | "cpp::VirtualArray" -> ctx.ctx_dbgout "/*D*/"; true
          | name ->
                let full_name = name ^ "." ^ member in
                ctx.ctx_dbgout ("/*R:"^full_name^"*/");
-               try ( let mem_type = (Hashtbl.find ctx.ctx_class_member_types full_name) in mem_type="Dynamic"||mem_type="cpp::ArrayBase" )
+               try ( let mem_type = (Hashtbl.find ctx.ctx_class_member_types full_name) in
+                  mem_type="Dynamic" || mem_type="cpp::ArrayBase" || mem_type="cpp::VirtualArray" )
                with Not_found -> true )
 ;;
 
@@ -1950,10 +1955,14 @@ let gen_expression_tree ctx retval expression_tree set_var tail_code =
                output ( "." ^ remap_name )
             else begin
                cast_if_required ctx field_object (type_string field_object.etype);
-               let remap_name = if (type_string field_object.etype)="cpp::ArrayBase" then
-                   match remap_name with
-                   | "length" -> remap_name
-                   | _ -> "__" ^ remap_name
+               let field_type = type_string field_object.etype in
+               let remap_name = if remap_name="length" then begin
+                  if field_type="cpp::VirtualArray" then
+                     "__length()"
+                  else
+                     remap_name
+               end else if field_type="cpp::ArrayBase" then
+                  "__" ^ remap_name
                else
                   remap_name
                in
@@ -2072,7 +2081,7 @@ let gen_expression_tree ctx retval expression_tree set_var tail_code =
          let cpp_type = member_type ctx obj field.cf_name in
          (not (is_scalar cpp_type)) && (
             let fixed = (cpp_type<>"?") && (expr_type<>"Dynamic") && (cpp_type<>"Dynamic") &&
-               (cpp_type<>expr_type) && (expr_type<>"Void") && (cpp_type<>"cpp::ArrayBase") in
+               (cpp_type<>expr_type) && (expr_type<>"Void") && (cpp_type<>"cpp::ArrayBase") && (cpp_type<>"cpp::VirtualArray") in
             if (fixed && (ctx.ctx_debug_level>1) ) then begin
                output ("/* " ^ (cpp_type) ^ " != " ^ expr_type ^ " -> cast */");
             end;
@@ -2117,7 +2126,7 @@ let gen_expression_tree ctx retval expression_tree set_var tail_code =
 
       if (cast_result) then output (")");
       if ( (is_variable func) && (not (is_cpp_function_member func) ) &&
-           (expr_type<>"Dynamic" && expr_type<>"cpp::ArrayBase" ) && (not is_super)  ) then
+           (expr_type<>"Dynamic" && expr_type<>"cpp::ArrayBase" && expr_type<>"cpp::VirtualArray" ) && (not is_super)  ) then
          ctx.ctx_output (".Cast< " ^ expr_type ^ " >()" );
 
       let rec cast_array_output func =
@@ -2201,7 +2210,9 @@ let gen_expression_tree ctx retval expression_tree set_var tail_code =
    | TLocal v -> output (keyword_remap v.v_name);
    | TArray (array_expr,_) when (is_null array_expr) -> output "Dynamic()"
    | TArray (array_expr,index) ->
-      let dynamic =  is_dynamic_in_cpp ctx array_expr || (type_string array_expr.etype) = "cpp::ArrayBase" in
+      let dynamic =  (is_dynamic_in_cpp ctx array_expr) ||
+                     (type_string array_expr.etype) = "cpp::ArrayBase" ||
+                     (is_virtual_array array_expr) in
       if ( assigning && (not dynamic) ) then begin
          if (is_array_implementer array_expr.etype) then begin
             output "hx::__ArrayImplRef(";
@@ -2331,8 +2342,16 @@ let gen_expression_tree ctx retval expression_tree set_var tail_code =
          | None -> ()
          | Some expression -> output " = "; gen_expression true expression);
          count := !count -1;
+      let get_var_name v =
+         let rec loop meta = match meta with
+            | (Meta.RealPath,[EConst (String s),_],_) :: _ -> s
+            | _ :: meta -> loop meta
+            | [] -> v.v_name
+         in
+         loop v.v_meta
+      in
       if (ctx.ctx_debug_level>0) then
-            output (";\t\tHX_STACK_VAR(" ^name ^",\""^ tvar.v_name ^"\")");
+            output (";\t\tHX_STACK_VAR(" ^name ^",\""^ (get_var_name tvar) ^"\")");
          if (!count > 0) then begin output ";\n"; output_i "" end
       end
    | TFor (tvar, init, loop) ->
@@ -2790,10 +2809,10 @@ let gen_member_def ctx class_def is_static is_interface field =
             end
          end else begin
             let return_type = (type_string function_def.tf_type) in
-   
+
             if ( not is_static && not nonVirtual ) then output "virtual ";
             output (if return_type="Void" && (has_meta_key field.cf_meta Meta.Void) then "void" else return_type );
-   
+
             output (" " ^ remap_name ^ "(" );
             output (gen_arg_list function_def.tf_args "" );
             output ");\n";
@@ -2810,7 +2829,7 @@ let gen_member_def ctx class_def is_static is_interface field =
          (* Variable access *)
          gen_type ctx field.cf_type;
          output (" " ^ remap_name ^ ";\n" );
-   
+
          (* Add a "dyn" function for variable to unify variable/function access *)
          (match follow field.cf_type with
          | _ when nativeGen  -> ()
@@ -5097,7 +5116,7 @@ class script_writer common_ctx ctx filename asciiOut =
             | "::String"  -> ArrayData "String"
             | "int" | "Float" | "bool" | "String" | "unsigned char" ->
                ArrayData typeName
-            | "cpp::ArrayBase" | "Dynamic" -> ArrayAny
+            | "cpp::ArrayBase" | "cpp::VirtualArray" | "Dynamic" -> ArrayAny
             | _ when is_interface_type param -> ArrayInterface (this#typeId (script_type_string param))
             | _ -> ArrayObject
             )

+ 3 - 1
genphp.ml

@@ -68,6 +68,8 @@ type context = {
 	mutable lib_path : string;
 }
 
+let follow = Abstract.follow_with_abstracts
+
 let join_class_path path separator =
 	let result = match fst path, snd path with
 	| [], s -> s
@@ -307,7 +309,7 @@ let is_keyword n =
 	| "clone" | "instanceof" | "break" | "case" | "class" | "continue" | "default"
 	| "do" | "else" | "extends" | "for" | "function" | "if" | "new" | "return"
 	| "static" | "switch" | "var" | "while" | "interface" | "implements" | "public"
-	| "private" | "try" | "catch" | "throw" | "goto"
+	| "private" | "try" | "catch" | "throw" | "goto" | "yield"
 		-> true
 	| _ -> false
 

+ 9 - 0
genswf9.ml

@@ -2017,7 +2017,16 @@ let check_constructor ctx c f =
 			error "You cannot assign some super class vars before calling super() in flash, this will reset them to default value" e.epos
 		| _ -> ()
 	in
+	(* only do so if we have a call to super() *)
+	let rec has_super e =
+		Type.iter has_super e;
+		match e.eexpr with
+		| TCall ({ eexpr = TConst TSuper },_) -> raise Exit
+		| _ -> ()
+	in
 	try
+		has_super f.tf_expr
+	with Exit -> try
 		loop f.tf_expr
 	with Exit ->
 		()

+ 1 - 7
main.ml

@@ -980,7 +980,7 @@ and do_connect host port args =
 
 and init ctx =
 	let usage = Printf.sprintf
-		"Haxe Compiler %s - (C)2005-2016 Haxe Foundation\n Usage : haxe%s -main <class> [-swf|-js|-neko|-php|-cpp|-as3|-cs|-java|-python|-hl] <output> [options]\n Options :"
+		"Haxe Compiler %s - (C)2005-2016 Haxe Foundation\n Usage : haxe%s -main <class> [-swf|-js|-neko|-php|-cpp|-as3|-cs|-java|-python] <output> [options]\n Options :"
 		s_version (if Sys.os_type = "Win32" then ".exe" else "")
 	in
 	let com = ctx.com in
@@ -1078,7 +1078,6 @@ try
 		("-python",Arg.String (fun dir ->
 			set_platform Python dir;
 		),"<file> : generate Python code as target file");
-		("-hl", Arg.String (set_platform Hl),"<file> : compile code to HL binary");
 		("-xml",Arg.String (fun file ->
 			Parser.use_doc := true;
 			xml_out := Some file
@@ -1473,9 +1472,6 @@ try
 		| Python ->
 			add_std "python";
 			"python"
-		| Hl ->
-			add_std "hl";
-			"hl"
 	) in
 	(* if we are at the last compilation step, allow all packages accesses - in case of macros or opening another project file *)
 	begin match com.display with
@@ -1573,8 +1569,6 @@ try
 					Genjava.generate,"java"
 				| Python ->
 					Genpy.generate,"python"
-				| Hl ->
-					Genhl.generate,"hl"
 				| Cross ->
 					assert false
 				in

+ 4 - 1
optimizer.ml

@@ -633,7 +633,10 @@ let rec type_inline ctx cf f ethis params tret config p ?(self_calling_closure=f
 		in
 		let e = (match e.eexpr, init with
 			| _, None when not !has_return_value ->
-				{e with etype = tret}
+				begin match e.eexpr with
+					| TBlock _ -> {e with etype = tret}
+					| _ -> mk (TBlock [e]) tret e.epos
+				end
 			| TBlock [e] , None -> wrap e
 			| _ , None -> wrap e
 			| TBlock l, Some vl ->

+ 2 - 4
std/StringTools.hx

@@ -388,8 +388,6 @@ class StringTools {
 		return (untyped s).charCodeAt(index);
 		#elseif python
 		return if (index >= s.length) -1 else python.internal.UBuiltins.ord(python.Syntax.arrayAccess(s, index));
-		#elseif hl
-		return @:privateAccess s.bytes.getUI16(index<<1);
 		#else
 		return untyped s.cca(index);
 		#end
@@ -399,7 +397,7 @@ class StringTools {
 		Tells if `c` represents the end-of-file (EOF) character.
 	*/
 	@:noUsing public static inline function isEof( c : Int ) : Bool {
-		#if (flash || cpp || hl)
+		#if (flash || cpp)
 		return c == 0;
 		#elseif js
 		return c != c; // fast NaN
@@ -457,7 +455,7 @@ class StringTools {
 	public static function quoteWinArg(argument:String, escapeMetaCharacters:Bool):String {
 		// If there is no space, tab, back-slash, or double-quotes, and it is not an empty string.
 		if (!~/^[^ \t\\"]+$/.match(argument)) {
-
+			
 			// Based on cpython's subprocess.list2cmdline().
 			// https://hg.python.org/cpython/file/50741316dd3a/Lib/subprocess.py#l620
 

+ 68 - 22
std/cpp/VirtualArray.hx

@@ -1,30 +1,76 @@
 package cpp;
 
-extern class VirtualArray
+@:native("cpp::VirtualArray")
+@:coreType extern class NativeVirtualArray implements ArrayAccess<Dynamic>
 {
-   function new() : Void;
-   var length(get,null) : Int;
+   public function new() : Void;
+   public var length(get,null) : Int;
    // concat<T>( a:Array<T> ) : Array<T> ?
-   function concat( a : VirtualArray ) : VirtualArray;
-   function join( sep : String ) : String;
-   function pop() : Dynamic;
-   function push(x : Dynamic) : Int;
-   function reverse() : Void;
-   function shift() : Dynamic;
-   function slice( pos : Int, ?end : Int ) : VirtualArray;
-   function sort( f : Dynamic -> Dynamic -> Int ) : Void;
-   function splice( pos : Int, len : Int ) : VirtualArray;
-   function toString() : String;
-   function unshift( x : Dynamic ) : Void;
-   function insert( pos : Int, x : Dynamic ) : Void;
-   function remove( x : Dynamic ) : Bool;
-   function indexOf( x : Dynamic, ?fromIndex:Int ) : Int;
-   function lastIndexOf( x : Dynamic, ?fromIndex:Int ) : Int;
-   function copy() : VirtualArray;
-   function iterator() : Iterator<Dynamic>;
-   function map<S>( f : Dynamic -> S ) : VirtualArray;
-   function filter( f : Dynamic -> Bool ) : VirtualArray;
+   public function concat( a : VirtualArray ) : VirtualArray;
+   public function join( sep : String ) : String;
+   public function pop() : Dynamic;
+   public function push(x : Dynamic) : Int;
+   public function reverse() : Void;
+   public function shift() : Dynamic;
+   public function slice( pos : Int, ?end : Int ) : VirtualArray;
+   public function sort( f : Dynamic -> Dynamic -> Int ) : Void;
+   public function splice( pos : Int, len : Int ) : VirtualArray;
+   public function toString() : String;
+   public function unshift( x : Dynamic ) : Void;
+   public function insert( pos : Int, x : Dynamic ) : Void;
+   public function remove( x : Dynamic ) : Bool;
+   public function indexOf( x : Dynamic, ?fromIndex:Int ) : Int;
+   public function lastIndexOf( x : Dynamic, ?fromIndex:Int ) : Int;
+   public function copy() : VirtualArray;
+   public function iterator() : Iterator<Dynamic>;
+   public function map<S>( f : Dynamic -> S ) : VirtualArray;
+   public function filter( f : Dynamic -> Bool ) : VirtualArray;
 }
 
 
+abstract VirtualArray(NativeVirtualArray)
+{
+   // Add these two functions...
+   @:from @:extern inline static public function fromArray<T>(a:Array<T>) : VirtualArray
+      return untyped a;
+   @:to @:extern inline public function toArray<T>() : Array<T>
+      return untyped this;
+
+
+
+
+   // The rest is just boiler-plate
+   inline public function new() this=new NativeVirtualArray();
+
+   @:extern @:arrayAccess inline function get(idx:Int) : Dynamic
+      return untyped this[idx];
+
+   @:extern @:arrayAccess inline function set<T>(pos:Int, value:T ) : T
+      return untyped this[idx] = value;
+
+   public var length(get,never) : Int;
+   @:extern inline public function get_length() : Int return this.length;
+
+
+
+   // concat<T>( a:Array<T> ) : Array<T> ?
+   @:extern inline public function concat( a : VirtualArray ) : VirtualArray return this.concat(a);
+   @:extern inline public function join( sep : String ) : String return this.join(sep);
+   @:extern inline public function pop() : Dynamic return this.pop();
+   @:extern inline public function push(x : Dynamic) : Int return this.push(x);
+   @:extern inline public function reverse() : Void this.reverse();
+   @:extern inline public function shift() : Dynamic return this.shift();
+   @:extern inline public function slice( pos : Int, ?end : Int ) : VirtualArray return this.slice(pos,end);
+   @:extern inline public function sort( f : Dynamic -> Dynamic -> Int ) : Void this.sort(f);
+   @:extern inline public function splice( pos : Int, len : Int ) : VirtualArray return this.slice(pos,len);
+   @:extern inline public function unshift( x : Dynamic ) : Void this.unshift(x);
+   @:extern inline public function insert( pos : Int, x : Dynamic ) : Void this.insert(pos,x);
+   @:extern inline public function remove( x : Dynamic ) : Bool return this.remove(x);
+   @:extern inline public function indexOf( x : Dynamic, ?fromIndex:Int ) : Int return this.indexOf(x,fromIndex);
+   @:extern inline public function lastIndexOf( x : Dynamic, ?fromIndex:Int ) : Int return this.lastIndexOf(x,fromIndex);
+   @:extern inline public function copy() : VirtualArray return this.copy();
+   @:extern inline public function iterator() : Iterator<Dynamic> return this.iterator();
+   @:extern inline public function map<S>( f : Dynamic -> S ) : VirtualArray return this.map(f);
+   @:extern inline public function filter( f : Dynamic -> Bool ) : VirtualArray return this.filter(f);
+}
 

+ 1 - 0
std/haxe/io/Bytes.hx

@@ -479,6 +479,7 @@ class Bytes {
 		#end
 	}
 
+	@:pure
 	public static function ofString( s : String ) : Bytes {
 		#if neko
 		return new Bytes(s.length,untyped __dollar__ssub(s.__s,0,s.length));

+ 7 - 7
std/js/Boot.hx

@@ -27,7 +27,7 @@ class ArrayBuffer {
 
 	public var byteLength : Int;
 	var a : Array<Int>;
-	
+
 	public function new( ?a : Dynamic ) {
 		if( Std.is(a,Array) ) {
 			this.a = a;
@@ -40,17 +40,17 @@ class ArrayBuffer {
 			byteLength = len;
 		}
 	}
-	
+
 	public function slice(begin,?end) {
 		return new ArrayBuffer(a.slice(begin,end));
 	}
-	
+
 	static function sliceImpl(begin,?end) {
-		var u = new js.html.Uint8Array(untyped __js__('this'), begin, end == null ? null : end - begin);
-        var result = new js.html.ArrayBuffer(u.byteLength);
-        var resultArray = new js.html.Uint8Array(result);
+		var u = new js.html.Uint8Array(js.Lib.nativeThis, begin, end == null ? null : end - begin);
+		var result = new js.html.ArrayBuffer(u.byteLength);
+		var resultArray = new js.html.Uint8Array(result);
 		resultArray.set(u);
-        return result;
+		return result;
 	}
 
 	static function __init__() untyped {

+ 8 - 8
std/js/html/compat/Float32Array.hx

@@ -22,6 +22,8 @@
 package js.html.compat;
 
 #if !nodejs
+import js.Lib.nativeThis;
+
 @:keep
 class Float32Array {
 
@@ -45,7 +47,7 @@ class Float32Array {
 			arr = [];
 			// decode buffer
 			for( i in 0...length ) {
-				var val = untyped buffer.a[offset++] | (buffer.a[offset++] << 8) | (buffer.a[offset++] << 16) | (buffer.a[offset++] << 24);  
+				var val = untyped buffer.a[offset++] | (buffer.a[offset++] << 8) | (buffer.a[offset++] << 16) | (buffer.a[offset++] << 24);
 				arr.push(haxe.io.FPHelper.i32ToFloat(val));
 			}
 			untyped {
@@ -79,26 +81,24 @@ class Float32Array {
 	}
 
 	static function _set( ?arg : Dynamic, ?offset : Int ) {
-		var t : Dynamic = untyped __js__("this");
 		if( Std.is(arg.buffer,ArrayBuffer) ) {
 			var a : Array<Int> = arg;
-			if( arg.byteLength + offset > t.byteLength )
+			if( arg.byteLength + offset > nativeThis.byteLength )
 				throw "set() outside of range";
 			for( i in 0...arg.byteLength )
-				t[i + offset] = a[i];
+				nativeThis[i + offset] = a[i];
 		} else if( Std.is(arg,Array) ) {
 			var a : Array<Int> = arg;
-			if( a.length + offset > t.byteLength )
+			if( a.length + offset > nativeThis.byteLength )
 				throw "set() outside of range";
 			for( i in 0...a.length )
-				t[i + offset] = a[i];
+				nativeThis[i + offset] = a[i];
 		} else
 			throw "TODO";
 	}
 
 	static function _subarray( start : Int, ?end : Int ) {
-		var t : Dynamic = untyped __js__("this");
-		var a = _new(t.slice(start,end));
+		var a = _new(nativeThis.slice(start,end));
 		a.byteOffset = start * 4;
 		return a;
 	}

+ 7 - 7
std/js/html/compat/Float64Array.hx

@@ -22,6 +22,8 @@
 package js.html.compat;
 
 #if !nodejs
+import js.Lib.nativeThis;
+
 @:keep
 class Float64Array {
 
@@ -86,26 +88,24 @@ class Float64Array {
 	}
 
 	static function _set( ?arg : Dynamic, ?offset : Int ) {
-		var t : Dynamic = untyped __js__("this");
 		if( Std.is(arg.buffer,ArrayBuffer) ) {
 			var a : Array<Int> = arg;
-			if( arg.byteLength + offset > t.byteLength )
+			if( arg.byteLength + offset > nativeThis.byteLength )
 				throw "set() outside of range";
 			for( i in 0...arg.byteLength )
-				t[i + offset] = a[i];
+				nativeThis[i + offset] = a[i];
 		} else if( Std.is(arg,Array) ) {
 			var a : Array<Int> = arg;
-			if( a.length + offset > t.byteLength )
+			if( a.length + offset > nativeThis.byteLength )
 				throw "set() outside of range";
 			for( i in 0...a.length )
-				t[i + offset] = a[i];
+				nativeThis[i + offset] = a[i];
 		} else
 			throw "TODO";
 	}
 
 	static function _subarray( start : Int, ?end : Int ) {
-		var t : Dynamic = untyped __js__("this");
-		var a = _new(t.slice(start,end));
+		var a = _new(nativeThis.slice(start,end));
 		a.byteOffset = start * 8;
 		return a;
 	}

+ 7 - 7
std/js/html/compat/Uint8Array.hx

@@ -22,6 +22,8 @@
 package js.html.compat;
 
 #if !nodejs
+import js.Lib.nativeThis;
+
 @:keep
 class Uint8Array {
 
@@ -70,26 +72,24 @@ class Uint8Array {
 	}
 
 	static function _set( ?arg : Dynamic, ?offset : Int ) {
-		var t : Dynamic = untyped __js__("this");
 		if( Std.is(arg.buffer,ArrayBuffer) ) {
 			var a : Array<Int> = arg;
-			if( arg.byteLength + offset > t.byteLength )
+			if( arg.byteLength + offset > nativeThis.byteLength )
 				throw "set() outside of range";
 			for( i in 0...arg.byteLength )
-				t[i + offset] = a[i];
+				nativeThis[i + offset] = a[i];
 		} else if( Std.is(arg,Array) ) {
 			var a : Array<Int> = arg;
-			if( a.length + offset > t.byteLength )
+			if( a.length + offset > nativeThis.byteLength )
 				throw "set() outside of range";
 			for( i in 0...a.length )
-				t[i + offset] = a[i];
+				nativeThis[i + offset] = a[i];
 		} else
 			throw "TODO";
 	}
 
 	static function _subarray( start : Int, ?end : Int ) {
-		var t : Dynamic = untyped __js__("this");
-		var a = _new(t.slice(start,end));
+		var a = _new(nativeThis.slice(start,end));
 		a.byteOffset = start;
 		return a;
 	}

+ 19 - 19
std/php/_std/haxe/ds/StringMap.hx

@@ -26,7 +26,6 @@ private typedef TravisConfig = {
 	var Java = "java";
 	var Cs = "cs";
 	var Python = "python";
-	var Hl = "hl";
 	var ThirdParty = "third-party";
 }
 
@@ -778,9 +777,18 @@ class RunCi {
 		for (test in tests) {
 			infoMsg('Now test $test');
 			changeDirectory(unitDir);
+
+			var args = switch (ci) {
+				case TravisCI:
+					["-D","travis"];
+				case AppVeyor:
+					["-D","appveyor"];
+				case _:
+					[];
+			}
 			switch (test) {
 				case Macro:
-					runCommand("haxe", ["compile-macro.hxml"]);
+					runCommand("haxe", ["compile-macro.hxml"].concat(args));
 
 					changeDirectory(miscDir);
 					getCsDependencies();
@@ -809,7 +817,7 @@ class RunCi {
 							// runCommand("haxe", ["compile-macro.hxml"]);
 					}
 				case Neko:
-					runCommand("haxe", ["compile-neko.hxml", "-D", "dump", "-D", "dump_ignore_var_ids"]);
+					runCommand("haxe", ["compile-neko.hxml", "-D", "dump", "-D", "dump_ignore_var_ids"].concat(args));
 					runCommand("neko", ["bin/unit.n"]);
 
 					changeDirectory(sysDir);
@@ -817,12 +825,6 @@ class RunCi {
 					runCommand("neko", ["bin/neko/sys.n"]);
 				case Php:
 					getPhpDependencies();
-					var args = switch (ci) {
-						case TravisCI:
-							["-D","travis"];
-						case _:
-							[];
-					}
 					runCommand("haxe", ["compile-php.hxml"].concat(args));
 					runCommand("php", ["bin/php/index.php"]);
 
@@ -832,7 +834,7 @@ class RunCi {
 				case Python:
 					var pys = getPythonDependencies();
 
-					runCommand("haxe", ["compile-python.hxml"]);
+					runCommand("haxe", ["compile-python.hxml"].concat(args));
 					for (py in pys) {
 						runCommand(py, ["bin/unit.py"]);
 					}
@@ -850,7 +852,7 @@ class RunCi {
 					}
 				case Cpp:
 					getCppDependencies();
-					runCommand("haxe", ["compile-cpp.hxml", "-D", "HXCPP_M32"]);
+					runCommand("haxe", ["compile-cpp.hxml", "-D", "HXCPP_M32"].concat(args));
 					runCpp("bin/cpp/Test-debug", []);
 
 					switch (ci) {
@@ -858,7 +860,7 @@ class RunCi {
 							//save time...
 						case _:
 							runCommand("rm", ["-rf", "cpp"]);
-							runCommand("haxe", ["compile-cpp.hxml", "-D", "HXCPP_M64"]);
+							runCommand("haxe", ["compile-cpp.hxml", "-D", "HXCPP_M64"].concat(args));
 							runCpp("bin/cpp/Test-debug", []);
 					}
 
@@ -880,7 +882,7 @@ class RunCi {
 						for (unflatten in [[], ["-D", "js-unflatten"]])
 						for (classic in   [[], ["-D", "js-classic"]])
 						{
-							var extras = [].concat(es5).concat(unflatten).concat(classic);
+							var extras = args.concat(es5).concat(unflatten).concat(classic);
 
 							runCommand("haxe", ["compile-js.hxml"].concat(extras));
 
@@ -937,10 +939,10 @@ class RunCi {
 					runCommand("haxe", ["run.hxml"]);
 				case Java:
 					getJavaDependencies();
-					runCommand("haxe", ["compile-java.hxml"]);
+					runCommand("haxe", ["compile-java.hxml"].concat(args));
 					runCommand("java", ["-jar", "bin/java/Test-Debug.jar"]);
 
-					runCommand("haxe", ["compile-java.hxml","-dce","no"]);
+					runCommand("haxe", ["compile-java.hxml","-dce","no"].concat(args));
 					runCommand("java", ["-jar", "bin/java/Test-Debug.jar"]);
 
 					changeDirectory(sysDir);
@@ -1006,7 +1008,7 @@ class RunCi {
 
 				case Flash9:
 					setupFlashPlayerDebugger();
-					runCommand("haxe", ["compile-flash9.hxml", "-D", "fdb", "-D", "dump", "-D", "dump_ignore_var_ids"]);
+					runCommand("haxe", ["compile-flash9.hxml", "-D", "fdb", "-D", "dump", "-D", "dump_ignore_var_ids"].concat(args));
 					var success = runFlash("bin/unit9.swf");
 					if (!success)
 						Sys.exit(1);
@@ -1029,12 +1031,10 @@ class RunCi {
 						runCommand("mxmlc", ["--version"]);
 					}
 
-					runCommand("haxe", ["compile-as3.hxml", "-D", "fdb"]);
+					runCommand("haxe", ["compile-as3.hxml", "-D", "fdb"].concat(args));
 					var success = runFlash("bin/unit9_as3.swf");
 					if (!success)
 						Sys.exit(1);
-				case Hl:
-					runCommand("haxe", ["compile-hl.hxml"]);
 				case ThirdParty:
 					getPhpDependencies();
 					getJavaDependencies();

+ 1 - 0
tests/misc/projects/Issue3361/compile1-fail.hxml.stderr

@@ -1,3 +1,4 @@
 Main.hx:5: lines 5-8 : Field v has different type than in I
+Main.hx:2: characters 8-28 : Interface field is defined here
 Main.hx:5: lines 5-8 : String -> Void should be Dynamic -> Void
 Main.hx:5: lines 5-8 : String should be Dynamic

+ 1 - 0
tests/misc/projects/Issue3361/compile2-fail.hxml.stderr

@@ -1,3 +1,4 @@
 Main2.hx:6: characters 16-45 : Field f has different type than in I
+Main2.hx:2: characters 16-43 : Interface field is defined here
 Main2.hx:6: characters 16-45 : s : String -> Void should be d : Dynamic -> Void
 Main2.hx:6: characters 16-45 : String should be Dynamic

+ 2 - 1
tests/misc/projects/Issue3417/compile-fail.hxml.stderr

@@ -1,2 +1,3 @@
 Main.hx:6: characters 11-26 : Field f has different type than in I
-Main.hx:6: characters 11-26 : Different number of function arguments
+Main.hx:2: characters 4-27 : Interface field is defined here
+Main.hx:6: characters 11-26 : Different number of function arguments

+ 1 - 0
tests/misc/projects/Issue4378/compile-fail.hxml.stderr

@@ -1,3 +1,4 @@
 Main.hx:5: lines 5-7 : Field test has different type than in I
+Main.hx:16: characters 1-31 : Interface field is defined here
 Main.hx:5: lines 5-7 : s : String -> Void should be s : Dynamic -> Void
 Main.hx:5: lines 5-7 : String should be Dynamic

+ 9 - 0
tests/optimization/src/TestJs.hx

@@ -548,6 +548,15 @@ class TestJs {
 		a[i++] = i++;
 	}
 
+	@:js('
+		var i = 5;
+		while(--i >= 0) TestJs["use"](i);
+	')
+	static function testPrefixRebuilding() {
+		var i:Int = 5;
+		while (--i >= 0) use(i);
+	}
+
 	static inline function inlineCall<S, T>(d1:S, d2:T) {
 		return call(d2, d1);
 	}

+ 9 - 12
tests/unit/src/unit/Test.hx

@@ -252,7 +252,7 @@ class Test {
 	}
 
 	static function resetTimer() {
-		#if (neko || php || cpp || java || cs || python || hl)
+		#if (neko || php || cpp || java || cs || python)
 		#else
 		if( timer != null ) timer.stop();
 		timer = new haxe.Timer(30000);
@@ -355,17 +355,14 @@ class Test {
 		#end
 
 		// SPOD tests
-		#if ( (neko || (php && (travis || php_sqlite)) || java || cpp || (cs && travis)) && !macro && !interp)
-		#if ( travis && !(cpp || cs) )
-		if (Sys.getEnv("CI") != null && switch (Sys.systemName()) { case "Linux"|"Mac": true; case _: false; })
-		{
-			classes.push(new TestSpod(sys.db.Mysql.connect({
-				host : "localhost",
-				user : "travis",
-				pass : "",
-				port : 3306,
-				database : "haxe_test" })));
-		}
+		#if ( (neko || (php && (travis || appveyor || php_sqlite)) || java || cpp || (cs && (travis || appveyor))) && !macro && !interp)
+		#if ( (travis || appveyor) && !(cpp || cs) )
+		classes.push(new TestSpod(sys.db.Mysql.connect({
+			host : "localhost",
+			user : "travis",
+			pass : "",
+			port : 3306,
+			database : "haxe_test" })));
 		#end
 		if (verbose)
 			logVerbose("Setup sqlite");

+ 4 - 4
tests/unit/src/unit/issues/Issue4695.hx

@@ -5,16 +5,16 @@ class Issue4695 extends unit.Test {
 	function eqCheck<T>(v1:T, v2:T) {
 		return v1 == v2;
 	}
-
+	
 	public function testNull() {
 		f("" == null);
 		f(eqCheck("", null));
-		#if !(cpp || flash9 || as3 || java || cs || hl)
+		#if !(cpp || flash9 || as3 || java || cs)
 		f(false == null);
 		f(eqCheck(false, null));
 		#end
 	}
-
+	
 	#if php
 	public function testNativeArray() {
 		var a1 = (untyped __php__)('array("f1" => 1, "f2" => 2, "f3" => 3)');
@@ -23,5 +23,5 @@ class Issue4695 extends unit.Test {
 		f(eqCheck(a1, a2));
 	}
 	#end
-
+	
 }

+ 18 - 0
tests/unit/src/unit/issues/Issue4798.hx

@@ -0,0 +1,18 @@
+package unit.issues;
+
+private abstract Lazy<T>(Void->T) {
+	inline function new(r) this = r;
+
+	@:to public inline function get():T
+		return (this)();
+
+	@:from static inline function ofConst<T>(c:T)
+		return new Lazy(function () return c);
+}
+
+class Issue4798 extends Test {
+	public static var INIT: Lazy<String> = 'b';
+	function test() {
+		eq("b", (INIT: String));
+	}
+}

+ 17 - 1
tests/unit/src/unitstd/EvaluationOrder.unit.hx

@@ -129,4 +129,20 @@ function f2() {
 
 var end = begin();
 f1()(f2());
-eq(end(), "1_2");
+eq(end(), "1_2");
+
+var d:Dynamic = { f1: f1 };
+
+function f3() {
+	buf.push(3);
+	d.f1 = function(i) {
+		buf.push(4);
+		return 4;
+	}
+	return 3;
+}
+
+var end = begin();
+d.f1()(f3());
+d.f1(f2());
+eq(end(), "1_3_2_4");

+ 2 - 0
typeload.ml

@@ -888,6 +888,7 @@ let check_overriding ctx c =
 				with
 					Unify_error l ->
 						display_error ctx ("Field " ^ i ^ " overloads parent class with different or incomplete type") p;
+						display_error ctx ("Base field is defined here") f2.cf_pos;
 						display_error ctx (error_msg (Unify l)) p;
 			with
 				Not_found ->
@@ -973,6 +974,7 @@ let rec check_interface ctx c intf params =
 				Unify_error l ->
 					if not (Meta.has Meta.CsNative c.cl_meta && c.cl_extern) then begin
 						display_error ctx ("Field " ^ i ^ " has different type than in " ^ s_type_path intf.cl_path) p;
+						display_error ctx ("Interface field is defined here") f.cf_pos;
 						display_error ctx (error_msg (Unify l)) p;
 					end
 		with

+ 3 - 19
typer.ml

@@ -671,7 +671,6 @@ let rec unify_call_args' ctx el args r callp inline force_inline =
 	let in_call_args = ctx.in_call_args in
 	ctx.in_call_args <- true;
 	let call_error err p =
-		ctx.in_call_args <- in_call_args;
 		raise (Error (Call_error err,p))
 	in
 	let arg_error ul name opt p =
@@ -698,7 +697,7 @@ let rec unify_call_args' ctx el args r callp inline force_inline =
 	(* let force_inline, is_extern = match cf with Some(TInst(c,_),f) -> is_forced_inline (Some c) f, c.cl_extern | _ -> false, false in *)
 	let type_against t e =
 		let e = type_expr ctx e (WithType t) in
-		(try Codegen.AbstractCast.cast_or_unify_raise ctx t e e.epos with Error (Unify l,p) -> ctx.in_call_args <- in_call_args; raise (WithTypeError (l,p)))
+		(try Codegen.AbstractCast.cast_or_unify_raise ctx t e e.epos with Error (Unify l,p) -> raise (WithTypeError (l,p)))
 	in
 	let rec loop el args = match el,args with
 		| [],[] ->
@@ -739,7 +738,7 @@ let rec unify_call_args' ctx el args r callp inline force_inline =
 						arg_error ul name false p
 			end
 	in
-	let el = loop el args in
+	let el = try loop el args with exc -> ctx.in_call_args <- in_call_args; raise exc; in
 	ctx.in_call_args <- in_call_args;
 	el,TFun(args,r)
 
@@ -3267,22 +3266,7 @@ and type_expr ctx (e,p) (with_type:with_type) =
 					)
 				) in
 				let e2 = type_expr ctx e2 NoValue in
-				(try
-					Optimizer.optimize_for_loop_iterator ctx i e1 e2 p
-				with Exit ->
-					if ctx.com.config.pf_for_to_while then begin
-						let v = gen_local ctx e1.etype in
-						mk (TBlock [
-							mk (TVar (v,Some e1)) ctx.t.tvoid p;
-							mk (TWhile (build_call ctx (type_field ctx (mk (TLocal v) v.v_type p) "hasNext" p MCall) [] Value p,
-								mk (TBlock [
-									mk (TVar (i, Some (build_call ctx (type_field ctx (mk (TLocal v) v.v_type p) "next" p MCall) [] Value p))) ctx.t.tvoid p;
-									e2
-								]) ctx.t.tvoid p
- 							,NormalWhile)) ctx.t.tvoid p;
-						]) ctx.t.tvoid p
-					end else
-						mk (TFor (i,e1,e2)) ctx.t.tvoid p)
+				(try Optimizer.optimize_for_loop_iterator ctx i e1 e2 p with Exit -> mk (TFor (i,e1,e2)) ctx.t.tvoid p)
 		) in
 		ctx.in_loop <- old_loop;
 		old_locals();