Jelajahi Sumber

Merge remote-tracking branch 'upstream/development' into intmap_iterator

SmerkyG 10 tahun lalu
induk
melakukan
5b7b713691

+ 7 - 4
analyzer.ml

@@ -890,7 +890,7 @@ module Ssa = struct
 						[]
 					| e :: el ->
 						if ctx.cur_data.nd_terminates then begin
-							ctx.com.warning (Printf.sprintf "Unreachable code: %s" (s_expr_pretty e)) e.epos;
+							(* ctx.com.warning (Printf.sprintf "Unreachable code: %s" (s_expr_pretty e)) e.epos; *)
 							[]
 						end else
 							let e = loop ctx e in
@@ -1081,7 +1081,7 @@ module ConstPropagation = struct
 			| TIf(e1,e2,eo) ->
 				let e1 = loop e1 in
 				let e2 = loop e2 in
-				begin match e1.eexpr with
+				let rec check_const e1 = match e1.eexpr with
 					| TConst (TBool true) ->
 						e2
 					| TConst (TBool false) ->
@@ -1091,10 +1091,13 @@ module ConstPropagation = struct
 							| Some e ->
 								loop e
 						end
+					| TParenthesis e1 ->
+						check_const e1
 					| _ ->
 						let eo = match eo with None -> None | Some e -> Some (loop e) in
 						{e with eexpr = TIf(e1,e2,eo)}
-				end;
+				in
+				check_const e1
 			| TSwitch(e1,cases,edef) ->
 				let e1 = loop e1 in
 				let rec check_constant e = match e.eexpr with
@@ -1318,7 +1321,7 @@ module Config = struct
 			simplifier_apply = true;
 			ssa_apply = true;
 			const_propagation = not (Common.raw_defined com "analyzer-no-const-propagation");
-			check_has_effect = not (Common.raw_defined com "analyzer-no-check-has-effect");
+			check_has_effect = (Common.raw_defined com "analyzer-check-has-effect");
 			check = not (Common.raw_defined com "analyzer-no-check");
 			local_dce = not (Common.raw_defined com "analyzer-no-local-dce");
 			ssa_unapply = not (Common.raw_defined com "analyzer-no-ssa-unapply");

+ 2 - 0
common.ml

@@ -150,6 +150,7 @@ type context = {
 	mutable net_libs : (string * bool * (unit -> path list) * (path -> IlData.ilclass option)) list; (* (path,std,all_files,lookup) *)
 	mutable net_std : string list;
 	net_path_map : (path,string list * string list * string) Hashtbl.t;
+	mutable c_args : string list;
 	mutable js_gen : (unit -> unit) option;
 	(* typing *)
 	mutable basic : basic_types;
@@ -708,6 +709,7 @@ let create v args =
 		net_libs = [];
 		net_std = [];
 		net_path_map = Hashtbl.create 0;
+		c_args = [];
 		neko_libs = [];
 		php_prefix = None;
 		js_gen = None;

+ 9 - 0
gencommon.ml

@@ -1086,6 +1086,15 @@ let dump_descriptor gen name path_s module_s =
 			end
 		) gen.gcon.net_libs;
 	SourceWriter.write w "end libs";
+	SourceWriter.newline w;
+	let args = gen.gcon.c_args in
+	if args <> [] then begin
+		SourceWriter.write w "begin opts";
+		SourceWriter.newline w;
+		List.iter (fun opt -> SourceWriter.write w opt; SourceWriter.newline w) (List.rev args);
+		SourceWriter.write w "end opts";
+		SourceWriter.newline w;
+	end;
 
 	let contents = SourceWriter.contents w in
 	let f = open_out (gen.gcon.file ^ "/" ^ name) in

+ 12 - 0
interp.ml

@@ -2547,6 +2547,18 @@ let macro_lib =
 			| _ ->
 				error()
 		);
