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

Merge branch 'development' into bugfix/8631-eval-statics-reset

Simon Krajewski преди 6 години
родител
ревизия
283dae9076
променени са 81 файла, в които са добавени 1483 реда и са изтрити 700 реда
  1. 1 0
      .gitignore
  2. 2 2
      Makefile
  3. 5 1
      libs/extc/extc_stubs.c
  4. 1 1
      libs/extlib-leftovers/Makefile
  5. 0 0
      libs/extlib-leftovers/uCharExt.ml
  6. 0 0
      libs/extlib-leftovers/uCharExt.mli
  7. 17 17
      libs/extlib-leftovers/uTF8.ml
  8. 1 1
      libs/extlib-leftovers/uTF8.mli
  9. 1 1
      libs/ttflib/tTFTools.ml
  10. 1 1
      opam
  11. 5 0
      src-json/define.json
  12. 6 4
      src/codegen/codegen.ml
  13. 42 12
      src/codegen/overloads.ml
  14. 102 190
      src/compiler/displayOutput.ml
  15. 40 16
      src/compiler/main.ml
  16. 3 5
      src/compiler/server.ml
  17. 1 1
      src/compiler/serverMessage.ml
  18. 21 7
      src/context/common.ml
  19. 1 0
      src/context/display/deprecationCheck.ml
  20. 8 3
      src/context/display/diagnostics.ml
  21. 12 75
      src/context/display/displayEmitter.ml
  22. 14 5
      src/context/display/displayException.ml
  23. 5 5
      src/context/display/displayFields.ml
  24. 232 0
      src/context/display/displayPath.ml
  25. 1 1
      src/context/display/displayToplevel.ml
  26. 1 1
      src/core/ast.ml
  27. 79 1
      src/core/display/completionItem.ml
  28. 3 3
      src/core/json/json.ml
  29. 24 1
      src/core/type.ml
  30. 1 1
      src/generators/gencpp.ml
  31. 1 1
      src/generators/gencs.ml
  32. 2 2
      src/generators/genhl.ml
  33. 2 2
      src/generators/genjava.ml
  34. 1 1
      src/generators/genswf9.ml
  35. 1 1
      src/generators/hlinterp.ml
  36. 1 1
      src/generators/jvm/jvmConstantPool.ml
  37. 7 5
      src/macro/eval/evalContext.ml
  38. 3 2
      src/macro/eval/evalDebug.ml
  39. 2 2
      src/macro/eval/evalDebugMisc.ml
  40. 7 7
      src/macro/eval/evalDebugSocket.ml
  41. 4 4
      src/macro/eval/evalStdLib.ml
  42. 3 3
      src/macro/eval/evalString.ml
  43. 0 1
      src/macro/macroApi.ml
  44. 1 1
      src/optimization/analyzer.ml
  45. 2 2
      src/syntax/lexer.ml
  46. 7 1
      src/syntax/parser.ml
  47. 135 19
      src/syntax/parserEntry.ml
  48. 18 3
      src/typing/calls.ml
  49. 8 12
      src/typing/macroContext.ml
  50. 125 56
      src/typing/matcher.ml
  51. 0 66
      src/typing/typeload.ml
  52. 32 13
      src/typing/typeloadFields.ml
  53. 4 4
      src/typing/typeloadModule.ml
  54. 135 5
      src/typing/typeloadParse.ml
  55. 2 2
      src/typing/typer.ml
  56. 8 6
      src/typing/typerDisplay.ml
  57. 126 116
      std/cpp/vm/Debugger.hx
  58. 10 0
      std/haxe/display/Display.hx
  59. 3 0
      std/haxe/display/Server.hx
  60. 2 2
      std/hl/Bytes.hx
  61. 1 1
      std/hl/_std/haxe/io/Bytes.hx
  62. 5 1
      std/js/_std/Array.hx
  63. 2 2
      std/php/_std/Array.hx
  64. 9 0
      tests/misc/java/projects/Issue2689/Main.hx
  65. 3 0
      tests/misc/java/projects/Issue2689/compile-fail.hxml
  66. 5 0
      tests/misc/java/projects/Issue2689/compile-fail.hxml.stderr
  67. 14 0
      tests/misc/projects/Issue5952/Main.hx
  68. 2 0
      tests/misc/projects/Issue5952/compile1-fail.hxml
  69. 1 0
      tests/misc/projects/Issue5952/compile1-fail.hxml.stderr
  70. 22 0
      tests/misc/projects/Issue6622/Main1.hx
  71. 2 0
      tests/misc/projects/Issue6622/compile1-fail.hxml
  72. 3 0
      tests/misc/projects/Issue6622/compile1-fail.hxml.stderr
  73. 6 0
      tests/misc/projects/Issue8677/Main.hx
  74. 1 0
      tests/misc/projects/Issue8677/compile-fail.hxml
  75. 1 0
      tests/misc/projects/Issue8677/compile-fail.hxml.stderr
  76. 35 0
      tests/optimization/src/issues/Issue5646.hx
  77. 24 0
      tests/optimization/src/issues/Issue6198.hx
  78. 21 0
      tests/sys/src/io/TestFileInput.hx
  79. 1 1
      tests/unit/src/unit/TestMain.hx
  80. 32 0
      tests/unit/src/unit/issues/Issue7672.hx
  81. 11 0
      tests/unit/src/unit/issues/Issue8700.hx

+ 1 - 0
.gitignore

@@ -120,6 +120,7 @@ tmp.tmp
 dev-display.hxml
 
 .DS_Store
