2
0
Эх сурвалжийг харах

Merge branch 'development' into genpy

Conflicts:
	.gitignore
	.travis.yml
	Makefile
	tests/RunTravis.hx
	tests/sys/src/Main.hx
	tests/sys/testsys.hxproj
Simon Krajewski 11 жил өмнө
parent
commit
a1fedbbcfa
61 өөрчлөгдсөн 1012 нэмэгдсэн , 297 устгасан
  1. 2 0
      .gitignore
  2. 9 1
      .travis.yml
  3. 79 59
      Makefile
  4. 15 7
      README.md
  5. 34 42
      codegen.ml
  6. 5 0
      common.ml
  7. 10 1
      extra/CHANGES.txt
  8. 1 1
      extra/haxelib_src
  9. 3 1
      extra/release-checklist.txt
  10. 4 2
      filters.ml
  11. 12 1
      gencommon.ml
  12. 18 9
      gencpp.ml
  13. 3 6
      gencs.ml
  14. 9 6
      genjava.ml
  15. 8 11
      genjs.ml
  16. 1 0
      genneko.ml
  17. 3 0
      genphp.ml
  18. 14 3
      interp.ml
  19. 1 1
      libs
  20. 1 1
      main.ml
  21. 8 3
      matcher.ml
  22. 16 8
      optimizer.ml
  23. 3 3
      std/Map.hx
  24. 16 11
      std/UInt.hx
  25. 4 0
      std/cpp/NativeArray.hx
  26. 3 1
      std/cpp/vm/Debugger.hx
  27. 1 1
      std/cpp/zip/Compress.hx
  28. 1 1
      std/cpp/zip/Flush.hx
  29. 1 1
      std/cpp/zip/Uncompress.hx
  30. 1 1
      std/flash/_std/EReg.hx
  31. 2 2
      std/flash/_std/haxe/Json.hx
  32. 5 2
      std/haxe/Json.hx
  33. 28 10
      std/haxe/ds/Vector.hx
  34. 45 13
      std/haxe/format/JsonPrinter.hx
  35. 11 1
      std/haxe/macro/Context.hx
  36. 16 2
      std/haxe/macro/Printer.hx
  37. 2 2
      std/js/_std/haxe/Json.hx
  38. 1 1
      std/neko/zip/Compress.hx
  39. 1 1
      std/neko/zip/Flush.hx
  40. 1 1
      std/neko/zip/Uncompress.hx
  41. 6 6
      std/php/_std/haxe/Json.hx
  42. 93 42
      tests/RunTravis.hx
  43. 3 0
      tests/sys/compile-each.hxml
  44. 2 0
      tests/sys/compile-neko.hxml
  45. 1 0
      tests/sys/compile.hxml
  46. 0 8
      tests/sys/run.hxml
  47. 3 1
      tests/sys/src/Main.hx
  48. 218 0
      tests/sys/src/io/TestFileInput.hx
  49. 1 1
      tests/sys/testsys.hxproj
  50. 23 0
      tests/unit/issues/Issue2580.hx
  51. 0 0
      tests/unit/issues/Issue2750.hx
  52. 25 0
      tests/unit/issues/Issue2786.hx
  53. 33 0
      tests/unit/issues/Issue2828.hx
  54. 37 0
      tests/unit/issues/Issue2835.hx
  55. 12 0
      tests/unit/issues/Issue2871.hx
  56. 44 0
      tests/unit/issues/Issue2874.hx
  57. 9 0
      tests/unit/issues/Issue2881.hx
  58. 10 0
      tests/unit/issues/Issue2900.hx
  59. 28 0
      tests/unit/issues/Issue2907.hx
  60. 1 0
      typeload.ml
  61. 65 22
      typer.ml

+ 2 - 0
.gitignore

@@ -60,3 +60,5 @@ tests/optimization/testopt.js
 tests/unit/unit.py
 tests/unit/unit.py.res1.txt
 tests/unit/unit.py.res2.bin
+*.cmo
+tests/sys/bin/

+ 9 - 1
.travis.yml

@@ -9,11 +9,19 @@ env:
   matrix:
     - TARGET=python
     - TARGET=polygonal-ds
+    - TARGET=flambe
+    - TARGET=hxtemplo
+    - TARGET=munit
+    - TARGET=openfl-samples
+    - TARGET=flixel-demos
+    - TARGET=neko-sys
+    - TARGET=bytecode
 
 matrix:
   fast_finish: true
   allow_failures:
     - env: TARGET=flash8
+    - env: TARGET=flixel-demos
 
 before_install:
   - travis_retry sudo apt-get update
@@ -22,7 +30,7 @@ before_install:
   - cd ~/neko && make && sudo make install && cd $TRAVIS_BUILD_DIR
 
 script:
-  - make
+  - /bin/sh -c '[ $TARGET = "bytecode" ] && make BYTECODE=1 || make'
   - make tools
   - sudo make install
   - cd tests/

+ 79 - 59
Makefile

@@ -18,31 +18,44 @@ OUTPUT=haxe
 EXTENSION=
 OCAMLOPT=ocamlopt
 OCAMLC=ocamlc
+LFLAGS=
 
 CFLAGS= -g -I libs/extlib -I libs/extc -I libs/neko -I libs/javalib -I libs/ziplib -I libs/swflib -I libs/xml-light -I libs/ttflib -I libs/ilib -I libs/objsize
 
-CC_CMD = $(OCAMLOPT) $(CFLAGS) -c $<
-CC_PARSER_CMD = $(OCAMLOPT) -pp camlp4o $(CFLAGS) -c parser.ml
-
-LIBS=unix.cmxa str.cmxa libs/extlib/extLib.cmxa libs/xml-light/xml-light.cmxa libs/swflib/swflib.cmxa \
-	libs/extc/extc.cmxa libs/neko/neko.cmxa libs/javalib/java.cmxa libs/ziplib/zip.cmxa \
-	libs/ttflib/ttf.cmxa libs/ilib/il.cmxa libs/objsize/objsize.cmxa
+LIBS=unix str libs/extlib/extLib libs/xml-light/xml-light libs/swflib/swflib \
+	libs/extc/extc libs/neko/neko libs/javalib/java libs/ziplib/zip \
+	libs/ttflib/ttf libs/ilib/il libs/objsize/objsize
 
 NATIVE_LIBS=-cclib libs/extc/extc_stubs.o -cclib -lz -cclib libs/objsize/c_objsize.o
 
+ifeq ($(BYTECODE),1)
+	TARGET_FLAG = bytecode
+	CC_CMD = $(OCAMLC)
+	LIB_EXT = cma
+	MODULE_EXT = cmo
+	NATIVE_LIB_FLAG = -custom
+else
+	TARGET_FLAG = native
+	CC_CMD = $(OCAMLOPT)
+	LIB_EXT = cmxa
+	MODULE_EXT = cmx
+endif
+
+CC_PARSER_CMD = $(CC_CMD) -pp camlp4o $(CFLAGS) -c parser.ml
+
 RELDIR=../../..
 
 MODULES=ast type lexer common genxml parser typecore optimizer typeload \
-codegen gencommon genas3 gencpp genjs genneko genphp genswf8 \
+	codegen gencommon genas3 gencpp genjs genneko genphp genswf8 \
 	genswf9 genswf genjava gencs genpy interp dce filters typer matcher version main
 
 ADD_REVISION=0
 
 # using $(CURDIR) on Windows will not work since it might be a Cygwin path
 ifdef SYSTEMROOT
-EXTENSION=.exe
+	EXTENSION=.exe
 else
-export HAXE_STD_PATH=$(CURDIR)/std
+	export HAXE_STD_PATH=$(CURDIR)/std
 endif
 
 ifneq ($(ADD_REVISION),0)
@@ -53,24 +66,20 @@ endif
 
 all: libs haxe
 
-version.cmx:
-	echo $(VERSION_EXTRA) > version.ml
-	$(OCAMLOPT) $(CFLAGS) -c version.ml
-
 libs:
-	make -C libs/extlib opt OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC)
-	make -C libs/extc native OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC)
-	make -C libs/neko OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC)
-	make -C libs/javalib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC)
-	make -C libs/ilib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC)
-	make -C libs/ziplib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC)
-	make -C libs/swflib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC)
-	make -C libs/xml-light xml-light.cmxa OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC)
-	make -C libs/ttflib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC)
-	make -C libs/objsize OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC)
-
-haxe: $(MODULES:=.cmx)
-	$(OCAMLOPT) -o $(OUTPUT) $(NATIVE_LIBS) $(LIBS) $(MODULES:=.cmx)
+	make -C libs/extlib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG)
+	make -C libs/extc OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG)
+	make -C libs/neko OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG)
+	make -C libs/javalib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG)
+	make -C libs/ilib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG)
+	make -C libs/ziplib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG)
+	make -C libs/swflib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG)
+	make -C libs/xml-light OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG)
+	make -C libs/ttflib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG)
+	make -C libs/objsize OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG)
+
+haxe: $(MODULES:=.$(MODULE_EXT))
+	$(CC_CMD) -o $(OUTPUT) $(NATIVE_LIBS) $(NATIVE_LIB_FLAG) $(LFLAGS) $(LIBS:=.$(LIB_EXT)) $(MODULES:=.$(MODULE_EXT))
 
 haxelib:
 	(cd $(CURDIR)/extra/haxelib_src && $(CURDIR)/$(OUTPUT) haxelib.hxml && nekotools boot bin/haxelib.n)
@@ -103,63 +112,72 @@ install_tools: tools
 uninstall:
 	rm -rf $(INSTALL_BIN_DIR)/haxe $(INSTALL_BIN_DIR)/haxelib $(INSTALL_LIB_DIR)
 
-codegen.cmx: optimizer.cmx typeload.cmx typecore.cmx type.cmx genxml.cmx common.cmx ast.cmx
+# Modules
+
+codegen.$(MODULE_EXT): optimizer.$(MODULE_EXT) typeload.$(MODULE_EXT) typecore.$(MODULE_EXT) type.$(MODULE_EXT) genxml.$(MODULE_EXT) common.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-common.cmx: type.cmx ast.cmx
+common.$(MODULE_EXT): type.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-dce.cmx: ast.cmx common.cmx codegen.cmx type.cmx
+dce.$(MODULE_EXT): ast.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) type.$(MODULE_EXT)
 
-filters.cmx: ast.cmx common.cmx type.cmx dce.cmx codegen.cmx typecore.cmx
+filters.$(MODULE_EXT): ast.$(MODULE_EXT) common.$(MODULE_EXT) type.$(MODULE_EXT) dce.$(MODULE_EXT) codegen.$(MODULE_EXT) typecore.$(MODULE_EXT)
 
-genas3.cmx: type.cmx common.cmx codegen.cmx ast.cmx
+genas3.$(MODULE_EXT): type.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-gencommon.cmx: type.cmx common.cmx codegen.cmx ast.cmx
+gencommon.$(MODULE_EXT): type.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-gencpp.cmx: type.cmx lexer.cmx common.cmx codegen.cmx ast.cmx
+gencpp.$(MODULE_EXT): type.$(MODULE_EXT) lexer.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-gencs.cmx: type.cmx lexer.cmx gencommon.cmx common.cmx codegen.cmx ast.cmx
+gencs.$(MODULE_EXT): type.$(MODULE_EXT) lexer.$(MODULE_EXT) gencommon.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-genjava.cmx: type.cmx gencommon.cmx common.cmx codegen.cmx ast.cmx
+genjava.$(MODULE_EXT): type.$(MODULE_EXT) gencommon.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-genjs.cmx: type.cmx optimizer.cmx lexer.cmx common.cmx codegen.cmx ast.cmx
+genjs.$(MODULE_EXT): type.$(MODULE_EXT) optimizer.$(MODULE_EXT) lexer.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-genneko.cmx: type.cmx lexer.cmx common.cmx codegen.cmx ast.cmx
+genneko.$(MODULE_EXT): type.$(MODULE_EXT) lexer.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-genphp.cmx: type.cmx lexer.cmx common.cmx codegen.cmx ast.cmx
+genphp.$(MODULE_EXT): type.$(MODULE_EXT) lexer.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-genpy.cmx: type.cmx lexer.cmx common.cmx codegen.cmx ast.cmx
+genpy.$(MODULE_EXT): type.$(MODULE_EXT) lexer.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-genswf.cmx: type.cmx genswf9.cmx genswf8.cmx common.cmx ast.cmx
+genswf.$(MODULE_EXT): type.$(MODULE_EXT) genswf9.$(MODULE_EXT) genswf8.$(MODULE_EXT) common.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-genswf8.cmx: type.cmx lexer.cmx common.cmx codegen.cmx ast.cmx
+genswf8.$(MODULE_EXT): type.$(MODULE_EXT) lexer.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-genswf9.cmx: type.cmx lexer.cmx genswf8.cmx common.cmx codegen.cmx ast.cmx
+genswf9.$(MODULE_EXT): type.$(MODULE_EXT) lexer.$(MODULE_EXT) genswf8.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-genxml.cmx: type.cmx lexer.cmx common.cmx ast.cmx
+genxml.$(MODULE_EXT): type.$(MODULE_EXT) lexer.$(MODULE_EXT) common.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-interp.cmx: typecore.cmx type.cmx lexer.cmx genneko.cmx common.cmx codegen.cmx ast.cmx genswf.cmx genjava.cmx parser.cmx
+interp.$(MODULE_EXT): typecore.$(MODULE_EXT) type.$(MODULE_EXT) lexer.$(MODULE_EXT) genneko.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT) genswf.$(MODULE_EXT) genjava.$(MODULE_EXT) parser.$(MODULE_EXT)
 
