Browse Source

Merge branch 'development' into hl

Conflicts:
	.travis.yml
Simon Krajewski 9 years ago
parent
commit
2a0ecd2603
23 changed files with 306 additions and 113 deletions
  1. 1 0
      .gitignore
  2. 5 0
      Makefile
  3. 1 0
      ast.ml
  4. 7 5
      common.ml
  5. BIN
      extra/deploy_key.enc
  6. 49 17
      gencpp.ml
  7. 2 1
      genswf.ml
  8. 1 1
      genxml.ml
  9. 11 0
      interp.ml
  10. 5 0
      main.ml
  11. 5 5
      std/UInt.hx
  12. 7 7
      std/Xml.hx
  13. 5 0
      std/cpp/cppia/HostClasses.hx
  14. 1 1
      std/haxe/crypto/BaseCode.hx
  15. 13 10
      std/haxe/macro/Compiler.hx
  16. 1 1
      std/haxe/macro/ComplexTypeTools.hx
  17. 12 0
      std/haxe/macro/Context.hx
  18. 1 1
      std/js/Lib.hx
  19. 19 4
      tests/RunCi.hx
  20. 16 0
      type.ml
  21. 11 0
      typecore.ml
  22. 3 1
      typeload.ml
  23. 130 59
      typer.ml

+ 1 - 0
.gitignore