+		"add_native_arg", Fun1 (fun v ->
+			match v with
+			| VString arg ->
+				let com = ccom() in
+				(match com.platform with
+				| Java | Cs | Cpp ->
+					com.c_args <- arg :: com.c_args
+				| _ -> failwith "Unsupported platform");
+				VNull
+			| _ ->
+				error()
+		);
 		"module_dependency", Fun2 (fun m file ->
 			match m, file with
 			| VString m, VString file ->

+ 3 - 0
main.ml

@@ -1139,6 +1139,9 @@ try
 		("-net-std",Arg.String (fun file ->
 			Gencs.add_net_std com file
 		),"<file> : add a root std .NET DLL search path");
+		("-c-arg",Arg.String (fun arg ->
+			com.c_args <- arg :: com.c_args
+		),"<arg> : pass option <arg> to the native Java/C# compiler");
 		("-x", Arg.String (fun file ->
 			let neko_file = file ^ ".n" in
 			set_platform Neko neko_file;

+ 18 - 0
optimizer.ml

@@ -727,6 +727,24 @@ let rec optimize_for_loop ctx (i,pi) e1 e2 p =
 	| _ ->
 		None
 
+let optimize_for_loop_iterator ctx v e1 e2 p =
+	let c,tl = (match follow e1.etype with TInst (c,pl) -> c,pl | _ -> raise Exit) in
+	let _, _, fhasnext = (try raw_class_field (fun cf -> apply_params c.cl_params tl cf.cf_type) c tl "hasNext" with Not_found -> raise Exit) in
+	if fhasnext.cf_kind <> Method MethInline then raise Exit;
+	let tmp = gen_local ctx e1.etype in
+	let eit = mk (TLocal tmp) e1.etype p in
+	let ehasnext = make_call ctx (mk (TField (eit,FInstance (c, tl, fhasnext))) (TFun([],ctx.t.tbool)) p) [] ctx.t.tbool p in
+	let enext = mk (TVar (v,Some (make_call ctx (mk (TField (eit,quick_field_dynamic eit.etype "next")) (TFun ([],v.v_type)) p) [] v.v_type p))) ctx.t.tvoid p in
+	let eblock = (match e2.eexpr with
+		| TBlock el -> { e2 with eexpr = TBlock (enext :: el) }
+		| _ -> mk (TBlock [enext;e2]) ctx.t.tvoid p
+	) in
+	mk (TBlock [
+		mk (TVar (tmp,Some e1)) ctx.t.tvoid p;
+		mk (TWhile (ehasnext,eblock,NormalWhile)) ctx.t.tvoid p
+	]) ctx.t.tvoid p
+
+
 (* ---------------------------------------------------------------------- *)
 (* SANITIZE *)
 

+ 2 - 2
std/Map.hx

@@ -134,11 +134,11 @@ abstract Map<K,V>(IMap<K,V> ) {
 		return v;
 	}
 
-	@:to static inline function toStringMap<V>(t:IMap<String,V>):StringMap<V> {
+	@:to static inline function toStringMap<K:String,V>(t:IMap<K,V>):StringMap<V> {
 		return new StringMap<V>();
 	}
 
-	@:to static inline function toIntMap<V>(t:IMap<Int,V>):IntMap<V> {
+	@:to static inline function toIntMap<K:Int,V>(t:IMap<K,V>):IntMap<V> {
 		return new IntMap<V>();
 	}
 

+ 21 - 0
std/StringTools.hx

@@ -26,6 +26,9 @@
 	If the first argument to any of the methods is null, the result is
 	unspecified.
 **/
+#if cpp
+using cpp.NativeString;
+#end
 #if cs
 @:keep
 #end
@@ -133,6 +136,15 @@ class StringTools {
 		return untyped s.startsWith(start);
 		#elseif cs
 		return untyped s.StartsWith(start);
+		#elseif cpp
+		if (s.length<start.length)
+			return false;
+		var p0 = s.c_str();
+		var p1 = start.c_str();
+		for(i in 0...start.length)
+			if ( p0.at(i) != p1.at(i) )
+				return false;
+		return true;
 		#else
 		return( s.length >= start.length && s.substr(0, start.length) == start );
 		#end
@@ -150,6 +162,15 @@ class StringTools {
 		return untyped s.endsWith(end);
 		#elseif cs
 		return untyped s.EndsWith(end);
+		#elseif cpp
+		if (s.length<end.length)
+			return false;
+		var p0 = s.c_str().add( s.length-end.length );
+		var p1 = end.c_str();
+		for(i in 0...end.length)
+			if ( p0.at(i) != p1.at(i) )
+				return false;
+		return true;
 		#else
 		var elen = end.length;
 		var slen = s.length;

+ 8 - 0
std/haxe/macro/Compiler.hx

@@ -89,6 +89,14 @@ class Compiler {
 		untyped load("add_native_lib",1)(name.__s);
 	}
 
+	/**
+		Adds an argument to be passed to the native compiler (eg : -javac-arg for Java)
+	 **/
+	public static function addNativeArg( argument : String )
+	{
+		untyped load("add_native_arg",1)(argument.__s);
+	}
+
 	/**
 		Includes all modules in package `pack` in the compilation.
 

+ 5 - 5
std/haxe/xml/Parser.hx

@@ -61,14 +61,14 @@ class Parser
 	/**
 		Parses the String into an XML Document. Set strict parsing to true in order to enable a strict check of XML attributes and entities.
 	**/
-	static public function parse(str:String,strict=false)
+	static public function parse(str:String, strict = false)
 	{
 		var doc = Xml.createDocument();
-		doParse(str, 0, strict, doc);
+		doParse(str, strict, 0, doc);
 		return doc;
 	}
 
-	static function doParse(str:String, p:Int = 0, strict:Bool, ?parent:Xml):Int
+	static function doParse(str:String, strict:Bool, p:Int = 0, ?parent:Xml):Int
 	{
 		var xml:Xml = null;
 		var state = S.BEGIN;
@@ -253,7 +253,7 @@ class Parser
 							next = S.BODY;
 					}
 				case S.CHILDS:
-					p = doParse(str, p, strict, xml);
+					p = doParse(str, strict, p, xml);
 					start = p;
 					state = S.BEGIN;
 				case S.WAIT_END:
@@ -321,7 +321,7 @@ class Parser
 							var c = s.fastCodeAt(1) == 'x'.code
 								? Std.parseInt("0" +s.substr(1, s.length - 1))
 								: Std.parseInt(s.substr(1, s.length - 1));
-							#if (neko || cpp)
+							#if (neko || cpp || php)
 							if( c >= 128 ) {
 								// UTF8-encode it
 								if( c <= 0x7FF ) {

+ 3 - 2
std/sys/db/RecordMacros.hx

@@ -367,9 +367,10 @@ class RecordMacros {
 					case DId: DInt;
 					case DUId: DUInt;
 					case DBigId: DBigInt;
-					default: throw "Unexpected id type, use either SId, SUId, SBigID";
+					case t = DString(_): t;
+					default: throw "Unexpected id type, use either SId, SUId, SBigID or SString";
 				}
-			
+
 			if( f == null ) {
 				f = {
 					name : r.key,

+ 1 - 1
tests/RunCi.hx

@@ -526,7 +526,7 @@ class RunCi {
 						runCommand("wget", ["-nv", "https://gist.github.com/santiycr/5139565/raw/sauce_connect_setup.sh"], true);
 						runCommand("chmod", ["a+x", "sauce_connect_setup.sh"]);
 						runCommand("./sauce_connect_setup.sh", []);
-						haxelibInstallGit("dionjwa", "nodejs-std", "master", "src", true, "nodejs");
+						haxelibInstallGit("dionjwa", "nodejs-std", "master", null, true, "nodejs");
 						runCommand("haxe", ["compile-saucelabs-runner.hxml"]);
 						var server = new Process("nekotools", ["server"]);
 						runCommand("node", ["bin/RunSauceLabs.js", "unit-js.html"]);

+ 1 - 0
tests/misc/projects/Issue2996/A.hx

@@ -0,0 +1 @@
+abstract A(String) {}

+ 5 - 0
tests/misc/projects/Issue2996/Main.hx

@@ -0,0 +1,5 @@
+import pack.B;
+
+class Main {
+
+}

+ 1 - 0
tests/misc/projects/Issue2996/compile1.hxml

@@ -0,0 +1 @@
+--display Main.hx@0@resolve@A

+ 3 - 0
tests/misc/projects/Issue2996/compile1.hxml.stderr

@@ -0,0 +1,3 @@
+<list>
+<pos>$$normPath(::cwd::/A.hx):1: characters 0-8</pos>
+</list>

+ 1 - 0
tests/misc/projects/Issue2996/compile2.hxml

@@ -0,0 +1 @@
+--display Main.hx@0@resolve@C

+ 3 - 0
tests/misc/projects/Issue2996/compile2.hxml.stderr

@@ -0,0 +1,3 @@
+<list>
+<pos>$$normPath(::cwd::/pack/B.hx):3: characters 0-5</pos>
+</list>

+ 3 - 0
tests/misc/projects/Issue2996/pack/B.hx

@@ -0,0 +1,3 @@
+package pack;
+
+class C {}

+ 14 - 0
tests/misc/projects/Issue3781/Main.hx

@@ -0,0 +1,14 @@
+enum E {
+    E1<T:String>(v:T);
+}
+
+abstract Ab(String) to String {}
+
+class Main<T:Ab> {
+    static function main() {
+    }
+
+    function doStuff(v:T) {
+        E1(v);
+    }
+}

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

@@ -0,0 +1 @@
+--run Main

+ 2 - 0
tests/misc/projects/Issue3781/compile-fail.hxml.stderr

@@ -0,0 +1,2 @@
+Main.hx:12: characters 8-10 : Constraint check failure for E1.T
+Main.hx:12: characters 8-10 : Main.T should be String

+ 11 - 0
tests/misc/projects/Issue3783/Main.hx

@@ -0,0 +1,11 @@
+class Main {
+	var field = function () {
+		method();
+	}
+
+	function method () {
+	}
+
+	private static function main () {
+	}
+}

+ 2 - 0
tests/misc/projects/Issue3783/compile-fail.hxml

@@ -0,0 +1,2 @@
+-main Main
+--interp

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

@@ -0,0 +1 @@
+Main.hx:3: characters 2-8 : Cannot access this or other member field in variable initialization

+ 13 - 0
tests/unit/src/unit/MySpodClass.hx

@@ -68,3 +68,16 @@ abstract AbstractSpodTest<A>(A) from A
 		return this;
 	}
 }
+
+@:id(name)
+@:keep class ClassWithStringId extends Object
+{
+	public var name:SString<255>;
+	public var field:SInt;
+}
+
+@:keep class ClassWithStringIdRef extends Object
+{
+	public var id:SId;
+	@:relation(ref_id) public var ref:ClassWithStringId;
+}

+ 59 - 0
tests/unit/src/unit/TestSpod.hx

@@ -9,6 +9,8 @@ import sys.db.TableCreate;
 import sys.FileSystem;
 import unit.MySpodClass;
 
+using Lambda;
+
 class TestSpod extends Test
 {
 	private var cnx:Connection;
@@ -20,9 +22,13 @@ class TestSpod extends Test
 		try cnx.request('DROP TABLE MySpodClass') catch(e:Dynamic) {}
 		try cnx.request('DROP TABLE OtherSpodClass') catch(e:Dynamic) {}
 		try cnx.request('DROP TABLE NullableSpodClass') catch(e:Dynamic) {}
+		try cnx.request('DROP TABLE ClassWithStringId') catch(e:Dynamic) {}
+		try cnx.request('DROP TABLE ClassWithStringIdRef') catch(e:Dynamic) {}
 		TableCreate.create(MySpodClass.manager);
 		TableCreate.create(OtherSpodClass.manager);
 		TableCreate.create(NullableSpodClass.manager);
+		TableCreate.create(ClassWithStringId.manager);
+		TableCreate.create(ClassWithStringIdRef.manager);
 	}
 
 	private function setManager()
@@ -54,6 +60,59 @@ class TestSpod extends Test
 		return scls;
 	}
 
+	public function testStringIdRel()
+	{
+		setManager();
+		var s = new ClassWithStringId();
+		s.name = "first";
+		s.field = 1;
+		s.insert();
+		var v1 = new ClassWithStringIdRef();
+		v1.ref = s;
+		v1.insert();
+		var v2 = new ClassWithStringIdRef();
+		v2.ref = s;
+		v2.insert();
+
+		s = new ClassWithStringId();
+		s.name = "second";
+		s.field = 2;
+		s.insert();
+		v1 = new ClassWithStringIdRef();
+		v1.ref = s;
+		v1.insert();
+		s = null; v1 = null; v2 = null;
+		Manager.cleanup();
+
+		var first = ClassWithStringId.manager.search($name == "first");
+		eq(first.length,1);
+		var first = first.first();
+		eq(first.field,1);
+		var frel = ClassWithStringIdRef.manager.search($ref == first);
+		eq(frel.length,2);
+		for (rel in frel)
+			eq(rel.ref, first);
+		var frel2 = ClassWithStringIdRef.manager.search($ref_id == "first");
+		eq(frel2.length,2);
+		for (rel in frel2)
+			eq(rel.ref, first);
+
+		var second = ClassWithStringId.manager.search($name == "second");
+		eq(second.length,1);
+		var second = second.first();
+		eq(second.field,2);
+		var srel = ClassWithStringIdRef.manager.search($ref == second);
+		eq(srel.length,1);
+		for (rel in srel)
+			eq(rel.ref, second);
+
+		eq(frel.array().indexOf(srel.first()), -1);
+		second.delete();
+		for (r in srel) r.delete();
+		first.delete();
+		for (r in frel) r.delete();
+	}
+
 	public function testEnum()
 	{
 		setManager();

+ 0 - 0
tests/unit/src/unit/issues/Issue3030.hx → tests/unit/src/unit/issues/Issue3030.hx.disabled


+ 17 - 0
tests/unit/src/unit/issues/Issue3777.hx

@@ -0,0 +1,17 @@
+package unit.issues;
+
+private class A<T:String> {
+    public function new() f();
+    function f():Map<T,Int> throw "not implemented";
+}
+
+private class B extends A<String> {
+    override function f() return ["a" => 1];
+}
+
+class Issue3777 extends unit.Test {
+    function test() {
+        // if it compiles, it works
+        new B();
+    }
+}

+ 25 - 8
type.ml

@@ -479,10 +479,17 @@ let map loop t =
 	| TFun (tl,r) ->
 		TFun (List.map (fun (s,o,t) -> s, o, loop t) tl,loop r)
 	| TAnon a ->
-		TAnon {
-			a_fields = PMap.map (fun f -> { f with cf_type = loop f.cf_type }) a.a_fields;
-			a_status = a.a_status;
-		}
+		let fields = PMap.map (fun f -> { f with cf_type = loop f.cf_type }) a.a_fields in
+		begin match !(a.a_status) with
+			| Opened ->
+				a.a_fields <- fields;
+				t
+			| _ ->
+	 			TAnon {
+					a_fields = fields;
+					a_status = a.a_status;
+				}
+		end
 	| TLazy f ->
 		let ft = !f() in
 		let ft2 = loop ft in
@@ -542,10 +549,17 @@ let apply_params cparams params t =
 		| TFun (tl,r) ->
 			TFun (List.map (fun (s,o,t) -> s, o, loop t) tl,loop r)
 		| TAnon a ->
-			TAnon {
-				a_fields = PMap.map (fun f -> { f with cf_type = loop f.cf_type }) a.a_fields;
-				a_status = a.a_status;
-			}
+			let fields = PMap.map (fun f -> { f with cf_type = loop f.cf_type }) a.a_fields in
+			begin match !(a.a_status) with
+				| Opened ->
+					a.a_fields <- fields;
+					t
+				| _ ->
+		 			TAnon {
+						a_fields = fields;
+						a_status = a.a_status;
+					}
+			end
 		| TLazy f ->
 			let ft = !f() in
 			let ft2 = loop ft in
@@ -2042,3 +2056,6 @@ let map_expr_type f ft fv e =
 		{ e with eexpr = TCast (f e1,t); etype = ft e.etype }
 	| TMeta (m,e1) ->
 		{e with eexpr = TMeta(m, f e1); etype = ft e.etype }
+
+let print_if b e =
+	if b then print_endline (s_expr_pretty "" (s_type (print_context())) e)

+ 2 - 0
typeload.ml

@@ -1828,6 +1828,8 @@ let init_class ctx c p context_init herits fields =
 								let rec has_this e = match e.eexpr with
 									| TConst TThis ->
 										display_error ctx "Cannot access this or other member field in variable initialization" e.epos;
+									| TLocal v when (match ctx.vthis with Some v2 -> v == v2 | None -> false) ->
+										display_error ctx "Cannot access this or other member field in variable initialization" e.epos;
 									| _ ->
 									Type.iter has_this e
 								in

+ 2 - 20
typer.ml

@@ -194,7 +194,7 @@ let check_constraints ctx tname tpl tl map delayed p =
 				) constr
 			) in
 			if delayed then
-				delay ctx PCheckConstraint f
+				delay ctx PCheckConstraint (fun () -> try f() with Unify_error l -> display_error ctx (error_msg (Unify l)) p)
 			else
 				f()
 		| _ ->
@@ -3096,25 +3096,7 @@ and type_expr ctx (e,p) (with_type:with_type) =
 					)
 				) in
 				let e2 = type_expr ctx e2 NoValue in
-				(* can we inline hasNext() ? *)
-				(try
-					let c,pl = (match follow e1.etype with TInst (c,pl) -> c,pl | _ -> raise Exit) in
-					let _, ft, fhasnext = (try class_field ctx c pl "hasNext" p with Not_found -> raise Exit) in
-					if fhasnext.cf_kind <> Method MethInline then raise Exit;
-					let tmp = gen_local ctx e1.etype in
-					let eit = mk (TLocal tmp) e1.etype p in
-					let ehasnext = make_call ctx (mk (TField (eit,FInstance (c, pl, fhasnext))) (TFun([],ctx.t.tbool)) p) [] ctx.t.tbool p in
-					let enext = mk (TVar (i,Some (make_call ctx (mk (TField (eit,quick_field_dynamic eit.etype "next")) (TFun ([],pt)) p) [] pt p))) ctx.t.tvoid p in
-					let eblock = (match e2.eexpr with
-						| TBlock el -> { e2 with eexpr = TBlock (enext :: el) }
-						| _ -> mk (TBlock [enext;e2]) ctx.t.tvoid p
-					) in
-					mk (TBlock [
-						mk (TVar (tmp,Some e1)) ctx.t.tvoid p;
-						mk (TWhile (ehasnext,eblock,NormalWhile)) ctx.t.tvoid p
-					]) ctx.t.tvoid p
-				with Exit ->
-					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();