-matcher.cmx: optimizer.cmx codegen.cmx typecore.cmx type.cmx typer.cmx common.cmx ast.cmx
+matcher.$(MODULE_EXT): optimizer.$(MODULE_EXT) codegen.$(MODULE_EXT) typecore.$(MODULE_EXT) type.$(MODULE_EXT) typer.$(MODULE_EXT) common.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-main.cmx: filters.cmx matcher.cmx typer.cmx typeload.cmx typecore.cmx type.cmx parser.cmx optimizer.cmx lexer.cmx interp.cmx genxml.cmx genswf.cmx genphp.cmx genneko.cmx genjs.cmx gencpp.cmx genas3.cmx common.cmx codegen.cmx ast.cmx gencommon.cmx genjava.cmx gencs.cmx genpy.cmx version.cmx
+main.$(MODULE_EXT): filters.$(MODULE_EXT) matcher.$(MODULE_EXT) typer.$(MODULE_EXT) typeload.$(MODULE_EXT) typecore.$(MODULE_EXT) type.$(MODULE_EXT) parser.$(MODULE_EXT) optimizer.$(MODULE_EXT) lexer.$(MODULE_EXT) interp.$(MODULE_EXT) genxml.$(MODULE_EXT) genswf.$(MODULE_EXT) genphp.$(MODULE_EXT) genneko.$(MODULE_EXT) genjs.$(MODULE_EXT) gencpp.$(MODULE_EXT) genas3.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT) gencommon.$(MODULE_EXT) genjava.$(MODULE_EXT) gencs.$(MODULE_EXT) genpy.$(MODULE_EXT) version.$(MODULE_EXT)
 
-optimizer.cmx: typecore.cmx type.cmx parser.cmx common.cmx ast.cmx
+optimizer.$(MODULE_EXT): typecore.$(MODULE_EXT) type.$(MODULE_EXT) parser.$(MODULE_EXT) common.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-parser.cmx: parser.ml lexer.cmx common.cmx ast.cmx
+parser.$(MODULE_EXT): parser.ml lexer.$(MODULE_EXT) common.$(MODULE_EXT) ast.$(MODULE_EXT)
 	$(CC_PARSER_CMD)
 
-type.cmx: ast.cmx
+type.$(MODULE_EXT): ast.$(MODULE_EXT)
+
+typecore.$(MODULE_EXT): type.$(MODULE_EXT) common.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-typecore.cmx: type.cmx common.cmx ast.cmx
+typeload.$(MODULE_EXT): typecore.$(MODULE_EXT) type.$(MODULE_EXT) parser.$(MODULE_EXT) optimizer.$(MODULE_EXT) lexer.$(MODULE_EXT) common.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-typeload.cmx: typecore.cmx type.cmx parser.cmx optimizer.cmx lexer.cmx common.cmx ast.cmx
+typer.$(MODULE_EXT): typeload.$(MODULE_EXT) typecore.$(MODULE_EXT) type.$(MODULE_EXT) parser.$(MODULE_EXT) optimizer.$(MODULE_EXT) lexer.$(MODULE_EXT) interp.$(MODULE_EXT) genneko.$(MODULE_EXT) genjs.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT) filters.$(MODULE_EXT)
 
-typer.cmx: typeload.cmx typecore.cmx type.cmx parser.cmx optimizer.cmx lexer.cmx interp.cmx genneko.cmx genjs.cmx common.cmx codegen.cmx ast.cmx filters.cmx
+lexer.$(MODULE_EXT): lexer.ml
 
-lexer.cmx: lexer.ml
+lexer.$(MODULE_EXT): ast.$(MODULE_EXT)
 
-lexer.cmx: ast.cmx
+ast.$(MODULE_EXT):
 
+version.$(MODULE_EXT):
+	echo $(VERSION_EXTRA) > version.ml
+	$(CC_CMD) $(CFLAGS) -c version.ml
+
+# Clean
 
 clean: clean_libs clean_haxe clean_tools
 
@@ -173,21 +191,23 @@ clean_libs:
 	make -C libs/swflib clean
 	make -C libs/xml-light clean
 	make -C libs/ttflib clean
+	make -C libs/objsize clean
 
 clean_haxe:
-	rm -f $(MODULES:=.obj) $(MODULES:=.o) $(MODULES:=.cmx) $(MODULES:=.cmi) lexer.ml $(OUTPUT)
+	rm -f $(MODULES:=.obj) $(MODULES:=.o) $(MODULES:=.cmx) $(MODULES:=.cmi) $(MODULES:=.cmo) lexer.ml $(OUTPUT)
 
 clean_tools:
 	rm -f $(OUTPUT) haxelib
 
 # SUFFIXES
+
 .ml.cmx:
-	$(CC_CMD)
+	$(CC_CMD) $(CFLAGS) -c $<
 
-.mli.cmi:
-	$(CC_CMD)
+.ml.cmo:
+	$(CC_CMD) $(CFLAGS) -c $<
 
 .mll.ml:
 	ocamllex $<
 
-.PHONY: haxe libs version.cmx haxelib
+.PHONY: haxe libs version.cmx version.cmo haxelib

+ 15 - 7
README.md

@@ -35,14 +35,14 @@ For the complete Haxe licenses, please see http://haxe.org/doc/license or [extra
 
 ## Installing Haxe
 