@@ -13,6 +13,7 @@
 /extra/*.swc
 /extra/bintray.json
 /extra/git-archive-all
+/extra/deploy_key
 
 /version.ml
 /haxe

+ 5 - 0
Makefile

@@ -220,9 +220,14 @@ install_dox:
 	haxelib git dox https://github.com/dpeek/dox
 
 package_doc:
+	mkdir -p $(PACKAGE_OUT_DIR)
 	cd $$(haxelib path dox | head -n 1) && haxe run.hxml && haxe gen.hxml
 	haxelib run dox --title "Haxe API" -o $(PACKAGE_OUT_DIR)/$(PACKAGE_FILE_NAME)_doc.zip -D version "$$(haxe -version 2>&1)" -i $$(haxelib path dox | head -n 1)bin/xml -ex microsoft -ex javax -ex cs.internal -D source-path https://github.com/HaxeFoundation/haxe/blob/$(BRANCH)/std/
 
+deploy_doc:
+	scp $(PACKAGE_OUT_DIR)/$(PACKAGE_FILE_NAME)_doc.zip [email protected]:/data/haxeapi/www/v/dev/api-latest.zip
+	ssh [email protected] "cd /data/haxeapi/www/v/dev && find . ! -name 'api-latest.zip' -maxdepth 1 -mindepth 1 -exec rm -rf {} + && unzip -q -o api-latest.zip"
+
 # Clean
 
 clean: clean_libs clean_haxe clean_tools clean_package

+ 1 - 0
ast.ml

@@ -160,6 +160,7 @@ module Meta = struct
 		| Strict
 		| Struct
 		| StructAccess
+		| StructInit
 		| SuppressWarnings
 		| This
 		| Throws

+ 7 - 5
common.ml

@@ -494,6 +494,7 @@ module MetaInfo = struct
 		| Strict -> ":strict",("Used to declare a native C# attribute or a native Java metadata. Is type checked",[Platforms [Java;Cs]])
 		| Struct -> ":struct",("Marks a class definition as a struct",[Platform Cs; UsedOn TClass])
 		| StructAccess -> ":structAccess",("Marks an extern class as using struct access('.') not pointer('->')",[Platform Cpp; UsedOn TClass])
+		| StructInit -> ":structInit",("Allows to initialize the class with a structure that matches constructor parameters",[UsedOn TClass])
 		| SuppressWarnings -> ":suppressWarnings",("Adds a SuppressWarnings annotation for the generated Java class",[Platform Java; UsedOn TClass])
 		| Throws -> ":throws",("Adds a 'throws' declaration to the generated function",[HasParam "Type as String"; Platform Java; UsedOn TClassField])
 		| This -> ":this",("Internally used to pass a 'this' expression to macros",[Internal; UsedOn TExpr])
@@ -805,12 +806,13 @@ let get_signature com =
 	match com.defines_signature with
 	| Some s -> s
 	| None ->
-		let str = String.concat "@" (PMap.foldi (fun k v acc ->
+		let defines = PMap.foldi (fun k v acc ->
 			(* don't make much difference between these special compilation flags *)
-			match k with
-			| "display" | "use_rtti_doc" | "macrotimes" -> acc
-			| _ -> k :: v :: acc
-		) com.defines []) in
+			match String.concat "_" (ExtString.String.nsplit k "-") with
+			| "display" | "use_rtti_doc" | "macro_times" | "display_details" | "no_copt" -> acc
+			| _ -> (k ^ "=" ^ v) :: acc
+		) com.defines [] in
+		let str = String.concat "@" (List.sort compare defines) in
 		let s = Digest.string str in
 		com.defines_signature <- Some s;
 		s

BIN
extra/deploy_key.enc


+ 49 - 17
gencpp.ml

@@ -304,12 +304,53 @@ let hash_iterate hash visitor =
    Hashtbl.iter (fun key value -> result :=  (visitor key value) :: !result ) hash;
    !result
 
+
+
+
+
+let is_internal_member member =
+   member = "toString" || (
+      (String.length member > 1) && (String.sub member 0 2 = "__") &&
+         (match member with
+         | "__ArgCount" | "__ArrayImplRef" | "__CStr" | "__Compare" | "__Create"
+         | "__CreateEmpty" | "__FieldRef" | "__FindArgCount"
+         | "__GetFieldMap" | "__GetHandle" | "__GetItem"
+         | "__GetScriptCallable" | "__GetScriptVTable"
+         | "__Param" | "__Remove" | "__SGetClass"
+         | "__Set" | "__SetItem" | "__TArrayImplRef"
+         | "__ToDouble" | "__ToInt" | "__ToInterface" | "__ToObject"
+         | "__Visit" | "__WCStr" | "__a" | "__blit" | "__boot"
+         | "__boot_all" | "__compare" | "__concat" | "__construct" | "__copy"
+         | "__filter" | "__get_args" | "__hx_dump_stack" | "__hx_field_iter" | "__hxt_gc_new"
+         | "__indexOf" | "__insert" | "__instanceof" | "__int" | "__iterator"
+         | "__join" | "__lastIndexOf" | "__loadprim" | "__mClass" | "__mDynamicFields"
+         | "__map" | "__memcmp" | "__new" | "__pop" | "__prime"
+         | "__push" | "__qsort" | "__unshift" | "__unsafeStringReference" | "__time_stamp"
+         | "__superString" | "__splice" | "__shift" | "__slice" | "__sort"
+         | "__s_id" | "__run" | "__root" | "__register" | "__remove"
+         | "__removeAt" | "__reverse" | "__zero" 
+         | "__Field" | "__IField" | "__Run" | "__Is" | "__GetClass" | "__GetType" | "__ToString"
+         | "__s" | "__GetPtr" | "__SetField" | "__length" | "__IsArray" | "__SetThis" | "__Internal"
+         | "__EnumParams" | "__Index" | "__Tag" | "__GetFields" | "__HasField"
+         | "__get" | "__set" | "__unsafe_get" | "__unsafe_set" | "__global__"
+         | "__SetSize" | "__trace" | "__GetRealObject" | "__SetSizeExact" | "__cpp__"
+         | "__URLEncode" | "__URLDecode" | "__IsEnum"
+               -> true
+         | _ -> false) );;
+      
+let is_known_member member =
+   match member with
+   | "__meta__" | "__rtti" | "_Compare"
+         -> true
+   | _ -> false;;
+
 (* Convert function names that can't be written in c++ ... *)
 let keyword_remap name =
-   match name with
-   | "__get" | "__set" | "__unsafe_get" | "__unsafe_set" | "__global__"
-   |   "__SetSize" | "__s" | "__trace" -> name
-   (* | _ when (String.length name > 1) && (String.sub name 0 2 = "__") -> "_hx" ^ name *)
+   if (is_internal_member name) || (is_known_member name) then
+      name
+   else if (String.length name > 1) && (String.sub name 0 2 = "__") then
+      "_hx_" ^ name 
+   else match name with
    | "int"
    | "auto" | "char" | "const" | "delete" | "double" | "Float" | "enum"
    | "extern" | "float" | "friend" | "goto" | "long" | "operator" | "protected"
@@ -890,16 +931,6 @@ let should_implement_field x = not (is_extern_field x);;
 let is_function_member expression =
    match (follow expression.etype) with | TFun (_,_) -> true | _ -> false;;
 
-let is_internal_member member =
-   match member with
-   | "__Field" | "__IField" | "__Run" | "__Is" | "__GetClass" | "__GetType" | "__ToString"
-   | "__s" | "__GetPtr" | "__SetField" | "__length" | "__IsArray" | "__SetThis" | "__Internal"
-   | "__EnumParams" | "__Index" | "__Tag" | "__GetFields" | "toString" | "__HasField"
-   | "__GetRealObject"
-         -> true
-   | _ -> false;;
-
-
 let is_extern_class class_def =
    class_def.cl_extern || (has_meta_key class_def.cl_meta Meta.Extern) ||
       (match class_def.cl_kind with
@@ -1400,7 +1431,7 @@ and is_dynamic_member_return_in_cpp ctx field_object field =
    if (is_internal_member member) then false else
    match field_object.eexpr with
    | TTypeExpr t ->
-         let full_name = "::" ^ (join_class_path (t_path t) "::" ) ^ "." ^ member in
+         let full_name = "::" ^ (join_class_path_remap (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" || mem_type="cpp::VirtualArray" )
@@ -1574,6 +1605,7 @@ let gen_expression_tree ctx retval expression_tree set_var tail_code =
 
 
       let pop_real_this_ptr = clear_real_this_ptr ctx true in
+      ctx.ctx_real_void <- false;
 
       writer#begin_block;
       if (ctx.ctx_debug_level>0) then begin
@@ -5305,7 +5337,7 @@ class script_writer common_ctx ctx filename asciiOut =
          | TField (obj,FInstance (_,_,field) ) when is_super obj ->
                   this#write ( (this#op IaCallSuper) ^ (this#typeText obj.etype) ^ " " ^ (this#stringText field.cf_name) ^
                      argN ^ "\n");
-         | TField (obj,FInstance (_,_,field) ) when is_real_function field ->
+         | TField (obj,FInstance (_,_,field) ) when not (is_dynamic_in_cppia ctx obj) && is_real_function field ->
                   this#write ( (this#op IaCallMember) ^ (this#typeText obj.etype) ^ " " ^ (this#stringText field.cf_name) ^
                      argN ^ "\n");
                   this#gen_expression obj;
@@ -5349,7 +5381,7 @@ class script_writer common_ctx ctx filename asciiOut =
          | _ -> gen_call();
       );
    | TField (obj, acc) ->
-      let typeText = this#typeText obj.etype in
+      let typeText = if is_dynamic_in_cppia ctx obj then this#typeTextString "Dynamic" else this#typeText obj.etype in
       (match acc with
       | FDynamic name -> this#write ( (this#op IaFName) ^ typeText ^ " " ^ (this#stringText name) ^ "\n");
             this#gen_expression obj;

+ 2 - 1
genswf.ml

@@ -1111,6 +1111,7 @@ let generate swf_header com =
 	let tags = build_swf9 com file swc in
 	let header, bg = (match swf_header with None -> default_header com | Some h -> convert_header com h) in
 	let bg = tag (TSetBgColor { cr = bg lsr 16; cg = (bg lsr 8) land 0xFF; cb = bg land 0xFF }) in
+	let scene = tag ~ext:true (TScenes ([(0,"Scene1")],[])) in
 	let swf_debug_password = try
 		Digest.to_hex(Digest.string (Common.defined_value com Define.SwfDebugPassword))
 	with Not_found ->
@@ -1143,7 +1144,7 @@ let generate swf_header com =
 	with Not_found ->
 		[]
 	in
-	let swf = header, fattr @ meta_data @ bg :: debug @ swf_script_limits @ tags @ [tag TShowFrame] in
+	let swf = header, fattr @ meta_data @ bg :: scene :: debug @ swf_script_limits @ tags @ [tag TShowFrame] in
 	(* merge swf libraries *)
 	let priority = ref (swf_header = None) in
 	let swf = List.fold_left (fun swf (file,lib,cl) ->

+ 1 - 1
genxml.ml

@@ -502,7 +502,7 @@ let generate_type com t =
 		) in
 		let ext = (match c.cl_path with
 			| ["flash";"utils"], "ByteArray" -> " implements ArrayAccess<Int>" :: ext
-			| ["flash";"utils"], "Dictionnary" -> [" implements ArrayAccess<Dynamic>"]
+			| ["flash";"utils"], "Dictionary" -> [" implements ArrayAccess<Dynamic>"]
 			| ["flash";"xml"], "XML" -> [" implements Dynamic<XMLList>"]
 			| ["flash";"xml"], "XMLList" -> [" implements ArrayAccess<XML>"]
 			| ["flash";"display"],"MovieClip" -> [" extends Sprite #if !flash_strict implements Dynamic #end"]

+ 11 - 0
interp.ml

@@ -103,6 +103,7 @@ type extern_api = {
 	on_type_not_found : (string -> value) -> unit;
 	parse_string : string -> Ast.pos -> bool -> Ast.expr;
 	type_expr : Ast.expr -> Type.texpr;
+	resolve_type  : Ast.complex_type -> Ast.pos -> t;
 	type_macro_expr : Ast.expr -> Type.texpr;
 	store_typed_expr : Type.texpr -> Ast.expr;
 	get_display : string -> string;
@@ -196,6 +197,8 @@ exception Sys_exit of int
 
 let get_ctx_ref = ref (fun() -> assert false)
 let encode_complex_type_ref = ref (fun t -> assert false)
+let decode_complex_type_ref = ref (fun t -> assert false)
+let decode_pos_ref = ref (fun v -> assert false)
 let encode_type_ref = ref (fun t -> assert false)
 let decode_type_ref = ref (fun t -> assert false)
 let encode_expr_ref = ref (fun e -> assert false)
@@ -215,7 +218,10 @@ let eval_expr_ref : (context -> texpr -> value option) ref = ref (fun _ _ -> ass
 let get_ctx() = (!get_ctx_ref)()
 let enc_array (l:value list) : value = (!enc_array_ref) l
 let dec_array (l:value) : value list = (!dec_array_ref) l
+
+let decode_complex_type (v:value) : Ast.complex_type = (!decode_complex_type_ref) v
 let encode_complex_type (t:Ast.complex_type) : value = (!encode_complex_type_ref) t
+let decode_pos (v:value) : Ast.pos = (!decode_pos_ref) v
 let encode_type (t:Type.t) : value = (!encode_type_ref) t
 let decode_type (v:value) : Type.t = (!decode_type_ref) v
 let encode_expr (e:Ast.expr) : value = (!encode_expr_ref) e
@@ -2428,6 +2434,9 @@ let macro_lib =
 		"type_expr", Fun1 (fun v ->
 			encode_texpr ((get_ctx()).curapi.type_expr (decode_expr v))
 		);
+		"resolve_type", Fun2 (fun t p ->
+			encode_type ((get_ctx()).curapi.resolve_type (decode_complex_type t) (decode_pos p));
+		);
 		"s_type", Fun1 (fun v ->
 			VString (Type.s_type (print_context()) (decode_type v))
 		);
@@ -5036,6 +5045,8 @@ let rec make_const e =
 
 ;;
 encode_complex_type_ref := encode_ctype;
+decode_complex_type_ref := decode_ctype;
+decode_pos_ref := decode_pos;
 enc_array_ref := enc_array;
 dec_array_ref := dec_array;
 encode_type_ref := encode_type;

+ 5 - 0
main.ml

@@ -875,6 +875,11 @@ and wait_loop boot_com host port =
 				if ctx.has_error then ssend sin "\x02\n" else cache_context ctx.com;
 			);
 			ctx.setup <- (fun() ->
+				if verbose then begin
+					let defines = PMap.foldi (fun k v acc -> (k ^ "=" ^ v) :: acc) ctx.com.defines [] in
+					print_endline ("Defines " ^ (String.concat "," (List.sort compare defines)));
+					print_endline ("Using signature " ^ Digest.to_hex (get_signature ctx.com));
+				end;
 				Parser.display_error := (fun e p -> has_parse_error := true; ctx.com.error (Parser.error_msg e) p);
 				if ctx.com.display <> DMNone then begin
 					let file = (!Parser.resume_display).Ast.pfile in

+ 5 - 5
std/UInt.hx

@@ -202,12 +202,12 @@ abstract UInt(Int) from Int to Int {
 	}
 
 	@:commutative @:op(A == B) private static inline function equalsFloat<T:Float>(a:UInt, b:T):Bool {
-        return a.toFloat() == b;
-    }
+		return a.toFloat() == b;
+	}
 
-    @:commutative @:op(A != B) private static inline function notEqualsFloat<T:Float>(a:UInt, b:T):Bool {
-        return a.toFloat() != b;
-    }
+	@:commutative @:op(A != B) private static inline function notEqualsFloat<T:Float>(a:UInt, b:T):Bool {
+		return a.toFloat() != b;
+	}
 
 	@:op(A >= B) private static inline function gteFloat(a:UInt, b:Float):Bool {
 		return a.toFloat() >= b;

+ 7 - 7
std/Xml.hx

@@ -122,28 +122,28 @@ class Xml {
 	var children:Array<Xml>;
 	var attributeMap:Map<String, String>;
 
-	inline function get_nodeName() {
+	#if !cppia inline #end function get_nodeName() {
 		if (nodeType != Element) {
 			throw 'Bad node type, expected Element but found $nodeType';
 		}
 		return nodeName;
 	}
 
-	inline function set_nodeName(v) {
+	#if !cppia inline #end function set_nodeName(v) {
 		if (nodeType != Element) {
 			throw 'Bad node type, expected Element but found $nodeType';
 		}
 		return this.nodeName = v;
 	}
 
-	inline function get_nodeValue() {
+	#if !cppia inline #end function get_nodeValue() {
 		if (nodeType == Document || nodeType == Element) {
 			throw 'Bad node type, unexpected $nodeType';
 		}
 		return nodeValue;
 	}
 
-	inline function set_nodeValue(v) {
+	#if !cppia inline #end function set_nodeValue(v) {
 		if (nodeType == Document || nodeType == Element) {
 			throw 'Bad node type, unexpected $nodeType';
 		}
@@ -269,7 +269,7 @@ class Xml {
 		Returns an iterator of all child nodes.
 		Only works if the current node is an Element or a Document.
 	**/