+.history
 tests/sourcemaps/bin
 /*_plugin.ml
 tests/benchs/export/

+ 2 - 2
Makefile

@@ -34,7 +34,7 @@ STATICLINK?=0
 HAXE_DIRECTORIES=core core/json core/display syntax context context/display codegen codegen/gencommon generators generators/jvm optimization filters macro macro/eval macro/eval/bytes typing compiler
 EXTLIB_LIBS=extlib-leftovers extc neko javalib swflib ttflib ilib objsize pcre ziplib
 OCAML_LIBS=unix str threads dynlink
-OPAM_LIBS=sedlex xml-light extlib ptmap sha
+OPAM_LIBS=sedlex.ppx xml-light extlib ptmap sha
 
 FINDLIB_LIBS=$(OCAML_LIBS)
 FINDLIB_LIBS+=$(OPAM_LIBS)
@@ -141,7 +141,7 @@ _build/src/core/metaList.ml: src-json/meta.json prebuild
 build_src: | $(BUILD_SRC) _build/src/syntax/grammar.ml _build/src/compiler/version.ml _build/src/core/defineList.ml _build/src/core/metaList.ml
 
 prebuild: _build/src/core/json/json.ml _build/src/prebuild/main.ml
-	$(COMPILER) -safe-string -linkpkg -g -o $(PREBUILD_OUTPUT) -package sedlex -package extlib -I _build/src/core/json _build/src/core/json/json.ml _build/src/prebuild/main.ml
+	$(COMPILER) -safe-string -linkpkg -g -o $(PREBUILD_OUTPUT) -package sedlex.ppx -package extlib -I _build/src/core/json _build/src/core/json/json.ml _build/src/prebuild/main.ml
 
 haxe: build_src
 	$(MAKE) -f $(MAKEFILENAME) build_pass_1

+ 5 - 1
libs/extc/extc_stubs.c

@@ -522,10 +522,14 @@ CAMLprim value sys_time() {
 	elapsedNano = time * sTimebaseInfo.numer / sTimebaseInfo.denom;
 
 	return caml_copy_double(time / 1000000000.0);
-#else
+#elif defined CLOCK_MONOTONIC_RAW
 	struct timespec t;
 	clock_gettime(CLOCK_MONOTONIC_RAW, &t);
 	return caml_copy_double(TimeSpecToSeconds(t));
+#else
+	struct timespec t;
+	clock_gettime(CLOCK_MONOTONIC, &t);
+	return caml_copy_double(TimeSpecToSeconds(t));
 #endif
 }
 

+ 1 - 1
libs/extlib-leftovers/Makefile

@@ -3,7 +3,7 @@ OCAMLOPT=ocamlopt
 OCAMLC=ocamlc
 
 MODULES = \
- multiArray rbuffer uChar uTF8
+ multiArray rbuffer uCharExt uTF8
 
 # the list is topologically sorted
 

+ 0 - 0
libs/extlib-leftovers/uChar.ml → libs/extlib-leftovers/uCharExt.ml


+ 0 - 0
libs/extlib-leftovers/uChar.mli → libs/extlib-leftovers/uCharExt.mli


+ 17 - 17
libs/extlib-leftovers/uTF8.ml

@@ -1,6 +1,6 @@
-(* 
+(*
  * UTF-8 - UTF-8 encoded Unicode string
- * Copyright 2002, 2003 (C) Yamagata Yoriyuki. 
+ * Copyright 2002, 2003 (C) Yamagata Yoriyuki.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -18,11 +18,11 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  *)
 
-open UChar
+open UCharExt
 
 type t = string
 type index = int
-  
+
 let look s i =
   let n' =
     let n = Char.code s.[i] in
@@ -42,7 +42,7 @@ let look s i =
       let n' = n' lsl 6 lor (0x7f land m) in
       let m = Char.code (String.unsafe_get s (i + 2)) in
       let n' = n' lsl 6 lor (0x7f land m) in
-      n' lsl 6 lor (0x7f land m0)     
+      n' lsl 6 lor (0x7f land m0)
     else if n <= 0xfb then
       let n' = n - 0xf8 in
       let m0 = Char.code s.[i + 4] in
@@ -52,7 +52,7 @@ let look s i =
       let n' = n' lsl 6 lor (0x7f land m) in
       let m = Char.code (String.unsafe_get s (i + 3)) in
       let n' = n' lsl 6 lor (0x7f land m) in
-      n' lsl 6 lor (0x7f land m0)     
+      n' lsl 6 lor (0x7f land m0)
     else if n <= 0xfd then
       let n' = n - 0xfc in
       let m0 = Char.code s.[i + 5] in
@@ -75,7 +75,7 @@ let rec search_head s i =
   if n < 0x80 || n >= 0xc2 then i else
   search_head s (i + 1)
 
-let next s i = 
+let next s i =
   let n = Char.code s.[i] in
   if n < 0x80 then i + 1 else
   if n < 0xc0 then search_head s (i + 1) else
@@ -121,7 +121,7 @@ let add_uchar buf u =
   let k = int_of_uchar u in
   if k < 0 || k >= 0x4000000 then begin
     Buffer.add_char buf (Char.chr (0xfc + (k lsr 30)));
-    Buffer.add_char buf (Char.unsafe_chr (0x80 lor ((k lsr 24) land masq))); 
+    Buffer.add_char buf (Char.unsafe_chr (0x80 lor ((k lsr 24) land masq)));
     Buffer.add_char buf (Char.unsafe_chr (0x80 lor ((k lsr 18) land masq)));
     Buffer.add_char buf (Char.unsafe_chr (0x80 lor ((k lsr 12) land masq)));
     Buffer.add_char buf (Char.unsafe_chr (0x80 lor ((k lsr 6) land masq)));
@@ -146,7 +146,7 @@ let add_uchar buf u =
     Buffer.add_char buf (Char.unsafe_chr (0x80 lor ((k lsr 12) land masq)));
     Buffer.add_char buf (Char.unsafe_chr (0x80 lor ((k lsr 6) land masq)));
     Buffer.add_char buf (Char.unsafe_chr (0x80 lor (k land masq)));
-  end 
+  end
 
 let init len f =
   let buf = Buffer.create len in
@@ -193,26 +193,26 @@ let validate s =
     let n = Char.code (String.unsafe_get s i) in
     if n < 0x80 then main (i + 1) else
     if n < 0xc2 then raise Malformed_code else
-    if n <= 0xdf then 
-      if trail 1 (i + 1) (n - 0xc0) < 0x80 then raise Malformed_code else 
+    if n <= 0xdf then
+      if trail 1 (i + 1) (n - 0xc0) < 0x80 then raise Malformed_code else
       main (i + 2)
-    else if n <= 0xef then 
-      if trail 2 (i + 1) (n - 0xe0) < 0x800 then raise Malformed_code else 
+    else if n <= 0xef then
+      if trail 2 (i + 1) (n - 0xe0) < 0x800 then raise Malformed_code else
       main (i + 3)
-    else if n <= 0xf7 then 
+    else if n <= 0xf7 then
       if trail 3 (i + 1) (n - 0xf0) < 0x10000 then raise Malformed_code else
       main (i + 4)
-    else if n <= 0xfb then 
+    else if n <= 0xfb then
       if trail 4 (i + 1) (n - 0xf8) < 0x200000 then raise Malformed_code else
       main (i + 5)
-    else if n <= 0xfd then 
+    else if n <= 0xfd then
       let n = trail 5 (i + 1) (n - 0xfc) in
       if n lsr 16 < 0x400 then raise Malformed_code else
       main (i + 6)
     else raise Malformed_code in
   main 0
 
-module Buf = 
+module Buf =
   struct
     include Buffer
     type buf = t

+ 1 - 1
libs/extlib-leftovers/uTF8.mli

@@ -23,7 +23,7 @@
    The Module for UTF-8 encoded Unicode strings.
 *)
 
-open UChar
+open UCharExt
 
 (** UTF-8 encoded Unicode strings. the type is normal string. *)
 type t = string

+ 1 - 1
libs/ttflib/tTFTools.ml

@@ -210,7 +210,7 @@ let parse_range_str str =
 	let range = ref false in
 	let lut = Hashtbl.create 0 in
 	UTF8.iter (fun code ->
-		let code = UChar.code code in
+		let code = UCharExt.code code in
 		if code = Char.code '-' && !last <> Char.code '\\' then
 			range := true
 		else if !range then begin

+ 1 - 1
opam

@@ -22,7 +22,7 @@ depends: [
   "ocaml"               {>= "4.02"}
   "ocamlfind"           {build}
   "camlp5"              {build}
-  "sedlex"              {build & <= "1.99.4"} #https://github.com/HaxeFoundation/haxe/issues/7958
+  "sedlex"              {build}
   "ppx_tools_versioned" {build & != "5.2.1"} #https://github.com/alainfrisch/sedlex/issues/64
   "xml-light"           {build}
   "extlib"              {build & >= "1.7.6"}

+ 5 - 0
src-json/define.json

@@ -111,6 +111,11 @@
 		"doc": "Dump typed AST in dump subdirectory using specified mode or non-prettified default.",
 		"params": ["mode: pretty | record | position | legacy"]
 	},
+	{
+		"name": "DumpPath",
+		"define": "dump_path",
+		"doc": "Path to generate dumps to (default: \"dump\")."
+	},
 	{
 		"name": "DumpDependencies",
 		"define": "dump_dependencies",

+ 6 - 4
src/codegen/codegen.ml

@@ -275,7 +275,7 @@ module Dump = struct
 			close_out ch)
 
 	let create_dumpfile_from_path com path =
-		let buf,close = create_dumpfile [] ("dump" :: (platform_name_macro com) :: fst path @ [snd path]) in
+		let buf,close = create_dumpfile [] ((dump_path com) :: (platform_name_macro com) :: fst path @ [snd path]) in
 		buf,close
 
 	let dump_types com s_expr =
@@ -422,7 +422,8 @@ module Dump = struct
 			| None -> platform_name_macro com
 			| Some s -> s
 		in
-		let buf,close = create_dumpfile [] ["dump";target_name;".dependencies"] in
+		let dump_dependencies_path = [dump_path com;target_name;".dependencies"] in
+		let buf,close = create_dumpfile [] dump_dependencies_path in
 		let print fmt = Printf.kprintf (fun s -> Buffer.add_string buf s) fmt in
 		let dep = Hashtbl.create 0 in
 		List.iter (fun m ->
@@ -434,7 +435,8 @@ module Dump = struct
 			) m.m_extra.m_deps;
 		) com.Common.modules;
 		close();
-		let buf,close = create_dumpfile [] ["dump";target_name;".dependants"] in
+		let dump_dependants_path = [dump_path com;target_name;".dependants"] in
+		let buf,close = create_dumpfile [] dump_dependants_path in
 		let print fmt = Printf.kprintf (fun s -> Buffer.add_string buf s) fmt in
 		Hashtbl.iter (fun n ml ->
 			print "%s:\n" n;
@@ -617,4 +619,4 @@ module ExtClass = struct
 		let ef1 = mk (TField(ethis,FStatic(c,cf))) cf.cf_type p in
 		let e_assign = mk (TBinop(OpAssign,ef1,e)) e.etype p in
 		add_cl_init c e_assign
-end
+end

+ 42 - 12
src/codegen/overloads.ml

@@ -1,13 +1,29 @@
+open Globals
 open Type
+open Typecore
 
-let same_overload_args ?(get_vmtype) t1 t2 f1 f2 =
+type overload_args_comparison =
+  | Same
+  | Different
+  | Impl_conflict
+
+let distinguishes_funs_as_params ctx =
+  	match ctx.com.platform with
+  	| Java -> false
+  	| _ -> true
+
+let compare_overload_args ?(get_vmtype) ?(ctx) t1 t2 f1 f2 =
 	let get_vmtype = match get_vmtype with
 		| None -> (fun f -> f)
 		| Some f -> f
 	in
 	if List.length f1.cf_params <> List.length f2.cf_params then
-		false
+		Different
 	else
+	let amb_funs =
+		match ctx with
+		| None -> false
+		| Some ctx -> not (distinguishes_funs_as_params ctx) in
 	let rec follow_skip_null t = match t with
 		| TMono r ->
 			(match !r with
@@ -21,25 +37,39 @@ let same_overload_args ?(get_vmtype) t1 t2 f1 f2 =
 			follow_skip_null (apply_params t.t_params tl t.t_type)
 		| _ -> t
 	in
-	let same_arg t1 t2 =
+	let compare_type t1 t2 =
+		(if type_iseq t1 t2 then
+			Same
+		else if amb_funs && type_iseq (ambiguate_funs t1) (ambiguate_funs t2) then
+			Impl_conflict
+		else
+			Different) in
+	let compare_arg t1 t2 =
 		let t1 = get_vmtype (follow_skip_null t1) in
 		let t2 = get_vmtype (follow_skip_null t2) in
 		match t1, t2 with
-			| TType _, TType _ -> type_iseq t1 t2
+			| TType _, TType _ -> compare_type t1 t2
 			| TType _, _
-			| _, TType _ -> false
-			| _ -> type_iseq t1 t2
+			| _, TType _ -> Different
+			| _ -> compare_type t1 t2
 	in
 
 	match follow (apply_params f1.cf_params (List.map (fun (_,t) -> t) f2.cf_params) t1), follow t2 with
 		| TFun(a1,_), TFun(a2,_) ->
-			(try
-				List.for_all2 (fun (_,_,t1) (_,_,t2) ->
-				same_arg t1 t2) a1 a2
-			with Invalid_argument _ ->
-				false)
+			let rec loop args1 args2 =
+				match args1, args2 with
+				| [], [] -> Same
+				| [], _ | _, [] -> Different
+				| (_,_,t1) :: rest1, (_,_,t2) :: rest2 ->
+					match compare_arg t1 t2 with
+					| Same -> loop rest1 rest2
+					| result -> result
+			in
+			loop a1 a2
 		| _ -> assert false
 
+let same_overload_args ?(get_vmtype) t1 t2 f1 f2 =
+	compare_overload_args ?get_vmtype t1 t2 f1 f2 <> Different
 
 (** retrieves all overloads from class c and field i, as (Type.t * tclass_field) list *)
 let rec get_overloads c i =
@@ -258,4 +288,4 @@ struct
 
 			let r = loop [] !rated in
 			List.map fst r
-end
+end

+ 102 - 190
src/compiler/displayOutput.ml

@@ -78,7 +78,7 @@ let print_fields fields =
 			"literal",s,s_type (print_context()) t,None
 		| ITLocal v -> "local",v.v_name,s_type (print_context()) v.v_type,None
 		| ITKeyword kwd -> "keyword",Ast.s_keyword kwd,"",None
-		| ITExpression _ | ITAnonymous _ | ITTypeParameter _ -> assert false
+		| ITExpression _ | ITAnonymous _ | ITTypeParameter _ | ITDefine _ -> assert false
 	in
 	let fields = List.sort (fun k1 k2 -> compare (legacy_sort k1) (legacy_sort k2)) fields in
 	let fields = List.map convert fields in
@@ -129,7 +129,7 @@ let print_toplevel il =
 			Buffer.add_string b (Printf.sprintf "<i k=\"timer\">%s</i>\n" s)
 		| ITTypeParameter c ->
 			Buffer.add_string b (Printf.sprintf "<i k=\"type\" p=\"%s\"%s>%s</i>\n" (s_type_path c.cl_path) ("") (snd c.cl_path));
-		| ITMetadata _ | ITModule _ | ITKeyword _ | ITAnonymous _ | ITExpression _ ->
+		| ITMetadata _ | ITModule _ | ITKeyword _ | ITAnonymous _ | ITExpression _ | ITDefine _ ->
 			(* compat: don't add *)
 			()
 	) il;
@@ -178,8 +178,16 @@ let print_positions pl =
 module Memory = struct
 	open CompilationServer
 
+	let clear_descendants md =
+		List.iter (function
+			| TClassDecl c ->
+				c.cl_descendants <- []
+			| _ ->
+				()
+		) md.m_types
+
 	let update_module_type_deps deps md =
-		deps := Obj.repr md :: !deps;
+		let deps = ref (Obj.repr md :: deps) in
 		List.iter (fun t ->
 			match t with
 			| TClassDecl c ->
@@ -192,7 +200,8 @@ module Memory = struct
 				List.iter (fun n -> deps := Obj.repr (PMap.find n e.e_constrs) :: !deps) e.e_names;
 			| TTypeDecl t -> deps := Obj.repr t :: !deps;
 			| TAbstractDecl a -> deps := Obj.repr a :: !deps;
-		) md.m_types
+		) md.m_types;
+		!deps
 
 	let rec scan_module_deps m h =
 		if Hashtbl.mem h m.m_id then
@@ -202,6 +211,20 @@ module Memory = struct
 			PMap.iter (fun _ m -> scan_module_deps m h) m.m_extra.m_deps
 		end
 
+	let module_sign key md =
+		if md.m_extra.m_sign = key then "" else "(" ^ (try Digest.to_hex md.m_extra.m_sign with _ -> "???" ^ md.m_extra.m_sign) ^ ")"
+
+	let collect_leaks m deps out =
+		let leaks = ref [] in
+		let leak s =
+			leaks := s :: !leaks
+		in
+		if (Objsize.objsize m deps [Obj.repr Common.memory_marker]).Objsize.reached then leak "common";
+		PMap.iter (fun _ md ->
+			if (Objsize.objsize m deps [Obj.repr md]).Objsize.reached then leak (s_type_path md.m_path ^ module_sign m.m_extra.m_sign md);
+		) out;
+		!leaks
+
 	let get_out out =
 		Obj.repr Common.memory_marker :: PMap.fold (fun m acc -> Obj.repr m :: acc) out []
 
@@ -212,16 +235,19 @@ module Memory = struct
 			scan_module_deps m mdeps;
 			let deps = ref [Obj.repr null_module] in
 			let out = ref all_modules in
-			Hashtbl.iter (fun _ md ->
+			let deps = Hashtbl.fold (fun _ md deps ->
 				out := PMap.remove md.m_id !out;
 				if m == md then
-					()
+					deps
 				else
 					update_module_type_deps deps md;
-			) mdeps;
-			let chk = get_out !out in
-			let inf = Objsize.objsize m !deps chk in
-			(m,Objsize.size_with_headers inf, (inf.Objsize.reached,!deps,!out)) :: acc
+			) mdeps !deps in
+			clear_descendants m;
+			let out = !out in
+			let chk = get_out out in
+			let inf = Objsize.objsize m deps chk in
+			let leaks = if inf.reached then collect_leaks m deps out else [] in
+			(m,Objsize.size_with_headers inf, (inf.reached,deps,out,leaks)) :: acc
 		) cs.c_modules [] in
 		modules
 
@@ -241,7 +267,7 @@ module Memory = struct
 		Gc.compact();
 		let contexts = Hashtbl.create 0 in
 		let add_context sign =
-			let ctx = (sign,ref [],ref 0) in
+			let ctx = (sign,ref [],ref [],ref 0) in
 			Hashtbl.add contexts sign ctx;
 			ctx
 		in
@@ -252,16 +278,18 @@ module Memory = struct
 				add_context sign
 		in
 		let modules = collect_memory_stats cs.cache in
-		List.iter (fun (m,size,(reached,deps,_)) ->
-			let (_,l,mem) = get_context m.m_extra.m_sign in
-			let deps = ref deps in
-			update_module_type_deps deps m;
-			let deps = !deps in
+
+		List.iter (fun (m,size,(reached,deps,out,mleaks)) ->
+			let (_,l,leaks,mem) = get_context m.m_extra.m_sign in
+			if reached then leaks := (m,mleaks) :: !leaks;
+			let deps = update_module_type_deps deps m in
 			let types = List.map (fun md ->
 				let fields,inf = match md with
 					| TClassDecl c ->
+						let own_deps = ref deps in
 						let field acc cf =
 							let repr = Obj.repr cf in
+							own_deps := List.filter (fun repr' -> repr != repr') !own_deps;
 							let deps = List.filter (fun repr' -> repr' != repr) deps in
 							let size = Objsize.size_with_headers (Objsize.objsize cf deps []) in
 							(cf.cf_name,size) :: acc
@@ -276,7 +304,7 @@ module Memory = struct
 							]
 						) fields in
 						let repr = Obj.repr c in
-						let deps = List.filter (fun repr' -> repr' != repr) deps in
+						let deps = List.filter (fun repr' -> repr' != repr) !own_deps in
 						fields,Objsize.objsize c deps []
 					| TEnumDecl en ->
 						let repr = Obj.repr en in
@@ -291,20 +319,28 @@ module Memory = struct
 						let deps = List.filter (fun repr' -> repr' != repr) deps in
 						[],Objsize.objsize a deps []
 				in
-				md,Objsize.size_with_headers inf,fields
-			) m.m_types in
-			let types = List.sort (fun (_,size1,_) (_,size2,_) -> compare size2 size1) types in
-			let ja = List.map (fun (md,size,fields) ->
-				jobject [
+				let size = Objsize.size_with_headers inf in
+				let jo = jobject [
 					"path",jstring (s_type_path (t_infos md).mt_path);
 					"size",jint size;
 					"fields",jarray fields;
-				]
-			) types in
-			l := (m,size,jarray ja) :: !l;
+				] in
+				jo,size
+			) m.m_types in
+			let types = List.sort (fun (_,size1) (_,size2) -> compare size2 size1) types in
+			let types =
+				let inf = Objsize.objsize m.m_extra deps [] in
+				let size = Objsize.size_with_headers inf in
+				(jobject [
+					"path",jstring "m_extra";
+					"size",jint size;
+					"fields",jarray []
+				],size) :: types
+			in
+			l := (m,size,jarray (List.map fst types)) :: !l;
 			mem := !mem + size;
 		) modules;
-		let ja = Hashtbl.fold (fun key (sign,modules,size) l ->
+		let ja = Hashtbl.fold (fun key (sign,modules,leaks,size) l ->
 			let modules = List.sort (fun (_,size1,_) (_,size2,_)  -> compare size2 size1) !modules in
 			let modules = List.map (fun (m,size,jmt) ->
 				jobject [
@@ -313,6 +349,23 @@ module Memory = struct
 					"types",jmt;
 				]
 			) modules in
+			let modules = match !leaks with
+				| [] -> modules
+				| leaks ->
+					let jleaks = List.map (fun (m,leaks) ->
+						let jleaks = List.map (fun s -> jobject ["path",jstring s;"size",jint 0]) leaks in
+						jobject [
+							"path",jstring (s_type_path m.m_path);
+							"size",jint 0;
+							"fields",jarray jleaks;
+						]
+					) leaks in
+					jobject [
+						"path",jstring "?LEAKS";
+						"size",jint 0;
+						"types",jarray jleaks;
+					] :: modules
+			in
 			let j = try (List.assoc sign cs.signs).cs_json with Not_found -> jnull in
 			let jo = jobject [
 				"context",j;
@@ -329,6 +382,8 @@ module Memory = struct
 				"parserCache",jint (mem_size cs.cache.c_files);
 				"moduleCache",jint (mem_size cs.cache.c_modules);
 				"nativeLibCache",jint (mem_size cs.cache.c_native_libs);
+				"macroInterpreter",jint (mem_size MacroContext.macro_interp_cache);
+				"completionResult",jint (mem_size (DisplayException.last_completion_result));
 			]
 		]
 
@@ -350,15 +405,12 @@ module Memory = struct
 			print ("  typed modules " ^ size c.c_modules ^ " (" ^ string_of_int (Hashtbl.length c.c_modules) ^ " modules stored)");
 			let modules = collect_memory_stats c in
 			let cur_key = ref "" and tcount = ref 0 and mcount = ref 0 in
-			List.iter (fun (m,size,(reached,deps,out)) ->
+			List.iter (fun (m,size,(reached,deps,out,leaks)) ->
 				let key = m.m_extra.m_sign in
 				if key <> !cur_key then begin
 					print (Printf.sprintf ("    --- CONFIG %s ----------------------------") (Digest.to_hex key));
 					cur_key := key;
 				end;
-				let sign md =
-					if md.m_extra.m_sign = key then "" else "(" ^ (try Digest.to_hex md.m_extra.m_sign with _ -> "???" ^ md.m_extra.m_sign) ^ ")"
-				in
 				print (Printf.sprintf "    %s : %s" (s_type_path m.m_path) (fmt_size size));
 				(if reached then try
 					incr mcount;
@@ -372,16 +424,13 @@ module Memory = struct
 							raise Exit;
 						end;
 					in
-					if (Objsize.objsize m deps [Obj.repr Common.memory_marker]).Objsize.reached then leak "common";
-					PMap.iter (fun _ md ->
-						if (Objsize.objsize m deps [Obj.repr md]).Objsize.reached then leak (s_type_path md.m_path ^ sign md);
-					) out;
+					List.iter leak leaks;
 				with Exit ->
 					());
 				if verbose then begin
 					print (Printf.sprintf "      %d total deps" (List.length deps));
 					PMap.iter (fun _ md ->
-						print (Printf.sprintf "      dep %s%s" (s_type_path md.m_path) (sign md));
+						print (Printf.sprintf "      dep %s%s" (s_type_path md.m_path) (module_sign key md));
 					) m.m_extra.m_deps;
 				end;
 				flush stdout
@@ -393,158 +442,6 @@ module Memory = struct
 			print "Cache dump complete")
 end
 
-module TypePathHandler = struct
-	let unique l =
-		let rec _unique = function
-			| [] -> []
-			| x1 :: x2 :: l when x1 = x2 -> _unique (x2 :: l)
-			| x :: l -> x :: _unique l
-		in
-		_unique (List.sort compare l)
-
-	let rec read_type_path com p =
-		let classes = ref [] in
-		let packages = ref [] in
-		let p = (match p with
-			| x :: l ->
-				(try
-					match PMap.find x com.package_rules with
-					| Directory d -> d :: l
-					| Remap s -> s :: l
-					| _ -> p
-				with
-					Not_found -> p)
-			| _ -> p
-		) in
-		List.iter (fun path ->
-			let dir = path ^ String.concat "/" p in
-			let r = (try Sys.readdir dir with _ -> [||]) in
-			Array.iter (fun f ->
-				if (try (Unix.stat (dir ^ "/" ^ f)).Unix.st_kind = Unix.S_DIR with _ -> false) then begin
-					if f.[0] >= 'a' && f.[0] <= 'z' then begin
-						if p = ["."] then
-							match read_type_path com [f] with
-							| [] , [] -> ()
-							| _ ->
-								try
-									match PMap.find f com.package_rules with
-									| Forbidden -> ()
-									| Remap f -> packages := f :: !packages
-									| Directory _ -> raise Not_found
-								with Not_found ->
-									packages := f :: !packages
-						else
-							packages := f :: !packages
-					end;
-				end else if file_extension f = "hx" && f <> "import.hx" then begin
-					let c = Filename.chop_extension f in
-					try
-						ignore(String.index c '.')
-					with Not_found ->
-						if String.length c < 2 || String.sub c (String.length c - 2) 2 <> "__" then classes := c :: !classes;
-				end;
-			) r;
-		) com.class_path;
-		let process_lib lib =
-			List.iter (fun (path,name) ->
-				if path = p then classes := name :: !classes else
-				let rec loop p1 p2 =
-					match p1, p2 with
-					| [], _ -> ()
-					| x :: _, [] -> packages := x :: !packages
-					| a :: p1, b :: p2 -> if a = b then loop p1 p2
-				in
-				loop path p
-			) lib#list_modules;
-		in
-		List.iter process_lib com.native_libs.swf_libs;
-		List.iter process_lib com.native_libs.net_libs;
-		List.iter process_lib com.native_libs.java_libs;
-		unique !packages, unique !classes
-
-	(** raise field completion listing packages and modules in a given package *)
-	let complete_type_path com p =
-		let packs, modules = read_type_path com p in
-		if packs = [] && modules = [] then
-			(abort ("No modules found in " ^ String.concat "." p) null_pos)
-		else
-			let packs = List.map (fun n -> make_ci_package (p,n) []) packs in
-			let modules = List.map (fun n -> make_ci_module (p,n)) modules in
-			Some (packs @ modules)
-
-	(** raise field completion listing module sub-types and static fields *)
-	let complete_type_path_inner com p c cur_package is_import =
-		try
-			let sl_pack,s_module = match List.rev p with
-				| s :: sl when s.[0] >= 'A' && s.[0] <= 'Z' -> List.rev sl,s
-				| _ -> p,c
-			in
-			let ctx = Typer.create com in
-			(* This is a bit wacky: We want to reset the display position so that revisiting the display file
-			   does not raise another TypePath exception. However, we still want to have it treated like the
-			   display file, so we just set the position to 0 (#6558). *)
-			let old = DisplayPosition.display_position#get in
-			DisplayPosition.display_position#set {old with pmin = 0; pmax = 0};
-			let rec lookup p =
-				try
-					TypeloadModule.load_module ctx (p,s_module) null_pos
-				with e ->
-					if cur_package then
-						match List.rev p with
-						| [] -> raise e
-						| _ :: p -> lookup (List.rev p)
-					else
-						raise e
-			in
-			let m = Std.finally (fun () -> DisplayPosition.display_position#set old) lookup sl_pack in
-			let statics = ref None in
-			let enum_statics = ref None in
-			let public_types = List.filter (fun t ->
-				let tinfos = t_infos t in
-				let is_module_type = snd tinfos.mt_path = c in
-				if is_import && is_module_type then begin match t with
-					| TClassDecl c | TAbstractDecl {a_impl = Some c} ->
-						ignore(c.cl_build());
-						statics := Some c
-					| TEnumDecl en ->
-						enum_statics := Some en
-					| _ -> ()
-				end;
-				not tinfos.mt_private
-			) m.m_types in
-			let types =
-				if c <> s_module then
-					[]
-				else
-					List.map (fun mt ->
-						make_ci_type (CompletionItem.CompletionModuleType.of_module_type mt) ImportStatus.Imported None
-					) public_types
-			in
-			let class_origin c = match c.cl_kind with
-				| KAbstractImpl a -> Self (TAbstractDecl a)
-				| _ -> Self (TClassDecl c)
-			in
-			let tpair t =
-				(t,DisplayEmitter.completion_type_of_type ctx t)
-			in
-			let make_field_doc c cf =
-				make_ci_class_field (CompletionClassField.make cf CFSStatic (class_origin c) true) (tpair cf.cf_type)
-			in
-			let fields = match !statics with
-				| None -> types
-				| Some c -> types @ (List.map (make_field_doc c) (List.filter (fun cf -> has_class_field_flag cf CfPublic) c.cl_ordered_statics))
-			in
-			let fields = match !enum_statics with
-				| None -> fields
-				| Some en -> PMap.fold (fun ef acc ->
-					make_ci_enum_field (CompletionEnumField.make ef (Self (TEnumDecl en)) true) (tpair ef.ef_type) :: acc
-				) en.e_constrs fields
-			in
-			Some fields
-		with _ ->
-			abort ("Could not load module " ^ (s_type_path (p,c))) null_pos
-end
-
 (* New JSON stuff *)
 
 open Json
@@ -658,6 +555,11 @@ let handle_display_argument com file_pos pre_compilation did_something =
 			pmax = pos;
 		}
 
+type display_path_kind =
+	| DPKNormal of path
+	| DPKMacro of path
+	| DPKNone
+
 let process_display_file com classes =
 	let get_module_path_from_file_path com spath =
 		let rec loop = function
@@ -681,7 +583,7 @@ let process_display_file com classes =
 	in
 	match com.display.dms_display_file_policy with
 		| DFPNo ->
-			None
+			DPKNone
 		| dfp ->
 			if dfp = DFPOnly then begin
 				classes := [];
@@ -691,8 +593,18 @@ let process_display_file com classes =
 			let path = match get_module_path_from_file_path com real with
 			| Some path ->
 				if com.display.dms_kind = DMPackage then raise_package (fst path);
-				classes := path :: !classes;
-				Some path
+				let path = match ExtString.String.nsplit (snd path) "." with
+					| [name;"macro"] ->
+						(* If we have a .macro.hx path, don't add the file to classes because the compiler won't find it.
+						   This can happen if we're completing in such a file. *)
+						DPKMacro (fst path,name)
+					| [name] ->
+						classes := path :: !classes;
+						DPKNormal path
+					| _ ->
+						assert false
+				in
+				path
 			| None ->
 				if not (Sys.file_exists real) then failwith "Display file does not exist";
 				(match List.rev (ExtString.String.nsplit real Path.path_sep) with

+ 40 - 16
src/compiler/main.ml

@@ -81,7 +81,7 @@ let error ctx msg p =
 	ctx.has_error <- true
 
 let reserved_flags = [
-	"cross";"js";"lua";"neko";"flash";"php";"cpp";"cs";"java";"python";
+	"true";"false";"null";"cross";"js";"lua";"neko";"flash";"php";"cpp";"cs";"java";"python";
 	"as3";"swc";"macro";"sys";"static";"utf16";"haxe";"haxe_ver"
 	]
 
@@ -478,20 +478,23 @@ let run_or_diagnose com f arg =
 	| _ ->
 		f arg
 
-(** Creates the typer context and types [classes] into it. *)
-let do_type ctx native_libs config_macros classes =
+let create_typer_context ctx native_libs =
 	let com = ctx.com in
 	ctx.setup();
 	Common.log com ("Classpath: " ^ (String.concat ";" com.class_path));
 	Common.log com ("Defines: " ^ (String.concat ";" (PMap.foldi (fun k v acc -> (match v with "1" -> k | _ -> k ^ "=" ^ v) :: acc) com.defines.Define.values [])));
-	let t = Timer.timer ["typing"] in
 	Typecore.type_expr_ref := (fun ?(mode=MGet) ctx e with_type -> Typer.type_expr ~mode ctx e with_type);
 	List.iter (fun f -> f ()) (List.rev com.callbacks#get_before_typer_create);
 	(* Native lib pass 1: Register *)
-	let fl = List.map (fun (file,extern) -> NativeLibraryHandler.add_native_lib com file extern) native_libs in
+	let fl = List.map (fun (file,extern) -> NativeLibraryHandler.add_native_lib com file extern) (List.rev native_libs) in
 	(* Native lib pass 2: Initialize *)
 	List.iter (fun f -> f()) fl;
-	let tctx = Typer.create com in
+	Typer.create com
+
+(** Creates the typer context and types [classes] into it. *)
+let do_type tctx config_macros classes =
+	let com = tctx.Typecore.com in
+	let t = Timer.timer ["typing"] in
 	let add_signature desc =
 		Option.may (fun cs -> CompilationServer.maybe_add_context_sign cs com desc) (CompilationServer.get ());
 	in
@@ -509,8 +512,7 @@ let do_type ctx native_libs config_macros classes =
 		| Some cs,DMUsage _ -> FindReferences.find_possible_references tctx cs;
 		| _ -> ()
 	end;
-	t();
-	tctx
+	t()
 
 let load_display_module_in_macro tctx display_file_dot_path clear = match display_file_dot_path with
 	| Some cpath ->
@@ -577,7 +579,13 @@ let filter ctx tctx display_file_dot_path =
 	com.modules <- modules;
 	(* Special case for diagnostics: We don't want to load the display file in macro mode because there's a chance it might not be
 		macro-compatible. This means that we might some macro-specific diagnostics, but I don't see what we could do about that. *)
-	if ctx.com.display.dms_force_macro_typing && (match ctx.com.display.dms_kind with DMDiagnostics _ -> false | _ -> true) then begin
+	let should_load_in_macro = match ctx.com.display.dms_kind with
+		(* Special case for the special case: If the display file has a block which becomes active if `macro` is defined, we can safely
+		   type the module in macro context. (#8682). *)
+		| DMDiagnostics _ -> com.display_information.display_module_has_macro_defines
+		| _ -> true
+	in
+	if ctx.com.display.dms_force_macro_typing && should_load_in_macro then begin
 		match load_display_module_in_macro  tctx display_file_dot_path false with
 		| None -> ()
 		| Some mctx ->
@@ -764,12 +772,13 @@ try
 			Common.raw_define com l;
 		),"<name[:ver]>","use a haxelib library");
 		("Compilation",["-D";"--define"],[],Arg.String (fun var ->
+			let flag = try fst (ExtString.String.split var "=") with _ -> var in
 			let raise_reserved description =
 				raise (Arg.Bad (description ^ " and cannot be defined from the command line"))
 			in
-			if List.mem var reserved_flags then raise_reserved (Printf.sprintf "`%s` is a reserved compiler flag" var);
+			if List.mem flag reserved_flags then raise_reserved (Printf.sprintf "`%s` is a reserved compiler flag" flag);
 			List.iter (fun ns ->
-				if ExtString.String.starts_with var (ns ^ ".") then raise_reserved (Printf.sprintf "`%s` uses the reserved compiler flag namespace `%s.*`" var ns)
+				if ExtString.String.starts_with flag (ns ^ ".") then raise_reserved (Printf.sprintf "`%s` uses the reserved compiler flag namespace `%s.*`" flag ns)
 			) reserved_flag_namespaces;
 			Common.raw_define com var;
 		),"<var[=value]>","define a conditional compilation flag");
@@ -1013,7 +1022,21 @@ try
 		if !cmds = [] && not !did_something then raise (HelpMessage (usage_string basic_args_spec usage));
 	end else begin
 		(* Actual compilation starts here *)
-		let tctx = do_type ctx !native_libs !config_macros !classes in
+		let tctx = create_typer_context ctx !native_libs in
+		let display_file_dot_path = match display_file_dot_path with
+			| DPKMacro path ->
+				ignore(load_display_module_in_macro tctx (Some path) true);
+				Some path
+			| DPKNormal path ->
+				Some path
+			| DPKNone ->
+				None
+		in
+		begin try
+			do_type tctx !config_macros !classes;
+		with TypeloadParse.DisplayInMacroBlock ->
+			ignore(load_display_module_in_macro tctx display_file_dot_path true);
+		end;
 		handle_display ctx tctx display_file_dot_path;
 		filter ctx tctx display_file_dot_path;
 		if ctx.has_error then raise Abort;
@@ -1053,7 +1076,7 @@ with
 		error ctx m p
 	| Arg.Bad msg ->
 		error ctx ("Error: " ^ msg) null_pos
-	| Failure msg when not (is_debug_run()) ->
+	| Failure msg when not is_debug_run ->
 		error ctx ("Error: " ^ msg) null_pos
 	| HelpMessage msg ->
 		com.info msg null_pos
@@ -1125,9 +1148,10 @@ with
 		let fields =
 			try begin match c with
 				| None ->
-					DisplayOutput.TypePathHandler.complete_type_path com p
+					DisplayPath.TypePathHandler.complete_type_path com p
 				| Some (c,cur_package) ->
-					DisplayOutput.TypePathHandler.complete_type_path_inner com p c cur_package is_import
+					let ctx = Typer.create com in
+					DisplayPath.TypePathHandler.complete_type_path_inner ctx p c cur_package is_import
 			end with Common.Abort(msg,p) ->
 				error ctx msg p;
 				None
@@ -1161,7 +1185,7 @@ with
 		raise exc
 	| Out_of_memory as exc ->
 		raise exc
-	| e when (try Sys.getenv "OCAMLRUNPARAM" <> "b" || CompilationServer.runs() with _ -> true) && not (is_debug_run()) ->
+	| e when (try Sys.getenv "OCAMLRUNPARAM" <> "b" || CompilationServer.runs() with _ -> true) && not is_debug_run ->
 		error ctx (Printexc.to_string e) null_pos
 
 ;;

+ 3 - 5
src/compiler/server.ml

@@ -16,8 +16,7 @@ let measure_times = ref false
 let prompt = ref false
 let start_time = ref (Timer.get_time())
 
-let is_debug_run() =
-	try Sys.getenv "HAXEDEBUG" = "1" with _ -> false
+let is_debug_run = try Sys.getenv "HAXEDEBUG" = "1" with _ -> false
 
 type context = {
 	com : Common.context;
@@ -527,9 +526,8 @@ let create sctx write params =
 			current file in order to run diagnostics on it again. *)
 		if ctx.com.display.dms_display || (match ctx.com.display.dms_kind with DMDiagnostics _ -> true | _ -> false) then begin
 			let file = (DisplayPosition.display_position#get).pfile in
-			let fkey = (file,sign) in
 			(* force parsing again : if the completion point have been changed *)
-			CompilationServer.remove_file cs fkey;
+			CompilationServer.remove_files cs file;
 			sctx.removed_modules <- CompilationServer.filter_modules cs file;
 			add_delay sctx recache_removed_modules;
 		end;
@@ -615,7 +613,7 @@ let wait_loop process_params verbose accept =
 			let estr = Printexc.to_string e in
 			ServerMessage.uncaught_error estr;
 			(try write ("\x02\n" ^ estr); with _ -> ());
-			if is_debug_run() then print_endline (estr ^ "\n" ^ Printexc.get_backtrace());
+			if is_debug_run then print_endline (estr ^ "\n" ^ Printexc.get_backtrace());
 			if e = Out_of_memory then begin
 				close();
 				exit (-1);

+ 1 - 1
src/compiler/serverMessage.ml

@@ -134,7 +134,7 @@ let message s =
 let gc_stats time =
 	if config.print_stats then begin
 		let stat = Gc.quick_stat() in
-		let size = (float_of_int stat.Gc.heap_words) *. 4. in
+		let size = (float_of_int stat.Gc.heap_words) *. (float_of_int (Sys.word_size / 8)) in
 		print_endline (Printf.sprintf "Compacted memory %.3fs %.1fMB" time (size /. (1024. *. 1024.)));
 	end
 

+ 21 - 7
src/context/common.ml

@@ -154,12 +154,13 @@ end
 type shared_display_information = {
 	mutable import_positions : (pos,bool ref * placed_name list) PMap.t;
 	mutable diagnostics_messages : (string * pos * DisplayTypes.DiagnosticsKind.t * DisplayTypes.DiagnosticsSeverity.t) list;
+	mutable dead_blocks : (string,(pos * expr) list) Hashtbl.t;
 }
 
 type display_information = {
 	mutable unresolved_identifiers : (string * pos * (string * CompletionItem.t * int) list) list;
 	mutable interface_field_implementations : (tclass * tclass_field * tclass * tclass_field option) list;
-	mutable dead_blocks : (string,pos list) Hashtbl.t;
+	mutable display_module_has_macro_defines : bool;
 }
 
 (* This information is shared between normal and macro context. *)
@@ -421,12 +422,13 @@ let create version s_version args =
 			shared_display_information = {
 				import_positions = PMap.empty;
 				diagnostics_messages = [];
+				dead_blocks = Hashtbl.create 0;
 			}
 		};
 		display_information = {
 			unresolved_identifiers = [];
 			interface_field_implementations = [];
-			dead_blocks = Hashtbl.create 0;
+			display_module_has_macro_defines = false;
 		};
 		sys_args = args;
 		debug = false;
@@ -504,7 +506,7 @@ let clone com =
 		display_information = {
 			unresolved_identifiers = [];
 			interface_field_implementations = [];
-			dead_blocks = Hashtbl.create 0;
+			display_module_has_macro_defines = false;
 		};
 		defines = {
 			values = com.defines.values;
@@ -750,12 +752,12 @@ let to_utf8 str p =
 		UTF8.Malformed_code ->
 			(* ISO to utf8 *)
 			let b = UTF8.Buf.create 0 in
-			String.iter (fun c -> UTF8.Buf.add_char b (UChar.of_char c)) str;
+			String.iter (fun c -> UTF8.Buf.add_char b (UCharExt.of_char c)) str;
 			UTF8.Buf.contents b
 	in
 	let ccount = ref 0 in
 	UTF8.iter (fun c ->
-		let c = UChar.code c in
+		let c = UCharExt.code c in
 		if (c >= 0xD800 && c <= 0xDFFF) || c >= 0x110000 then abort "Invalid unicode char" p;
 		incr ccount;
 		if c > 0x10000 then incr ccount;
@@ -779,7 +781,7 @@ let utf16_add buf c =
 
 let utf8_to_utf16 str zt =
 	let b = Buffer.create (String.length str * 2) in
-	(try UTF8.iter (fun c -> utf16_add b (UChar.code c)) str with Invalid_argument _ | UChar.Out_of_range -> ()); (* if malformed *)
+	(try UTF8.iter (fun c -> utf16_add b (UCharExt.code c)) str with Invalid_argument _ | UCharExt.Out_of_range -> ()); (* if malformed *)
 	if zt then utf16_add b 0;
 	Buffer.contents b
 
@@ -821,4 +823,16 @@ let dump_context com = s_record_fields "" [
 	"class_path",s_list ", " (fun s -> s) com.class_path;
 	"defines",s_pmap (fun s -> s) (fun s -> s) com.defines.values;
 	"defines_signature",s_opt (fun s -> Digest.to_hex s) com.defines.defines_signature;
-]
+]
+
+let dump_path com =
+	Define.defined_value_safe ~default:"dump" com.defines Define.DumpPath
+
+let adapt_defines_to_macro_context defines =
+	let values = ref defines.values in
+	List.iter (fun p -> values := PMap.remove (Globals.platform_name p) !values) Globals.platforms;
+	let to_remove = List.map (fun d -> fst (Define.infos d)) [Define.NoTraces] in
+	let to_remove = to_remove @ List.map (fun (_,d) -> "flash" ^ d) flash_versions in
+	values := PMap.foldi (fun k v acc -> if List.mem k to_remove then acc else PMap.add k v acc) !values PMap.empty;
+	values := PMap.add "macro" "1" !values;
+	{values = !values; defines_signature = None }

+ 1 - 0
src/context/display/deprecationCheck.ml

@@ -90,6 +90,7 @@ let run com =
 			(match c.cl_init with None -> () | Some e -> run_on_expr com e);
 			List.iter (run_on_field com) c.cl_ordered_statics;
 			List.iter (run_on_field com) c.cl_ordered_fields;
+			curclass := null_class;
 		| _ ->
 			()
 	) com.types

+ 8 - 3
src/context/display/diagnostics.ml

@@ -194,10 +194,15 @@ module Printer = struct
 			add DKDeprecationWarning p DiagnosticsSeverity.Warning (JString s);
 		) DeprecationCheck.warned_positions;
 		Hashtbl.iter (fun file ranges ->
-			List.iter (fun p ->
-				add DKInactiveBlock p DiagnosticsSeverity.Hint JNull
+			List.iter (fun (p,e) ->
+				let jo = JObject [
+					"expr",JObject [
+						"string",JString (Ast.Printer.s_expr e)
+					]
+				] in
+				add DKInactiveBlock p DiagnosticsSeverity.Hint jo
 			) ranges
-		) com.display_information.dead_blocks;
+		) com.shared.shared_display_information.dead_blocks;
 		let jl = Hashtbl.fold (fun file diag acc ->
 			let jl = Hashtbl.fold (fun _ (dk,p,sev,jargs) acc ->
 				(JObject [

+ 12 - 75
src/context/display/displayEmitter.ml

@@ -74,75 +74,12 @@ let sort_fields l with_type tk =
 	in
 	l
 
-let completion_type_of_type ctx ?(values=PMap.empty) t =
-	let get_import_status path =
-		try
-			let mt' = ctx.g.do_load_type_def ctx null_pos {tpackage = []; tname = snd path; tparams = []; tsub = None} in
-			if path <> (t_infos mt').mt_path then Shadowed else Imported
-		with _ ->
-			Unimported
-	in
-	let rec ppath mpath tpath tl = {
-		ct_pack = fst tpath;
-		ct_module_name = snd mpath;
-		ct_type_name = snd tpath;
-		ct_import_status = get_import_status tpath;
-		ct_params = List.map (from_type PMap.empty) tl;
-	}
-	and funarg value (name,opt,t) = {
-		ct_name = name;
-		ct_optional = opt;
-		ct_type = from_type PMap.empty t;
-		ct_value = value
-	}
-	and from_type values t = match t with
-		| TMono r ->
-			begin match !r with
-				| None -> CTMono
-				| Some t -> from_type values t
-			end
-		| TLazy r ->
-			from_type values (lazy_type r)
-		| TInst({cl_kind = KTypeParameter _} as c,_) ->
-			CTInst ({
-				ct_pack = fst c.cl_path;
-				ct_module_name = snd c.cl_module.m_path;
-				ct_type_name = snd c.cl_path;
-				ct_import_status = Imported;
-				ct_params = [];
-			})
-		| TInst(c,tl) ->
-			CTInst (ppath c.cl_module.m_path c.cl_path tl)
-		| TEnum(en,tl) ->
-			CTEnum (ppath en.e_module.m_path en.e_path tl)
-		| TType(td,tl) ->
-			CTTypedef (ppath td.t_module.m_path td.t_path tl)
-		| TAbstract(a,tl) ->
-			CTAbstract (ppath a.a_module.m_path a.a_path tl)
-		| TFun(tl,t) when not (PMap.is_empty values) ->
-			let get_arg n = try Some (PMap.find n values) with Not_found -> None in
-			CTFunction {
-				ct_args = List.map (fun (n,o,t) -> funarg (get_arg n) (n,o,t)) tl;
-				ct_return = from_type PMap.empty t;
-			}
-		| TFun(tl,t) ->
-			CTFunction {
-				ct_args = List.map (funarg None) tl;
-				ct_return = from_type PMap.empty t;
-			}
-		| TAnon an ->
-			let afield af = {
-				ctf_field = af;
-				ctf_type = from_type PMap.empty af.cf_type;
-			} in
-			CTAnonymous {
-				ct_fields = PMap.fold (fun cf acc -> afield cf :: acc) an.a_fields [];
-				ct_status = !(an.a_status);
-			}
-		| TDynamic t ->
-			CTDynamic (if t == t_dynamic then None else Some (from_type PMap.empty t))
-	in
-	from_type values t
+let get_import_status ctx path =
+	try
+		let mt' = ctx.g.do_load_type_def ctx null_pos {tpackage = []; tname = snd path; tparams = []; tsub = None} in
+		if path <> (t_infos mt').mt_path then Shadowed else Imported
+	with _ ->
+		Unimported
 
 let display_module_type ctx mt p = match ctx.com.display.dms_kind with
 	| DMDefinition | DMTypeDefinition ->
@@ -158,7 +95,7 @@ let display_module_type ctx mt p = match ctx.com.display.dms_kind with
 		ReferencePosition.set (snd infos.mt_path,infos.mt_name_pos,KModuleType)
 	| DMHover ->
 		let t = type_of_module_type mt in
-		let ct = completion_type_of_type ctx t in
+		let ct = CompletionType.from_type (get_import_status ctx) t in
 		raise_hover (make_ci_type (CompletionModuleType.of_module_type mt) ImportStatus.Imported (Some (t,ct))) None p
 	| _ -> ()
 
@@ -173,7 +110,7 @@ let rec display_type ctx t p =
 		| _ ->
 			match dm.dms_kind with
 			| DMHover ->
-				let ct = completion_type_of_type ctx t in
+				let ct = CompletionType.from_type (get_import_status ctx) t in
 				let ci = make_ci_expr (mk (TConst TNull) t p) (t,ct) in
 				raise_hover ci None p
 			| _ ->
@@ -213,7 +150,7 @@ let display_variable ctx v p = match ctx.com.display.dms_kind with
 	| DMTypeDefinition -> raise_position_of_type v.v_type
 	| DMUsage _ -> ReferencePosition.set (v.v_name,v.v_pos,KVar)
 	| DMHover ->
-		let ct = completion_type_of_type ctx ~values:(get_value_meta v.v_meta) v.v_type in
+		let ct = CompletionType.from_type (get_import_status ctx) ~values:(get_value_meta v.v_meta) v.v_type in
 		raise_hover (make_ci_local v (v.v_type,ct)) None p
 	| _ -> ()
 
@@ -239,7 +176,7 @@ let display_field ctx origin scope cf p = match ctx.com.display.dms_kind with
             | Self (TClassDecl c),CFSConstructor,TFun(tl,_) -> {cf with cf_type = TFun(tl,TInst(c,List.map snd c.cl_params))}
             | _ -> cf
         in
-		let ct = completion_type_of_type ctx ~values:(get_value_meta cf.cf_meta) cf.cf_type in
+		let ct = CompletionType.from_type (get_import_status ctx) ~values:(get_value_meta cf.cf_meta) cf.cf_type in
 		raise_hover (make_ci_class_field (CompletionClassField.make cf scope origin true) (cf.cf_type,ct)) None p
 	| _ -> ()
 
@@ -251,7 +188,7 @@ let display_enum_field ctx en ef p = match ctx.com.display.dms_kind with
 	| DMTypeDefinition -> raise_position_of_type ef.ef_type
 	| DMUsage _ -> ReferencePosition.set (ef.ef_name,ef.ef_name_pos,KEnumField)
 	| DMHover ->
-		let ct = completion_type_of_type ctx ef.ef_type in
+		let ct = CompletionType.from_type (get_import_status ctx) ef.ef_type in
 		raise_hover (make_ci_enum_field (CompletionEnumField.make ef (Self (TEnumDecl en)) true) (ef.ef_type,ct)) None p
 	| _ -> ()
 
@@ -302,7 +239,7 @@ let check_field_modifiers ctx c cf override display_modifier =
 			let l = PMap.fold (fun (c,cf) fields ->
 				let origin = Parent (TClassDecl c) in
 				ignore(follow cf.cf_type);
-				let ct = completion_type_of_type ctx ~values:(get_value_meta cf.cf_meta) cf.cf_type in
+				let ct = CompletionType.from_type (get_import_status ctx) ~values:(get_value_meta cf.cf_meta) cf.cf_type in
 				make_ci_class_field (CompletionClassField.make cf CFSMember origin true) (cf.cf_type,ct) :: fields
 			) missing_fields [] in
 			let l = sort_fields l NoValue TKOverride in

+ 14 - 5
src/context/display/displayException.ml

@@ -95,23 +95,32 @@ let filter_somehow ctx items kind subj =
 		if DynArray.length ret < !max_completion_items then
 			DynArray.add ret (CompletionItem.to_json ctx (Some index) item);
 	) acc_types;
-	DynArray.to_list ret,DynArray.length ret = !max_completion_items
+	DynArray.to_list ret,DynArray.length ret
 
 let fields_to_json ctx fields kind subj =
 	last_completion_result := Array.of_list fields;
 	let needs_filtering = !max_completion_items > 0 && Array.length !last_completion_result > !max_completion_items in
-	let ja,did_filter = if needs_filtering then
+	let ja,num_items = if needs_filtering then
 		filter_somehow ctx fields kind subj
 	else
-		List.mapi (fun i item -> CompletionItem.to_json ctx (Some i) item) fields,false
+		List.mapi (fun i item -> CompletionItem.to_json ctx (Some i) item) fields,Array.length !last_completion_result
  	in
+	let did_filter = num_items = !max_completion_items in
 	if did_filter then last_completion_pos := Some subj.s_start_pos;
+	let filter_string = (match subj.s_name with None -> "" | Some name -> name) in
+	let p = Parser.cut_pos_at_display subj.s_insert_pos in
+	(* print_endline (Printf.sprintf "FIELDS OUTPUT:\n\tfilter_string: %s\n\t    num items: %i\n\t     position: %s\n\t   before cut: %s"
+		filter_string
+		num_items
+		(Printer.s_pos p)
+		(Printer.s_pos subj.s_insert_pos)
+	); *)
 	let fl =
 		("items",jarray ja) ::
 		("isIncomplete",jbool did_filter) ::
 		("mode",CompletionResultKind.to_json ctx kind) ::
-		("filterString",(match subj.s_name with None -> jstring "" | Some name -> jstring name)) ::
-		("replaceRange",generate_pos_as_range (Parser.cut_pos_at_display subj.s_insert_pos)) ::
+		("filterString",jstring filter_string) ::
+		("replaceRange",generate_pos_as_range p) ::
 		[]
 	in
 	jobject fl

+ 5 - 5
src/context/display/displayFields.ml

@@ -76,7 +76,7 @@ let collect_static_extensions ctx items e p =
 									| _ -> TClassDecl c
 								in
 								let origin = StaticExtension(decl) in
-								let ct = DisplayEmitter.completion_type_of_type ctx ~values:(get_value_meta f.cf_meta) f.cf_type in
+								let ct = CompletionType.from_type (get_import_status ctx) ~values:(get_value_meta f.cf_meta) f.cf_type in
 								let item = make_ci_class_field (CompletionClassField.make f CFSMember origin true) (f.cf_type,ct) in
 								PMap.add f.cf_name item acc
 							end
@@ -115,7 +115,7 @@ let collect ctx e_ast e dk with_type p =
 			can_access ctx c cf stat
 	in
 	let make_class_field origin cf =
-		let ct = DisplayEmitter.completion_type_of_type ctx ~values:(get_value_meta cf.cf_meta) cf.cf_type in
+		let ct = CompletionType.from_type (get_import_status ctx) ~values:(get_value_meta cf.cf_meta) cf.cf_type in
 		make_ci_class_field (CompletionClassField.make cf CFSMember origin true) (cf.cf_type,ct)
 	in
 	let rec loop items t =
@@ -210,7 +210,7 @@ let collect ctx e_ast e dk with_type p =
 						should_access c cf false &&
 						(not (Meta.has Meta.Impl cf.cf_meta) || Meta.has Meta.Enum cf.cf_meta)
 					in
-					let ct = DisplayEmitter.completion_type_of_type ctx ~values:(get_value_meta cf.cf_meta) cf.cf_type in
+					let ct = CompletionType.from_type (get_import_status ctx) ~values:(get_value_meta cf.cf_meta) cf.cf_type in
 					let add origin make_field =
 						PMap.add name (make_field (CompletionClassField.make cf CFSMember origin true) (cf.cf_type,ct)) acc
 					in
@@ -253,7 +253,7 @@ let collect ctx e_ast e dk with_type p =
 				let t = opt_args args ret in
 				let cf = mk_field "bind" (tfun [t] t) p null_pos in
 				cf.cf_kind <- Method MethNormal;
-				let ct = DisplayEmitter.completion_type_of_type ctx ~values:(get_value_meta cf.cf_meta) t in
+				let ct = CompletionType.from_type (get_import_status ctx) ~values:(get_value_meta cf.cf_meta) t in
 				let item = make_ci_class_field (CompletionClassField.make cf CFSStatic BuiltIn true) (t,ct) in
 				PMap.add "bind" item items
 			end else
@@ -267,7 +267,7 @@ let collect ctx e_ast e dk with_type p =
 			let cf = mk_field "code" ctx.t.tint e.epos null_pos in
 			cf.cf_doc <- Some "The character code of this character (inlined at compile-time).";
 			cf.cf_kind <- Var { v_read = AccNormal; v_write = AccNever };
-			let ct = DisplayEmitter.completion_type_of_type ctx ~values:(get_value_meta cf.cf_meta) cf.cf_type in
+			let ct = CompletionType.from_type (get_import_status ctx) ~values:(get_value_meta cf.cf_meta) cf.cf_type in
 			let item = make_ci_class_field (CompletionClassField.make cf CFSMember BuiltIn true) (cf.cf_type,ct) in
 			PMap.add cf.cf_name item PMap.empty
 		| _ ->

+ 232 - 0
src/context/display/displayPath.ml

@@ -0,0 +1,232 @@
+open Globals
+open Typecore
+open Type
+open Common
+open CompletionItem
+open ClassFieldOrigin
+open DisplayException
+open DisplayEmitter
+open DisplayPosition
+open ImportHandling
+
+module TypePathHandler = struct
+	let unique l =
+		let rec _unique = function
+			| [] -> []
+			| x1 :: x2 :: l when x1 = x2 -> _unique (x2 :: l)
+			| x :: l -> x :: _unique l
+		in
+		_unique (List.sort compare l)
+
+	let rec read_type_path com p =
+		let classes = ref [] in
+		let packages = ref [] in
+		let p = (match p with
+			| x :: l ->
+				(try
+					match PMap.find x com.package_rules with
+					| Directory d -> d :: l
+					| Remap s -> s :: l
+					| _ -> p
+				with
+					Not_found -> p)
+			| _ -> p
+		) in
+		List.iter (fun path ->
+			let dir = path ^ String.concat "/" p in
+			let r = (try Sys.readdir dir with _ -> [||]) in
+			Array.iter (fun f ->
+				if (try (Unix.stat (dir ^ "/" ^ f)).Unix.st_kind = Unix.S_DIR with _ -> false) then begin
+					if f.[0] >= 'a' && f.[0] <= 'z' then begin
+						if p = ["."] then
+							match read_type_path com [f] with
+							| [] , [] -> ()
+							| _ ->
+								try
+									match PMap.find f com.package_rules with
+									| Forbidden -> ()
+									| Remap f -> packages := f :: !packages
+									| Directory _ -> raise Not_found
+								with Not_found ->
+									packages := f :: !packages
+						else
+							packages := f :: !packages
+					end;
+				end else if file_extension f = "hx" && f <> "import.hx" then begin
+					let c = Filename.chop_extension f in
+					try
+						ignore(String.index c '.')
+					with Not_found ->
+						if String.length c < 2 || String.sub c (String.length c - 2) 2 <> "__" then classes := c :: !classes;
+				end;
+			) r;
+		) com.class_path;
+		let process_lib lib =
+			List.iter (fun (path,name) ->
+				if path = p then classes := name :: !classes else
+				let rec loop p1 p2 =
+					match p1, p2 with
+					| [], _ -> ()
+					| x :: _, [] -> packages := x :: !packages
+					| a :: p1, b :: p2 -> if a = b then loop p1 p2
+				in
+				loop path p
+			) lib#list_modules;
+		in
+		List.iter process_lib com.native_libs.swf_libs;
+		List.iter process_lib com.native_libs.net_libs;
+		List.iter process_lib com.native_libs.java_libs;
+		unique !packages, unique !classes
+
+	(** raise field completion listing packages and modules in a given package *)
+	let complete_type_path com p =
+		let packs, modules = read_type_path com p in
+		if packs = [] && modules = [] then
+			(abort ("No modules found in " ^ String.concat "." p) null_pos)
+		else
+			let packs = List.map (fun n -> make_ci_package (p,n) []) packs in
+			let modules = List.map (fun n -> make_ci_module (p,n)) modules in
+			Some (packs @ modules)
+
+	(** raise field completion listing module sub-types and static fields *)
+	let complete_type_path_inner ctx p c cur_package is_import =
+		try
+			let sl_pack,s_module = match List.rev p with
+				| s :: sl when s.[0] >= 'A' && s.[0] <= 'Z' -> List.rev sl,s
+				| _ -> p,c
+			in
+			(* This is a bit wacky: We want to reset the display position so that revisiting the display file
+			   does not raise another TypePath exception. However, we still want to have it treated like the
+			   display file, so we just set the position to 0 (#6558). *)
+			let old = display_position#get in
+			display_position#set {old with pmin = 0; pmax = 0};
+			let rec lookup p =
+				try
+					ctx.g.do_load_module ctx (p,s_module) null_pos
+				with e ->
+					if cur_package then
+						match List.rev p with
+						| [] -> raise e
+						| _ :: p -> lookup (List.rev p)
+					else
+						raise e
+			in
+			let m = Std.finally (fun () -> display_position#set old) lookup sl_pack in
+			let statics = ref None in
+			let enum_statics = ref None in
+			let public_types = List.filter (fun t ->
+				let tinfos = t_infos t in
+				let is_module_type = snd tinfos.mt_path = c in
+				if is_import && is_module_type then begin match t with
+					| TClassDecl c | TAbstractDecl {a_impl = Some c} ->
+						ignore(c.cl_build());
+						statics := Some c
+					| TEnumDecl en ->
+						enum_statics := Some en
+					| _ -> ()
+				end;
+				not tinfos.mt_private
+			) m.m_types in
+			let types =
+				if c <> s_module then
+					[]
+				else
+					List.map (fun mt ->
+						make_ci_type (CompletionItem.CompletionModuleType.of_module_type mt) ImportStatus.Imported None
+					) public_types
+			in
+			let class_origin c = match c.cl_kind with
+				| KAbstractImpl a -> Self (TAbstractDecl a)
+				| _ -> Self (TClassDecl c)
+			in
+			let tpair t =
+				(t,CompletionType.from_type (get_import_status ctx) t)
+			in
+			let make_field_doc c cf =
+				make_ci_class_field (CompletionClassField.make cf CFSStatic (class_origin c) true) (tpair cf.cf_type)
+			in
+			let fields = match !statics with
+				| None -> types
+				| Some c -> types @ (List.map (make_field_doc c) (List.filter (fun cf -> has_class_field_flag cf CfPublic) c.cl_ordered_statics))
+			in
+			let fields = match !enum_statics with
+				| None -> fields
+				| Some en -> PMap.fold (fun ef acc ->
+					make_ci_enum_field (CompletionEnumField.make ef (Self (TEnumDecl en)) true) (tpair ef.ef_type) :: acc
+				) en.e_constrs fields
+			in
+			Some fields
+		with _ ->
+			abort ("Could not load module " ^ (s_type_path (p,c))) null_pos
+end
+
+let resolve_position_by_path ctx path p =
+	let mt = ctx.g.do_load_type_def ctx p path in
+	let p = (t_infos mt).mt_pos in
+	raise_positions [p]
+
+
+let handle_path_display ctx path p =
+	let class_field c name =
+		ignore(c.cl_build());
+		let cf = PMap.find name c.cl_statics in
+		let origin = match c.cl_kind with
+			| KAbstractImpl a -> Self (TAbstractDecl a)
+			| _ -> Self (TClassDecl c)
+		in
+		display_field ctx origin CFSStatic cf p
+	in
+	match ImportHandling.convert_import_to_something_usable display_position#get path,ctx.com.display.dms_kind with
+		| (IDKPackage [s],p),DMDefault ->
+			DisplayToplevel.collect_and_raise ctx TKType WithType.no_value CRImport (s,p) p
+		| (IDKPackage sl,p),DMDefault ->
+			let sl = match List.rev sl with
+				| s :: sl -> List.rev sl
+				| [] -> assert false
+			in
+			raise (Parser.TypePath(sl,None,true,p))
+		| (IDKPackage _,_),_ ->
+			() (* ? *)
+		| (IDKModule(sl,s),_),(DMDefinition | DMTypeDefinition) ->
+			(* We assume that we want to go to the module file, not a specific type
+			   which might not even exist anyway. *)
+			let mt = ctx.g.do_load_module ctx (sl,s) p in
+			let p = { pfile = mt.m_extra.m_file; pmin = 0; pmax = 0} in
+			raise_positions [p]
+		| (IDKModule(sl,s),_),DMHover ->
+			let m = ctx.g.do_load_module ctx (sl,s) p in
+			begin try
+				let mt = List.find (fun mt -> snd (t_infos mt).mt_path = s) m.m_types in
+				display_module_type ctx mt p;
+			with Not_found ->
+				()
+			end
+		| (IDKSubType(sl,sm,st),p),DMHover ->
+			(* TODO: remove code duplication once load_type_def change is in *)
+			let m = ctx.g.do_load_module ctx (sl,sm) p in
+			begin try
+				let mt = List.find (fun mt -> snd (t_infos mt).mt_path = st) m.m_types in
+				display_module_type ctx mt p;
+			with Not_found ->
+				()
+			end
+		| (IDKModule(sl,s),p),_ ->
+			raise (Parser.TypePath(sl,None,true,p))
+		| (IDKSubType(sl,sm,st),p),(DMDefinition | DMTypeDefinition) ->
+			resolve_position_by_path ctx { tpackage = sl; tname = sm; tparams = []; tsub = Some st} p
+		| (IDKSubType(sl,sm,st),p),_ ->
+			raise (Parser.TypePath(sl,Some(sm,false),true,p))
+		| ((IDKSubTypeField(sl,sm,st,sf) | IDKModuleField(sl,(sm as st),sf)),p),DMDefault ->
+			raise (Parser.TypePath(sl @ [sm],Some(st,false),true,p));
+		| ((IDKSubTypeField(sl,sm,st,sf) | IDKModuleField(sl,(sm as st),sf)),p),_ ->
+			let m = ctx.g.do_load_module ctx (sl,sm) p in
+			List.iter (fun t -> match t with
+				| TClassDecl c when snd c.cl_path = st ->
+					class_field c sf
+				| TAbstractDecl {a_impl = Some c; a_path = (_,st')} when st' = st ->
+					class_field c sf
+				| _ ->
+					()
+			) m.m_types;
+		| (IDK,_),_ ->
+			()

+ 1 - 1
src/context/display/displayToplevel.ml

@@ -233,7 +233,7 @@ let collect ctx tk with_type =
 	(* Collection starts here *)
 
 	let tpair ?(values=PMap.empty) t =
-		let ct = DisplayEmitter.completion_type_of_type ctx ~values t in
+		let ct = CompletionType.from_type (DisplayEmitter.get_import_status ctx) ~values t in
 		(t,ct)
 	in
 	begin match tk with

+ 1 - 1
src/core/ast.ml

@@ -542,7 +542,7 @@ let unescape s =
 					in
 					if u >= 0xD800 && u < 0xE000 then
 						fail (Some "UTF-16 surrogates are not allowed in strings.");
-					UTF8.add_uchar b (UChar.uchar_of_int u);
+					UTF8.add_uchar b (UCharExt.uchar_of_int u);
 					inext := !inext + a;
 				| _ ->
 					fail None);

+ 79 - 1
src/core/display/completionItem.ml

@@ -412,6 +412,69 @@ module CompletionType = struct
 
 	let to_json ctx ct =
 		generate_type ctx ct
+
+	let from_type get_import_status ?(values=PMap.empty) t =
+		let rec ppath mpath tpath tl = {
+			ct_pack = fst tpath;
+			ct_module_name = snd mpath;
+			ct_type_name = snd tpath;
+			ct_import_status = get_import_status tpath;
+			ct_params = List.map (from_type PMap.empty) tl;
+		}
+		and funarg value (name,opt,t) = {
+			ct_name = name;
+			ct_optional = opt;
+			ct_type = from_type PMap.empty t;
+			ct_value = value
+		}
+		and from_type values t = match t with
+			| TMono r ->
+				begin match !r with
+					| None -> CTMono
+					| Some t -> from_type values t
+				end
+			| TLazy r ->
+				from_type values (lazy_type r)
+			| TInst({cl_kind = KTypeParameter _} as c,_) ->
+				CTInst ({
+					ct_pack = fst c.cl_path;
+					ct_module_name = snd c.cl_module.m_path;
+					ct_type_name = snd c.cl_path;
+					ct_import_status = Imported;
+					ct_params = [];
+				})
+			| TInst(c,tl) ->
+				CTInst (ppath c.cl_module.m_path c.cl_path tl)
+			| TEnum(en,tl) ->
+				CTEnum (ppath en.e_module.m_path en.e_path tl)
+			| TType(td,tl) ->
+				CTTypedef (ppath td.t_module.m_path td.t_path tl)
+			| TAbstract(a,tl) ->
+				CTAbstract (ppath a.a_module.m_path a.a_path tl)
+			| TFun(tl,t) when not (PMap.is_empty values) ->
+				let get_arg n = try Some (PMap.find n values) with Not_found -> None in
+				CTFunction {
+					ct_args = List.map (fun (n,o,t) -> funarg (get_arg n) (n,o,t)) tl;
+					ct_return = from_type PMap.empty t;
+				}
+			| TFun(tl,t) ->
+				CTFunction {
+					ct_args = List.map (funarg None) tl;
+					ct_return = from_type PMap.empty t;
+				}
+			| TAnon an ->
+				let afield af = {
+					ctf_field = af;
+					ctf_type = from_type PMap.empty af.cf_type;
+				} in
+				CTAnonymous {
+					ct_fields = PMap.fold (fun cf acc -> afield cf :: acc) an.a_fields [];
+					ct_status = !(an.a_status);
+				}
+			| TDynamic t ->
+				CTDynamic (if t == t_dynamic then None else Some (from_type PMap.empty t))
+		in
+		from_type values t
 end
 
 open CompletionModuleType
@@ -433,6 +496,7 @@ type t_kind =
 	| ITAnonymous of tanon
 	| ITExpression of texpr
 	| ITTypeParameter of tclass
+	| ITDefine of string * string option
 
 type t = {
 	ci_kind : t_kind;
@@ -458,6 +522,7 @@ let make_ci_keyword kwd = make (ITKeyword kwd) None
 let make_ci_anon an t = make (ITAnonymous an) (Some t)
 let make_ci_expr e t = make (ITExpression e) (Some t)
 let make_ci_type_param c t = make (ITTypeParameter c) (Some t)
+let make_ci_define n v t = make (ITDefine(n,v)) (Some t)
 
 let get_index item = match item.ci_kind with
 	| ITLocal _ -> 0
@@ -474,6 +539,7 @@ let get_index item = match item.ci_kind with
 	| ITAnonymous _ -> 11
 	| ITExpression _ -> 12
 	| ITTypeParameter _ -> 13
+	| ITDefine _ -> 14
 
 let get_sort_index tk item p expected_name = match item.ci_kind with
 	| ITLocal v ->
@@ -523,7 +589,8 @@ let get_sort_index tk item p expected_name = match item.ci_kind with
 	| ITAnonymous _
 	| ITExpression _
 	| ITTimer _
-	| ITMetadata _ ->
+	| ITMetadata _
+	| ITDefine _ ->
 		500,""
 
 let legacy_sort item = match item.ci_kind with
@@ -549,6 +616,7 @@ let legacy_sort item = match item.ci_kind with
 	| ITAnonymous _ -> 11,""
 	| ITExpression _ -> 12,""
 	| ITTypeParameter _ -> 13,""
+	| ITDefine _ -> 14,""
 
 let get_name item = match item.ci_kind with
 	| ITLocal v -> v.v_name
@@ -564,6 +632,7 @@ let get_name item = match item.ci_kind with
 	| ITAnonymous _ -> ""
 	| ITExpression _ -> ""
 	| ITTypeParameter c -> snd c.cl_path
+	| ITDefine(n,_) -> n
 
 let get_type item = item.ci_type
 
@@ -581,6 +650,7 @@ let get_filter_name item = match item.ci_kind with
 	| ITAnonymous _ -> ""
 	| ITExpression _ -> ""
 	| ITTypeParameter c -> snd c.cl_path
+	| ITDefine(n,_) -> n
 
 let get_documentation item = match item.ci_kind with
 	| ITClassField cf | ITEnumAbstractField(_,cf) -> cf.field.cf_doc
@@ -701,6 +771,14 @@ let to_json ctx index item =
 				]
 			| _ -> assert false
 			end
+		| ITDefine(n,v) -> "Define",jobject [
+			"name",jstring n;
+			"value",(match v with
+				| None -> jnull
+				| Some v -> jstring v
+			);
+			(* TODO: docs etc *)
+		]
 	in
 	let jindex = match index with
 		| None -> []

+ 3 - 3
src/core/json/json.ml

@@ -315,7 +315,7 @@ module Reader = struct
 	and finish_escaped_char buf lexbuf =
 		match%sedlex lexbuf with
 		| '"' | '\\' | '/' ->
-			Buffer.add_char buf (char_of_int (Sedlexing.lexeme_char lexbuf 0))
+			Buffer.add_char buf (Uchar.to_char (Sedlexing.lexeme_char lexbuf 0))
 		| 'b' ->
 			Buffer.add_char buf '\b'
 		| 'f' ->
@@ -329,7 +329,7 @@ module Reader = struct
 		| 'u', hex, hex, hex, hex ->
 			let a,b,c,d =
 				match Sedlexing.lexeme lexbuf with
-				| [|_; a; b; c; d|] -> a, b, c, d
+				| [|_; a; b; c; d|] -> Uchar.to_int a, Uchar.to_int b, Uchar.to_int c, Uchar.to_int d
 				| _ -> assert false
 			in
 			let x =
@@ -347,7 +347,7 @@ module Reader = struct
 		| "\\u", hex, hex, hex, hex ->
 			let a,b,c,d =
 				match Sedlexing.lexeme lexbuf with
-				| [|_;_ ; a; b; c; d|] -> a, b, c, d
+				| [|_;_ ; a; b; c; d|] -> Uchar.to_int a, Uchar.to_int b, Uchar.to_int c, Uchar.to_int d
 				| _ -> assert false
 			in
 			let y =

+ 24 - 1
src/core/type.ml

@@ -807,6 +807,29 @@ let rec follow t =
 		follow t
 	| _ -> t
 
+(** Assumes `follow` has already been applied *)
+let rec ambiguate_funs t =
+	match t with
+	| TFun _ -> TFun ([], t_dynamic)
+	| TMono r ->
+		(match !r with
+		| Some _ -> assert false
+		| _ -> t)
+	| TInst (a, pl) ->
+	    TInst (a, List.map ambiguate_funs pl)
+	| TEnum (a, pl) ->
+	    TEnum (a, List.map ambiguate_funs pl)
+	| TAbstract (a, pl) ->
+	    TAbstract (a, List.map ambiguate_funs pl)
+	| TType (a, pl) ->
+	    TType (a, List.map ambiguate_funs pl)
+	| TDynamic _ -> t
+	| TAnon a ->
+	    TAnon { a with a_fields =
+		    PMap.map (fun af -> { af with cf_type =
+				ambiguate_funs af.cf_type }) a.a_fields }
+	| TLazy _ -> assert false
+
 let rec is_nullable = function
 	| TMono r ->
 		(match !r with None -> false | Some t -> is_nullable t)
@@ -3094,4 +3117,4 @@ let s_class_path c =
 		| KAbstractImpl a -> a.a_path
 		| _ -> c.cl_path
 	in
-	s_type_path path
+	s_type_path path

+ 1 - 1
src/generators/gencpp.ml

@@ -1095,7 +1095,7 @@ let strq ctx s =
             | c when c > 0xFFFF -> Buffer.add_string b (Printf.sprintf "\\U%08x" c)
             | c -> Buffer.add_char b (Char.chr c)
       in
-      UTF8.iter (fun c -> add (UChar.code c) ) s;
+      UTF8.iter (fun c -> add (UCharExt.code c) ) s;
       "HX_W(u\"" ^ (Buffer.contents b) ^ "\"," ^ (gen_wqstring_hash s) ^ ")"
    else
        gen_str "HX_" gen_qstring_hash s

+ 1 - 1
src/generators/gencs.ml

@@ -1135,7 +1135,7 @@ let generate con =
 			let b = Buffer.create 0 in
 			(try
 				UTF8.validate s;
-				UTF8.iter (fun c -> escape (UChar.code c) b) s
+				UTF8.iter (fun c -> escape (UCharExt.code c) b) s
 			with
 				UTF8.Malformed_code ->
 					String.iter (fun c -> escape (Char.code c) b) s

+ 2 - 2
src/generators/genhl.ml

@@ -164,12 +164,12 @@ let to_utf8 str p =
 		UTF8.Malformed_code ->
 			(* ISO to utf8 *)
 			let b = UTF8.Buf.create 0 in
-			String.iter (fun c -> UTF8.Buf.add_char b (UChar.of_char c)) str;
+			String.iter (fun c -> UTF8.Buf.add_char b (UCharExt.of_char c)) str;
 			UTF8.Buf.contents b
 	in
 	let ccount = ref 0 in
 	UTF8.iter (fun c ->
-		let c = UChar.code c in
+		let c = UCharExt.code c in
 		if (c >= 0xD800 && c <= 0xDFFF) || c >= 0x110000 then abort "Invalid unicode char" p;
 		incr ccount;
 		if c >= 0x10000 then incr ccount;

+ 2 - 2
src/generators/genjava.ml

@@ -341,7 +341,7 @@ struct
 		(try
 			UTF8.validate s;
 			UTF8.iter (fun c ->
-				let c = (UChar.code c) in
+				let c = (UCharExt.code c) in
 				if c > 0xFFFF then
 					(h := Int32.add (Int32.mul thirtyone !h)
 						(Int32.of_int (high_surrogate c));
@@ -1352,7 +1352,7 @@ let generate con =
 		let b = Buffer.create 0 in
 		(try
 			UTF8.validate s;
-			UTF8.iter (fun c -> escape (UChar.code c) b) s
+			UTF8.iter (fun c -> escape (UCharExt.code c) b) s
 		with
 			UTF8.Malformed_code ->
 				String.iter (fun c -> escape (Char.code c) b) s

+ 1 - 1
src/generators/genswf9.ml

@@ -657,7 +657,7 @@ let to_utf8 str =
 	with
 		UTF8.Malformed_code ->
 			let b = UTF8.Buf.create 0 in
-			String.iter (fun c -> UTF8.Buf.add_char b (UChar.of_char c)) str;
+			String.iter (fun c -> UTF8.Buf.add_char b (UCharExt.of_char c)) str;
 			UTF8.Buf.contents b
 
 let gen_constant ctx c t p =

+ 1 - 1
src/generators/hlinterp.ml

@@ -329,7 +329,7 @@ let hl_to_caml str =
 		loop 0
 	in
 	let b = UTF8.Buf.create (String.length str / 2) in
-	utf16_iter (fun c -> UTF8.Buf.add_char b (UChar.chr c)) (utf16_eof str);
+	utf16_iter (fun c -> UTF8.Buf.add_char b (UCharExt.chr c)) (utf16_eof str);
 	UTF8.Buf.contents b
 
 let null_access() =

+ 1 - 1
src/generators/jvm/jvmConstantPool.ml

@@ -27,7 +27,7 @@ open JvmSignature
 let utf8jvm (input : string) : bytes =
 	let channel = IO.output_bytes () in
 	UTF8.iter (fun c ->
-		let code = UChar.code c in
+		let code = UCharExt.code c in
 		match code with
 			| b when (b > 0 && b <= 0x7F) ->
 			IO.write_byte channel b

+ 7 - 5
src/macro/eval/evalContext.ml

@@ -18,7 +18,6 @@
  *)
 
 open Globals
-open Type
 open EvalValue
 open EvalHash
 open EvalString
@@ -71,7 +70,9 @@ type env_debug = {
 	(* The current line being executed. This in conjunction with `env_info.pfile` is used to find breakpoints. *)
 	mutable line : int;
 	(* The current expression being executed *)
-	mutable expr : texpr;
+	mutable debug_expr : string;
+	(* The current expression position being executed *)
+	mutable debug_pos : pos;
 }
 
 (* An environment in which code is executed. Environments are created whenever a function is called and when
@@ -155,7 +156,7 @@ type builtins = {
 }
 
 type debug_scope_info = {
-	ds_expr : texpr;
+	ds_expr : string;
 	ds_return : value option;
 }
 
@@ -387,13 +388,14 @@ let flush_core_context f =
 
 let no_timer = fun () -> ()
 let empty_array = [||]
-let no_expr = mk (TConst TNull) t_dynamic null_pos
+let no_expr = ""
 
 let no_debug = {
 	timer = no_timer;
 	scopes = [];
 	line = 0;
-	expr = no_expr;
+	debug_expr = no_expr;
+	debug_pos = null_pos;
 }
 
 let create_env_info static pfile kind capture_infos =

+ 3 - 2
src/macro/eval/evalDebug.ml

@@ -31,7 +31,7 @@ let rec run_loop run env : value =
 			check_breakpoint();
 			run env
 		| DbgNext(env',p) ->
-			let b = DisplayPosition.encloses_position (env.env_debug.expr.epos) p in
+			let b = DisplayPosition.encloses_position (env.env_debug.debug_pos) p in
 			let rec is_on_stack env =
 				match env.env_parent with
 				| Some env -> env == env' || is_on_stack env
@@ -116,7 +116,8 @@ let debug_loop jit conn e f =
 	let run_set env =
 		env.env_debug.scopes <- scopes;
 		env.env_debug.line <- line;
-		env.env_debug.expr <- e;
+		env.env_debug.debug_pos <- e.epos;
+		env.env_debug.debug_expr <- s_expr_pretty e;
 		run_loop run_check_breakpoint env;
 	in
 	run_set

+ 2 - 2
src/macro/eval/evalDebugMisc.ml

@@ -81,7 +81,7 @@ exception Parse_expr_error of string
 let parse_expr ctx s p =
 	let error s = raise (Parse_expr_error s) in
 	match ParserEntry.parse_expr_string (ctx.curapi.get_com()).Common.defines s p error true with
-	| ParseSuccess data | ParseDisplayFile(data,_,_) -> data
+	| ParseSuccess data | ParseDisplayFile(data,_) -> data
 	| ParseError(_,(msg,_),_) -> error (Parser.error_msg msg)
 
 (* Vars *)
@@ -93,7 +93,7 @@ let get_var_slot_by_name env is_read scopes name =
 				let id = Hashtbl.find scope.local_ids name in
 				let slot = Hashtbl.find scope.locals id in
 				let vi = Hashtbl.find scope.local_infos slot in
-				if is_read && not (declared_before vi env.env_debug.expr.epos) then raise Not_found;
+				if is_read && not (declared_before vi env.env_debug.debug_pos) then raise Not_found;
 				slot + scope.local_offset
 			with Not_found ->
 				loop scopes

+ 7 - 7
src/macro/eval/evalDebugSocket.ml

@@ -199,7 +199,7 @@ let output_scopes ctx env =
 		scopes
 	else begin
 		let dbg = {
-			ds_expr = env.env_debug.expr;
+			ds_expr = env.env_debug.debug_expr;
 			ds_return = env.env_eval.last_return;
 		} in
 		(mk_scope (ctx.debug.debug_context#add_debug_scope dbg env) "Eval" null_pos) :: scopes
@@ -217,13 +217,13 @@ let output_capture_vars infos env =
 
 let output_debug_scope dbg env =
 	let ja = [
-		var_to_json "expr" (VString (EvalString.create_ascii (Type.s_expr_pretty true "" false (s_type (print_context())) env.env_debug.expr))) None env;
+		var_to_json "expr" (VString (EvalString.create_ascii env.env_debug.debug_expr)) None env;
 		var_to_json "last return" (match dbg.ds_return with None -> vnull | Some v -> v) None env;
 	] in
 	JArray ja
 
 let output_scope_vars env scope =
-	let p = env.env_debug.expr.epos in
+	let p = env.env_debug.debug_pos in
 	let vars = Hashtbl.fold (fun local_slot vi acc ->
 		if declared_before vi p then begin
 			let slot = local_slot + scope.local_offset in
@@ -548,7 +548,7 @@ let handler =
 		"next",(fun hctx ->
 			let eval = select_thread hctx in
 			let env = expect_env hctx eval.env in
-			eval.debug_state <- DbgNext(env,env.env_debug.expr.epos);
+			eval.debug_state <- DbgNext(env,env.env_debug.debug_pos);
 			ignore(Event.poll (Event.send eval.debug_channel ()));
 			JNull
 		);
@@ -566,7 +566,7 @@ let handler =
 		"stackTrace",(fun hctx ->
 			let eval = select_thread hctx in
 			let env = expect_env hctx eval.env in
-			output_call_stack hctx.ctx eval env.env_debug.expr.epos
+			output_call_stack hctx.ctx eval env.env_debug.debug_pos
 		);
 		"getScopes",(fun hctx ->
 			let env = select_frame hctx in
@@ -660,7 +660,7 @@ let handler =
 			let name = hctx.jsonrpc#get_string_param "name" in
 			let value = hctx.jsonrpc#get_string_param "value" in
 			let get_value env = try
-				let e = parse_expr hctx.ctx value env.env_debug.expr.epos in
+				let e = parse_expr hctx.ctx value env.env_debug.debug_pos in
 				expr_to_value hctx.ctx env e
 			with Parse_expr_error e ->
 				hctx.send_error e
@@ -711,7 +711,7 @@ let handler =
 			let env = try select_frame hctx with _ -> expect_env hctx ctx.eval.env in
 			let s = hctx.jsonrpc#get_string_param "expr" in
 			begin try
-				let e = parse_expr ctx s env.env_debug.expr.epos in
+				let e = parse_expr ctx s env.env_debug.debug_pos in
 				let v = handle_in_temp_thread ctx env (fun () -> expr_to_value ctx env e) in
 				var_to_json "" v None env
 			with

+ 4 - 4
src/macro/eval/evalStdLib.ml

@@ -2995,7 +2995,7 @@ module StdUtf8 = struct
 		| v -> unexpected_value v "string"
 
 	let addChar = vifun1 (fun vthis c ->
-		UTF8.Buf.add_char (this vthis) (UChar.uchar_of_int (decode_int c));
+		UTF8.Buf.add_char (this vthis) (UCharExt.uchar_of_int (decode_int c));
 		vnull
 	)
 
@@ -3012,7 +3012,7 @@ module StdUtf8 = struct
 		let buf = Bytes.create (UTF8.length s) in
 		let i = ref 0 in
 		UTF8.iter (fun uc ->
-			Bytes.unsafe_set buf !i (UChar.char_of uc);
+			Bytes.unsafe_set buf !i (UCharExt.char_of uc);
 			incr i
 		) s;
 		let s = Bytes.unsafe_to_string buf in
@@ -3021,12 +3021,12 @@ module StdUtf8 = struct
 
 	let encode = vfun1 (fun s ->
 		let s = decode_string s in
-		create_unknown (UTF8.init (String.length s) (fun i -> UChar.of_char s.[i]))
+		create_unknown (UTF8.init (String.length s) (fun i -> UCharExt.of_char s.[i]))
 	)
 
 	let iter = vfun2 (fun s f ->
 		let s = decode_string s in
-		UTF8.iter (fun uc -> ignore(call_value f [vint (UChar.int_of_uchar uc)])) s;
+		UTF8.iter (fun uc -> ignore(call_value f [vint (UCharExt.int_of_uchar uc)])) s;
 		vnull
 	)
 

+ 3 - 3
src/macro/eval/evalString.ml

@@ -184,7 +184,7 @@ let char_at s c_index =
 	char
 
 let string_of_char_code i =
-	UTF8.init 1 (fun _ ->  UChar.uchar_of_int i)
+	UTF8.init 1 (fun _ ->  UCharExt.uchar_of_int i)
 
 let from_char_code i =
 	create_with_length (string_of_char_code i) 1
@@ -239,11 +239,11 @@ let case_map this upper =
 	let buf = UTF8.Buf.create 0 in
 	let a,m = if upper then EvalBytes.Unicase._UPPER,1022 else EvalBytes.Unicase._LOWER,1021 in
 	UTF8.iter (fun uc ->
-		let c = UChar.int_of_uchar uc in
+		let c = UCharExt.int_of_uchar uc in
 		let up = c lsr 6 in
 		let uc = if up < m then begin
 			let c = a.(up).(c land ((1 lsl 6) - 1)) in
-			if c <> 0 then UChar.uchar_of_int c
+			if c <> 0 then UCharExt.uchar_of_int c
 			else uc
 		end else
 			uc

+ 0 - 1
src/macro/macroApi.ml

@@ -50,7 +50,6 @@ type 'value compiler_api = {
 	encode_ctype : Ast.type_hint -> 'value;
 	decode_type : 'value -> t;
 	flush_context : (unit -> t) -> t;
-	typer_ctx : Typecore.typer;
 }
 
 

+ 1 - 1
src/optimization/analyzer.ml

@@ -809,7 +809,7 @@ module Debug = struct
 		) g.g_var_infos
 
 	let get_dump_path ctx c cf =
-		"dump" :: [platform_name_macro ctx.com] @ (fst c.cl_path) @ [Printf.sprintf "%s.%s" (snd c.cl_path) cf.cf_name]
+		(dump_path ctx.com) :: [platform_name_macro ctx.com] @ (fst c.cl_path) @ [Printf.sprintf "%s.%s" (snd c.cl_path) cf.cf_name]
 
 	let dot_debug ctx c cf =
 		let g = ctx.graph in

+ 2 - 2
src/syntax/lexer.ml

@@ -272,7 +272,7 @@ let mk_keyword lexbuf kwd =
 	mk lexbuf (Kwd kwd)
 
 let invalid_char lexbuf =
-	error (Invalid_character (lexeme_char lexbuf 0)) (lexeme_start lexbuf)
+	error (Invalid_character (Uchar.to_int (lexeme_char lexbuf 0))) (lexeme_start lexbuf)
 
 let ident = [%sedlex.regexp?
 	(
@@ -556,7 +556,7 @@ and regexp lexbuf =
 	| '\\', ('\\' | '$' | '.' | '*' | '+' | '^' | '|' | '{' | '}' | '[' | ']' | '(' | ')' | '?' | '-' | '0'..'9') -> add (lexeme lexbuf); regexp lexbuf
 	| '\\', ('w' | 'W' | 'b' | 'B' | 's' | 'S' | 'd' | 'D' | 'x') -> add (lexeme lexbuf); regexp lexbuf
 	| '\\', ('u' | 'U'), ('0'..'9' | 'a'..'f' | 'A'..'F'), ('0'..'9' | 'a'..'f' | 'A'..'F'), ('0'..'9' | 'a'..'f' | 'A'..'F'), ('0'..'9' | 'a'..'f' | 'A'..'F') -> add (lexeme lexbuf); regexp lexbuf
-	| '\\', Compl '\\' -> error (Invalid_character (lexeme_char lexbuf 0)) (lexeme_end lexbuf - 1)
+	| '\\', Compl '\\' -> error (Invalid_character (Uchar.to_int (lexeme_char lexbuf 0))) (lexeme_end lexbuf - 1)
 	| '/' -> regexp_options lexbuf, lexeme_end lexbuf
 	| Plus (Compl ('\\' | '/' | '\r' | '\n')) -> store lexbuf; regexp lexbuf
 	| _ -> assert false

+ 7 - 1
src/syntax/parser.ml

@@ -70,9 +70,15 @@ type parse_data = string list * (type_def * pos) list
 
 type parse_error = (error_msg * pos)
 
+type parser_display_information = {
+	pd_errors : parse_error list;
+	pd_dead_blocks : (pos * expr) list;
+	pd_conditions : expr list;
+}
+
 type 'a parse_result =
 	(* Parsed display file. There can be errors. *)
-	| ParseDisplayFile of 'a * parse_error list * pos list
+	| ParseDisplayFile of 'a * parser_display_information
 	(* Parsed non-display-file without errors. *)
 	| ParseSuccess of 'a
 	(* Parsed non-display file with errors *)

+ 135 - 19
src/syntax/parserEntry.ml

@@ -43,6 +43,14 @@ let s_small_type v =
 	| TString _ -> "string"
 	| TVersion _ -> "version"
 
+let s_value v =
+	match v with
+	| TNull -> "null"
+	| TBool b -> "boolean " ^ (string_of_bool b)
+	| TFloat f -> "float " ^ (string_of_float f)
+	| TString s -> "string \"" ^ s ^ "\""
+	| TVersion (r,p) -> "version " ^ (Semver.to_string (r,p))
+
 let parse_version s p =
 	try match parse_version s with release,pre -> TVersion (release,pre)
 	with Invalid_argument msg -> error (Custom msg) p
@@ -53,11 +61,10 @@ let cmp v1 v2 =
 	| TFloat a, TFloat b -> compare a b
 	| TString a, TString b -> compare a b
 	| TBool a, TBool b -> compare a b
-	| TString a, TFloat b -> compare (float_of_string a) b
-	| TFloat a, TString b -> compare a (float_of_string b)
 	| TVersion (release1,pre1), TVersion (release2,pre2) -> compare_version (release1,pre1) (release2,pre2)
-	| _, TVersion _
-	| TVersion _, _ -> raise (Invalid_argument ("Cannot compare " ^ (s_small_type v1) ^ " and " ^ (s_small_type v2)))
+	| TString _, TFloat _ | TFloat _, TString _
+	| _, TVersion _ | TVersion _, _ ->
+		raise (Invalid_argument ("Cannot compare " ^ (s_value v1) ^ " and " ^ (s_value v2)))
 	| _ -> raise Exit (* always false *)
 
 let rec eval ctx (e,p) =
@@ -97,32 +104,130 @@ let rec eval ctx (e,p) =
 	| _ ->
 		error (Custom "Invalid condition expression") p
 
+(**
+	Attempt to auto-cast operands to a common type
+*)
 and eval_binop_exprs ctx e1 e2 =
 	match eval ctx e1, eval ctx e2 with
-	| (TVersion _ as v1), (TVersion _ as v2) -> (v1, v2)
+	| (TString s1 as v1), (TFloat _ as v2) ->
+		(try TFloat (float_of_string s1), v2
+		with Failure _ -> v1, v2)
+	| (TFloat _ as v1), (TString s2 as v2) ->
+		(try v1, TFloat (float_of_string s2)
+		with Failure _ -> v1, v2)
 	| (TVersion _ as v1), TString s -> (v1, parse_version s (snd e2))
 	| TString s, (TVersion _ as v2) -> (parse_version s (snd e1), v2)
 	| v1, v2 -> (v1, v2)
 
-class dead_block_collector = object(self)
+class condition_handler_nop = object(self)
+	val null = EConst(Ident "null"),null_pos
+
+	method cond_if (e : expr) =
+		()
+
+	method cond_else =
+		()
+
+	method cond_elseif (e : expr) =
+		()
+
+	method cond_end =
+		()
+
+	method get_current_condition : expr =
+		null
+
+	method get_conditions : expr list =
+		[]
+end
+
+class condition_Handler = object(self)
+	inherit condition_handler_nop
+	val mutable conditional_expressions = []
+	val mutable conditional_stack = []
+	val mutable depths = []
+
+	method private maybe_parent allow_and e = match fst e with
+		| EBinop(op,_,_) ->
+			if op = OpBoolAnd && allow_and then e
+			else (EParenthesis e,pos e)
+		| _ -> e
+
+	method private negate (e : expr) = match fst e with
+		| EUnop(Not,_,e1) -> e1
+		| EBinop(OpBoolAnd,e1,e2) -> (EBinop(OpBoolOr,self#negate e1,self#negate e2),(pos e))
+		| EBinop(OpBoolOr,e1,e2) -> (EBinop(OpBoolAnd,self#negate e1,self#negate e2),(pos e))
+		| _ -> (EUnop(Not,Prefix,e),(pos e))
+
+	method private conjoin (lhs : expr) (rhs : expr) =
+		let lhs = self#maybe_parent true lhs in
+		let rhs = self#maybe_parent true rhs in
+		(EBinop(OpBoolAnd,lhs,rhs),punion (pos lhs) (pos rhs))
+
+	method private cond_if' (e : expr) =
+		conditional_expressions <- e :: conditional_expressions;
+		conditional_stack <- e :: conditional_stack
+
+	method cond_if (e : expr) =
+		self#cond_if' e;
+		depths <- 1 :: depths
+
+	method cond_else = match conditional_stack with
+		| e :: el ->
+			conditional_stack <- (self#negate e) :: el
+		| [] ->
+			assert false
+
+	method cond_elseif (e : expr) =
+		self#cond_else;
+		self#cond_if' e;
+		match depths with
+		| [] -> assert false
+		| depth :: depths' ->
+			depths <- (depth + 1) :: depths'
+
+	method cond_end =
+		let rec loop d el =
+			if d = 0 then el
+			else loop (d - 1) (List.tl el)
+		in
+		match depths with
+			| [] -> assert false
+			| depth :: depths' ->
+				conditional_stack <- loop depth conditional_stack;
+				depths <- depths'
+
+	method get_current_condition = match conditional_stack with
+		| e :: el ->
+			List.fold_left self#conjoin e el
+		| [] ->
+			(EConst (Ident "true"),null_pos)
+
+	method get_conditions =
+		conditional_expressions
+end
+
+class dead_block_collector conds = object(self)
 	val dead_blocks = DynArray.create ()
 	val mutable current_block = []
 
 	method open_dead_block (p : pos) =
-		current_block <- {p with pmin = p.pmax} :: current_block
+		current_block <- ({p with pmin = p.pmax},conds#get_current_condition) :: current_block
 
 	method close_dead_block (p : pos) = match current_block with
 		| [] ->
 			error (Custom "Internal error: Trying to close dead block that's not open") p;
-		| p0 :: pl ->
+		| (p0,cond) :: pl ->
 			current_block <- pl;
-			DynArray.add dead_blocks ({p0 with pmax = p.pmin})
+			DynArray.add dead_blocks ({p0 with pmax = p.pmin},cond)
 
-	method get_dead_blocks =
+	method get_dead_blocks : (pos * expr) list =
 		assert(current_block = []);
 		DynArray.to_list dead_blocks
 end
 
+let nop_handler = new condition_handler_nop
+
 (* parse main *)
 let parse ctx code file =
 	let old = Lexer.save() in
@@ -154,7 +259,8 @@ let parse ctx code file =
 		error (Custom line) p
 	in
 
-	let dbc = new dead_block_collector in
+	let conds = if !in_display_file then new condition_Handler else nop_handler in
+	let dbc = new dead_block_collector conds in
 	let sraw = Stream.from (fun _ -> Some (Lexer.sharp_token code)) in
 	let rec next_token() = process_token (Lexer.token code)
 
@@ -173,13 +279,15 @@ let parse ctx code file =
 			(match !mstack with
 			| [] -> tk
 			| _ :: l ->
+				conds#cond_end;
 				mstack := l;
 				next_token())
 		| Sharp "elseif" ->
 			(match !mstack with
 			| [] -> tk
 			| _ :: l ->
-				let _,(_,pe) = parse_macro_cond sraw in
+				let _,(e,pe) = parse_macro_cond sraw in
+				conds#cond_elseif (e,pe);
 				dbc#open_dead_block pe;
 				mstack := l;
 				let tk = skip_tokens (pos tk) false in
@@ -188,12 +296,13 @@ let parse ctx code file =
 			(match !mstack with
 			| [] -> tk
 			| _ :: l ->
+				conds#cond_else;
 				dbc#open_dead_block (pos tk);
 				mstack := l;
 				let tk = skip_tokens (pos tk) false in
 				process_token tk)
 		| Sharp "if" ->
-			process_token (enter_macro (snd tk))
+			process_token (enter_macro true (snd tk))
 		| Sharp "error" ->
 			(match Lexer.token code with
 			| (Const (String(s,_)),p) -> error (Custom s) p
@@ -210,8 +319,9 @@ let parse ctx code file =
 		| _ ->
 			tk
 
-	and enter_macro p =
+	and enter_macro is_if p =
 		let tk, e = parse_macro_cond sraw in
+		(if is_if then conds#cond_if else conds#cond_elseif) e;
 		let tk = (match tk with None -> Lexer.token code | Some tk -> tk) in
 		if is_true (eval ctx e) then begin
 			mstack := p :: !mstack;
@@ -224,26 +334,32 @@ let parse ctx code file =
 	and skip_tokens_loop p test tk =
 		match fst tk with
 		| Sharp "end" ->
+			conds#cond_end;
 			dbc#close_dead_block (pos tk);
 			Lexer.token code
 		| Sharp "elseif" when not test ->
 			dbc#close_dead_block (pos tk);
-			let _,(_,pe) = parse_macro_cond sraw in
+			let _,(e,pe) = parse_macro_cond sraw in
+			conds#cond_elseif (e,pe);
 			dbc#open_dead_block pe;
 			skip_tokens p test
 		| Sharp "else" when not test ->
+			conds#cond_else;
 			dbc#close_dead_block (pos tk);
 			dbc#open_dead_block (pos tk);
 			skip_tokens p test
 		| Sharp "else" ->
+			conds#cond_else;
 			dbc#close_dead_block (pos tk);
 			mstack := snd tk :: !mstack;
 			Lexer.token code
 		| Sharp "elseif" ->
 			dbc#close_dead_block (pos tk);
-			enter_macro (snd tk)
+			enter_macro false (snd tk)
 		| Sharp "if" ->
-			dbc#open_dead_block (pos tk);
+			let _,e = parse_macro_cond sraw in
+			conds#cond_if e;
+			dbc#open_dead_block (pos e);
 			let tk = skip_tokens p false in
 			skip_tokens_loop p test tk
 		| Sharp ("error" | "line") ->
@@ -270,7 +386,7 @@ let parse ctx code file =
 		restore();
 		Lexer.restore old;
 		if was_display_file then
-			ParseDisplayFile(l,List.rev !syntax_errors,dbc#get_dead_blocks)
+			ParseDisplayFile(l,{pd_errors = List.rev !syntax_errors;pd_dead_blocks = dbc#get_dead_blocks;pd_conditions = conds#get_conditions})
 		else begin match List.rev !syntax_errors with
 			| [] -> ParseSuccess l
 			| error :: errors -> ParseError(l,error,errors)
@@ -333,4 +449,4 @@ let parse_expr_string com s p error inl =
 	match parse_string com (head ^ s ^ ";}") p error inl with
 	| ParseSuccess data -> ParseSuccess(extract_expr data)
 	| ParseError(data,error,errors) -> ParseError(extract_expr data,error,errors)
-	| ParseDisplayFile(data,errors,dead) -> ParseDisplayFile(extract_expr data,errors,dead)
+	| ParseDisplayFile(data,pdi) -> ParseDisplayFile(extract_expr data,pdi)

+ 18 - 3
src/typing/calls.ml

@@ -475,7 +475,21 @@ let rec acc_get ctx g p =
 		| _ -> assert false)
 	| AKInline (e,f,fmode,t) ->
 		(* do not create a closure for static calls *)
-		let cmode = (match fmode with FStatic _ -> fmode | FInstance (c,tl,f) -> FClosure (Some (c,tl),f) | _ -> assert false) in
+		let cmode,apply_params = match fmode with
+			| FStatic(c,_) ->
+				let f = match c.cl_kind with
+					| KAbstractImpl a when Meta.has Meta.Enum a.a_meta ->
+						(* Enum abstracts have to apply their type parameters because they are basically statics with type params (#8700). *)
+						let monos = List.map (fun _ -> mk_mono()) a.a_params in
+						apply_params a.a_params monos;
+					| _ -> (fun t -> t)
+				in
+				fmode,f
+			| FInstance (c,tl,f) ->
+				(FClosure (Some (c,tl),f),(fun t -> t))
+			| _ ->
+				assert false
+		in
 		ignore(follow f.cf_type); (* force computing *)
 		begin match f.cf_kind,f.cf_expr with
 		| _ when not (ctx.com.display.dms_inline) ->
@@ -525,10 +539,11 @@ let rec acc_get ctx g p =
 				| _ -> e_def
 			end
 		| Var _,Some e ->
-			let rec loop e = Type.map_expr loop { e with epos = p } in
+			let rec loop e = Type.map_expr loop { e with epos = p; etype = apply_params e.etype } in
 			let e = loop e in
 			let e = Inline.inline_metadata e f.cf_meta in
-			if not (type_iseq f.cf_type e.etype) then mk (TCast(e,None)) f.cf_type e.epos
+			let tf = apply_params f.cf_type in
+			if not (type_iseq tf e.etype) then mk (TCast(e,None)) tf e.epos
 			else e
 		| Var _,None when ctx.com.display.dms_display ->
 			 mk (TField (e,cmode)) t p

+ 8 - 12
src/typing/macroContext.ml

@@ -44,11 +44,11 @@ end
 let macro_enable_cache = ref false
 let macro_interp_cache = ref None
 
-let safe_decode v expected t p f =
+let safe_decode ctx v expected t p f =
 	try
 		f ()
 	with MacroApi.Invalid_expr | EvalContext.RunTimeException _ ->
-		let path = ["dump";"decoding_error"] in
+		let path = [dump_path ctx.com;"decoding_error"] in
 		let ch = Path.create_file false ".txt" [] path  in
 		let errors = Interp.handle_decoding_error (output_string ch) v t in
 		List.iter (fun (s,i) -> Printf.fprintf ch "\nline %i: %s" i s) (List.rev errors);
@@ -129,7 +129,7 @@ let make_macro_api ctx p =
 			try
 				begin match ParserEntry.parse_expr_string ctx.com.defines s p error inl with
 					| ParseSuccess data -> data
-					| ParseDisplayFile(data,_,_) when inl -> data (* ignore errors when inline-parsing in display file *)
+					| ParseDisplayFile(data,_) when inl -> data (* ignore errors when inline-parsing in display file *)
 					| ParseDisplayFile _ -> assert false (* cannot happen because ParserEntry.parse_string sets `display_position := null_pos;` *)
 					| ParseError _ -> raise MacroApi.Invalid_expr
 				end
@@ -306,7 +306,7 @@ let make_macro_api ctx p =
 			let mctx = (match ctx.g.macros with None -> assert false | Some (_,mctx) -> mctx) in
 			let ttype = Typeload.load_instance mctx (cttype,p) false in
 			let f () = Interp.decode_type_def v in
-			let m, tdef, pos = safe_decode v "TypeDefinition" ttype p f in
+			let m, tdef, pos = safe_decode ctx v "TypeDefinition" ttype p f in
 			let add is_macro ctx =
 				let mdep = Option.map_default (fun s -> TypeloadModule.load_module ctx (parse_path s) pos) ctx.m.curmod mdep in
 				let mnew = TypeloadModule.type_module ctx m mdep.m_extra.m_file [tdef,pos] pos in
@@ -396,7 +396,6 @@ let make_macro_api ctx p =
 		MacroApi.encode_expr = Interp.encode_expr;
 		MacroApi.encode_ctype = Interp.encode_ctype;
 		MacroApi.decode_type = Interp.decode_type;
-		MacroApi.typer_ctx = ctx;
 	}
 
 let rec init_macro_interp ctx mctx mint =
@@ -482,15 +481,12 @@ let get_macro_context ctx p =
 		com2.main_class <- None;
 		(* Inherit most display settings, but require normal typing. *)
 		com2.display <- {ctx.com.display with dms_kind = DMNone; dms_display = false; dms_full_typing = true; dms_force_macro_typing = true; dms_inline = true; };
-		List.iter (fun p -> com2.defines.Define.values <- PMap.remove (Globals.platform_name p) com2.defines.Define.values) Globals.platforms;
-		com2.defines.Define.defines_signature <- None;
 		com2.class_path <- List.filter (fun s -> not (ExtString.String.exists s "/_std/")) com2.class_path;
 		let name = platform_name !Globals.macro_platform in
 		com2.class_path <- List.map (fun p -> p ^ name ^ "/_std/") com2.std_path @ com2.class_path;
-		let to_remove = List.map (fun d -> fst (Define.infos d)) [Define.NoTraces] in
-		let to_remove = to_remove @ List.map (fun (_,d) -> "flash" ^ d) Common.flash_versions in
-		com2.defines.Define.values <- PMap.foldi (fun k v acc -> if List.mem k to_remove then acc else PMap.add k v acc) com2.defines.Define.values PMap.empty;
-		Common.define com2 Define.Macro;
+		let defines = adapt_defines_to_macro_context com2.defines; in
+		com2.defines.values <- defines.values;
+		com2.defines.defines_signature <- None;
 		Common.init_platform com2 !Globals.macro_platform;
 		let mctx = ctx.g.do_create com2 in
 		mctx.is_display_file <- false;
@@ -720,7 +716,7 @@ let type_macro ctx mode cpath f (el:Ast.expr list) p =
 						Some (EBlock [],p)
 					)
 			in
-			safe_decode v expected mret p process
+			safe_decode ctx v expected mret p process
 	in
 	let e = if ctx.in_macro then
 		Some (EThrow((EConst(String("macro-in-macro",SDoubleQuotes))),p),p)

+ 125 - 56
src/typing/matcher.ml

@@ -42,7 +42,18 @@ let type_field_access ctx ?(resume=false) e name =
 	Calls.acc_get ctx (Fields.type_field (Fields.TypeFieldConfig.create resume) ctx e name e.epos MGet) e.epos
 
 let unapply_type_parameters params monos =
-	List.iter2 (fun (_,t1) t2 -> match t2,follow t2 with TMono m1,TMono m2 when m1 == m2 -> Type.unify t1 t2 | _ -> ()) params monos
+	let unapplied = ref [] in
+	List.iter2 (fun (_,t1) t2 ->
+		match t2,follow t2 with
+		| TMono m1,TMono m2 ->
+			unapplied := (m1,!m1) :: !unapplied;
+			m1 := Some t1;
+		| _ -> ()
+	) params monos;
+	!unapplied
+
+let reapply_type_parameters unapplied =
+	List.iter (fun (m,o) -> m := o) unapplied
 
 let get_general_module_type ctx mt p =
 	let rec loop = function
@@ -145,6 +156,7 @@ module Pattern = struct
 		mutable current_locals : (string, tvar * pos) PMap.t;
 		mutable in_reification : bool;
 		is_postfix_match : bool;
+		unapply_type_parameters : unit -> (Type.t option ref * Type.t option) list;
 	}
 
 	exception Bad_pattern of string
@@ -219,6 +231,8 @@ module Pattern = struct
 					loop e1
 				| TField _ ->
 					raise (Bad_pattern "Only inline or read-only (default, never) fields can be used as a pattern")
+				| TTypeExpr mt ->
+					PatConstructor(con_type_expr mt e.epos,[])
 				| _ ->
 					raise Exit
 			in
@@ -232,14 +246,12 @@ module Pattern = struct
 			ctx.untyped <- true;
 			let e = try type_expr ctx e (WithType.with_type t) with exc -> ctx.untyped <- old; raise exc in
 			ctx.untyped <- old;
-			match e.eexpr with
-				| TTypeExpr mt ->
-					unify_type_pattern ctx mt t e.epos;
-					PatConstructor(con_type_expr mt e.epos,[])
-				| _ ->
-					let pat = check_expr e in
-					unify ctx e.etype t p;
-					pat
+			let pat = check_expr e in
+			begin match pat with
+				| PatConstructor((ConTypeExpr mt,_),_) -> unify_type_pattern ctx mt t e.epos;
+				| _ -> unify ctx e.etype t p;
+			end;
+			pat
 		in
 		let handle_ident s p =
 			try
@@ -320,8 +332,8 @@ module Pattern = struct
 					| TField(_, FEnum(en,ef)),TFun(_,TEnum(_,tl)) ->
 						let monos = List.map (fun _ -> mk_mono()) ef.ef_params in
 						let map t = apply_params en.e_params tl (apply_params ef.ef_params monos t) in
-						(* We cannot use e1.etype here because it has applied type parameters (issue #1310). *)
-						let args = match follow (map ef.ef_type) with
+						unify ctx (map ef.ef_type) e1.etype e1.epos;
+						let args = match follow e1.etype with
 							| TFun(args,r) ->
 								unify_expected r;
 								args
@@ -343,9 +355,7 @@ module Pattern = struct
 								error "Too many arguments" p
 						in
 						let patterns = loop el args in
-						(* We want to change the original monomorphs back to type parameters, but we don't want to do that
-						   if they are bound to other monomorphs (issue #4578). *)
-						unapply_type_parameters ef.ef_params monos;
+						ignore(unapply_type_parameters ef.ef_params monos);
 						PatConstructor(con_enum en ef e1.epos,patterns)
 					| _ ->
 						fail()
@@ -467,7 +477,11 @@ module Pattern = struct
 				let restore = save_locals ctx in
 				ctx.locals <- pctx.ctx_locals;
 				let v = add_local false "_" null_pos in
+				(* Tricky stuff: Extractor expressions are like normal expressions, so we don't want to deal with GADT-applied types here.
+				   Let's unapply, then reapply after we're done with the extractor (#5952). *)
+				let unapplied = pctx.unapply_type_parameters () in
 				let e1 = type_expr ctx e1 WithType.value in
+				reapply_type_parameters unapplied;
 				v.v_name <- "tmp";
 				restore();
 				let pat = make pctx toplevel e1.etype e2 in
@@ -500,21 +514,11 @@ module Pattern = struct
 		in
 		let pat = loop e in
 		pat,p
-
-	let make ctx t e postfix_match =
-		let pctx = {
-			ctx = ctx;
-			current_locals = PMap.empty;
-			ctx_locals = ctx.locals;
-			or_locals = None;
-			in_reification = false;
-			is_postfix_match = postfix_match;
-		} in
-		make pctx true t e
 end
 
 module Case = struct
 	open Typecore
+	open Pattern
 
 	type t = {
 		case_guard : texpr option;
@@ -543,8 +547,17 @@ module Case = struct
 		) ctx.locals [] in
 		let old_ret = ctx.ret in
 		ctx.ret <- map ctx.ret;
-		let pat = Pattern.make ctx (map t) e postfix_match in
-		unapply_type_parameters ctx.type_params monos;
+		let pctx = {
+			ctx = ctx;
+			current_locals = PMap.empty;
+			ctx_locals = ctx.locals;
+			or_locals = None;
+			in_reification = false;
+			is_postfix_match = postfix_match;
+			unapply_type_parameters = (fun () -> unapply_type_parameters ctx.type_params monos);
+		} in
+		let pat = Pattern.make pctx true (map t) e in
+		ignore(unapply_type_parameters ctx.type_params monos);
 		let eg = match eg with
 			| None -> None
 			| Some e -> Some (type_expr ctx e WithType.value)
@@ -599,31 +612,82 @@ module Decision_tree = struct
 		mutable dt_texpr : texpr option;
 	}
 
-	let s_case_expr tabs case = match case.case_expr with
-		| None -> ""
-		| Some e -> Type.s_expr_pretty false tabs false s_type e
-
-	let rec to_string tabs dt = match dt.dt_t with
-		| Leaf case ->
-			s_case_expr tabs case
-		| Switch(e,cases,dt) ->
-			let s_case (con,b,dt) =
-				Printf.sprintf "\n%2i\t%scase %s%s: %s" dt.dt_i tabs (Constructor.to_string con) (if b then "(unguarded) " else "") (to_string (tabs ^ "\t") dt)
-			in
-			let s_cases = String.concat "" (List.map s_case cases) in
-			let s_default = to_string (tabs ^ "\t") dt in
-			Printf.sprintf "switch (%s) {%s\n%2i%s\tdefault: %s\n%s}" (Type.s_expr_pretty false tabs false s_type e) s_cases dt.dt_i tabs s_default tabs
-		| Bind(bl,dt) ->
-			(String.concat "" (List.map (fun (v,_,e) -> if v.v_name = "_" then "" else Printf.sprintf "%s<%i> = %s; " v.v_name v.v_id (s_expr_pretty e)) bl)) ^
-			to_string tabs dt
-		| Guard(e,dt1,dt2) ->
-			Printf.sprintf "if (%s) {\n%2i\t%s%s\n%s} else {\n%2i\t%s%s\n%s}" (s_expr_pretty e) dt1.dt_i tabs (to_string (tabs ^ "\t") dt1) tabs dt2.dt_i tabs (to_string (tabs ^ "\t") dt2) tabs
-		| GuardNull(e,dt1,dt2) ->
-			Printf.sprintf "if (%s == null) {\n%2i\t%s%s\n%s} else {\n%2i\t%s%s\n%s}" (s_expr_pretty e) dt1.dt_i tabs (to_string (tabs ^ "\t") dt1) tabs dt2.dt_i tabs (to_string (tabs ^ "\t") dt2) tabs
-		| Fail ->
-			"<fail>"
-
-	let to_string tabs dt = Printf.sprintf "%2i %s" dt.dt_i (to_string tabs dt)
+	let tab_string = "    "
+
+	let to_string dt =
+		let buf = Buffer.create 0 in
+		let indices = Stack.create () in
+		let push_index i = Stack.push i indices in
+		let add_line tabs s =
+			if Buffer.length buf > 0 then Buffer.add_char buf '\n';
+			if not (Stack.is_empty indices) then begin
+				Buffer.add_string buf (Printf.sprintf "%2i" (Stack.pop indices));
+				Buffer.add_substring buf tabs 0 (String.length tabs - 2);
+			end else
+				Buffer.add_string buf tabs;
+			Buffer.add_string buf s
+		in
+		let add s =
+			Buffer.add_string buf s
+		in
+		let s_expr tabs e =
+			Type.s_expr_pretty false tabs false s_type e
+		in
+		let print_expr_noblock tabs e = match e.eexpr with
+			| TBlock el ->
+				List.iter (fun e ->
+					add_line tabs (s_expr tabs e) ;
+				) el
+			| _ ->
+				add_line tabs (s_expr tabs e)
+		in
+		let print_case_expr tabs case = match case.case_expr with
+			| None ->
+				()
+			| Some e ->
+				print_expr_noblock tabs e
+		in
+		let rec loop tabs dt =
+			push_index dt.dt_i;
+			match dt.dt_t with
+			| Leaf case ->
+				print_case_expr tabs case
+			| Switch(e,cases,dt) ->
+				add_line tabs (Printf.sprintf "switch (%s)" (s_expr tabs e));
+				List.iter (fun (con,unguarded,dt) ->
+					add_line (tabs ^ tab_string) "case ";
+					add (Constructor.to_string con);
+					add (if unguarded then "(unguarded)" else "guarded");
+					add ":";
+					loop (tabs ^ tab_string ^ tab_string) dt;
+				) cases;
+				add_line (tabs ^ tab_string) "default";
+				loop (tabs ^ tab_string ^ tab_string) dt;
+			| Bind(bl,dt) ->
+				List.iter (fun (v,_,e) ->
+					add_line tabs "var ";
+					add v.v_name;
+					add " = ";
+					add (s_expr tabs e);
+				) bl;
+				loop tabs dt
+			| Guard(e,dt1,dt2) ->
+				print_guard tabs e dt1 dt2 false
+			| GuardNull(e,dt1,dt2) ->
+				print_guard tabs e dt1 dt2 true
+			| Fail ->
+				add_line tabs "<fail>";
+		and print_guard tabs e dt1 dt2 is_null_guard =
+			add_line tabs "if (";
+			add (s_expr tabs e);
+			if is_null_guard then add " == null";
+			add ")";
+			loop (tabs ^ tab_string) dt1;
+			add_line tabs "else";
+			loop (tabs ^ tab_string) dt2;
+		in
+		loop tab_string dt;
+		Buffer.contents buf
 
 	let equal_dt dt1 dt2 = dt1.dt_i = dt2.dt_i
 
@@ -1441,15 +1505,17 @@ module TexprConverter = struct
 								| Some e -> Some (List.map (Constructor.to_texpr ctx match_debug) (List.sort Constructor.compare cons),e)
 							end
 						) cases in
+						let is_nullable_subject = is_explicit_null e_subject.etype in
 						let e_subject = match kind with
 							| SKValue -> e_subject
 							| SKEnum -> if match_debug then mk_name_call e_subject else mk_index_call e_subject
 							| SKLength -> type_field_access ctx e_subject "length"
 						in
-						begin match cases with
-							| [_,e2] when e_default = None && (match finiteness with RunTimeFinite -> true | _ -> false) ->
+						begin match cases,e_default,with_type with
+							| [_,e2],None,_ when (match finiteness with RunTimeFinite -> true | _ -> false) && not is_nullable_subject ->
 								{e2 with etype = t_switch}
-							| [[e1],e2] when (with_type = NoValue || e_default <> None) && ctx.com.platform <> Java (* TODO: problem with TestJava.hx:285 *) ->
+							| [[e1],e2],Some _,_
+							| [[e1],e2],None,NoValue when ctx.com.platform <> Java (* TODO: problem with TestJava.hx:285 *) ->
 								let e_op = mk (TBinop(OpEq,e_subject,e1)) ctx.t.tbool e_subject.epos in
 								begin match e2.eexpr with
 									| TIf(e_op2,e3,e_default2) when (match e_default,e_default2 with Some(e1),Some(e2) when e1 == e2 -> true | _ -> false) ->
@@ -1458,6 +1524,9 @@ module TexprConverter = struct
 									| _ ->
 										mk (TIf(e_op,e2,e_default)) t_switch dt.dt_pos
 								end
+							| [([{eexpr = TConst (TBool true)}],e1);([{eexpr = TConst (TBool false)}],e2)],None,_
+							| [([{eexpr = TConst (TBool false)}],e2);([{eexpr = TConst (TBool true)}],e1)],None,_ ->
+								mk (TIf(e_subject,e1,Some e2)) t_switch dt.dt_pos
 							| _ ->
 								let e_subject = match finiteness with
 									| RunTimeFinite | CompileTimeFinite when e_default = None ->
@@ -1591,7 +1660,7 @@ module Match = struct
 		let dt = Compile.compile ctx match_debug subjects cases p in
 		if match_debug then begin
 			print_endline "DECISION TREE BEGIN";
-			print_endline (Decision_tree.to_string "" dt);
+			print_endline (Decision_tree.to_string dt);
 			print_endline "DECISION TREE END";
 		end;
 		let e = try

+ 0 - 66
src/typing/typeload.ml

@@ -833,72 +833,6 @@ let string_list_of_expr_path (e,p) =
 	try string_list_of_expr_path_raise (e,p)
 	with Exit -> error "Invalid path" p
 
-let handle_path_display ctx path p =
-	let open ImportHandling in
-	let class_field c name =
-		ignore(c.cl_build());
-		let cf = PMap.find name c.cl_statics in
-		let origin = match c.cl_kind with
-			| KAbstractImpl a -> Self (TAbstractDecl a)
-			| _ -> Self (TClassDecl c)
-		in
-		DisplayEmitter.display_field ctx origin CFSStatic cf p
-	in
-	match ImportHandling.convert_import_to_something_usable DisplayPosition.display_position#get path,ctx.com.display.dms_kind with
-		| (IDKPackage [s],p),DMDefault ->
-			DisplayToplevel.collect_and_raise ctx TKType WithType.no_value CRImport (s,p) p
-		| (IDKPackage sl,p),DMDefault ->
-			let sl = match List.rev sl with
-				| s :: sl -> List.rev sl
-				| [] -> assert false
-			in
-			raise (Parser.TypePath(sl,None,true,p))
-		| (IDKPackage _,_),_ ->
-			() (* ? *)
-		| (IDKModule(sl,s),_),(DMDefinition | DMTypeDefinition) ->
-			(* We assume that we want to go to the module file, not a specific type
-			   which might not even exist anyway. *)
-			let mt = ctx.g.do_load_module ctx (sl,s) p in
-			let p = { pfile = mt.m_extra.m_file; pmin = 0; pmax = 0} in
-			DisplayException.raise_positions [p]
-		| (IDKModule(sl,s),_),DMHover ->
-			let m = ctx.g.do_load_module ctx (sl,s) p in
-			begin try
-				let mt = List.find (fun mt -> snd (t_infos mt).mt_path = s) m.m_types in
-				DisplayEmitter.display_module_type ctx mt p;
-			with Not_found ->
-				()
-			end
-		| (IDKSubType(sl,sm,st),p),DMHover ->
-			(* TODO: remove code duplication once load_type_def change is in *)
-			let m = ctx.g.do_load_module ctx (sl,sm) p in
-			begin try
-				let mt = List.find (fun mt -> snd (t_infos mt).mt_path = st) m.m_types in
-				DisplayEmitter.display_module_type ctx mt p;
-			with Not_found ->
-				()
-			end
-		| (IDKModule(sl,s),p),_ ->
-			raise (Parser.TypePath(sl,None,true,p))
-		| (IDKSubType(sl,sm,st),p),(DMDefinition | DMTypeDefinition) ->
-			resolve_position_by_path ctx { tpackage = sl; tname = sm; tparams = []; tsub = Some st} p
-		| (IDKSubType(sl,sm,st),p),_ ->
-			raise (Parser.TypePath(sl,Some(sm,false),true,p))
-		| ((IDKSubTypeField(sl,sm,st,sf) | IDKModuleField(sl,(sm as st),sf)),p),DMDefault ->
-			raise (Parser.TypePath(sl @ [sm],Some(st,false),true,p));
-		| ((IDKSubTypeField(sl,sm,st,sf) | IDKModuleField(sl,(sm as st),sf)),p),_ ->
-			let m = ctx.g.do_load_module ctx (sl,sm) p in
-			List.iter (fun t -> match t with
-				| TClassDecl c when snd c.cl_path = st ->
-					class_field c sf
-				| TAbstractDecl {a_impl = Some c; a_path = (_,st')} when st' = st ->
-					class_field c sf
-				| _ ->
-					()
-			) m.m_types;
-		| (IDK,_),_ ->
-			()
-
 let handle_using ctx path p =
 	let t = match List.rev path with
 		| (s1,_) :: (s2,_) :: sl ->

+ 32 - 13
src/typing/typeloadFields.ml

@@ -645,7 +645,7 @@ let bind_type (ctx,cctx,fctx) cf r p =
 	in
 	if ctx.com.display.dms_full_typing then begin
 		if fctx.is_macro && not ctx.in_macro then
-			()
+			force_macro ()
 		else begin
 			cf.cf_type <- TLazy r;
 			(* is_lib ? *)
@@ -1347,16 +1347,38 @@ let init_field (ctx,cctx,fctx) f =
 	| FProp (get,set,t,eo) ->
 		create_property (ctx,cctx,fctx) c f (get,set,t,eo) p
 
+let check_overload ctx f fs =
+	try
+		let f2 =
+			List.find (fun f2 ->
+				f != f2 &&
+				Overloads.compare_overload_args ~ctx f.cf_type f2.cf_type f f2 = Overloads.Same
+			) fs
+		in
+		display_error ctx ("Another overloaded field of same signature was already declared : " ^ f.cf_name) f.cf_pos;
+		display_error ctx ("The second field is declared here") f2.cf_pos
+	with Not_found ->
+		try
+			let f2 =
+				List.find (fun f2 ->
+					f != f2 &&
+					Overloads.compare_overload_args ~ctx f.cf_type f2.cf_type f f2 = Overloads.Impl_conflict
+				) fs
+			in
+			display_error ctx (
+				"Another overloaded field of similar signature was already declared : " ^
+				f.cf_name ^
+				"\nThe signatures are different in Haxe, but not in the target language"
+			) f.cf_pos;
+			display_error ctx ("The second field is declared here") f2.cf_pos
+		with | Not_found -> ()
+
 let check_overloads ctx c =
 	(* check if field with same signature was declared more than once *)
 	List.iter (fun f ->
 		if Meta.has Meta.Overload f.cf_meta then
-			List.iter (fun f2 ->
-				try
-					ignore (List.find (fun f3 -> f3 != f2 && Overloads.same_overload_args f2.cf_type f3.cf_type f2 f3) (f :: f.cf_overloads));
-					display_error ctx ("Another overloaded field of same signature was already declared : " ^ f2.cf_name) f2.cf_pos
-				with | Not_found -> ()
-		) (f :: f.cf_overloads)) (c.cl_ordered_fields @ c.cl_ordered_statics)
+			check_overload ctx f (f :: f.cf_overloads)
+	) (c.cl_ordered_fields @ c.cl_ordered_statics)
 
 let init_class ctx c p context_init herits fields =
 	let ctx,cctx = create_class_context ctx c context_init p in
@@ -1509,13 +1531,10 @@ let init_class ctx c p context_init herits fields =
 	(* check overloaded constructors *)
 	(if ctx.com.config.pf_overload && not cctx.is_lib then match c.cl_constructor with
 	| Some ctor ->
-		delay ctx PTypeField (fun() ->
+		delay ctx PTypeField (fun () ->
+			(* TODO: consider making a broader check, and treat some types, like TAnon and type parameters as Dynamic *)
 			List.iter (fun f ->
-				try
-					(* TODO: consider making a broader check, and treat some types, like TAnon and type parameters as Dynamic *)
-					ignore(List.find (fun f2 -> f != f2 && Overloads.same_overload_args f.cf_type f2.cf_type f f2) (ctor :: ctor.cf_overloads));
-					display_error ctx ("Another overloaded field of same signature was already declared : " ^ f.cf_name) f.cf_pos;
-				with Not_found -> ()
+				check_overload ctx f (ctor :: ctor.cf_overloads)
 			) (ctor :: ctor.cf_overloads)
 		)
 	| _ -> ());

+ 4 - 4
src/typing/typeloadModule.ml

@@ -357,9 +357,9 @@ let init_module_type ctx context_init do_init (decl,p) =
 			ImportHandling.add_import_position ctx.com p path;
 		| DMUsage _ ->
 			ImportHandling.add_import_position ctx.com p path;
-			if DisplayPosition.display_position#is_in_file p.pfile then handle_path_display ctx path p
+			if DisplayPosition.display_position#is_in_file p.pfile then DisplayPath.handle_path_display ctx path p
 		| _ ->
-			if DisplayPosition.display_position#is_in_file p.pfile then handle_path_display ctx path p
+			if DisplayPosition.display_position#is_in_file p.pfile then DisplayPath.handle_path_display ctx path p
 	in
 	match decl with
 	| EImport (path,mode) ->
@@ -911,7 +911,7 @@ let handle_import_hx ctx m decls p =
 			if Sys.file_exists path then begin
 				let _,r = match !TypeloadParse.parse_hook ctx.com path p with
 					| ParseSuccess data -> data
-					| ParseDisplayFile(data,_,_) -> data
+					| ParseDisplayFile(data,_) -> data
 					| ParseError(_,(msg,p),_) -> Parser.error msg p
 				in
 				List.iter (fun (d,p) -> match d with EImport _ | EUsing _ -> () | _ -> error "Only import and using is allowed in import.hx files" p) r;
@@ -938,7 +938,7 @@ let type_module ctx mpath file ?(is_extern=false) tdecls p =
 	if is_extern then m.m_extra.m_kind <- MExtern;
 	begin if ctx.is_display_file then match ctx.com.display.dms_kind with
 		| DMResolve s ->
-			resolve_position_by_path ctx {tname = s; tpackage = []; tsub = None; tparams = []} p
+			DisplayPath.resolve_position_by_path ctx {tname = s; tpackage = []; tsub = None; tparams = []} p
 		| _ ->
 			()
 	end;

+ 135 - 5
src/typing/typeloadParse.ml

@@ -24,9 +24,12 @@ open Ast
 open DisplayTypes.DiagnosticsSeverity
 open DisplayTypes.DisplayMode
 open Common
+open Type
 open Typecore
 open Error
 
+exception DisplayInMacroBlock
+
 let parse_file_from_lexbuf com file p lexbuf =
 	let t = Timer.timer ["parsing"] in
 	Lexer.init file;
@@ -43,7 +46,7 @@ let parse_file_from_lexbuf com file p lexbuf =
 	in
 	begin match !Parser.display_mode,parse_result with
 		| DMModuleSymbols (Some ""),_ -> ()
-		| DMModuleSymbols filter,(ParseSuccess data | ParseDisplayFile(data,_,_)) when filter = None && DisplayPosition.display_position#is_in_file file ->
+		| DMModuleSymbols filter,(ParseSuccess data | ParseDisplayFile(data,_)) when filter = None && DisplayPosition.display_position#is_in_file file ->
 			let ds = DocumentSymbols.collect_module_symbols (filter = None) data in
 			DisplayException.raise_module_symbols (DocumentSymbols.Printer.print_module_symbols com [file,ds] filter);
 		| _ ->
@@ -122,7 +125,7 @@ let resolve_module_file com m remap p =
 			| [] -> []
 		in
 		let meta =  match parse_result with
-			| ParseSuccess(_,decls) | ParseDisplayFile((_,decls),_,_) -> loop decls
+			| ParseSuccess(_,decls) | ParseDisplayFile((_,decls),_) -> loop decls
 			| ParseError _ -> []
 		in
 		if not (Meta.has Meta.NoPackageRestrict meta) then begin
@@ -144,6 +147,133 @@ let resolve_module_file com m remap p =
 	let timer = Timer.timer ["typing";"resolve_module_file"] in
 	Std.finally timer (resolve_module_file com m remap) p *)
 
+module ConditionDisplay = struct
+	open ParserEntry
+	open CompletionItem.CompletionType
+	open DisplayPosition
+
+	exception Result of expr
+
+	let t_semver = TInst(mk_class null_module ([],"SemVer") null_pos null_pos,[])
+
+	let convert_small_type com = function
+		| TNull -> "null",Type.mk_mono()
+		| TBool b -> string_of_bool b,com.basic.tbool
+		| TFloat f -> string_of_float f,com.basic.tfloat
+		| TString s -> "\"" ^ StringHelper.s_escape s ^ "\"",com.basic.tstring
+		| TVersion(r,p) -> Semver.to_string (r,p),t_semver
+
+	let check_condition com e =
+		let check_position = (if com.display.dms_kind = DMHover then
+			encloses_position_gt
+		else
+			encloses_position
+		) display_position#get in
+		let tpair t = (t,CompletionItem.CompletionType.from_type (fun _ -> Imported) t) in
+		let check_expr (e,p) =
+			match e with
+				| ECall ((EConst (Ident "version"),p),_)  ->
+					let t = TFun ([("s",false,com.basic.tstring)],t_semver) in
+					if check_position p then
+						DisplayException.raise_hover (CompletionItem.make_ci_class_field {
+							field = {
+								cf_name = "version";
+								cf_type = t;
+								cf_pos = null_pos;
+								cf_name_pos = null_pos;
+								cf_doc = Some (
+"Allows comparing defines (such as the version of a Haxelib or Haxe) with SemVer semantics.
+Both the define and the string passed to `version()` must be valid semantic versions.
+
+Example:
+```haxe
+#if (haxe >= version(\"4.0.0-rc.3\"))\n
+```
+
+Note: this syntax does not parse with Haxe versions earlier than 4.0.0-rc.3,
+so it should be avoided if backwards-compatibility with earlier versions is needed.
+
+@see https://semver.org/");
+								cf_meta = [];
+								cf_kind = Method MethNormal;
+								cf_params = [];
+								cf_expr = None;
+								cf_expr_unoptimized = None;
+								cf_overloads = [];
+								cf_flags = set_flag 0 (int_of_class_field_flag CfPublic);
+							};
+							scope = CFSStatic;
+							origin = BuiltIn;
+							is_qualified = true;
+						} (tpair t)) None p
+				| EConst(Ident(n)) ->
+					let v = eval com.defines (e,p) in
+					DisplayException.raise_hover (CompletionItem.make_ci_define n (match v with
+						| TNull -> None
+						| TString s -> Some (StringHelper.s_escape s)
+						| _ -> assert false
+					) (tpair com.basic.tstring)) None p
+				| _ ->
+					()
+		in
+		let rec loop (e,p) =
+			if check_position p then check_expr (e,p);
+			Ast.iter_expr loop (e,p);
+			if check_position p then
+				let v = eval com.defines (e,p) in
+				let s,t = convert_small_type com v in
+				DisplayException.raise_hover (CompletionItem.make_ci_literal s (tpair t)) None p
+		in
+		loop e;
+end
+
+module PdiHandler = struct
+	open Parser
+	open DisplayPosition
+
+	let is_true defines e =
+		ParserEntry.is_true (ParserEntry.eval defines e)
+
+	let handle_pdi com file pdi =
+		let macro_defines = adapt_defines_to_macro_context com.defines in
+		let check = (if com.display.dms_kind = DMHover then
+			encloses_position_gt
+		else
+			encloses_position
+		) display_position#get in
+		List.iter (fun (p,e) ->
+			let has_macro_define = is_true macro_defines e in
+			if has_macro_define then com.display_information.display_module_has_macro_defines <- true;
+			if check p then begin
+				if has_macro_define then
+					raise DisplayInMacroBlock;
+				begin match com.display.dms_kind with
+				| DMHover ->
+					raise (DisplayException.DisplayException(DisplayHover None))
+				| _ ->
+					()
+				end;
+			end;
+		) pdi.pd_dead_blocks;
+		begin match com.display.dms_kind with
+		| DMHover ->
+			List.iter (ConditionDisplay.check_condition com) pdi.pd_conditions;
+		| _ ->
+			()
+		end;
+		let display_defines = {macro_defines with values = PMap.add "display" "1" macro_defines.values} in
+		let dead_blocks = List.filter (fun (_,e) -> not (is_true display_defines e)) pdi.pd_dead_blocks in
+		let sdi = com.shared.shared_display_information in
+		begin try
+			let dead_blocks2 = Hashtbl.find sdi.dead_blocks file in
+			(* Intersect *)
+			let dead_blocks2 = List.filter (fun (p,_) -> List.mem_assoc p dead_blocks) dead_blocks2 in
+			Hashtbl.replace sdi.dead_blocks file dead_blocks2
+		with Not_found ->
+			Hashtbl.add sdi.dead_blocks file dead_blocks
+		end;
+end
+
 let parse_module_file com file p =
 	let handle_parser_error msg p =
 		let msg = Parser.error_msg msg in
@@ -154,12 +284,12 @@ let parse_module_file com file p =
 	in
 	let pack,decls = match (!parse_hook) com file p with
 		| ParseSuccess data -> data
-		| ParseDisplayFile(data,errors,dead) ->
-			begin match errors with
+		| ParseDisplayFile(data,pdi) ->
+			begin match pdi.pd_errors with
 			| (msg,p) :: _ -> handle_parser_error msg p
 			| [] -> ()
 			end;
-			if dead <> [] then Hashtbl.replace com.display_information.dead_blocks file dead;
+			PdiHandler.handle_pdi com file pdi;
 			data
 		| ParseError(data,(msg,p),_) ->
 			handle_parser_error msg p;

+ 2 - 2
src/typing/typer.ml

@@ -1577,7 +1577,7 @@ and format_string ctx s p =
 				let ep = { p with pmin = !pmin + pos + 2; pmax = !pmin + send + 1 } in
 				try
 					begin match ParserEntry.parse_expr_string ctx.com.defines scode ep error true with
-						| ParseSuccess data | ParseDisplayFile(data,_,_) -> data
+						| ParseSuccess data | ParseDisplayFile(data,_) -> data
 						| ParseError(_,(msg,p),_) -> error (Parser.error_msg msg) p
 					end
 				with Exit ->
@@ -2450,7 +2450,7 @@ and type_expr ?(mode=MGet) ctx (e,p) (with_type:WithType.t) =
 	match e with
 	| EField ((EConst (String(s,_)),ps),"code") ->
 		if UTF8.length s <> 1 then error "String must be a single UTF8 char" ps;
-		mk (TConst (TInt (Int32.of_int (UChar.code (UTF8.get s 0))))) ctx.t.tint p
+		mk (TConst (TInt (Int32.of_int (UCharExt.code (UTF8.get s 0))))) ctx.t.tint p
 	| EField(_,n) when starts_with n '$' ->
 		error "Field names starting with $ are not allowed" p
 	| EConst (Ident s) ->

+ 8 - 6
src/typing/typerDisplay.ml

@@ -17,7 +17,7 @@ open Fields
 open Calls
 open Error
 
-let convert_function_signature ctx values (args,ret) = match DisplayEmitter.completion_type_of_type ctx ~values (TFun(args,ret)) with
+let convert_function_signature ctx values (args,ret) = match CompletionType.from_type (get_import_status ctx) ~values (TFun(args,ret)) with
 	| CompletionType.CTFunction ctf -> ((args,ret),ctf)
 	| _ -> assert false
 
@@ -30,7 +30,7 @@ let completion_item_of_expr ctx e =
 			false
 	in
 	let tpair ?(values=PMap.empty) t =
-		let ct = DisplayEmitter.completion_type_of_type ctx ~values t in
+		let ct = CompletionType.from_type (get_import_status ctx) ~values t in
 		(t,ct)
 	in
 	let of_field e origin cf scope make_ci =
@@ -138,7 +138,9 @@ let get_expected_type ctx with_type =
 	in
 	match t with
 		| None -> None
-		| Some t -> Some (completion_type_of_type ctx t,completion_type_of_type ctx (follow t))
+		| Some t ->
+			let from_type = CompletionType.from_type (get_import_status ctx) in
+			Some (from_type t,from_type (follow t))
 
 let raise_toplevel ctx dk with_type (subject,psubject) =
 	let expected_type = get_expected_type ctx with_type in
@@ -229,7 +231,7 @@ let rec handle_signature_display ctx e_ast with_type =
 					let e = expr_of_type_path (["haxe";"Log"],"trace") p in
 					type_expr ctx e WithType.value
 				| Error (Unknown_ident "$type",p) ->
-					display_dollar_type ctx p (fun t -> t,(DisplayEmitter.completion_type_of_type ctx t))
+					display_dollar_type ctx p (fun t -> t,(CompletionType.from_type (get_import_status ctx) t))
 			in
 			let e1 = match e1 with
 				| (EField (e,"bind"),p) ->
@@ -444,7 +446,7 @@ let handle_structure_display ctx e fields origin =
 	let fields = PMap.foldi (fun _ cf acc -> cf :: acc) fields [] in
 	let fields = List.sort (fun cf1 cf2 -> -compare cf1.cf_pos.pmin cf2.cf_pos.pmin) fields in
 	let tpair ?(values=PMap.empty) t =
-		let ct = DisplayEmitter.completion_type_of_type ctx ~values t in
+		let ct = CompletionType.from_type (get_import_status ctx) ~values t in
 		(t,ct)
 	in
 	let make_field_item cf =
@@ -485,7 +487,7 @@ let handle_display ?resume_typing ctx e_ast dk with_type =
 	ctx.in_display <- true;
 	ctx.in_call_args <- false;
 	let tpair t =
-		let ct = DisplayEmitter.completion_type_of_type ctx t in
+		let ct = CompletionType.from_type (get_import_status ctx) t in
 		(t,ct)
 	in
 	let e = match e_ast,with_type with

+ 126 - 116
std/cpp/vm/Debugger.hx

@@ -23,9 +23,9 @@
 package cpp.vm;
 
 /**
- * Parameter describes a function parameter.  Instances of this class are
- * embedded in stack frame objects to describe the function parameters that
- * were used in the invocation of the function that defines that stack frame.
+	Parameter describes a function parameter. Instances of this class are
+	embedded in stack frame objects to describe the function parameters that
+	were used in the invocation of the function that defines that stack frame.
 **/
 class Parameter {
 	public var name(default, null):String;
@@ -38,7 +38,7 @@ class Parameter {
 }
 
 /**
- * StackFrame describes one call stack frame.
+	`StackFrame` describes one call stack frame.
 **/
 class StackFrame {
 	public var fileName(default, null):String;
@@ -57,7 +57,7 @@ class StackFrame {
 }
 
 /**
- * ThreadInfo describes the state of a single thread.
+	`ThreadInfo` describes the state of a single thread.
 **/
 class ThreadInfo {
 	public static inline var STATUS_RUNNING = 1;
@@ -66,14 +66,18 @@ class ThreadInfo {
 	public static inline var STATUS_STOPPED_UNCAUGHT_EXCEPTION = 4;
 	public static inline var STATUS_STOPPED_CRITICAL_ERROR = 5;
 
-	// 0 is never a valid thread number
+	/** 0 is never a valid thread number **/
 	public var number(default, null):Int;
+
 	public var status(default, null):Int;
-	// If status is "stopped breakpoint", this is the breakpoint number
+
+	/** If status is "stopped breakpoint", this is the breakpoint number **/
 	public var breakpoint(default, null):Int;
-	// If status is "critical error", this describes the error
+
+	/** If status is "critical error", this describes the error **/
 	public var criticalErrorDescription(default, null):String;
-	// Stack will be listed with the lowest frame first
+
+	/** Stack will be listed with the lowest frame first **/
 	public var stack(default, null):Array<StackFrame>;
 
 	public function new(number:Int, status:Int, breakpoint:Int = -1, criticalErrorDescription:String = null) {
@@ -86,8 +90,8 @@ class ThreadInfo {
 }
 
 /**
- * This class wraps the hxcpp C++ implementation to provide a Haxe interface
- * to the low level debugging features
+	This class wraps the hxcpp C++ implementation to provide a Haxe interface
+	to the low level debugging features
 **/
 class Debugger {
 	public static inline var THREAD_CREATED = 1;
@@ -99,143 +103,149 @@ class Debugger {
 	public static inline var STEP_OVER = 2;
 	public static inline var STEP_OUT = 3;
 
-	// This tagging value is returned by getStackVariableValue() and
-	// setStackVariableValue if the requested value does not exist at the
-	// requested stack frame
-	public static var NONEXISTENT_VALUE = new String("NONEXISTENT_VALUE");
-	// This tagging value is returned by getStackVariableValue and
-	// setStackVariableValue if the stack variable that is being set is on a
-	// thread that is running, in which case the set does not take place.
-	public static var THREAD_NOT_STOPPED = new String("THREAD_NOT_STOPPED");
+	/**
+		This tagging value is returned by `getStackVariableValue()` and
+		`setStackVariableValue()` if the requested value does not exist at the
+		requested stack frame
+	**/
+	public static var NONEXISTENT_VALUE = "NONEXISTENT_VALUE";
+
+	/**
+		This tagging value is returned by `getStackVariableValue()` and
+		`setStackVariableValue()` if the stack variable that is being set is on a
+		thread that is running, in which case the set does not take place.
+	**/
+	public static var THREAD_NOT_STOPPED = "THREAD_NOT_STOPPED";
 
 	/**
-	 * Sets the handler callback to be made when asynchronous events occur,
-	 * specifically, when threads are created, terminated, started, or
-	 * stopped.  The calling thread becomes the "debugger" thread, which means
-	 * that it will be discluded from any breakpoints and will not be reported
-	 * on by any thread reporting requests.
-	 *
-	 * Be aware that this callback is made asynchronously and possibly by
-	 * multiple threads simultaneously.
-	 *
-	 * Setting this to null prevents further callbacks.
-	 *
-	 * Throws a string exception if the program does not support debugging
-	 * because it was not compiled with the HXCPP_DEBUGGER flag set.
-	 *
-	 * @param handler is a function that will be called back by asynchronous
-	 *        thread events.  Note that this function is called directly from
-	 *        the thread experiencing the event and the handler should return
-	 *        quickly to avoid blocking the calling thread unnecessarily.
-	 *        The parameters to handler are:
-	 *          - threadNumber, the thread number of the event
-	 *          - event, one of THREAD_CREATED, THREAD_TERMINATED,
-	 *            THREAD_STARTED, or THREAD_STOPPED
-	 *          - stackFrame, the stack frame number at which the thread is stopped,
-	 *            undefined if event is not THREAD_STOPPED
-	 *          - className, the class name at which the thread is stopped,
-	 *            undefined if event is not THREAD_STOPPED
-	 *          - functionName, the function name at which the thread is
-	 *            stopped, undefined if event is not THREAD_STOPPED
-	 *          - fileName, the file name at which the thread is stopped,
-	 *            undefined if event is not THREAD_STOPPED
-	 *          - lineNumber, the line number at which the thread is stopped,
-	 *            undefined if event is not THREAD_STOPPED
+		Sets the handler callback to be made when asynchronous events occur,
+		specifically, when threads are created, terminated, started, or
+		stopped. The calling thread becomes the "debugger" thread, which means
+		that it will be discluded from any breakpoints and will not be reported
+		on by any thread reporting requests.
+
+		Be aware that this callback is made asynchronously and possibly by
+		multiple threads simultaneously.
+
+		Setting this to `null` prevents further callbacks.
+
+		Throws a string exception if the program does not support debugging
+		because it was not compiled with the `HXCPP_DEBUGGER` flag set.
+
+		@param handler is a function that will be called back by asynchronous
+			   thread events.  Note that this function is called directly from
+			   the thread experiencing the event and the handler should return
+			   quickly to avoid blocking the calling thread unnecessarily.
+			   The parameters to handler are:
+				 - `threadNumber`, the thread number of the event
+				 - event, one of `THREAD_CREATED`, `THREAD_TERMINATED`,
+				   `THREAD_STARTED`, or `THREAD_STOPPED`
+				 - stackFrame, the stack frame number at which the thread is stopped,
+				   undefined if event is not `THREAD_STOPPED`
+				 - `className`, the class name at which the thread is stopped,
+				   undefined if event is not `THREAD_STOPPED`
+				 - `functionName`, the function name at which the thread is
+				   stopped, undefined if event is not `THREAD_STOPPED`
+				 - `fileName`, the file name at which the thread is stopped,
+				   undefined if event is not `THREAD_STOPPED`
+				 - `lineNumber`, the line number at which the thread is stopped,
+				   undefined if event is not `THREAD_STOPPED`
 	**/
-	public static function setEventNotificationHandler(handler:Int->Int->Int->String->String->String->Int->Void) {
+	public static function setEventNotificationHandler(handler:(threadNumber:Int, event:Int, stackFrame:Int, className:String, functionName:String,
+		fileName:String, lineNumber:Int) -> Void) {
 		untyped __global__.__hxcpp_dbg_setEventNotificationHandler(handler);
 	}
 
 	/**
-	 * This can be called to turn off (and then back on) all stopping of
-	 * debugged threads temporarily.  It should only be used by classes that
-	 * actually implement the debugger to hide themselves from the debugger as
-	 * necessary.
+		This can be called to turn off (and then back on) all stopping of
+		debugged threads temporarily. It should only be used by classes that
+		actually implement the debugger to hide themselves from the debugger as
+		necessary.
 	**/
 	public static function enableCurrentThreadDebugging(enabled:Bool) {
 		untyped __global__.__hxcpp_dbg_enableCurrentThreadDebugging(enabled);
 	}
 
 	/**
-	 * Returns the thread number of the calling thread.
-	 *
-	 * @return the thread number of the calling thread.
+		Returns the thread number of the calling thread.
+
+		@return the thread number of the calling thread.
 	**/
 	public static function getCurrentThreadNumber():Int {
 		return untyped __global__.__hxcpp_dbg_getCurrentThreadNumber();
 	}
 
 	/**
-	 * Returns the set of source files known to the debugger.  This is a copy
-	 * of the original array and could be quite large.  The caller should
-	 * cache this value to avoid multiple copies needing to be made.
-	 *
-	 * @return the set of source files known to the debugger.
+		Returns the set of source files known to the debugger. This is a copy
+		of the original array and could be quite large. The caller should
+		cache this value to avoid multiple copies needing to be made.
+
+		@return the set of source files known to the debugger.
 	**/
 	public static function getFiles():Array<String> {
 		return untyped __global__.__hxcpp_dbg_getFiles();
 	}
 
 	/**
-	 * Returns the full paths of the set of source files known to the debugger.
-	 * This is a copy of the original array and could be quite large.
-	 * It is possible that this set will be empty, in which case the full paths are not known.
-	 * The index of these files matches the index from "getFiles", so the full path for
-	 * a given short path can be calculated.
-	 *
-	 * @return the known full paths of the set of source files
+		Returns the full paths of the set of source files known to the debugger.
+		This is a copy of the original array and could be quite large.
+		It is possible that this set will be empty, in which case the full paths are not known.
+		The index of these files matches the index from `getFiles()`, so the full path for
+		a given short path can be calculated.
+
+		@return the known full paths of the set of source files
 	**/
 	public static function getFilesFullPath():Array<String> {
 		return untyped __global__.__hxcpp_dbg_getFilesFullPath();
 	}
 
 	/**
-	 * Returns the set of class names of all classes known to the debugger.
-	 * This is a copy of the original array and could be quite large.  The
-	 * caller should cache this value to avoid multiple copies needing to be
-	 * made.
-	 *
-	 * @return the set of class names of all classes known to the debugger.
+		Returns the set of class names of all classes known to the debugger.
+		This is a copy of the original array and could be quite large. The
+		caller should cache this value to avoid multiple copies needing to be
+		made.
+
+		@return the set of class names of all classes known to the debugger.
 	**/
 	public static function getClasses():Array<String> {
 		return untyped __global__.__hxcpp_dbg_getClasses();
 	}
 
 	/**
-	 * Returns a ThreadInfo object describing every thread that existed at the
-	 * moment that the call was made, except for the debugger thread.
+		Returns a `ThreadInfo` object describing every thread that existed at the
+		moment that the call was made, except for the debugger thread.
 	**/
 	public static function getThreadInfos():Array<ThreadInfo> {
 		return untyped __global__.__hxcpp_dbg_getThreadInfos();
 	}
 
 	/**
-	 * Returns a ThreadInfo object describing a single thread, or null if
-	 * there is no such thread or the thread queried about was the debugger
-	 * thread and unsafe was not true.
+		Returns a `ThreadInfo` object describing a single thread, or `null` if
+		there is no such thread or the thread queried about was the debugger
+		thread and `unsafe` was not `true`.
 	**/
 	public static function getThreadInfo(threadNumber:Int, unsafe:Bool):ThreadInfo {
 		return untyped __global__.__hxcpp_dbg_getThreadInfo(threadNumber, unsafe);
 	}
 
 	/**
-	 * Adds a new file:line breakpoint.  The breakpoint number of the newly
-	 * added breakpoint is returned.
+		Adds a new `file:line` breakpoint. The breakpoint number of the newly
+		added breakpoint is returned.
 	**/
 	public static function addFileLineBreakpoint(file:String, line:Int):Int {
 		return untyped __global__.__hxcpp_dbg_addFileLineBreakpoint(file, line);
 	}
 
 	/**
-	 * Adds a new class:function breakpoint.  The breakpoint number of the
-	 * newly added breakpoint is returned.
+		Adds a new `class:function` breakpoint. The breakpoint number of the
+		newly added breakpoint is returned.
 	**/
 	public static function addClassFunctionBreakpoint(className:String, functionName:String):Int {
 		return untyped __global__.__hxcpp_dbg_addClassFunctionBreakpoint(className, functionName);
 	}
 
 	/**
-	 * Deletes a breakpoint, or all breakpoints.
+		Deletes a breakpoint, or all breakpoints.
 	**/
 	public static function deleteBreakpoint(number:Null<Int>) {
 		if (number == null) {
@@ -246,65 +256,65 @@ class Debugger {
 	}
 
 	/**
-	 * Breaks all threads except the debugger thread (which should be the same
-	 * as the calling thread!).
-	 *
-	 * If `wait` is true, waits up to 2 seconds for all threads to be broken.
-	 * Threads which are in blocking system calls and cannot break after 2
-	 * seconds remain running when this function returns.
+		Breaks all threads except the debugger thread (which should be the same
+		as the calling thread!).
+
+		If `wait` is `true`, waits up to 2 seconds for all threads to be broken.
+		Threads which are in blocking system calls and cannot break after 2
+		seconds remain running when this function returns.
 	**/
 	public static function breakNow(wait:Bool = true) {
 		untyped __global__.__hxcpp_dbg_breakNow(wait);
 	}
 
 	/**
-	 * Continue execution of all stopped threads.  If specialThreadNumber
-	 * is a valid thread number, then it will be continued past
-	 * `continueCount` breakpoints instead of just 1 like all of the other
-	 * threads.
+		Continue execution of all stopped threads. If `specialThreadNumber`
+		is a valid thread number, then it will be continued past
+		`continueCount` breakpoints instead of just 1 like all of the other
+		threads.
 	**/
 	public static function continueThreads(specialThreadNumber:Int, continueCount:Int) {
 		untyped __global__.__hxcpp_dbg_continueThreads(specialThreadNumber, continueCount);
 	}
 
 	/**
-	 * Single steps the given thread.
+		Single steps the given thread.
 	**/
 	public static function stepThread(threadNumber:Int, stepType:Int, stepCount:Int = 1) {
 		untyped __global__.__hxcpp_dbg_stepThread(threadNumber, stepType, stepCount);
 	}
 
 	/**
-	 * Returns the list of local variables (including "this", function
-	 * arguments, and local variables) visible to the given thread at the
-	 * given stack frame.
-	 *
-	 * Returns a list with a single entry, THREAD_NOT_STOPPED, if the
-	 * thread is not stopped and thus variables cannot be fetched and
-	 * unsafe is not true.
-	 *
-	 * @return the list of local variables (including "this", function
-	 *         arguments, and local variables) visible to the given thread at
-	 *         the given stack frame.
+		Returns the list of local variables (including `this`, function
+		arguments, and local variables) visible to the given thread at the
+		given stack frame.
+
+		Returns a list with a single entry, `THREAD_NOT_STOPPED`, if the
+		thread is not stopped and thus variables cannot be fetched and
+		`unsafe` is not `true`.
+
+		@return the list of local variables (including `this`, function
+				arguments, and local variables) visible to the given thread at
+				the given stack frame.
 	**/
 	public static function getStackVariables(threadNumber:Int, stackFrameNumber:Int, unsafe:Bool):Array<String> {
 		return untyped __global__.__hxcpp_dbg_getStackVariables(threadNumber, stackFrameNumber, unsafe, THREAD_NOT_STOPPED);
 	}
 
 	/**
-	 * Returns the value of a stack variable, or NONEXISTENT_VALUE if the
-	 * requested value does not exist.  If the thread is actively running
-	 * and unsafe is not true, returns THREAD_NOT_STOPPED.
+		Returns the value of a stack variable, or `NONEXISTENT_VALUE` if the
+		requested value does not exist.  If the thread is actively running
+		and `unsafe` is not `true`, returns `THREAD_NOT_STOPPED`.
 	**/
 	public static function getStackVariableValue(threadNumber:Int, stackFrameNumber:Int, name:String, unsafe:Bool):Dynamic {
 		return untyped __global__.__hxcpp_dbg_getStackVariableValue(threadNumber, stackFrameNumber, name, unsafe, NONEXISTENT_VALUE, THREAD_NOT_STOPPED);
 	}
 
 	/**
-	 * Sets the value of a stack variable and returns that value.  If the
-	 * variable does not exist, on the stack, this function returns
-	 * NONEXISTENT_VALUE.  If the thread is actively running and unsafe is not
-	 * true, returns THREAD_NOT_STOPPED, and the value is not set.
+		Sets the value of a stack variable and returns that value. If the
+		variable does not exist, on the stack, this function returns
+		`NONEXISTENT_VALUE`. If the thread is actively running and `unsafe` is not
+		`true`, returns `THREAD_NOT_STOPPED`, and the value is not set.
 	**/
 	public static function setStackVariableValue(threadNumber:Int, stackFrameNumber:Int, name:String, value:Dynamic, unsafe:Bool):Dynamic {
 		return untyped __global__.__hxcpp_dbg_setStackVariableValue(threadNumber, stackFrameNumber, name, value, unsafe, NONEXISTENT_VALUE,

+ 10 - 0
std/haxe/display/Display.hx

@@ -292,6 +292,15 @@ typedef Metadata = {
 	var ?links:Array<String>;
 }
 
+typedef Define = {
+	var name:String;
+	var value:Null<String>;
+	var doc:JsonDoc;
+	var parameters:Array<String>;
+	var platforms:Array<Platform>;
+	var links:Array<String>;
+}
+
 typedef Keyword = {
 	var name:KeywordKind;
 }
@@ -368,6 +377,7 @@ enum abstract DisplayItemKind<T>(String) {
 	var AnonymousStructure:DisplayItemKind<JsonAnon>;
 	var Expression:DisplayItemKind<JsonTExpr>;
 	var TypeParameter:DisplayItemKind<DisplayModuleTypeParameter>;
+	var Define:DisplayItemKind<Define>;
 }
 
 typedef DisplayItem<T> = {

+ 3 - 0
std/haxe/display/Server.hx

@@ -117,6 +117,9 @@ typedef HaxeMemoryResult = {
 		final parserCache:Int;
 		final moduleCache:Int;
 		final nativeLibCache:Int;
+		final macroInterpreter:Int;
+		final completionResult:Int;
+		final ?additionalSizes:Array<{name:String, size:Int}>;
 	}
 }
 

+ 2 - 2
std/hl/Bytes.hx

@@ -174,8 +174,8 @@ package hl;
 		return null;
 	}
 
-	@:hlNative("std", "utf16_to_utf8")
-	public function utf16ToUtf8(bytePos:Int, outSize:Ref<Int>):Bytes {
+	@:hlNative("std","utf16_to_utf8")
+	public function utf16ToUtf8(len:Int, outSize:Ref<Int>) : Bytes {
 		return null;
 	}
 

+ 1 - 1
std/hl/_std/haxe/io/Bytes.hx

@@ -221,7 +221,7 @@ class Bytes {
 				return new Bytes(s.bytes.sub(0, s.length << 1), s.length << 1);
 			case UTF8:
 				var size = 0;
-				var b = s.bytes.utf16ToUtf8(0, size);
+				var b = s.bytes.utf16ToUtf8(s.length, size);
 				return new Bytes(b, size);
 		}
 	}

+ 5 - 1
std/js/_std/Array.hx

@@ -63,7 +63,11 @@ extern class Array<T> {
 	}
 
 	@:runtime inline function map<S>(f:T->S):Array<S> {
-		return [for (v in this) f(v)];
+		var result:Array<S> = js.Syntax.construct(Array, length);
+		for(i in 0...length) {
+			result[i] = f(this[i]);
+		}
+		return result;
 	}
 
 	@:runtime inline function filter(f:T->Bool):Array<T> {

+ 2 - 2
std/php/_std/Array.hx

@@ -211,8 +211,8 @@ final class Array<T> implements ArrayAccess<Int, T> {
 	@:noCompletion
 	function offsetSet(offset:Int, value:T):Void {
 		if (length <= offset) {
-			if (length < offset) {
-				arr = Global.array_pad(arr, offset + 1, null);
+			for(i in length...offset + 1) {
+				arr[i] = null;
 			}
 			length = offset + 1;
 		}

+ 9 - 0
tests/misc/java/projects/Issue2689/Main.hx

@@ -0,0 +1,9 @@
+class Main {
+	static function main() {}
+
+	@:overload static function conflict(fn:(Int)->String) {}
+	@:overload static function conflict(fn:(Bool)->String) {}
+
+	@:overload static function same(fn:(Int)->String) {}
+	@:overload static function same(fn:(Int)->String) {}
+}

+ 3 - 0
tests/misc/java/projects/Issue2689/compile-fail.hxml

@@ -0,0 +1,3 @@
+-main Main
+-java bin
+--no-output

+ 5 - 0
tests/misc/java/projects/Issue2689/compile-fail.hxml.stderr

@@ -0,0 +1,5 @@
+Main.hx:4: characters 13-58 : Another overloaded field of similar signature was already declared : conflict
+Main.hx:4: characters 13-58 : The signatures are different in Haxe, but not in the target language
+Main.hx:5: characters 13-59 : The second field is declared here
+Main.hx:7: characters 13-54 : Another overloaded field of same signature was already declared : same
+Main.hx:8: characters 13-54 : The second field is declared here

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

@@ -0,0 +1,14 @@
+class Main {
+    public static function foo<T>(v:T):T return v;
+
+    public static function main():Void {
+        var a = foo;
+        doSwitch(a);
+    }
+
+    public static function doSwitch<A, T:A->A>(a:T):Void {
+        switch (a){
+            case _.bind("asdf", "foo") => b: trace(b());
+        }
+    }
+}

+ 2 - 0
tests/misc/projects/Issue5952/compile1-fail.hxml

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

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

@@ -0,0 +1 @@
+Main.hx:11: characters 20-24 : doSwitch.T has no field bind

+ 22 - 0
tests/misc/projects/Issue6622/Main1.hx

@@ -0,0 +1,22 @@
+enum FmtOption<A> {
+	FixedPrecision:FmtOption<A>;
+}
+
+enum Fmt<A,B> {
+	Opt<C>(opt:FmtOption<C>):Fmt<A,C>;
+}
+
+class Main {
+	static public function main() {
+	}
+
+	static function eval<A, B>(fmt:Fmt<A, B>, f:String -> A):B {
+		return switch (fmt) {
+			case Opt(FixedPrecision):
+				$type(fmt);
+				var r =f("");
+				$type(f);
+				r;
+		}
+	}
+}

+ 2 - 0
tests/misc/projects/Issue6622/compile1-fail.hxml

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

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

@@ -0,0 +1,3 @@
+Main1.hx:16: characters 11-14 : Warning : Fmt<eval.A, eval.B>
+Main1.hx:18: characters 11-12 : Warning : String -> eval.A
+Main1.hx:15: lines 15-19 : eval.A should be eval.B

+ 6 - 0
tests/misc/projects/Issue8677/Main.hx

@@ -0,0 +1,6 @@
+class Main {
+	static function main() {
+		#if (dce > 0)
+		#end
+	}
+}

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

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

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

@@ -0,0 +1 @@
+Main.hx:3: characters 8-15 : Cannot compare string "std" and float 0.

+ 35 - 0
tests/optimization/src/issues/Issue5646.hx

@@ -0,0 +1,35 @@
+package issues;
+
+class Issue5646 {
+	static var mode = true;
+
+	@:js('
+		if(issues_Issue5646.mode) {
+			issues_Issue5646.use("a");
+		} else {
+			issues_Issue5646.use("b");
+		}
+	')
+	static function test1() {
+        switch (mode) {
+            case true: use("a");
+            case false: use("b");
+        }
+	}
+
+	@:js('
+		if(issues_Issue5646.mode) {
+			issues_Issue5646.use("a");
+		} else {
+			issues_Issue5646.use("b");
+		}
+	')
+	static function test2() {
+        switch (mode) {
+			case false: use("b");
+            case true: use("a");
+        }
+	}
+
+	@:pure(false) static function use(a) { }
+}

+ 24 - 0
tests/optimization/src/issues/Issue6198.hx

@@ -0,0 +1,24 @@
+package issues;
+
+private enum E {
+    A;
+}
+class Issue6198 {
+	@:js('
+		if(issues_Issue6198.getNull()._hx_index == 0) {
+			issues_Issue6198.use("e = E.A");
+		}
+	')
+	static function test1() {
+        var e:Null<E> = getNull();
+        switch(e)
+        {
+            case E.A:
+                use("e = E.A");
+        }
+	}
+
+	static function getNull() { return null; }
+
+	@:pure(false) static function use(a) { }
+}

+ 21 - 0
tests/sys/src/io/TestFileInput.hx

@@ -213,5 +213,26 @@ class TestFileInput extends utest.Test {
 		}
 		file.close();
 	}
+
+	function testIssue7544() {
+		var file = sys.io.File.read(path, true);
+		var buf = haxe.io.Bytes.alloc(contentBytes.length);
+
+		function next() {
+			try {
+				var read = file.readBytes(buf, 0, contentBytes.length);
+				return Std.string(read);
+			} catch(e:haxe.io.Eof) {
+				return Std.string('eof');
+			} catch(e:Dynamic) {
+				return Std.string(e);
+			}
+		}
+
+		Assert.equals('24', next());
+		next(); // TODO: at this line, some target produce '0', some produce 'eof', do we need to unify?
+		Assert.equals('eof', next());
+		file.close();
+	}
 }
 

+ 1 - 1
tests/unit/src/unit/TestMain.hx

@@ -71,7 +71,7 @@ class TestMain {
 			new TestCasts(),
 			new TestSyntaxModule(),
 			new TestNull(),
-			#if (!azure || !(php && Windows))
+			#if (!no_http && (!azure || !(php && Windows)))
 			new TestHttp(),
 			#end
 			#if !no_pattern_matching

+ 32 - 0
tests/unit/src/unit/issues/Issue7672.hx

@@ -0,0 +1,32 @@
+package unit.issues;
+
+private enum EListingField<T:Obj> {
+	ELCounter;
+	ELID;
+}
+
+private typedef TListingConf<T:Obj> = {
+	fields:Array<EListingField<T>>
+}
+
+private class Obj {
+	public var id : Int;
+}
+
+class Issue7672 extends unit.Test {
+	function test() {
+		doesnt({ fields: [ELID] }, [null]);
+	}
+
+	function doesnt<T:Obj>( conf : TListingConf<T>, iterable : Iterable<T> )
+		for (o in iterable)
+			for (field in conf.fields) {
+				switch field {
+					case ELCounter:
+						'<td>&nbsp;</td>';
+					case ELID:
+						HelperMacros.typedAs((null : T), o);
+						'<td>${o.id}</td>';
+				}
+			}
+}

+ 11 - 0
tests/unit/src/unit/issues/Issue8700.hx

@@ -0,0 +1,11 @@
+package unit.issues;
+
+private enum abstract JsonTypeKind<T>(String) {
+	var TMono;
+}
+
+class Issue8700 extends unit.Test {
+	function test() {
+		eq("unit.issues._Issue8700.JsonTypeKind<Unknown<0>>", HelperMacros.typeString(TMono));
+	}
+}