-The latest stable release is [Haxe v3.1.2](http://haxe.org/download). Pre-built binaries are available for your platform:
+The latest stable release is [Haxe v3.1.3](http://haxe.org/download). Pre-built binaries are available for your platform:
 
- * **[Windows installer](http://haxe.org/file/haxe-3.1.2-win.exe)**
- * **[Windows binaries](http://haxe.org/file/haxe-3.1.2-win.zip)**
- * **[OSX installer](http://haxe.org/file/haxe-3.1.2-osx-installer.pkg)**
- * **[OSX binaries](http://haxe.org/file/haxe-3.1.2-osx.tar.gz)**
- * **[Linux 32-bit binaries](http://haxe.org/file/haxe-3.1.2-linux32.tar.gz)**
- * **[Linux 64-bit binaries](http://haxe.org/file/haxe-3.1.2-linux64.tar.gz)**
+ * **[Windows installer](http://haxe.org/file/haxe-3.1.3-win.exe)**
+ * **[Windows binaries](http://haxe.org/file/haxe-3.1.3-win.zip)**
+ * **[OSX installer](http://haxe.org/file/haxe-3.1.3-osx-installer.pkg)**
+ * **[OSX binaries](http://haxe.org/file/haxe-3.1.3-osx.tar.gz)**
+ * **[Linux 32-bit binaries](http://haxe.org/file/haxe-3.1.3-linux32.tar.gz)**
+ * **[Linux 64-bit binaries](http://haxe.org/file/haxe-3.1.3-linux64.tar.gz)**
 
 Automated development builds are available from [build.haxe.org](http://build.haxe.org).
 
@@ -70,3 +70,11 @@ You can get help and talk with fellow Haxers from around the world via:
 
  * the [official Haxe Google Group](https://groups.google.com/forum/#!forum/haxelang)
  * the [Haxe IRC chatroom](http://unic0rn.github.io/tiramisu/haxe/), #haxe on chat.freenode.net
+
+## Version compatibility
+
+Haxe   | neko
+----   | -----
+2.*    | 1.*
+3.0.0  | 2.0.0
+3.1.3  | 2.0.0

+ 34 - 42
codegen.ml

@@ -681,9 +681,6 @@ module Abstract = struct
 		make_static_call ctx c cf (apply_params a.a_types pl) args t p
 
 	let rec do_check_cast ctx tleft eright p =
-		let tright = follow eright.etype in
-		let tleft = follow tleft in
-		if tleft == tright then eright else
 		let recurse cf f =
 			if cf == ctx.curfield || List.mem cf !cast_stack then error "Recursive implicit cast" p;
 			cast_stack := cf :: !cast_stack;
@@ -691,43 +688,38 @@ module Abstract = struct
 			cast_stack := List.tl !cast_stack;
 			r
 		in
-		try (match tright,tleft with
-			| (TAbstract({a_impl = Some c1} as a1,pl1) as t1),(TAbstract({a_impl = Some c2} as a2,pl2) as t2) ->
-				if a1 == a2 then
-					eright
-				else begin
-					let c,cfo,a,pl = try
-						if Meta.has Meta.MultiType a1.a_meta then raise Not_found;
-						c1,snd (find_to a1 pl1 t2),a1,pl1
-					with Not_found ->
-						if Meta.has Meta.MultiType a2.a_meta then raise Not_found;
-						c2,snd (find_from a2 pl2 t1 t2),a2,pl2
-					in
-					match cfo with
-					| None -> eright
-					| Some cf ->
-						recurse cf (fun () -> make_static_call ctx c cf a pl [eright] tleft p)
-				end
-			| _, TMono _ | TMono _, _ ->
-				eright
-			| TAbstract({a_impl = Some c} as a,pl),t2 when not (Meta.has Meta.MultiType a.a_meta) ->
-				begin match find_to a pl t2 with
-					| tcf,None ->
-						let tcf = apply_params a.a_types pl tcf in
-						if type_iseq tcf tleft then eright else do_check_cast ctx tcf eright p
-					| _,Some cf ->
-						recurse cf (fun () -> make_static_call ctx c cf a pl [eright] tleft p)
-				end
-			| t1,(TAbstract({a_impl = Some c} as a,pl) as t2) when not (Meta.has Meta.MultiType a.a_meta) ->
-				begin match find_from a pl t1 t2 with
-					| tcf,None ->
-						let tcf = apply_params a.a_types pl tcf in
-						if type_iseq tcf tleft then eright else do_check_cast ctx tcf eright p
-					| _,Some cf ->
-						recurse cf (fun () -> make_static_call ctx c cf a pl [eright] tleft p)
-				end
-			| _ ->
-				eright)
+		let find a tl f =
+			let tcf,cfo = f() in
+			match cfo,a.a_impl with
+				| None,_ ->
+					let tcf = apply_params a.a_types tl tcf in
+					if type_iseq tcf tleft then
+						eright
+					else
+						(* TODO: causes Java overload issues *)
+						(* let eright = mk (TCast(eright,None)) tleft p in *)
+						do_check_cast ctx tcf eright p
+				| Some cf,Some c ->
+					recurse cf (fun () -> make_static_call ctx c cf a tl [eright] tleft p)
+				| _ ->
+					assert false
+		in
+		if type_iseq tleft eright.etype then
+			eright
+		else try
+			begin match follow eright.etype with
+				| TAbstract(a,tl) ->
+					find a tl (fun () -> find_to a tl tleft)
+				| _ ->
+					raise Not_found
+			end
+		with Not_found -> try
+			begin match follow tleft with
+				| TAbstract(a,tl) ->
+					find a tl (fun () -> find_from a tl eright.etype tleft)
+				| _ ->
+					raise Not_found
+			end
 		with Not_found ->
 			eright
 
@@ -770,10 +762,10 @@ module Abstract = struct
 				{e with etype = m}
 			| TCall({eexpr = TField(_,FStatic({cl_path=[],"Std"},{cf_name = "string"}))},[e1]) when (match follow e1.etype with TAbstract({a_impl = Some _},_) -> true | _ -> false) ->
 				begin match follow e1.etype with
-					| TAbstract({a_impl = Some c} as a,_) ->
+					| TAbstract({a_impl = Some c} as a,tl) ->
 						begin try
 							let cf = PMap.find "toString" c.cl_statics in
-							make_static_call ctx c cf a [] [e1] ctx.t.tstring e.epos
+							make_static_call ctx c cf a tl [e1] ctx.t.tstring e.epos
 						with Not_found ->
 							e
 						end

+ 5 - 0
common.ml

@@ -937,6 +937,11 @@ let rec mkdir_recursive base dir_list =
 				Unix.mkdir path 0o755;
 		mkdir_recursive (if (path = "") then "/" else path) remaining
 
+let mkdir_from_path path =
+	let parts = Str.split_delim (Str.regexp "[\\/]+") path in
+	let dir_list = List.rev (List.tl (List.rev parts)) in
+	mkdir_recursive "" dir_list
+
 let mem_size v =
 	Objsize.size_with_headers (Objsize.objsize v [] [])
 

+ 10 - 1
extra/CHANGES.txt

@@ -1,18 +1,27 @@
-2014-??-??: 3.1.3
+2014-??-??: 3.2.0
+
+	all : fixed nullability of abstracts over functions
+
+2014-04-13: 3.1.3
 
 	Bugfixes:
 
+	all : fixed handling of abstract variance
 	flash : ensure correct endianess in haxe.io.BytesBuffer
+	cpp : fixed issue involving class paths with spaces
+	php : fixed >>>
 	macro : fixed haxe.macro.Compiler.keep
 
 	General improvements and optimizations:
 
 	all : give @:deprecated warnings by default, allow -D no-deprecation-warnings
+	cpp : optimized Vector implementation
 
 	Standard Library:
 
 	all : renamed Bytes.readDouble/Float to getDouble/Float to avoid inheritance issues
 	all : deprecated Bytes.readString in favor of getString
+	all : added pretty-printing to haxe.format.JsonPrinter (and haxe.Json)
 
 2014-03-29: 3.1.2
 

+ 1 - 1
extra/haxelib_src

@@ -1 +1 @@
-Subproject commit 2d2252dc3ad44a62834a029b8bdcef84d72db8f4
+Subproject commit 8c5fb02d784ad257ac4684ffc443c719a96f3020

+ 3 - 1
extra/release-checklist.txt

@@ -9,8 +9,10 @@
 - Run it with the fileName corresponding to the latest master file name on builds.haxe.org.
 - Upload generated files to some place.
 - Update Haxe download page.
+- Update Github README page.
 - Double-check that you got the links right.
 - Regenerate and upload API documentation.
 - Update http://haxe.org/file/CHANGES.txt
 - Write announcement post.
-- Post announcement post.
+- Post announcement post.
+

+ 4 - 2
filters.ml

@@ -1118,12 +1118,14 @@ let run com tctx main =
 	if not (Common.defined com Define.As3 || dce_mode = "no" || Common.defined com Define.DocGen) then Dce.run com main (dce_mode = "full" && not (Common.defined com Define.Interp));
 	(* always filter empty abstract implementation classes (issue #1885) *)
 	List.iter (fun mt -> match mt with
-		| TClassDecl({cl_kind = KAbstractImpl _} as c) ->
+		| TClassDecl({cl_kind = KAbstractImpl _} as c) when c.cl_ordered_statics = [] && c.cl_ordered_fields = [] && not (Meta.has Meta.Used c.cl_meta) ->
+			c.cl_extern <- true
+		| TClassDecl({cl_kind = KAbstractImpl a} as c) when Meta.has Meta.Enum a.a_meta ->
 			let is_runtime_field cf =
 				not (Meta.has Meta.Enum cf.cf_meta)
 			in
 			(* also filter abstract implementation classes that have only @:enum fields (issue #2858) *)
-			if not (Meta.has Meta.Used c.cl_meta) || not (List.exists is_runtime_field c.cl_ordered_statics) then
+			if not (Meta.has Meta.Used c.cl_meta || Common.defined com Define.As3) || not (List.exists is_runtime_field c.cl_ordered_statics) then
 				c.cl_extern <- true
 		| _ -> ()
 	) com.types;

+ 12 - 1
gencommon.ml

@@ -5714,6 +5714,9 @@ struct
         mk_cast to_t e)
       | TAbstract (a_to, _), TAbstract(a_from, _) when a_to == a_from ->
         e
+      | TAbstract _, TInst({ cl_kind = KTypeParameter _ }, _)
+      | TInst({ cl_kind = KTypeParameter _ }, _), TAbstract _ ->
+        do_unsafe_cast()
       | TAbstract _, _
       | _, TAbstract _ ->
         (try
@@ -7358,6 +7361,14 @@ struct
         let do_field cf cf_type is_static =
           let get_field ethis = { eexpr = TField (ethis, if is_static then FStatic (cl, cf) else FInstance(cl, cf)); etype = cf_type; epos = pos } in
           let this = if is_static then mk_classtype_access cl pos else { eexpr = TConst(TThis); etype = t; epos = pos } in
+          let value_local = if is_float then match follow cf_type with
+            | TInst({ cl_kind = KTypeParameter _ }, _) ->
+              mk_cast t_dynamic value_local
+            | _ ->
+              value_local
+            else
+              value_local
+          in
 
           let ret =
           {
@@ -7450,7 +7461,7 @@ struct
         let do_field cf cf_type static =
           let this = if static then mk_classtype_access cl pos else { eexpr = TConst(TThis); etype = t; epos = pos } in
           match is_float, follow cf_type with
-            | true, TInst( { cl_kind = KTypeParameter _ }, [] ) ->
+            | true, TInst( { cl_kind = KTypeParameter _ }, _ ) ->
               mk_return (mk_cast basic.tfloat (mk_cast t_dynamic (get_field cf cf_type this cl cf.cf_name)))
             | _ ->
               mk_return (maybe_cast (get_field cf cf_type this cl cf.cf_name ))

+ 18 - 9
gencpp.ml

@@ -1379,7 +1379,6 @@ and define_local_return_block_ctx ctx expression name retval =
    let output_i = writer#write_i in
    let output = ctx.ctx_output in
    let check_this = function | "this" when not ctx.ctx_real_this_ptr -> "__this" | x -> x in
-   let reference = function | "this" -> " *__this" | "_this" -> " _this" | name -> " &" ^name in
    let rec define_local_return_block expression  =
       let declarations = Hashtbl.create 0 in
       let undeclared = Hashtbl.create 0 in
@@ -1399,8 +1398,17 @@ and define_local_return_block_ctx ctx expression name retval =
          | TObjectDecl _ -> "Dynamic"
          | _ -> type_string expression.etype in
       output_i ("inline static " ^ ret_type ^ " Block( ");
-      output (String.concat "," ( (List.map (fun var ->
-            (Hashtbl.find undeclared var) ^ (reference var)) ) vars));
+      output (String.concat "," (
+         (List.map
+            (fun var ->
+               let var_type = Hashtbl.find undeclared var in
+               (* Args passed into inline-block should be references, so they can be changed.
+                  Fake 'this' pointers can't be changed, so needn't be references *)
+               match var with
+               | "this" -> "hx::ObjectPtr< " ^ var_type ^ " > __this"
+               | "_this" -> var_type ^ " _this"
+               | name -> var_type ^ " &" ^name
+            ) vars) ) );
       output (")");
       let return_data = ret_type <> "Void" in
       writer#begin_block;
@@ -3023,7 +3031,8 @@ let generate_class_files common_ctx member_types super_deps constructor_deps cla
                   if has_meta_key definition.cf_meta Meta.NoDebug then ctx.ctx_debug_level <- 0;
                   if ctx.ctx_debug_level >0 then begin
                      hx_stack_push ctx output_cpp dot_name "new" function_def.tf_expr.epos;
-                     List.iter (fun (a,(t,o)) -> output_cpp ("\nHX_STACK_ARG(" ^ (keyword_remap o) ^ ",\"" ^ a ^"\")\n") ) constructor_arg_var_list;
+                     output_cpp "HX_STACK_THIS(this)\n";
+                     List.iter (fun (a,(t,o)) -> output_cpp ("HX_STACK_ARG(" ^ (keyword_remap o) ^ ",\"" ^ a ^"\")\n") ) constructor_arg_var_list;
                   end;
 
                   if (has_default_values function_def.tf_args) then begin
@@ -3829,7 +3838,7 @@ and s_fun t void =
 
 and s_type_params = function
    | [] -> ""
-   | l -> "<" ^ String.concat ", " (List.map s_type  l) ^ ">"
+   | l -> "< " ^ String.concat ", " (List.map s_type  l) ^ " >"
 
 ;;
 
@@ -3866,7 +3875,7 @@ let gen_extern_class common_ctx class_def file_info =
    in
 
 
-   let params = function [] -> "" | l ->  "<" ^ (String.concat "," (List.map (fun (n,t) -> n) l) ^ ">")  in
+   let params = function [] -> "" | l ->  "< " ^ (String.concat "," (List.map (fun (n,t) -> n) l) ^ " >")  in
    let output = file#write in
 
    let print_field stat f =
@@ -3909,8 +3918,8 @@ let gen_extern_class common_ctx class_def file_info =
             ^ " " ^ (snd path) ^ (params c.cl_types) );
    (match c.cl_super with None -> () | Some (c,pl) -> output (" extends " ^  (s_type (TInst (c,pl)))));
    List.iter (fun (c,pl) -> output ( " implements " ^ (s_type (TInst (c,pl))))) (real_interfaces c.cl_implements);
-   (match c.cl_dynamic with None -> () | Some t -> output (" implements Dynamic<" ^ (s_type t) ^ ">"));
-   (match c.cl_array_access with None -> () | Some t -> output (" implements ArrayAccess<" ^ (s_type t) ^ ">"));
+   (match c.cl_dynamic with None -> () | Some t -> output (" implements Dynamic< " ^ (s_type t) ^ " >"));
+   (match c.cl_array_access with None -> () | Some t -> output (" implements ArrayAccess< " ^ (s_type t) ^ " >"));
    output "{\n";
    (match c.cl_constructor with
    | None -> ()
@@ -3931,7 +3940,7 @@ let gen_extern_enum common_ctx enum_def file_info =
    let file = new_source_file common_ctx common_ctx.file  "extern" ".hx" path in
    let output = file#write in
 
-   let params = function [] -> "" | l ->  "<" ^ (String.concat "," (List.map (fun (n,t) -> n) l) ^ ">")  in
+   let params = function [] -> "" | l ->  "< " ^ (String.concat "," (List.map (fun (n,t) -> n) l) ^ " >")  in
    output ( "package " ^ (String.concat "." (fst path)) ^ ";\n" );
    output ( "@:include extern " ^ (if enum_def.e_private then "private " else "")
             ^ " enum " ^ (snd path) ^ (params enum_def.e_types) );

+ 3 - 6
gencs.ml

@@ -1055,7 +1055,7 @@ let configure gen =
 						write w " += ";
 						expr_s w ev
 					end else
-						do_call w e []
+						do_call w e [ev]
 				| TCall( ({ eexpr = TField(ef,f) } as e), [ev] ) when String.starts_with (field_name f) "remove_" ->
 					let name = field_name f in
 					let propname = String.sub name 7 (String.length name - 7) in
@@ -1066,7 +1066,7 @@ let configure gen =
 						write w " -= ";
 						expr_s w ev
 					end else
-						do_call w e []
+						do_call w e [ev]
 				| TCall( ({ eexpr = TField(ef,f) } as e), [] ) when String.starts_with (field_name f) "get_" ->
 					let name = field_name f in
 					let propname = String.sub name 4 (String.length name - 4) in
@@ -2657,10 +2657,7 @@ let configure gen =
     mkdir (gen.gcon.file ^ "/src/Resources");
     Hashtbl.iter (fun name v ->
       let full_path = gen.gcon.file ^ "/src/Resources/" ^ name in
-      let parts = Str.split_delim (Str.regexp "[\\/]+") full_path in
-      let dir_list = List.rev (List.tl (List.rev parts)) in
-
-      Common.mkdir_recursive "" dir_list;
+      mkdir_from_path full_path;
 
       let f = open_out full_path in
       output_string f v;

+ 9 - 6
genjava.ml

@@ -1624,7 +1624,13 @@ let configure gen =
     print w "%s %s %s %s" access (String.concat " " modifiers) clt (change_clname (snd cl.cl_path));
     (* type parameters *)
     let params, _ = get_string_params cl.cl_types in
-    let cl_p_to_string (c,p) = path_param_s cl.cl_pos (TClassDecl c) c.cl_path p in
+    let cl_p_to_string (c,p) =
+      let p = List.map (fun t -> match follow t with
+        | TMono _ | TDynamic _ -> t_empty
+        | _ -> t) p
+      in
+      path_param_s cl.cl_pos (TClassDecl c) c.cl_path p
+    in
     print w "%s" params;
     (if is_some cl.cl_super then print w " extends %s" (cl_p_to_string (get cl.cl_super)));
     (match cl.cl_implements with
@@ -2135,10 +2141,7 @@ let configure gen =
       res := { eexpr = TConst(TString name); etype = gen.gcon.basic.tstring; epos = Ast.null_pos } :: !res;
 
       let full_path = gen.gcon.file ^ "/src/" ^ name in
-      let parts = Str.split_delim (Str.regexp "[\\/]+") full_path in
-      let dir_list = List.rev (List.tl (List.rev parts)) in
-
-      Common.mkdir_recursive "" dir_list;
+      mkdir_from_path full_path;
 
       let f = open_out full_path in
       output_string f v;
@@ -2455,7 +2458,7 @@ let convert_java_enum ctx p pe =
     ) field.jf_flags;
 
     List.iter (function
-      | AttrDeprecated -> cff_meta := (Meta.Deprecated, [], p) :: !cff_meta
+      | AttrDeprecated when jc.cpath <> (["java";"util"],"Date") -> cff_meta := (Meta.Deprecated, [], p) :: !cff_meta
       (* TODO: pass anotations as @:meta *)
       | AttrVisibleAnnotations ann ->
         List.iter (function

+ 8 - 11
genjs.ml

@@ -1223,7 +1223,7 @@ let generate com =
 
 		(* Wrap output in a closure *)
 		if (anyExposed && (Common.defined com Define.ShallowExpose)) then (
-			print ctx "var $hx_exports = {}";
+			print ctx "var $hx_exports = $hx_exports || {}";
 			ctx.separator <- true;
 			newline ctx
 		);
@@ -1231,18 +1231,15 @@ let generate com =
 		if (anyExposed && not (Common.defined com Define.ShallowExpose)) then print ctx "$hx_exports";
 		print ctx ") { \"use strict\"";
 		newline ctx;
-		let rec print_obj { os_fields = fields } = (
-			print ctx "{";
-			concat ctx "," (fun ({ os_name = name } as f) -> print ctx "%s" (name ^ ":"); print_obj f) fields;
-			print ctx "}";
+		let rec print_obj f root = (
+			let path = root ^ "." ^ f.os_name in
+			print ctx "%s = %s || {}" path path;
+			ctx.separator <- true;
+			newline ctx;
+			concat ctx ";" (fun g -> print_obj g path) f.os_fields
 		)
 		in
-		List.iter (fun f ->
-			print ctx "$hx_exports.%s = " f.os_name;
-			print_obj f;
-			ctx.separator <- true;
-			newline ctx
-		) exposedObject.os_fields;
+		List.iter (fun f -> print_obj f "$hx_exports") exposedObject.os_fields;
 	end;
 
 	(* TODO: fix $estr *)

+ 1 - 0
genneko.ml

@@ -848,6 +848,7 @@ let generate com =
 	let use_nekoc = Common.defined com Define.UseNekoc in
 	if not use_nekoc then begin
 		try
+			mkdir_from_path com.file;
 			let ch = IO.output_channel (open_out_bin com.file) in
 			Nbytecode.write ch (Ncompile.compile ctx.version e);
 			IO.close_out ch;

+ 3 - 0
genphp.ml

@@ -1517,6 +1517,9 @@ and gen_expr ctx e =
 		print ctx "while($%s->hasNext()) {" tmp;
 		let bend = open_block ctx in
 		newline ctx;
+		(* unset loop variable (issue #2900) *)
+		print ctx "unset($%s)" v;
+		newline ctx;
 		print ctx "$%s = $%s->next()" v tmp;
 		gen_while_expr ctx e;
 		bend();

+ 14 - 3
interp.ml

@@ -202,6 +202,7 @@ let dec_array_ref = ref (fun v -> assert false)
 let enc_string_ref = ref (fun s -> assert false)
 let make_ast_ref = ref (fun _ -> assert false)
 let make_complex_type_ref = ref (fun _ -> assert false)
+let encode_tvar_ref = ref (fun _ -> assert false)
 let get_ctx() = (!get_ctx_ref)()
 let enc_array (l:value list) : value = (!enc_array_ref) l
 let dec_array (l:value) : value list = (!dec_array_ref) l
@@ -217,6 +218,7 @@ let enc_hash (h:('a,'b) Hashtbl.t) : value = (!enc_hash_ref) h
 let make_ast (e:texpr) : Ast.expr = (!make_ast_ref) e
 let enc_string (s:string) : value = (!enc_string_ref) s
 let make_complex_type (t:Type.t) : Ast.complex_type = (!make_complex_type_ref) t
+let encode_tvar (v:tvar) : value = (!encode_tvar_ref) v
 
 let to_int f = Int32.of_float (mod_float f 2147483648.0)
 let need_32_bits i = Int32.compare (Int32.logand (Int32.add i 0x40000000l) 0x80000000l) Int32.zero <> 0
@@ -2426,10 +2428,18 @@ let macro_lib =
 		"local_using", Fun0 (fun() ->
 			enc_array (List.map encode_clref ((get_ctx()).curapi.get_local_using()))
 		);
-		"local_vars", Fun0 (fun() ->
+		"local_vars", Fun1 (fun as_var ->
+			let as_var = match as_var with
+				| VNull | VBool false -> false
+				| VBool true -> true
+				| _ -> error()
+			in
 			let vars = (get_ctx()).curapi.get_local_vars() in
 			let h = Hashtbl.create 0 in
-			PMap.iter (fun n v -> Hashtbl.replace h (VString n) (encode_type v.v_type)) vars;
+			if as_var then
+				PMap.iter (fun n v -> Hashtbl.replace h (VString n) (encode_tvar v)) vars
+			else
+				PMap.iter (fun n v -> Hashtbl.replace h (VString n) (encode_type v.v_type)) vars;
 			enc_hash h
 		);
 		"follow", Fun2 (fun v once ->
@@ -4954,4 +4964,5 @@ encode_clref_ref := encode_clref;
 enc_string_ref := enc_string;
 enc_hash_ref := enc_hash;
 encode_texpr_ref := encode_texpr;
-decode_texpr_ref := decode_texpr
+decode_texpr_ref := decode_texpr;
+encode_tvar_ref := encode_tvar;

+ 1 - 1
libs

@@ -1 +1 @@
-Subproject commit 3a4b14d06216b5fe3aef666acc5cc436ce76dd86
+Subproject commit 7c8941a5567ff0b705ffa2748795072bc9844d84

+ 1 - 1
main.ml

@@ -45,7 +45,7 @@ exception Abort
 exception Completion of string
 
 
-let version = 3103
+let version = 3200
 let version_major = version / 1000
 let version_minor = (version mod 1000) / 100
 let version_revision = (version mod 100)

+ 8 - 3
matcher.ml

@@ -798,7 +798,7 @@ let rec is_explicit_null = function
 
 let rec all_ctors mctx t =
 	let h = ref PMap.empty in
-	(* if is_explicit_null t then h := PMap.add (CConst TNull) Ast.null_pos !h; *)
+	if is_explicit_null t then h := PMap.add (CConst TNull) Ast.null_pos !h;
 	match follow t with
 	| TAbstract({a_path = [],"Bool"},_) ->
 		h := PMap.add (CConst(TBool true)) Ast.null_pos !h;
@@ -1032,7 +1032,11 @@ let convert_switch mctx st cases loop =
 		| _ -> DTSwitch(e, List.map (fun (c,dt) -> convert_con ctx c, loop dt) cases, !def)
 	in
 	match !null with
-	| None -> dt
+	| None when is_explicit_null st.st_type ->
+		let econd = mk (TBinop(OpNotEq,e_st,mk (TConst TNull) (mk_mono()) p)) ctx.t.tbool p in
+		DTGuard(econd,dt,!def)
+	| None ->
+		dt
 	| Some dt_null ->
 		let econd = mk (TBinop(OpEq,e_st,mk (TConst TNull) (mk_mono()) p)) ctx.t.tbool p in
 		DTGuard(econd,dt_null,Some dt)
@@ -1097,7 +1101,8 @@ let transform_extractors eval cases p =
 		| [] ->
 			[]
 	in
-	loop cases,!has_extractor
+	let cases = loop cases in
+	cases,!has_extractor
 
 let extractor_depth = ref 0
 

+ 16 - 8
optimizer.ml

@@ -774,11 +774,16 @@ let sanitize_expr com e =
 	in
 	match e.eexpr with
 	| TConst TNull ->
-		if com.config.pf_static && not (is_nullable e.etype) then
-			(match follow e.etype with
-			| TMono _ -> () (* in these cases the null will cast to default value *)
-			| TFun _ -> () (* this is a bit a particular case, maybe flash-specific actually *)
-			| _ -> com.error ("On static platforms, null can't be used as basic type " ^ s_type (print_context()) e.etype) e.epos);
+		if com.config.pf_static && not (is_nullable e.etype) then begin
+			let rec loop t = match follow t with
+				| TMono _ -> () (* in these cases the null will cast to default value *)
+				| TFun _ -> () (* this is a bit a particular case, maybe flash-specific actually *)
+				(* TODO: this should use get_underlying_type, but we do not have access to Codegen here.  *)
+				| TAbstract(a,tl) when not (Meta.has Meta.CoreType a.a_meta) -> loop (apply_params a.a_types tl a.a_this)
+				| _ -> com.error ("On static platforms, null can't be used as basic type " ^ s_type (print_context()) e.etype) e.epos
+			in
+			loop e.etype
+		end;
 		e
 	| TBinop (op,e1,e2) ->
 		let swap op1 op2 =
@@ -1266,23 +1271,26 @@ let inline_constructors ctx e =
 			) ([],PMap.empty) assigns),el_init
 		) vars in
 		let el_b = ref [] in
+		let append e = el_b := e :: !el_b in
 		let rec subst e =
 			match e.eexpr with
 			| TBlock el ->
 				let old = !el_b in
 				el_b := [];
-				List.iter (fun e -> el_b := (subst e) :: !el_b) el;
+				List.iter (fun e -> append (subst e)) el;
 				let n = !el_b in
 				el_b := old;
 				{e with eexpr = TBlock (List.rev n)}
 			| TVar (v,Some e) when v.v_id < 0 ->
 				let (vars, _),el_init = PMap.find (-v.v_id) vfields in
-				el_b := (List.rev_map subst el_init) @ !el_b;
+				List.iter (fun e ->
+					append (subst e)
+				) el_init;
 				let (v_first,e_first),vars = match vars with
 					| v :: vl -> v,vl
 					| [] -> assert false
 				in
-				List.iter (fun (v,e) -> el_b := (mk (TVar(v,Some (subst e))) ctx.t.tvoid e.epos) :: !el_b) (List.rev vars);
+				List.iter (fun (v,e) -> append (mk (TVar(v,Some (subst e))) ctx.t.tvoid e.epos)) (List.rev vars);
 				mk (TVar (v_first, Some (subst e_first))) ctx.t.tvoid e.epos
 			| TField ({ eexpr = TLocal v },FInstance (c,cf)) when v.v_id < 0 ->
 				let (_, vars),el_init = PMap.find (-v.v_id) vfields in

+ 3 - 3
std/Map.hx

@@ -150,15 +150,15 @@ abstract Map<K,V>(IMap<K,V> ) {
 	}
 
 	@:from static inline function fromStringMap<V>(map:StringMap<V>):Map< String, V > {
-		return map;
+		return cast map;
 	}
 
 	@:from static inline function fromIntMap<V>(map:IntMap<V>):Map< Int, V > {
-		return map;
+		return cast map;
 	}
 
 	@:from static inline function fromObjectMap<K:{ }, V>(map:ObjectMap<K,V>):Map<K,V> {
-		return map;
+		return cast map;
 	}
 }
 

+ 16 - 11
std/UInt.hx

@@ -20,7 +20,7 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#if (flash9 || flash9doc || cs || doc_gen)
+#if ((flash9 || flash9doc || cs) && !doc_gen)
 /**
 	The unsigned Int type is only defined for Flash9 and C#. It's currently
 	handled the same as a normal Int.
@@ -31,8 +31,7 @@
 	The unsigned Int type is only defined for Flash9 and C#.
 	Simulate it for other platforms.
 **/
-@:coreType
-abstract UInt from Int {
+abstract UInt(Int) from Int to Int {
 
 	@:op(A + B) private static inline function add(a:UInt, b:UInt):UInt {
 		return a.toInt() + b.toInt();
@@ -130,11 +129,19 @@ abstract UInt from Int {
 		return a.toFloat() > b;
 	}
 
-	@:commutative @:op(A == B) private static inline function equalsFloat(a:UInt, b:Float):Bool {
+	@:commutative @:op(A == B) private static inline function equalsInt<T:Int>(a:UInt, b:T):Bool {
+		return a.toInt() == b;
+	}
+
+	@:commutative @:op(A != B) private static inline function notEqualsInt<T:Int>(a:UInt, b:T):Bool {
+		return a.toInt() != b;
+	}
+
+	@:commutative @:op(A == B) private static inline function equalsFloat<T:Float>(a:UInt, b:T):Bool {
         return a.toFloat() == b;
     }
 
-    @:commutative @:op(A != B) private static inline function notEqualsFloat(a:UInt, b:Float):Bool {
+    @:commutative @:op(A != B) private static inline function notEqualsFloat<T:Float>(a:UInt, b:T):Bool {
         return a.toFloat() != b;
     }
 
@@ -159,7 +166,6 @@ abstract UInt from Int {
 		return a.toFloat() <= b;
 	}
 
-
 	@:op(A < B) private static inline function floatLt(a:Float, b:UInt):Bool {
 		return a < b.toFloat();
 	}
@@ -201,6 +207,10 @@ abstract UInt from Int {
 		return Std.string(toFloat());
 	}
 
+	private inline function toInt():Int {
+		return this;
+	}
+
 	@:to private inline function toFloat():Float {
 		var int = toInt();
 		if (int < 0) {
@@ -212,10 +222,5 @@ abstract UInt from Int {
 			return int + 0.0;
 		}
 	}
-
-	@:to private inline function toInt():Int {
-		return cast this;
-	}
-
 }
 #end

+ 4 - 0
std/cpp/NativeArray.hx

@@ -22,4 +22,8 @@ class NativeArray {
 	public static inline function memcmp<T>( inArrayA:Array<T>, inArrayB:Array<T>) : Int {
 		return untyped inArrayA.memcmp(inArrayB);
 	}
+
+	public static inline function setSize<T>( ioArray:Array<T>, inSize:Int) : Array<T> {
+		return untyped ioArray.__SetSizeExact(inSize);
+   }
 }

+ 3 - 1
std/cpp/vm/Debugger.hx

@@ -140,6 +140,8 @@ class Debugger
      *          - 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
@@ -150,7 +152,7 @@ class Debugger
      *            undefined if event is not THREAD_STOPPED
      **/
     public static function setEventNotificationHandler(
-             handler : Int -> Int -> String -> String -> String -> Int -> Void)
+             handler : Int -> Int -> Int -> String -> String -> String -> Int -> Void)
     {
         untyped __global__.__hxcpp_dbg_setEventNotificationHandler(handler);
     }

+ 1 - 1
std/cpp/zip/Compress.hx

@@ -1,5 +1,5 @@
 package cpp.zip;
 
-#if (haxe_ver < 3.2)
+#if (haxe_ver < 3.4)
 typedef Compress = haxe.zip.Compress;
 #end

+ 1 - 1
std/cpp/zip/Flush.hx

@@ -1,5 +1,5 @@
 package cpp.zip;
 
-#if (haxe_ver < 3.2)
+#if (haxe_ver < 3.4)
 typedef Flush = haxe.zip.FlushMode;
 #end

+ 1 - 1
std/cpp/zip/Uncompress.hx

@@ -1,5 +1,5 @@
 package cpp.zip;
 
-#if (haxe_ver < 3.2)
+#if (haxe_ver < 3.4)
 typedef Uncompress = haxe.zip.Uncompress;
 #end

+ 1 - 1
std/flash/_std/EReg.hx

@@ -22,7 +22,7 @@
 @:coreApi class EReg {
 
 	var r : flash.utils.RegExp;
-	var result : {> Array<String>, index : Int, input : String };
+	var result : Dynamic;
 
 	public function new( r : String, opt : String ) : Void {
 		this.r = new flash.utils.RegExp(r,opt);

+ 2 - 2
std/flash/_std/haxe/Json.hx

@@ -33,7 +33,7 @@ class Json {
 	}
 
 	#if (haxeJSON || !flash11) inline #end
-	public static function stringify( value : Dynamic, ?replacer:Dynamic -> Dynamic -> Dynamic ) : String {
-		return haxe.format.JsonPrinter.print(value, replacer);
+	public static function stringify( value : Dynamic, ?replacer:Dynamic -> Dynamic -> Dynamic, ?space:String ) : String {
+		return haxe.format.JsonPrinter.print(value, replacer, space);
 	}
 }

+ 5 - 2
std/haxe/Json.hx

@@ -46,9 +46,12 @@ class Json {
 		If `replacer` is given and is not null, it is used to retrieve
 		actual object to be encoded. The `replacer` function two parameters,
 		the key and the value being encoded. Initial key value is an empty string.
+		
+		If `space` is given and is not null, the result will be pretty-printed.
+		Successive levels will be indented by this string.
 	**/
-	public static inline function stringify( value : Dynamic, ?replacer:Dynamic -> Dynamic -> Dynamic ) : String {
-		return haxe.format.JsonPrinter.print(value, replacer);
+	public static inline function stringify( value : Dynamic, ?replacer:Dynamic -> Dynamic -> Dynamic, ?space : String ) : String {
+		return haxe.format.JsonPrinter.print(value, replacer, space);
 	}
 
 }

+ 28 - 10
std/haxe/ds/Vector.hx

@@ -21,6 +21,10 @@
  */
 package haxe.ds;
 
+#if cpp
+using cpp.NativeArray;
+#end
+
 private typedef VectorData<T> = #if flash10
 	flash.Vector<T>
 #elseif neko
@@ -80,7 +84,11 @@ abstract Vector<T>(VectorData<T>) {
 		unspecified.
 	**/
 	@:arrayAccess public inline function get(index:Int):Null<T> {
+		#if cpp
+		return this.unsafeGet(index);
+		#else
 		return this[index];
+		#end
 	}
 
 	/**
@@ -90,7 +98,11 @@ abstract Vector<T>(VectorData<T>) {
 		unspecified.
 	**/
 	@:arrayAccess public inline function set(index:Int, val:T):T {
+		#if cpp
+		return this.unsafeSet(index,val);
+		#else
 		return this[index] = val;
+		#end
 	}
 
 	/**
@@ -119,7 +131,7 @@ abstract Vector<T>(VectorData<T>) {
 		The results are unspecified if `length` results in out-of-bounds access,
 		or if `src` or `dest` are null
 	**/
-	public static #if (cs || java || neko) inline #end function blit<T>(src:Vector<T>, srcPos:Int, dest:Vector<T>, destPos:Int, len:Int):Void
+	public static #if (cs || java || neko || cpp) inline #end function blit<T>(src:Vector<T>, srcPos:Int, dest:Vector<T>, destPos:Int, len:Int):Void
 	{
 		#if neko
 			untyped __dollar__ablit(dest,destPos,src,srcPos,len);
@@ -127,6 +139,8 @@ abstract Vector<T>(VectorData<T>) {
 			java.lang.System.arraycopy(src, srcPos, dest, destPos, len);
 		#elseif cs
 			cs.system.Array.Copy(cast src, srcPos,cast dest, destPos, len);
+		#elseif cpp
+			dest.toData().blit(destPos,src.toData(), srcPos,len);
 		#else
 			for (i in 0...len)
 			{
@@ -138,16 +152,20 @@ abstract Vector<T>(VectorData<T>) {
 	/**
 		Creates a new Array, copy the content from the Vector to it, and returns it.
 	**/
-	public #if flash inline #end function toArray():Array<T> {
-		var a = new Array();
-		var len = length;
-		#if (cpp || neko)
-		// prealloc good size
-		if( len > 0 ) a[len - 1] = get(0);
+	public #if (flash || cpp) inline #end function toArray():Array<T> {
+		#if cpp
+			return this.copy();
+		#else
+			var a = new Array();
+			var len = length;
+			#if (neko)
+			// prealloc good size
+			if( len > 0 ) a[len - 1] = get(0);
+			#end
+			for( i in 0...len )
+				a[i] = get(i);
+			return a;
 		#end
-		for( i in 0...len )
-			a[i] = get(i);
-		return a;
 	}
 
 	/**

+ 45 - 13
std/haxe/format/JsonPrinter.hx

@@ -2,17 +2,23 @@ package haxe.format;
 
 class JsonPrinter {
 
-	static public function print(o:Dynamic, ?replacer:Dynamic -> Dynamic -> Dynamic) : String {
-		var printer = new JsonPrinter(replacer);
+	static public function print(o:Dynamic, ?replacer:Dynamic -> Dynamic -> Dynamic, ?space:String) : String {
+		var printer = new JsonPrinter(replacer, space);
 		printer.write("", o);
 		return printer.buf.toString();
 	}
 
 	var buf : #if flash9 flash.utils.ByteArray #else StringBuf #end;
 	var replacer : Dynamic -> Dynamic -> Dynamic;
-
-	function new(replacer:Dynamic -> Dynamic -> Dynamic) {
+	var indent:String;
+	var pretty:Bool;
+	var nind:Int;
+	
+	function new(replacer:Dynamic -> Dynamic -> Dynamic, space:String) {
 		this.replacer = replacer;
+		this.indent = space;
+		this.pretty = space != null;
+		this.nind = 0;
 
 		#if flash9
 		buf = new flash.utils.ByteArray();
@@ -22,6 +28,14 @@ class JsonPrinter {
 		buf = new StringBuf();
 		#end
 	}
+	
+	inline function ipad ():Void {
+		if (pretty) add(StringTools.lpad('', indent, nind * indent.length));
+	}
+	
+	inline function newl ():Void {
+		if (pretty) addChar('\n'.code);
+	}
 
 	function write(k:Dynamic, v:Dynamic) {
 		if (replacer != null) v = replacer(k, v);
@@ -42,13 +56,20 @@ class JsonPrinter {
 			else if( c == Array ) {
 				var v : Array<Dynamic> = v;
 				addChar('['.code);
+
 				var len = v.length;
-				if( len > 0 ) {
-					write(0, v[0]);
-					var i = 1;
-					while( i < len ) {
-						addChar(','.code);
-						write(i, v[i++]);
+				var last = len - 1;
+				for (i in 0...len)
+				{
+					if (i > 0) addChar(','.code) else nind++;
+					newl();
+					ipad();
+					write(i, v[i]);
+					if (i == last)
+					{
+						nind--;
+						newl();
+						ipad();
 					}
 				}
 				addChar(']'.code);
@@ -105,15 +126,26 @@ class JsonPrinter {
 	}
 
 	function fieldsString( v : Dynamic, fields : Array<String> ) {
-		var first = true;
 		addChar('{'.code);
-		for( f in fields ) {
+		var len = fields.length;
+		var last = len - 1;
+		for( i in 0...len ) {
+			var f = fields[i];
 			var value = Reflect.field(v,f);
 			if( Reflect.isFunction(value) ) continue;
-			if( first ) first = false else addChar(','.code);
+			if( i > 0 ) addChar(','.code) else nind++;
+			newl();
+			ipad();
 			quote(f);
 			addChar(':'.code);
+			if (pretty) addChar(' '.code);
 			write(f, value);
+			if (i == last)
+			{
+				nind--;
+				newl();
+				ipad();
+			}
 		}
 		addChar('}'.code);
 	}

+ 11 - 1
std/haxe/macro/Context.hx

@@ -175,10 +175,20 @@ class Context {
 
 		Modifying the returned map has no effect on the compiler.
 	**/
+	@:deprecated("Use Context.getLocalTVars() instead")
 	public static function getLocalVars() : haxe.ds.StringMap<Type> {
-		return load("local_vars", 0)();
+		return load("local_vars", 1)(false);
 	}
 
+	/**
+		Similar to `getLocalVars`, but returns elements of type `TVar` instead
+		of `Type`.
+	**/
+	@:require(haxe_ver >= 3.102)
+	public static function getLocalTVars() : haxe.ds.StringMap<Type.TVar> {
+		return load("local_vars", 1)(true);
+	}
+	
 	/**
 		Tells if compiler directive `s` has been set.
 

+ 16 - 2
std/haxe/macro/Printer.hx

@@ -24,6 +24,7 @@ package haxe.macro;
 
 import haxe.macro.Expr;
 using Lambda;
+using StringTools;
 
 class Printer {
 	var tabs:String;
@@ -69,9 +70,19 @@ class Printer {
 			printBinop(op)
 			+ "=";
 	}
+
+	function escapeString(s:String,delim:String) {
+		return delim + s.replace("\n","\\n").replace("\t","\\t").replace("'","\\'").replace('"',"\\\"") #if sys .replace("\x00","\\x00") #end + delim;
+	}
+
+	public function printFormatString(s:String) {
+		return escapeString(s,"'");
+	}
+
 	public function printString(s:String) {
-		return '"' + s.split("\n").join("\\n").split("\t").join("\\t").split("'").join("\\'").split('"').join("\\\"") #if sys .split("\x00").join("\\x00") #end + '"';
+		return escapeString(s,'"');
 	}
+
 	public function printConstant(c:Constant) return switch(c) {
 		case CString(s): printString(s);
 		case CIdent(s),
@@ -150,6 +161,9 @@ class Printer {
 
 
 	public function printExpr(e:Expr) return e == null ? "#NULL" : switch(e.expr) {
+		#if macro
+		case EConst(CString(s)): haxe.macro.MacroStringTools.isFormatExpr(e) ? printFormatString(s) : printString(s);
+		#end
 		case EConst(c): printConstant(c);
 		case EArray(e1, e2): '${printExpr(e1)}[${printExpr(e2)}]';
 		case EBinop(op, e1, e2): '${printExpr(e1)} ${printBinop(op)} ${printExpr(e2)}';
@@ -292,4 +306,4 @@ class Printer {
 	}
 
 	function opt<T>(v:T, f:T->String, prefix = "") return v == null ? "" : (prefix + f(v));
-}
+}

+ 2 - 2
std/js/_std/haxe/Json.hx

@@ -33,8 +33,8 @@ class Json {
 	}
 
 	#if haxeJSON inline #end
-	public static function stringify( value : Dynamic, ?replacer:Dynamic -> Dynamic -> Dynamic ) : String {
-		return haxe.format.JsonPrinter.print(value, replacer);
+	public static function stringify( value : Dynamic, ?replacer:Dynamic -> Dynamic -> Dynamic, ?space:String ) : String {
+		return haxe.format.JsonPrinter.print(value, replacer, space);
 	}
 
 	#if (!haxeJSON && old_browser)

+ 1 - 1
std/neko/zip/Compress.hx

@@ -1,5 +1,5 @@
 package neko.zip;
 
-#if (haxe_ver < 3.2)
+#if (haxe_ver < 3.4)
 typedef Compress = haxe.zip.Compress;
 #end

+ 1 - 1
std/neko/zip/Flush.hx

@@ -1,5 +1,5 @@
 package neko.zip;
 
-#if (haxe_ver < 3.2)
+#if (haxe_ver < 3.4)
 typedef Flush = haxe.zip.FlushMode;
 #end

+ 1 - 1
std/neko/zip/Uncompress.hx

@@ -1,5 +1,5 @@
 package neko.zip;
 
-#if (haxe_ver < 3.2)
+#if (haxe_ver < 3.4)
 typedef Uncompress = haxe.zip.Uncompress;
 #end

+ 6 - 6
std/php/_std/haxe/Json.hx

@@ -32,11 +32,11 @@ class Json {
 		#end
 	}
 
-	public static inline function stringify( value : Dynamic, ?replacer:Dynamic -> Dynamic -> Dynamic ) : String {
+	public static inline function stringify( value : Dynamic, ?replacer:Dynamic -> Dynamic -> Dynamic, ?space:String ) : String {
 		#if !haxeJSON
-		return phpJsonEncode(value, replacer);
+		return phpJsonEncode(value, replacer, space);
 		#else
-		return haxe.format.JsonPrinter.print(value, replacer);
+		return haxe.format.JsonPrinter.print(value, replacer, space);
 		#end
 	}
 
@@ -59,9 +59,9 @@ class Json {
 			return val;
 	}
 
-	static function phpJsonEncode(val:Dynamic, ?replacer:Dynamic -> Dynamic -> Dynamic):String {
-		if(null != replacer)
-			return haxe.format.JsonPrinter.print(val, replacer);
+	static function phpJsonEncode(val:Dynamic, ?replacer:Dynamic -> Dynamic -> Dynamic, ?space:String):String {
+		if(null != replacer || null != space)
+			return haxe.format.JsonPrinter.print(val, replacer, space);
 		var json = untyped __call__("json_encode", convertBeforeEncode(val));
 		if (untyped __physeq__(json, false))
 			return throw "invalid json";

+ 93 - 42
tests/RunTravis.hx

@@ -41,6 +41,27 @@ class RunTravis {
 		Sys.exit(exitCode);
 	}
 
+	static function haxelibInstallGit(account:String, repository:String, ?branch:String, ?srcPath:String, useRetry:Bool = false, ?altName:String):Void {
+		var name:String = (altName == null) ? repository : altName;
+		var args:Array<String> = ["git", name, 'https://github.com/$account/$repository'];
+		if (branch != null) {
+			args.push(branch);
+		}
+		if (srcPath != null) {
+			args.push(srcPath);
+		}
+
+		runCommand("haxelib", args, useRetry);
+	}
+
+	static function haxelibInstall(library:String):Void {
+		runCommand("haxelib", ["install", library]);
+	}
+
+	static function haxelibRun(args:Array<String>, useRetry:Bool = false):Void {
+		runCommand("haxelib", ["run"].concat(args), useRetry);
+	}
+
 	static function getHaxelibPath(libName:String) {
 		var proc = new sys.io.Process("haxelib", ["path", libName]);
 		var result;
@@ -178,19 +199,35 @@ class RunTravis {
 		runCommand("sudo", ["apt-get", "install", "gcc-multilib", "g++-multilib", "-y"], true);
 
 		//install and build hxcpp
-		runCommand("haxelib", ["git", "hxcpp", "https://github.com/HaxeFoundation/hxcpp.git"], true);
+		haxelibInstallGit("HaxeFoundation", "hxcpp", true);
 		Sys.setCwd(Sys.getEnv("HOME") + "/haxelib/hxcpp/git/project/");
 		runCommand("neko", ["build.n"]);
 		Sys.setCwd(unitDir);
 	}
 
 	static function getJavaDependencies() {
-		runCommand("haxelib", ["git", "hxjava", "https://github.com/HaxeFoundation/hxjava.git"], true);
+		haxelibInstallGit("HaxeFoundation", "hxjava", true);
 	}
 
 	static function getCsDependencies() {
 		runCommand("sudo", ["apt-get", "install", "mono-devel", "mono-mcs", "-y"], true);
-		runCommand("haxelib", ["git", "hxcs", "https://github.com/HaxeFoundation/hxcs.git"], true);
+		haxelibInstallGit("HaxeFoundation", "hxcs", true);
+	}
+
+	static function getOpenFLDependencies(unitDir:String) {
+		getCppDependencies(unitDir);
+
+		haxelibInstallGit("HaxeFoundation", "format");
+		haxelibInstallGit("haxenme", "nme");
+		haxelibInstallGit("haxenme", "nme-dev");
+		haxelibInstallGit("openfl", "svg");
+		haxelibInstallGit("openfl", "lime");
+		haxelibInstallGit("openfl", "lime-tools");
+		haxelibInstallGit("openfl", "openfl-native");
+		haxelibInstallGit("openfl", "openfl");
+
+		haxelibRun(["openfl", "rebuild", "linux"]);
+		haxelibRun(["openfl", "rebuild", "tools"]);
 	}
 
 	static function getPythonDependencies() {
@@ -205,24 +242,24 @@ class RunTravis {
 
 		Sys.setCwd(unitDir);
 		switch (Sys.getEnv("TARGET")) {
-			case "macro", null:
+			case "macro", "bytecode", null:
 				runCommand("haxe", ["compile-macro.hxml"]);
 
 				//generate documentation
-				runCommand("haxelib", ["git", "hxparse", "https://github.com/Simn/hxparse", "development", "src"], true);
-				runCommand("haxelib", ["git", "hxtemplo", "https://github.com/Simn/hxtemplo", "master", "src"], true);
-				runCommand("haxelib", ["git", "hxargs", "https://github.com/Simn/hxargs.git"], true);
-				runCommand("haxelib", ["git", "markdown", "https://github.com/dpeek/haxe-markdown.git", "master", "src"], true);
+				haxelibInstallGit("Simn", "hxparse", "development", "src", true);
+				haxelibInstallGit("Simn", "hxtemplo", "master", "src", true);
+				haxelibInstallGit("Simn", "hxargs", true);
+				haxelibInstallGit("dpeek", "haxe-markdown", "master", "src", true, "markdown");
 
-				runCommand("haxelib", ["git", "hxcpp", "https://github.com/HaxeFoundation/hxcpp.git"], true);
-				runCommand("haxelib", ["git", "hxjava", "https://github.com/HaxeFoundation/hxjava.git"], true);
-				runCommand("haxelib", ["git", "hxcs", "https://github.com/HaxeFoundation/hxcs.git"], true);
+				haxelibInstallGit("HaxeFoundation", "hxcpp", true);
+				haxelibInstallGit("HaxeFoundation", "hxjava", true);
+				haxelibInstallGit("HaxeFoundation", "hxcs", true);
 
-				runCommand("haxelib", ["git", "dox", "https://github.com/dpeek/dox.git"], true);
+				haxelibInstallGit("dpeek", "dox", true);
 				Sys.setCwd(Sys.getEnv("HOME") + "/haxelib/dox/git/");
 				runCommand("haxe", ["run.hxml"]);
 				runCommand("haxe", ["gen.hxml"]);
-				runCommand("haxelib", ["run", "dox", "-o", "bin/api.zip", "-i", "bin/xml"]);
+				haxelibRun(["dox", "-o", "bin/api.zip", "-i", "bin/xml"]);
 			case "neko":
 				runCommand("haxe", ["compile-neko.hxml"]);
 				runCommand("neko", ["unit.n"]);
@@ -251,7 +288,7 @@ class RunTravis {
 					//https://saucelabs.com/opensource/travis
 					runCommand("npm", ["install", "wd"], true);
 					runCommand("curl", ["https://gist.github.com/santiycr/5139565/raw/sauce_connect_setup.sh", "-L", "|", "bash"], true);
-					runCommand("haxelib", ["git", "nodejs", "https://github.com/dionjwa/nodejs-std.git", "master", "src"], true);
+					haxelibInstallGit("dionjwa", "nodejs-std", "master", "src", true, "nodejs");
 					runCommand("haxe", ["compile-saucelabs-runner.hxml"]);
 					runCommand("nekotools", ["server", "&"]);
 					runCommand("node", ["RunSauceLabs.js"]);
@@ -296,23 +333,20 @@ class RunTravis {
 
 				runCommand("haxe", ["compile-as3.hxml", "-D", "fdb"]);
 				runFlash("unit9_as3.swf");
+			case "neko-sys":
+				Sys.setCwd("../sys");
+				runCommand("haxe", ["compile-neko.hxml"]);
+				Sys.setCwd("bin/neko");
+				runCommand("neko", ["sys.n"]);
 			case "openfl-samples":
-				getCppDependencies(unitDir);
-				runCommand("haxelib", ["git", "hxlibc", "https://github.com/openfl/hxlibc"]);
-				runCommand("haxelib", ["git", "actuate", "https://github.com/jgranick/actuate"]);
-				runCommand("haxelib", ["git", "box2d", "https://github.com/jgranick/box2d"]);
-				runCommand("haxelib", ["git", "swf", "https://github.com/openfl/swf"]);
-				runCommand("haxelib", ["git", "layout", "https://github.com/jgranick/layout"]);
-				runCommand("haxelib", ["git", "format", "https://github.com/HaxeFoundation/format"]);
-				runCommand("haxelib", ["git", "svg", "https://github.com/openfl/svg"]);
-				runCommand("haxelib", ["git", "lime", "https://github.com/openfl/lime"]);
-				runCommand("haxelib", ["git", "lime-build", "https://github.com/openfl/lime-build"]);
-				runCommand("haxelib", ["git", "lime-tools", "https://github.com/openfl/lime-tools"]);
-				runCommand("haxelib", ["git", "openfl-native", "https://github.com/openfl/openfl-native"]);
-				runCommand("haxelib", ["git", "openfl", "https://github.com/openfl/openfl"]);
-				runCommand("haxelib", ["git", "openfl-samples", "https://github.com/Simn/openfl-samples"]);
-				runCommand("haxelib", ["run", "openfl", "rebuild", "linux"]);
-				runCommand("haxelib", ["run", "openfl", "rebuild", "tools"]);
+				getOpenFLDependencies(unitDir);
+
+				haxelibInstallGit("jgranick", "actuate");
+				haxelibInstallGit("jgranick", "box2d");
+				haxelibInstallGit("jgranick", "layout");
+				haxelibInstallGit("openfl", "swf");
+				haxelibInstallGit("openfl", "openfl-samples");
+
 				var path = getHaxelibPath("openfl-samples");
 				var old = Sys.getEnv("pwd");
 				Sys.putEnv("pwd", path);
@@ -321,10 +355,9 @@ class RunTravis {
 					Sys.putEnv("pwd", old);
 				}
 			case "polygonal-ds":
-				getPythonDependencies();
-				runCommand("haxelib", ["git", "polygonal-ds", "https://github.com/Simn/ds", "python-support"]);
-				runCommand("haxelib", ["git", "polygonal-core", "https://github.com/polygonal/core", "master", "src"]);
-				runCommand("haxelib", ["git", "polygonal-printf", "https://github.com/polygonal/printf", "master", "src"]);
+				haxelibInstallGit("Simn", "ds", "python-support", null, false, "polygonal-ds");
+				haxelibInstallGit("polygonal", "core", "master", "src", false, "polygonal-core");
+				haxelibInstallGit("polygonal", "printf", "master", "src", false, "polygonal-printf");
 				changeDirectory(getHaxelibPath("polygonal-ds"));
 				runCommand("haxe", ["build.hxml"]);
 				runCommand("node", ["unit.js"]);
@@ -336,8 +369,8 @@ class RunTravis {
 				getJavaDependencies();
 				getPhpDependencies();
 				getCppDependencies(unitDir);
-				runCommand("haxelib", ["git", "hxparse", "https://github.com/Simn/hxparse", "development", "src"]);
-				runCommand("haxelib", ["git", "hxtemplo", "https://github.com/Simn/hxtemplo"]);
+				haxelibInstallGit("Simn", "hxparse", "development", "src");
+				haxelibInstallGit("Simn", "hxtemplo");
 
 				changeDirectory(getHaxelibPath("hxtemplo"));
 				runCommand("haxe", ["build.hxml"]);
@@ -348,15 +381,33 @@ class RunTravis {
 				runCommand("php", ["bin/php/index.php"]);
 				runCommand("./bin/cpp/Test", []);
 			case "munit":
-				runCommand("haxelib", ["git", "mconsole", "https://github.com/massiveinteractive/mconsole", "master", "src"]);
-				runCommand("haxelib", ["git", "mcover", "https://github.com/massiveinteractive/MassiveCover", "master", "src"]);
-				runCommand("haxelib", ["git", "mlib", "https://github.com/massiveinteractive/MassiveLib", "master", "src"]);
-				runCommand("haxelib", ["git", "munit", "https://github.com/massiveinteractive/MassiveUnit", "master", "src"]);
+				haxelibInstallGit("massiveinteractive", "mconsole", "master", "src");
+				haxelibInstallGit("massiveinteractive", "MassiveCover", "master", "src", false, "mcover");
+				haxelibInstallGit("massiveinteractive", "MassiveLib", "master", "src", false, "mlib");
+				haxelibInstallGit("massiveinteractive", "MassiveUnit", "master", "src", false, "munit");
 				changeDirectory(haxe.io.Path.join([getHaxelibPath("munit"), "..", "tool"]));
 				runCommand("haxe", ["build.hxml"]);
-				runCommand("haxelib", ["run", "munit", "test", "-result-exit-code", "-neko"]);
+				haxelibRun(["munit", "test", "-result-exit-code", "-neko"]);
 				changeDirectory("../");
-				runCommand("haxelib", ["run", "munit", "test", "-result-exit-code", "-neko"]);
+				haxelibRun(["munit", "test", "-result-exit-code", "-neko"]);
+			case "flixel-demos":
+				getOpenFLDependencies(unitDir);
+
+				haxelibInstall("systools");
+				haxelibInstall("spinehx");
+				haxelibInstall("nape");
+				haxelibInstall("task");
+
+				haxelibInstallGit("larsiusprime", "firetongue");
+
+				haxelibInstallGit("HaxeFlixel", "flixel");
+				haxelibInstallGit("HaxeFlixel", "flixel-addons");
+				haxelibInstallGit("HaxeFlixel", "flixel-ui");
+				haxelibInstallGit("HaxeFlixel", "flixel-demos");
+				haxelibInstallGit("HaxeFlixel", "flixel-tools");
+
+				haxelibRun(["flixel-tools", "testdemos", "-flash"]);
+				haxelibRun(["flixel-tools", "testdemos", "-neko"]);
 			case target:
 				throw "unknown target: " + target;
 		}

+ 3 - 0
tests/sys/compile-each.hxml

@@ -0,0 +1,3 @@
+-debug
+-cp src
+-main Main

+ 2 - 0
tests/sys/compile-neko.hxml

@@ -0,0 +1,2 @@
+compile-each.hxml
+-neko bin/neko/sys.n

+ 1 - 0
tests/sys/compile.hxml

@@ -0,0 +1 @@
+compile-neko.hxml

+ 0 - 8
tests/sys/run.hxml

@@ -1,8 +0,0 @@
--cp src
--main Main
-
---each
--neko bin/sys.n
-
---next
--python bin/sys.py

+ 3 - 1
tests/sys/src/Main.hx

@@ -2,6 +2,8 @@ class Main {
 	static public function main() {
 		var runner = new haxe.unit.TestRunner();
 		runner.add(new TestSys());
-		runner.run();
+		runner.add(new io.TestFileInput());
+		var code = runner.run() ? 0 : 1;
+		Sys.exit(code);
 	}
 }

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

@@ -0,0 +1,218 @@
+package io;
+
+import sys.io.FileInput;
+import sys.FileSystem;
+import sys.io.File;
+import sys.io.FileSeek;
+
+/**
+ * Class TestFileInput
+ *
+ * @author        Maximilian Ruta <[email protected]>
+ */
+class TestFileInput extends haxe.unit.TestCase {
+
+	private var path : String;
+
+	public function new() {
+		super();
+		path = 'testcase-test-file';
+	}
+
+	override public function setup() {
+		File.saveContent(path, "test\n1234");
+	}
+
+	override public function tearDown() {
+		FileSystem.deleteFile(path);
+	}
+
+	public function testRead() {
+		var file : FileInput = File.read(path, false);
+		assertEquals(0, file.tell());
+		assertEquals(116, file.readByte());
+		assertEquals(1, file.tell());
+		assertEquals(101, file.readByte());
+		assertEquals(2, file.tell());
+		assertEquals(115, file.readByte());
+		assertEquals(3, file.tell());
+		assertEquals(116, file.readByte());
+		assertEquals(4, file.tell());
+		file.close();
+	}
+
+	public function testSeekBeginCur() {
+		var file : FileInput = File.read(path, false);
+		assertEquals(116, file.readByte());
+		assertEquals(101, file.readByte());
+		assertEquals(115, file.readByte());
+		assertEquals(116, file.readByte());
+
+		file.seek(-4, FileSeek.SeekCur);
+		assertEquals(0, file.tell());
+		assertEquals(116, file.readByte());
+		assertEquals(1, file.tell());
+		file.close();
+	}
+
+	public function testSeekBeginEnd() {
+		var file : FileInput = File.read(path, false);
+		assertEquals(116, file.readByte());
+		assertEquals(101, file.readByte());
+		assertEquals(115, file.readByte());
+		assertEquals(116, file.readByte());
+
+		file.seek(-9, FileSeek.SeekEnd);
+		assertEquals(0, file.tell());
+		assertEquals(116, file.readByte());
+		assertEquals(1, file.tell());
+		file.close();
+	}
+
+	public function testSeekBegin() {
+		var file : FileInput = File.read(path, false);
+		assertEquals(116, file.readByte());
+		assertEquals(101, file.readByte());
+		assertEquals(115, file.readByte());
+		assertEquals(116, file.readByte());
+
+		file.seek(0, FileSeek.SeekBegin);
+		assertEquals(0, file.tell());
+		assertEquals(116, file.readByte());
+		assertEquals(1, file.tell());
+		file.close();
+	}
+
+	public function testSeekPosBegin() {
+		var file : FileInput = File.read(path, false);
+		assertEquals(116, file.readByte());
+		assertEquals(101, file.readByte());
+		assertEquals(115, file.readByte());
+		assertEquals(116, file.readByte());
+
+		file.seek(1, FileSeek.SeekBegin);
+		assertEquals(1, file.tell());
+		assertEquals(101, file.readByte());
+		assertEquals(2, file.tell());
+		file.close();
+	}
+
+	public function testSeekPosBeginMulti() {
+		var file : FileInput = File.read(path, false);
+		assertEquals(116, file.readByte());
+		assertEquals(101, file.readByte());
+		assertEquals(115, file.readByte());
+		assertEquals(116, file.readByte());
+
+		file.seek(1, FileSeek.SeekBegin);
+		assertEquals(1, file.tell());
+		assertEquals(101, file.readByte());
+		assertEquals(2, file.tell());
+		file.seek(3, FileSeek.SeekBegin);
+		assertEquals(3, file.tell());
+		assertEquals(116, file.readByte());
+		assertEquals(4, file.tell());
+		file.close();
+	}
+
+	public function testSeekEnd() {
+		var file : FileInput = File.read(path, false);
+		assertEquals(116, file.readByte());
+		assertEquals(101, file.readByte());
+		assertEquals(115, file.readByte());
+		assertEquals(116, file.readByte());
+
+		file.seek(-1, FileSeek.SeekEnd);
+		assertEquals(8, file.tell());
+		assertEquals(52, file.readByte());
+		assertEquals(9, file.tell());
+		file.close();
+	}
+
+	public function testSeekEofLast() {
+		var file : FileInput = File.read(path, false);
+		assertEquals(116, file.readByte());
+		assertEquals(101, file.readByte());
+		assertEquals(115, file.readByte());
+		assertEquals(116, file.readByte());
+
+		file.seek(0, FileSeek.SeekEnd);
+		assertEquals(9, file.tell());
+		assertFalse(file.eof());
+		try {
+			file.readByte();
+			assertTrue(false);
+		} catch(e : haxe.io.Eof) {
+			assertTrue(true);
+		}
+		assertTrue(file.eof());
+		file.close();
+	}
+
+	public function testSeekEof() {
+		var file : FileInput = File.read(path, false);
+		assertEquals(116, file.readByte());
+		assertEquals(101, file.readByte());
+		assertEquals(115, file.readByte());
+		assertEquals(116, file.readByte());
+
+		file.seek(0, FileSeek.SeekEnd);
+		assertEquals(9, file.tell());
+		assertFalse(file.eof());
+		try {
+			file.readByte();
+			assertTrue(false);
+		} catch(e : haxe.io.Eof) {
+			assertTrue(true);
+		}
+		assertTrue(file.eof());
+		assertEquals(9, file.tell());
+		file.seek(-1, FileSeek.SeekCur);
+		assertEquals(8, file.tell());
+		assertEquals(52, file.readByte());
+		assertEquals(9, file.tell());
+		assertFalse(file.eof());
+		try {
+			file.readByte();
+			assertTrue(false);
+		} catch(e : haxe.io.Eof) {
+			assertTrue(true);
+		}
+		assertTrue(file.eof());
+		assertEquals(9, file.tell());
+		try {
+			file.readByte();
+			assertTrue(false);
+		} catch(e : haxe.io.Eof) {
+			assertTrue(true);
+		}
+
+		file.seek(5, FileSeek.SeekEnd);
+		assertFalse(file.eof());
+		try {
+			file.readByte();
+			assertTrue(false);
+		} catch(e : haxe.io.Eof) {
+			assertTrue(true);
+		}
+		assertTrue(file.eof());
+		file.seek(1, FileSeek.SeekEnd);
+		assertFalse(file.eof());
+		try {
+			file.readByte();
+			assertTrue(false);
+		} catch(e : haxe.io.Eof) {
+			assertTrue(true);
+		}
+		assertTrue(file.eof());
+		try {
+			file.readByte();
+			assertTrue(false);
+		} catch(e : haxe.io.Eof) {
+			assertTrue(true);
+		}
+		file.close();
+	}
+
+}
+

+ 1 - 1
tests/sys/testsys.hxproj

@@ -39,7 +39,7 @@
     <hidden path="obj" />
   </hiddenPaths>
   <!-- Executed before build -->
-  <preBuildCommand>haxe run.hxml</preBuildCommand>
+  <preBuildCommand>haxe compile.hxml</preBuildCommand>
   <!-- Executed after build -->
   <postBuildCommand alwaysRun="False" />
   <!-- Other project options -->

+ 23 - 0
tests/unit/issues/Issue2580.hx

@@ -0,0 +1,23 @@
+package unit.issues;
+
+private enum T {
+    T1(x:Null<T>);
+    T2(x:Int);
+}
+
+class Issue2580 extends Test {
+	function test() {
+		function match(t) {
+			return switch (t) {
+				case T1(T1(_)): 0;
+				case T1(T2(_)): 1;
+				case T1(_): 2;
+				case T2(_): 3;
+			}
+		}
+		eq(0, match(T1(T1(null))));
+		eq(1, match(T1(T2(1))));
+		eq(2, match(T1(null)));
+		eq(3, match(T2(2)));
+	}
+}

+ 0 - 0
tests/unit/issues/Issue2750.hx.disabled → tests/unit/issues/Issue2750.hx


+ 25 - 0
tests/unit/issues/Issue2786.hx

@@ -0,0 +1,25 @@
+package unit.issues;
+
+@:enum
+private abstract E(Int) to Int {
+    var A = 1;
+    var B = 2;
+    @:op(a | b) static function or(a:E, b:E):E;
+}
+
+@:enum
+private abstract E2(Int) to Int {
+    var A = 1;
+    var B = 2;
+    @:op(a | b) static function or(a:E2, b:E2):E2;
+    @:op(a | b) static function or2(a:E2, b:E2):E2;
+}
+
+class Issue2786 extends Test {
+	function test() {
+		var a:E = A | B;
+		eq(3, a);
+
+		t(unit.TestType.typeError((A | B : E2)));
+	}
+}

+ 33 - 0
tests/unit/issues/Issue2828.hx

@@ -0,0 +1,33 @@
+package unit.issues;
+
+class Issue2828 extends unit.Test
+{
+	public function test()
+	{
+		var u:T1<Dynamic> = new U1();
+		u.foo(1,1);
+		t(u.call());
+	}
+}
+
+private interface T1<X>
+{
+  public function foo <A>(a:X, c:A):Void;
+	public function call():Bool;
+}
+
+private class U1 implements T1<Dynamic>
+{
+  public function new () {}
+	public var didCall:Bool = false;
+
+	public function call()
+	{
+		return didCall;
+	}
+
+  public function foo <A>(a:Dynamic, c:A):Void
+	{
+		didCall = true;
+	}
+}

+ 37 - 0
tests/unit/issues/Issue2835.hx

@@ -0,0 +1,37 @@
+package unit.issues;
+
+class Issue2835 extends unit.Test
+{
+	private function test()
+	{
+		var t = new Test(42);
+		eq(42,t.get());
+		t.fromFloat(12);
+		eq(12,t.get());
+		eq(12.0,t.toFloat());
+	}
+}
+
+private class Test<T:(Float)>
+{
+	public var value:T;
+	public function new(value)
+	{
+		this.value = value;
+	}
+
+	public function toFloat():Float
+	{
+		return value;
+	}
+
+	public function fromFloat(v:Float)
+	{
+		this.value = cast v;
+	}
+
+	public function get():T
+	{
+		return value;
+	}
+}

+ 12 - 0
tests/unit/issues/Issue2871.hx

@@ -0,0 +1,12 @@
+package unit.issues;
+
+class Issue2871 extends Test {
+    function call(myUInt:Null<UInt> = null):Int {
+        return myUInt == null ? 0 : myUInt;
+    }
+
+	function test() {
+		eq(0, call(null));
+		eq(1, call((1:UInt)));
+	}
+}

+ 44 - 0
tests/unit/issues/Issue2874.hx

@@ -0,0 +1,44 @@
+package unit.issues;
+
+class Issue2874 extends unit.Test
+{
+	private function test()
+	{
+		var a = new Arr(["1","2"]);
+		var a2 = a.map(function(v) return Std.parseInt(v));
+		eq(1,a2[0]);
+		eq(2,a2[1]);
+		// var a3:Arr<Int> = a.map(function(v) return Std.parseInt(v));
+		// eq(1,a3[0]);
+		// eq(2,a3[1]);
+	}
+
+	private function testArray()
+	{
+		var a = ["1","2"];
+		var a2 = a.map(function(v) return Std.parseInt(v));
+		eq(1,a2[0]);
+		eq(2,a2[1]);
+		// var a3:Array<Int> = a.map(function(v) return Std.parseInt(v));
+		// eq(1,a3[0]);
+		// eq(2,a3[1]);
+	}
+}
+
+@:arrayAccess abstract Arr<T>(Array<T>)
+{
+	@:extern inline public function new(a)
+	{
+		this = a;
+	}
+
+	@:extern inline public function map<X>(fn:T->X):Arr<X>
+	{
+		var arr2 = [];
+		for (v in this)
+		{
+			arr2.push(fn(v));
+		}
+		return new Arr(arr2);
+	}
+}

+ 9 - 0
tests/unit/issues/Issue2881.hx

@@ -0,0 +1,9 @@
+package unit.issues;
+
+private abstract Callback<T>(T->Void) from (T->Void) {}
+
+class Issue2881 extends Test {
+	function test() {
+		var cb:Callback<Int> = null;
+	}
+}

+ 10 - 0
tests/unit/issues/Issue2900.hx

@@ -0,0 +1,10 @@
+package unit.issues;
+
+class Issue2900 extends Test {
+	function test() {
+		var objs:Iterable<Int> = [10, 20];
+		var fns = [for (obj in objs) function() return obj];
+		eq(10, fns[0]());
+		eq(20, fns[1]());
+	}
+}

+ 28 - 0
tests/unit/issues/Issue2907.hx

@@ -0,0 +1,28 @@
+package unit.issues;
+
+private class MyTestClass {
+	public function new() { }
+}
+
+class Issue2907 extends Test {
+
+	@:generic function catchGeneric<T>(t:T) {
+		try {
+			throw "foo";
+		} catch(e:T) {
+			return e;
+		} catch(e:Dynamic) {
+			return null;
+		}
+		return null;
+	}
+
+	function test<T>() {
+		t(unit.TestType.typeError(
+			try { }
+			catch(e:T) { }
+		));
+		eq("foo", catchGeneric("foo"));
+		eq(null, catchGeneric(new MyTestClass()));
+	}
+}

+ 1 - 0
typeload.ml

@@ -419,6 +419,7 @@ and load_complex_type ctx p t =
 				| TInst ({cl_kind = KTypeParameter _},_) ->
 					error "Cannot structurally extend type parameters" p
 				| TInst (c,tl) ->
+					ctx.com.warning "Structurally extending classes is deprecated and will be removed" p;
 					let c2 = mk_class null_module (fst c.cl_path,"+" ^ snd c.cl_path) p in
 					c2.cl_private <- true;
 					PMap.iter (fun f _ ->

+ 65 - 22
typer.ml

@@ -161,26 +161,35 @@ let rec is_pos_infos = function
 	| _ ->
 		false
 
-let check_constraints ctx tname tpl tl map p =
+let check_constraints ctx tname tpl tl map delayed p =
 	List.iter2 (fun m (name,t) ->
 		match follow t with
 		| TInst ({ cl_kind = KTypeParameter constr },_) when constr <> [] ->
-			delay ctx PCheckConstraint (fun() ->
+			let f = (fun() ->
 				List.iter (fun ct ->
 					try
 						Type.unify (map m) (map ct)
 					with Unify_error l ->
-						display_error ctx (error_msg (Unify (Constraint_failure (tname ^ "." ^ name) :: l))) p;
+						let l = Constraint_failure (tname ^ "." ^ name) :: l in
+						raise (Unify_error l)
 				) constr
-			);
+			) in
+			if delayed then
+				delay ctx PCheckConstraint f
+			else
+				f()
 		| _ ->
 			()
 	) tl tpl
 
 let enum_field_type ctx en ef tl_en tl_ef p =
 	let map t = apply_params en.e_types tl_en (apply_params ef.ef_params tl_ef t) in
-	check_constraints ctx (s_type_path en.e_path) en.e_types tl_en map p;
-	check_constraints ctx ef.ef_name ef.ef_params tl_ef map p;
+	begin try
+		check_constraints ctx (s_type_path en.e_path) en.e_types tl_en map true p;
+		check_constraints ctx ef.ef_name ef.ef_params tl_ef map true p;
+	with Unify_error l ->
+		display_error ctx (error_msg (Unify l)) p
+	end;
 	map ef.ef_type
 
 let add_constraint_checks ctx ctypes pl f tl p =
@@ -698,7 +707,8 @@ let make_call ctx e params t p =
 				begin match t with
 					| TAbstract(a,pl) ->
 						let has_params = a.a_types <> [] || f.cf_params <> [] in
-						let map_type = fun t -> apply_params a.a_types pl (monomorphs f.cf_params t) in
+						let monos = List.map (fun _ -> mk_mono()) f.cf_params in
+						let map_type = fun t -> apply_params a.a_types pl (apply_params f.cf_params monos t) in
 						Some (has_params,map_type)
 					| _ ->
 						None
@@ -1512,7 +1522,7 @@ let call_to_string ctx c e =
 	let cf = PMap.find "toString" c.cl_statics in
 	make_call ctx (mk (TField(et,FStatic(c,cf))) cf.cf_type e.epos) [e] ctx.t.tstring e.epos
 
-let rec type_binop ctx op e1 e2 is_assign_op p =
+let rec type_binop ctx op e1 e2 is_assign_op with_type p =
 	match op with
 	| OpAssign ->
 		let e1 = type_access ctx (fst e1) (snd e1) MSet in
@@ -1563,7 +1573,7 @@ let rec type_binop ctx op e1 e2 is_assign_op p =
 		(match type_access ctx (fst e1) (snd e1) MSet with
 		| AKNo s -> error ("Cannot access field or identifier " ^ s ^ " for writing") p
 		| AKExpr e ->
-			let eop = type_binop ctx op e1 e2 true p in
+			let eop = type_binop ctx op e1 e2 true with_type p in
 			(match eop.eexpr with
 			| TBinop (_,_,e2) ->
 				unify ctx eop.etype e.etype p;
@@ -1581,7 +1591,7 @@ let rec type_binop ctx op e1 e2 is_assign_op p =
 			let l = save_locals ctx in
 			let v = gen_local ctx e.etype in
 			let ev = mk (TLocal v) e.etype p in
-			let get = type_binop ctx op (EField ((EConst (Ident v.v_name),p),cf.cf_name),p) e2 true p in
+			let get = type_binop ctx op (EField ((EConst (Ident v.v_name),p),cf.cf_name),p) e2 true with_type p in
 			unify ctx get.etype t p;
 			l();
 			mk (TBlock [
@@ -1600,7 +1610,7 @@ let rec type_binop ctx op e1 e2 is_assign_op p =
 			let ev = mk (TLocal v) ta p in
 			(* this relies on the fact that cf_name is set_name *)
 			let getter_name = String.sub cf.cf_name 4 (String.length cf.cf_name - 4) in
-			let get = type_binop ctx op (EField ((EConst (Ident v.v_name),p),getter_name),p) e2 true p in
+			let get = type_binop ctx op (EField ((EConst (Ident v.v_name),p),getter_name),p) e2 true with_type p in
 			unify ctx get.etype ret p;
 			l();
 			mk (TBlock [
@@ -1625,7 +1635,7 @@ let rec type_binop ctx op e1 e2 is_assign_op p =
 			in
 			let ast_call = ECall((EField(Interp.make_ast ebase,cf_get.cf_name),p),[Interp.make_ast ekey]),p in
 			let ast_call = (EMeta((Meta.PrivateAccess,[],pos ast_call),ast_call),pos ast_call) in
-			let eget = type_binop ctx op ast_call e2 true p in
+			let eget = type_binop ctx op ast_call e2 true with_type p in
 			unify ctx eget.etype r_get p;
 			let cf_set,tf_set,r_set =
 				try find_array_access a pl ekey.etype eget.etype true
@@ -1650,8 +1660,24 @@ let rec type_binop ctx op e1 e2 is_assign_op p =
 		| AKInline _ | AKMacro _ ->
 			assert false)
 	| _ ->
-	let e1 = type_expr ctx e1 Value in
-	let e2 = type_expr ctx e2 (if op == OpEq || op == OpNotEq then WithType e1.etype else Value) in
+	(* If the with_type is an abstract which has exactly one applicable @:op method, we can promote it
+	   to the individual arguments (issue #2786). *)
+	let wt = match with_type with
+		| WithType t | WithTypeResume t ->
+			begin match follow t with
+				| TAbstract(a,_) ->
+					begin match List.filter (fun (o,_) -> o = OpAssignOp(op) || o == op) a.a_ops with
+						| [_] -> with_type
+						| _ -> Value
+					end
+				| _ ->
+					Value
+			end
+		| _ ->
+			Value
+	in
+	let e1 = type_expr ctx e1 wt in
+	let e2 = type_expr ctx e2 (if op == OpEq || op == OpNotEq then WithType e1.etype else wt) in
 	let tint = ctx.t.tint in
 	let tfloat = ctx.t.tfloat in
 	let tstring = ctx.t.tstring in
@@ -1833,7 +1859,8 @@ let rec type_binop ctx op e1 e2 is_assign_op p =
 			| [] -> raise Not_found
 			| (o,cf) :: ops when is_assign_op && o = OpAssignOp(op) || o == op ->
 				let impl = Meta.has Meta.Impl cf.cf_meta in
-				let tcf = monomorphs cf.cf_params cf.cf_type in
+				let monos = List.map (fun _ -> mk_mono()) cf.cf_params in
+				let tcf = apply_params cf.cf_params monos cf.cf_type in
 				let tcf = if impl then apply_params a.a_types pl tcf else tcf in
 				(match follow tcf with
 				| TFun([(_,_,t1);(_,_,t2)],r) ->
@@ -1847,7 +1874,16 @@ let rec type_binop ctx op e1 e2 is_assign_op p =
 								else
 									type_eq EqStrict (TAbstract(a,pl)) t1;
 							end;
+							(* special case for == and !=: if the second type is a monomorph, assume that we want to unify
+							   it with the first type to preserve comparison semantics. *)
+							begin match op,follow t with
+								| (OpEq | OpNotEq),TMono _ ->
+									Type.unify (if left then e1.etype else e2.etype) t
+								| _ ->
+									()
+							end;
 							Type.unify t t2;
+							check_constraints ctx "" cf.cf_params monos (apply_params a.a_types pl) false cf.cf_pos;
 							cf,t2,r,o = OpAssignOp(op),Meta.has Meta.Commutative cf.cf_meta
 						with Unify_error _ ->
 							loop ops
@@ -2005,7 +2041,7 @@ and type_unop ctx op flag e p =
 		let eget = (EField ((EConst (Ident v.v_name),p),cf.cf_name),p) in
 		match flag with
 		| Prefix ->
-			let get = type_binop ctx op eget one false p in
+			let get = type_binop ctx op eget one false Value p in
 			unify ctx get.etype t p;
 			l();
 			mk (TBlock [
@@ -2016,7 +2052,7 @@ and type_unop ctx op flag e p =
 			let v2 = gen_local ctx t in
 			let ev2 = mk (TLocal v2) t p in
 			let get = type_expr ctx eget Value in
-			let plusone = type_binop ctx op (EConst (Ident v2.v_name),p) one false p in
+			let plusone = type_binop ctx op (EConst (Ident v2.v_name),p) one false Value p in
 			unify ctx get.etype t p;
 			l();
 			mk (TBlock [
@@ -2447,8 +2483,7 @@ and type_expr ctx (e,p) (with_type:with_type) =
 	| EField(_,n) when n.[0] = '$' ->
 		error "Field names starting with $ are not allowed" p
 	| EConst (Ident s) ->
-		(* TODO: let's deal with this later *)
-		(* if s = "super" && with_type <> NoValue then error "Cannot use super as value" p; *)
+		if s = "super" && with_type <> NoValue then error "Cannot use super as value" p;
 		(try
 			acc_get ctx (type_ident_raise ~imported_enums:false ctx s p MGet) p
 		with Not_found -> try
@@ -2491,7 +2526,7 @@ and type_expr ctx (e,p) (with_type:with_type) =
 	| EConst c ->
 		Codegen.type_constant ctx.com c p
     | EBinop (op,e1,e2) ->
-		type_binop ctx op e1 e2 false p
+		type_binop ctx op e1 e2 false with_type p
 	| EBlock [] when with_type <> NoValue ->
 		type_expr ctx (EObjectDecl [],p) with_type
 	| EBlock l ->
@@ -2845,7 +2880,10 @@ and type_expr ctx (e,p) (with_type:with_type) =
 		let catches = List.fold_left (fun acc (v,t,e) ->
 			let t = Typeload.load_complex_type ctx (pos e) t in
 			let rec loop t = match follow t with
-				| TInst ({ cl_path = path },params) | TEnum ({ e_path = path },params) ->
+				| TInst ({ cl_kind = KTypeParameter _} as c,_) when not (Typeload.is_generic_parameter ctx c) ->
+					error "Cannot catch non-generic type parameter" p
+				| TInst ({ cl_path = path },params)
+				| TEnum ({ e_path = path },params) ->
 					List.iter (fun pt ->
 						if pt != t_dynamic then error "Catch class parameter must be Dynamic" p;
 					) params;
@@ -3325,7 +3363,12 @@ and type_expr ctx (e,p) (with_type:with_type) =
 					| TAbstract({a_impl = Some c},_) when PMap.mem "toString" c.cl_statics -> call_to_string ctx c e
 					| _ -> e)
 			| (Meta.This,_,_) ->
-				List.hd ctx.this_stack
+				let e = List.hd ctx.this_stack in
+				let rec loop e = match e.eexpr with
+					| TConst TThis -> get_this ctx e.epos
+					| _ -> Type.map_expr loop e
+				in
+				loop e
 			| _ -> e()
 		in
 		ctx.meta <- old;