-	public inline function iterator() : Iterator<Xml> {
+	public #if !cppia inline #end function iterator() : Iterator<Xml> {
 		ensureElementType();
 		return children.iterator();
 	}
@@ -297,7 +297,7 @@ class Xml {
 	/**
 		Returns the first child node.
 	**/
-	public inline function firstChild() : Xml {
+	public #if !cppia inline #end function firstChild() : Xml {
 		ensureElementType();
 		return children[0];
 	}
@@ -361,7 +361,7 @@ class Xml {
 	/**
 		Returns a String representation of the Xml node.
 	**/
-	public inline function toString() : String {
+	public #if !cppia inline #end function toString() : String {
 		return haxe.xml.Printer.print(this);
 	}
 

+ 5 - 0
std/cpp/cppia/HostClasses.hx

@@ -72,6 +72,7 @@ class HostClasses
    "Type",
    "Xml",
    "Date",
+   "Lambda",
    "DateTools",
    "List",
    "Math",
@@ -82,6 +83,7 @@ class HostClasses
    "haxe.ds.IntMap",
    "haxe.ds.ObjectMap",
    "haxe.ds.StringMap",
+   "haxe.ds.BalancedTree",
    "haxe.CallStack",
    "haxe.Serializer",
    "haxe.Unserializer",
@@ -184,6 +186,9 @@ class HostClasses
       externs.set("haxe._Int64.___Int64",true);
       externs.set("haxe._Int32.Int32_Impl_",true);
       externs.set("haxe._Int32.___Int32",true);
+      // Hidded in implementation classes
+      externs.set("haxe.ds.TreeNode",true);
+      externs.set("haxe.xml.XmlParserException",true);
       for(e in classes)
          externs.set(e,true);
 

+ 1 - 1
std/haxe/crypto/BaseCode.hx

@@ -22,7 +22,7 @@
 package haxe.crypto;
 
 /**
-	Allows to encode/decode String and bytes using a power of two base dictionnary.
+	Allows to encode/decode String and bytes using a power of two base dictionary.
 **/
 class BaseCode {
 

+ 13 - 10
std/haxe/macro/Compiler.hx

@@ -63,7 +63,7 @@ class Compiler {
 
 	/**
 		Removes a (static) field from a given class by name.
-		An error is thrown when className or field is invalid.
+		An error is thrown when `className` or `field` is invalid.
 	**/
 	public static function removeField( className : String, field : String, ?isStatic : Bool ) {
 		if( !path.match(className) ) throw "Invalid "+className;
@@ -73,7 +73,7 @@ class Compiler {
 
 	/**
 		Set the type of a (static) field at a given class by name.
-		An error is thrown when className or field is invalid.
+		An error is thrown when `className` or `field` is invalid.
 	**/
 	public static function setFieldType( className : String, field : String, type : String, ?isStatic : Bool ) {
 		if( !path.match(className) ) throw "Invalid "+className;
@@ -83,7 +83,7 @@ class Compiler {
 
 	/**
 		Add metadata to a (static) field or class by name.
-		An error is thrown when className or field is invalid.
+		An error is thrown when `className` or `field` is invalid.
 	**/
 	public static function addMetadata( meta : String, className : String, ?field : String, ?isStatic : Bool ) {
 		if( !path.match(className) ) throw "Invalid "+className;
@@ -111,14 +111,14 @@ class Compiler {
 	}
 
 	/**
-		Adds a native library depending on the platform (e.g. `-swf-lib` for Flash)
+		Adds a native library depending on the platform (e.g. `-swf-lib` for Flash).
 	**/
 	public static function addNativeLib( name : String ) {
 		untyped load("add_native_lib",1)(name.__s);
 	}
 
 	/**
-		Adds an argument to be passed to the native compiler (e.g. `-javac-arg` for Java)
+		Adds an argument to be passed to the native compiler (e.g. `-javac-arg` for Java).
 	 **/
 	public static function addNativeArg( argument : String )
 	{
@@ -183,7 +183,7 @@ class Compiler {
 	}
 
 	/**
-		Exclude a class or a enum without changing it to @:nativeGen.
+		Exclude a class or an enum without changing it to `@:nativeGen`.
 	**/
 	static function excludeBaseType( baseType : Type.BaseType ) : Void {
 		if (!baseType.isExtern) {
@@ -196,7 +196,10 @@ class Compiler {
 	}
 
 	/**
-		Exclude a given class or a complete package from being generated.
+		Exclude a specific class, enum, or all classes and enums in a
+		package from being generated. Excluded types become `extern`.
+		
+		@param rec If true, recursively excludes all sub-packages.
 	**/
 	public static function exclude( pack : String, ?rec = true ) {
 		Context.onGenerate(function(types) {
@@ -219,7 +222,7 @@ class Compiler {
 	}
 
 	/**
-		Exclude classes listed in an extern file (one per line) from being generated.
+		Exclude classes and enums listed in an extern file (one per line) from being generated.
 	**/
 	public static function excludeFile( fileName : String ) {
 		fileName = Context.resolvePath(fileName);
@@ -246,7 +249,7 @@ class Compiler {
 	}
 
 	/**
-		Load a type patch file that can modify declared classes fields types
+		Load a type patch file that can modify the field types within declared classes and enums.
 	**/
 	public static function patchTypes( file : String ) : Void {
 		var file = Context.resolvePath(file);
@@ -303,7 +306,7 @@ class Compiler {
 
 		In order to include module sub-types directly, their full dot path
 		including the containing module has to be used
-		(e.g. msignal.Signal.Signal0).
+		(e.g. `msignal.Signal.Signal0`).
 
 		This operation has no effect if the type has already been loaded, e.g.
 		through `Context.getType`.

+ 1 - 1
std/haxe/macro/ComplexTypeTools.hx

@@ -48,7 +48,7 @@ class ComplexTypeTools {
 		If [c] is null, the result is null.
 	**/
 	static public function toType( c : ComplexType ) : Null<Type>
-		return c == null ? null : haxe.macro.Context.typeof( { expr: ECheckType(macro null, c), pos: Context.currentPos() } );
+		return c == null ? null : Context.resolveType(c,Context.currentPos());
 
 	#end
 }

+ 12 - 0
std/haxe/macro/Context.hx

@@ -368,6 +368,18 @@ class Context {
 		return load("type_expr", 1)(e);
 	}
 
+	/**
+		Resolve type `t` and returns the corresponding `Type`.
+
+		Resolving the type may result in a compiler error which can be
+		caught using `try ... catch`.
+		Resolution is performed based on the current context in which the macro is called.
+	**/
+	@:require(haxe_ver >= 3.3)
+	public static function resolveType( t : ComplexType, p : Position ) : Type {
+		return load("resolve_type", 2)(t,p);
+	}
+	
 	/**
 		Returns the `ComplexType` corresponding to the given `Type` `t`.
 

+ 1 - 1
std/js/Lib.hx

@@ -50,7 +50,7 @@ class Lib {
 		This is only supported in environments where `require` function
 		is available, such as Node.js or RequireJS.
 	**/
-	public static inline function require( module:String ) : Dynamic {
+	@:extern public static inline function require( module:String ) : Dynamic {
 		return untyped __js__("require")(module);
 	}
 

+ 19 - 4
tests/RunCi.hx

@@ -64,21 +64,22 @@ class RunCi {
 		If `useRetry` is `true`, the command will be re-run if it exits with non-zero code (3 trials).
 		It is useful for running network-dependent commands.
 	*/
-	static function runCommand(cmd:String, args:Array<String>, useRetry:Bool = false):Void {
+	static function runCommand(cmd:String, ?args:Array<String>, useRetry:Bool = false):Void {
 		var trials = useRetry ? 3 : 1;
 		var exitCode:Int = 1;
+		var cmdStr = cmd + (args == null ? '' : ' $args');
 
 		while (trials-->0) {
-			Sys.println('Command: $cmd $args');
+			Sys.println('Command: $cmdStr');
 
 			var t = Timer.stamp();
 			exitCode = Sys.command(cmd, args);
 			var dt = Math.round(Timer.stamp() - t);
 
 			if (exitCode == 0)
-				successMsg('Command exited with $exitCode in ${dt}s: $cmd $args');
+				successMsg('Command exited with $exitCode in ${dt}s: $cmdStr');
 			else
-				failMsg('Command exited with $exitCode in ${dt}s: $cmd $args');
+				failMsg('Command exited with $exitCode in ${dt}s: $cmdStr');
 
 			if (exitCode == 0) {
 				return;
@@ -627,6 +628,20 @@ class RunCi {
 			// generate doc
 			runCommand("make", ["-s", "install_dox"]);
 			runCommand("make", ["-s", "package_doc"]);
+
+			// deploy doc to api.haxe.org
+			if (
+				gitInfo.branch == "development" && 
+				Sys.getEnv("DEPLOY") != null && 
+				Sys.getEnv("deploy_key_decrypt") != null
+			) {
+				//setup deploy_key
+				runCommand("openssl aes-256-cbc -k \"$deploy_key_decrypt\" -in extra/deploy_key.enc -out extra/deploy_key -d");
+				runCommand("chmod 600 extra/deploy_key");
+				runCommand("ssh-add extra/deploy_key");
+
+				runCommand("make", ["-s", "deploy_doc"]);
+			}
 		}
 	}
 

+ 16 - 0
type.ml

@@ -500,6 +500,22 @@ let map loop t =
 	| TDynamic t2 ->
 		if t == t2 then	t else TDynamic (loop t2)
 
+let dup t =
+	let monos = ref [] in
+	let rec loop t =
+		match t with
+		| TMono { contents = None } ->
+			(try
+				List.assq t !monos
+			with Not_found ->
+				let m = mk_mono() in
+				monos := (t,m) :: !monos;
+				m)
+		| _ ->
+			map loop t
+	in
+	loop t
+
 (* substitute parameters with other types *)
 let apply_params cparams params t =
 	match cparams with

+ 11 - 0
typecore.ml

@@ -365,6 +365,17 @@ let delay ctx p f =
 	in
 	ctx.g.delayed <- loop ctx.g.delayed
 
+let delay_late ctx p f =
+	let rec loop = function
+		| [] -> [p,[f]]
+		| (p2,l) :: rest ->
+			if p2 <= p then
+				(p2,l) :: loop rest
+			else
+				(p,[f]) :: (p2,l) :: rest
+	in
+	ctx.g.delayed <- loop ctx.g.delayed
+
 let rec flush_pass ctx p (where:string) =
 	match ctx.g.delayed with
 	| (p2,l) :: rest when p2 <= p ->

+ 3 - 1
typeload.ml

@@ -91,6 +91,8 @@ let module_pass_1 com m tdecls loadp =
 			let priv = List.mem HPrivate d.d_flags in
 			let path = make_path d.d_name priv in
 			let c = mk_class m path p in
+			(* we shouldn't load any other type until we propertly set cl_build *)
+			c.cl_build <- (fun() -> assert false);
 			c.cl_module <- m;
 			c.cl_private <- priv;
 			c.cl_doc <- d.d_doc;
@@ -2957,7 +2959,7 @@ let init_module_type ctx context_init do_init (decl,p) =
 				true;
 			with Exit ->
 				c.cl_build <- make_pass ctx build;
-				delay ctx PTypeField (fun() -> ignore(c.cl_build())); (* delay after PBuildClass, not very good but better than forgotten *)
+				delay_late ctx PBuildClass (fun() -> ignore(c.cl_build()));
 				false
 			| exn ->
 				c.cl_build <- (fun()-> true);

+ 130 - 59
typer.ml

@@ -62,6 +62,11 @@ type access_kind =
 	| AKUsing of texpr * tclass * tclass_field * texpr
 	| AKAccess of tabstract * tparams * tclass * texpr * texpr
 
+type object_decl_kind =
+	| ODKWithStructure of tanon
+	| ODKWithClass of tclass * tparams
+	| ODKPlain
+
 let build_call_ref : (typer -> access_kind -> expr list -> with_type -> pos -> texpr) ref = ref (fun _ _ _ _ _ -> assert false)
 
 let mk_infos ctx p params =
@@ -133,6 +138,20 @@ let get_iterable_param t =
 			raise Not_found)
 	| _ -> raise Not_found
 
+let get_abstract_froms a pl =
+	let l = List.map (apply_params a.a_params pl) a.a_from in
+	List.fold_left (fun acc (t,f) ->
+		match follow (field_type f) with
+		| TFun ([_,_,v],t) ->
+			(try
+				ignore(type_eq EqStrict t (TAbstract(a,List.map dup pl))); (* unify fields monomorphs *)
+				v :: acc
+			with Unify_error _ ->
+				acc)
+		| _ ->
+			acc
+	) l a.a_from_field
+
 (*
 	temporally remove the constant flag from structures to allow larger unification
 *)
@@ -3026,52 +3045,39 @@ and type_expr ctx (e,p) (with_type:with_type) =
 		let dynamic_parameter = ref None in
 		let a = (match with_type with
 		| WithType t ->
-			(match follow t with
-			| TAnon a when not (PMap.is_empty a.a_fields) -> Some a
-			(* issues with https://github.com/HaxeFoundation/haxe/issues/3437 *)
-(* 			| TAbstract (a,tl) when not (Meta.has Meta.CoreType a.a_meta) && a.a_from <> [] ->
-				begin match follow (Abstract.get_underlying_type a tl) with
-					| TAnon a when not (PMap.is_empty a.a_fields) -> Some a
-					| _ -> None
-				end *)
-			| TDynamic t when (follow t != t_dynamic) ->
-				dynamic_parameter := Some t;
-				Some {
-					a_status = ref Closed;
-					a_fields = PMap.empty;
-				}
-			| _ -> None)
-		| _ -> None
+			let rec loop t =
+				match follow t with
+				| TAnon a when not (PMap.is_empty a.a_fields) -> ODKWithStructure a
+				| TAbstract (a,pl) when not (Meta.has Meta.CoreType a.a_meta) ->
+					(match List.fold_left (fun acc t -> match loop t with ODKPlain -> acc | t -> t :: acc) [] (get_abstract_froms a pl) with
+					| [t] -> t
+					| _ -> ODKPlain)
+				| TDynamic t when (follow t != t_dynamic) ->
+					dynamic_parameter := Some t;
+					ODKWithStructure {
+						a_status = ref Closed;
+						a_fields = PMap.empty;
+					}
+				| TInst(c,tl) when Meta.has Meta.StructInit c.cl_meta ->
+					ODKWithClass(c,tl)
+				| _ ->
+					ODKPlain
+			in
+			loop t
+		| _ ->
+			ODKPlain
 		) in
 		let wrap_quoted_meta e =
 			mk (TMeta((Meta.QuotedField,[],e.epos),e)) e.etype e.epos
 		in
-		(match a with
-		| None ->
-			let rec loop (l,acc) (f,e) =
-				let f,is_quoted,is_valid = Parser.unquote_ident f in
-				if PMap.mem f acc then error ("Duplicate field in object declaration : " ^ f) p;
-				let e = type_expr ctx e Value in
-				(match follow e.etype with TAbstract({a_path=[],"Void"},_) -> error "Fields of type Void are not allowed in structures" e.epos | _ -> ());
-				let cf = mk_field f e.etype e.epos in
-				let e = if is_quoted then wrap_quoted_meta e else e in
-				((f,e) :: l, if is_valid then begin
-					if String.length f > 0 && f.[0] = '$' then error "Field names starting with a dollar are not allowed" p;
-					PMap.add f cf acc
-				end else acc)
-			in
-			let fields , types = List.fold_left loop ([],PMap.empty) fl in
-			let x = ref Const in
-			ctx.opened <- x :: ctx.opened;
-			mk (TObjectDecl (List.rev fields)) (TAnon { a_fields = types; a_status = x }) p
-		| Some a ->
+		let type_fields field_map =
 			let fields = ref PMap.empty in
 			let extra_fields = ref [] in
 			let fl = List.map (fun (n, e) ->
 				let n,is_quoted,is_valid = Parser.unquote_ident n in
 				if PMap.mem n !fields then error ("Duplicate field in object declaration : " ^ n) p;
 				let e = try
-					let t = (match !dynamic_parameter with Some t -> t | None -> (PMap.find n a.a_fields).cf_type) in
+					let t = (match !dynamic_parameter with Some t -> t | None -> (PMap.find n field_map).cf_type) in
 					let e = type_expr ctx e (WithType t) in
 					let e = Codegen.AbstractCast.cast_or_unify ctx t e p in
 					(try type_eq EqStrict e.etype t; e with Unify_error _ -> mk (TCast (e,None)) t e.epos)
@@ -3090,7 +3096,7 @@ and type_expr ctx (e,p) (with_type:with_type) =
 			) fl in
 			let t = (TAnon { a_fields = !fields; a_status = ref Const }) in
 			if not ctx.untyped then begin
-				(match PMap.foldi (fun n cf acc -> if not (Meta.has Meta.Optional cf.cf_meta) && not (PMap.mem n !fields) then n :: acc else acc) a.a_fields [] with
+				(match PMap.foldi (fun n cf acc -> if not (Meta.has Meta.Optional cf.cf_meta) && not (PMap.mem n !fields) then n :: acc else acc) field_map [] with
 					| [] -> ()
 					| [n] -> raise_or_display ctx [Unify_custom ("Object requires field " ^ n)] p
 					| nl -> raise_or_display ctx [Unify_custom ("Object requires fields: " ^ (String.concat ", " nl))] p);
@@ -3098,8 +3104,63 @@ and type_expr ctx (e,p) (with_type:with_type) =
 				| [] -> ()
 				| _ -> raise_or_display ctx (List.map (fun n -> has_extra_field t n) !extra_fields) p);
 			end;
+			t, fl
+		in
+		(match a with
+		| ODKPlain ->
+			let rec loop (l,acc) (f,e) =
+				let f,is_quoted,is_valid = Parser.unquote_ident f in
+				if PMap.mem f acc then error ("Duplicate field in object declaration : " ^ f) p;
+				let e = type_expr ctx e Value in
+				(match follow e.etype with TAbstract({a_path=[],"Void"},_) -> error "Fields of type Void are not allowed in structures" e.epos | _ -> ());
+				let cf = mk_field f e.etype e.epos in
+				let e = if is_quoted then wrap_quoted_meta e else e in
+				((f,e) :: l, if is_valid then begin
+					if String.length f > 0 && f.[0] = '$' then error "Field names starting with a dollar are not allowed" p;
+					PMap.add f cf acc
+				end else acc)
+			in
+			let fields , types = List.fold_left loop ([],PMap.empty) fl in
+			let x = ref Const in
+			ctx.opened <- x :: ctx.opened;
+			mk (TObjectDecl (List.rev fields)) (TAnon { a_fields = types; a_status = x }) p
+		| ODKWithStructure a ->
+			let t, fl = type_fields a.a_fields in
 			if !(a.a_status) <> Const then a.a_status := Closed;
-			mk (TObjectDecl fl) t p)
+			mk (TObjectDecl fl) t p
+		| ODKWithClass (c,tl) ->
+			let _,ctor = get_constructor ctx c tl p in
+			let args = match follow ctor.cf_type with
+				| TFun(args,_) -> args
+				| _ -> assert false
+			in
+			let fields = List.fold_left (fun acc (n,opt,t) ->
+				let f = mk_field n t ctor.cf_pos in
+				if opt then f.cf_meta <- [(Meta.Optional,[],ctor.cf_pos)];
+				PMap.add n f acc
+			) PMap.empty args in
+			let t,fl = type_fields fields in
+			let evars,fl,_ = List.fold_left (fun (evars,elocs,had_side_effect) (s,e) ->
+				begin match e.eexpr with
+				| TConst _ | TTypeExpr _ | TFunction _ ->
+					evars,(s,e) :: elocs,had_side_effect
+				| _ ->
+					if had_side_effect then begin
+						let v = gen_local ctx e.etype in
+						let ev = mk (TVar(v,Some e)) e.etype e.epos in
+						let eloc = mk (TLocal v) v.v_type e.epos in
+						(ev :: evars),((s,eloc) :: elocs),had_side_effect
+					end else
+						evars,(s,e) :: elocs,Optimizer.has_side_effect e
+				end
+			) ([],[],false) (List.rev fl) in
+			let el = List.map (fun (n,_,t) ->
+				try List.assoc n fl
+				with Not_found -> mk (TConst TNull) t p
+			) args in
+			let e = mk (TNew(c,tl,el)) (TInst(c,tl)) p in
+			mk (TBlock (List.rev (e :: (List.rev evars)))) e.etype e.epos
+		)
 	| EArrayDecl [(EFor _,_) | (EWhile _,_) as e] ->
 		let v = gen_local ctx (mk_mono()) in
 		let et = ref (EConst(Ident "null"),p) in
@@ -3197,18 +3258,25 @@ and type_expr ctx (e,p) (with_type:with_type) =
 	| EArrayDecl el ->
 		let tp = (match with_type with
 		| WithType t ->
-			(match follow t with
-			| TInst ({ cl_path = [],"Array" },[tp]) ->
-				(match follow tp with
-				| TMono _ -> None
-				| _ -> Some tp)
-			| TAnon _ ->
-				(try
-					Some (get_iterable_param t)
-				with Not_found ->
-					None)
-			| t ->
-				if t == t_dynamic then Some t else None)
+			let rec loop t =
+				(match follow t with
+				| TInst ({ cl_path = [],"Array" },[tp]) ->
+					(match follow tp with
+					| TMono _ -> None
+					| _ -> Some tp)
+				| TAnon _ ->
+					(try
+						Some (get_iterable_param t)
+					with Not_found ->
+						None)
+				| TAbstract (a,pl) ->
+					(match List.fold_left (fun acc t -> match loop t with None -> acc | Some t -> t :: acc) [] (get_abstract_froms a pl) with
+					| [t] -> Some t
+					| _ -> None)
+				| t ->
+					if t == t_dynamic then Some t else None)
+			in
+			loop t
 		| _ ->
 			None
 		) in
@@ -4410,14 +4478,14 @@ let get_type_patch ctx t sub =
 let macro_timer ctx path =
 	Common.timer (if Common.defined ctx.com Define.MacroTimes then "macro " ^ path else "macro execution")
 
-let typing_timer ctx f =
+let typing_timer ctx need_type f =
 	let t = Common.timer "typing" in
 	let old = ctx.com.error and oldp = ctx.pass in
 	(*
 		disable resumable errors... unless we are in display mode (we want to reach point of completion)
 	*)
 	if ctx.com.display = DMNone then ctx.com.error <- (fun e p -> raise (Error(Custom e,p)));
-	if ctx.pass < PTypeField then ctx.pass <- PTypeField;
+	if need_type && ctx.pass < PTypeField then ctx.pass <- PTypeField;
 	let exit() =
 		t();
 		ctx.com.error <- old;
@@ -4441,13 +4509,13 @@ let load_macro_ref : (typer -> path -> string -> pos -> (typer * ((string * bool
 
 let make_macro_api ctx p =
 	let parse_expr_string s p inl =
-		typing_timer ctx (fun() -> parse_expr_string ctx s p inl)
+		typing_timer ctx false (fun() -> parse_expr_string ctx s p inl)
 	in
 	{
 		Interp.pos = p;
 		Interp.get_com = (fun() -> ctx.com);
 		Interp.get_type = (fun s ->
-			typing_timer ctx (fun() ->
+			typing_timer ctx false (fun() ->
 				let path = parse_path s in
 				let tp = match List.rev (fst path) with
 					| s :: sl when String.length s > 0 && (match s.[0] with 'A'..'Z' -> true | _ -> false) ->
@@ -4462,8 +4530,11 @@ let make_macro_api ctx p =
 					None
 			)
 		);
+		Interp.resolve_type = (fun t p ->
+			typing_timer ctx false (fun() -> Typeload.load_complex_type ctx p t)
+		);
 		Interp.get_module = (fun s ->
-			typing_timer ctx (fun() ->
+			typing_timer ctx false (fun() ->
 				let path = parse_path s in
 				let m = List.map type_of_module_type (Typeload.load_module ctx path p).m_types in
 				m
@@ -4494,10 +4565,10 @@ let make_macro_api ctx p =
 		);
 		Interp.parse_string = parse_expr_string;
 		Interp.type_expr = (fun e ->
-			typing_timer ctx (fun() -> (type_expr ctx e Value))
+			typing_timer ctx true (fun() -> type_expr ctx e Value)
 		);
 		Interp.type_macro_expr = (fun e ->
-			let e = typing_timer ctx (fun() -> (type_expr ctx e Value)) in
+			let e = typing_timer ctx true (fun() -> type_expr ctx e Value) in
 			let rec loop e = match e.eexpr with
 				| TField(_,FStatic(c,({cf_kind = Method _} as cf))) -> ignore(!load_macro_ref ctx c.cl_path cf.cf_name e.epos)
 				| _ -> Type.iter loop e
@@ -4560,7 +4631,7 @@ let make_macro_api ctx p =
 		);
 		Interp.allow_package = (fun v -> Common.allow_package ctx.com v);
 		Interp.type_patch = (fun t f s v ->
-			typing_timer ctx (fun() ->
+			typing_timer ctx false (fun() ->
 				let v = (match v with None -> None | Some s ->
 					match parse_string ctx.com ("typedef T = " ^ s) null_pos false with
 					| _,[ETypedef { d_data = ct },_] -> Some ct
@@ -4712,7 +4783,7 @@ let make_macro_api ctx p =
 			end
 		);
 		Interp.module_dependency = (fun mpath file ismacro ->
-			let m = typing_timer ctx (fun() -> Typeload.load_module ctx (parse_path mpath) p) in
+			let m = typing_timer ctx false (fun() -> Typeload.load_module ctx (parse_path mpath) p) in
 			if ismacro then
 				m.m_extra.m_macro_calls <- file :: List.filter ((<>) file) m.m_extra.m_macro_calls
 			else