Răsfoiți Sursa

Merge branch 'development' into hl_vector_over_native_array

# Conflicts:
#	src/generators/hl2c.ml
Simon Krajewski 1 an în urmă
părinte
comite
99d06ed3d1
100 a modificat fișierele cu 1662 adăugiri și 884 ștergeri
  1. 87 30
      .github/workflows/main.yml
  2. 19 0
      .github/workflows/target.yml
  3. 1 6
      .gitignore
  4. 1 0
      Earthfile
  5. 32 8
      Makefile
  6. 7 0
      Makefile.win
  7. 1 2
      README.md
  8. 61 0
      extra/CHANGES.txt
  9. 16 8
      extra/github-actions/build-mac.yml
  10. 1 1
      extra/github-actions/build-windows.yml
  11. 2 0
      extra/github-actions/install-neko-unix.yml
  12. 1 1
      extra/github-actions/install-nsis.yml
  13. 1 1
      extra/github-actions/test-windows.yml
  14. 58 19
      extra/github-actions/workflows/main.yml
  15. 2 2
      haxe.opam
  16. 2 2
      libs/mbedtls/mbedtls.ml
  17. 51 52
      libs/mbedtls/mbedtls_stubs.c
  18. 16 1
      src-json/define.json
  19. 8 3
      src/codegen/codegen.ml
  20. 1 1
      src/codegen/genxml.ml
  21. 2 10
      src/codegen/javaModern.ml
  22. 1 1
      src/codegen/swfLoader.ml
  23. 9 12
      src/compiler/args.ml
  24. 28 10
      src/compiler/compilationCache.ml
  25. 12 4
      src/compiler/compilationContext.ml
  26. 13 8
      src/compiler/compiler.ml
  27. 35 30
      src/compiler/displayProcessing.ml
  28. 49 21
      src/compiler/generate.ml
  29. 4 4
      src/compiler/hxb/hxbData.ml
  30. 16 2
      src/compiler/hxb/hxbLib.ml
  31. 52 13
      src/compiler/hxb/hxbReader.ml
  32. 12 0
      src/compiler/hxb/hxbReaderApi.ml
  33. 124 98
      src/compiler/hxb/hxbWriter.ml
  34. 3 1
      src/compiler/hxb/hxbWriterConfig.ml
  35. 79 67
      src/compiler/messageReporting.ml
  36. 51 36
      src/compiler/server.ml
  37. 1 3
      src/compiler/serverConfig.ml
  38. 6 5
      src/context/abstractCast.ml
  39. 12 1
      src/context/common.ml
  40. 28 16
      src/context/commonCache.ml
  41. 13 21
      src/context/display/displayJson.ml
  42. 1 1
      src/context/display/displayPath.ml
  43. 1 1
      src/context/display/displayTexpr.ml
  44. 1 1
      src/context/display/documentSymbols.ml
  45. 3 3
      src/context/display/importHandling.ml
  46. 63 8
      src/context/memory.ml
  47. 1 1
      src/context/typecore.ml
  48. 1 1
      src/core/define.ml
  49. 1 1
      src/core/display/completionItem.ml
  50. 5 1
      src/core/display/displayPosition.ml
  51. 27 0
      src/core/ds/stringDynArray.ml
  52. 43 0
      src/core/ds/stringPool.ml
  53. 7 0
      src/core/error.ml
  54. 3 1
      src/core/globals.ml
  55. 1 1
      src/core/json/genjson.ml
  56. 25 7
      src/core/tFunctions.ml
  57. 2 46
      src/core/tOther.ml
  58. 10 2
      src/core/tPrinting.ml
  59. 23 5
      src/core/tType.ml
  60. 45 6
      src/core/tUnification.ml
  61. 1 0
      src/core/texpr.ml
  62. 2 2
      src/filters/exceptions.ml
  63. 21 10
      src/filters/filters.ml
  64. 3 3
      src/filters/localStatic.ml
  65. 18 7
      src/generators/gencpp.ml
  66. 160 93
      src/generators/genhl.ml
  67. 3 3
      src/generators/genjs.ml
  68. 11 8
      src/generators/genjvm.ml
  69. 14 6
      src/generators/genlua.ml
  70. 3 3
      src/generators/genneko.ml
  71. 1 1
      src/generators/genphp7.ml
  72. 2 2
      src/generators/genpy.ml
  73. 2 2
      src/generators/genswf.ml
  74. 3 3
      src/generators/genswf9.ml
  75. 8 4
      src/generators/hl2c.ml
  76. 12 6
      src/generators/hlcode.ml
  77. 10 24
      src/generators/hlinterp.ml
  78. 31 7
      src/generators/hlopt.ml
  79. 4 1
      src/macro/eval/evalContext.ml
  80. 1 0
      src/macro/eval/evalDebugMisc.ml
  81. 2 2
      src/macro/eval/evalDebugSocket.ml
  82. 15 8
      src/macro/eval/evalExceptions.ml
  83. 1 1
      src/macro/eval/evalJit.ml
  84. 1 1
      src/macro/eval/evalMain.ml
  85. 4 4
      src/macro/eval/evalSsl.ml
  86. 2 0
      src/macro/eval/evalStackTrace.ml
  87. 12 6
      src/macro/macroApi.ml
  88. 1 1
      src/optimization/analyzer.ml
  89. 4 3
      src/optimization/analyzerTexpr.ml
  90. 1 1
      src/optimization/dce.ml
  91. 2 1
      src/optimization/inline.ml
  92. 21 8
      src/optimization/inlineConstructors.ml
  93. 5 0
      src/syntax/lexer.ml
  94. 10 12
      src/typing/callUnification.ml
  95. 4 3
      src/typing/fields.ml
  96. 15 24
      src/typing/generic.ml
  97. 1 1
      src/typing/instanceBuilder.ml
  98. 62 34
      src/typing/macroContext.ml
  99. 2 2
      src/typing/matcher/compile.ml
  100. 6 1
      src/typing/matcher/exprToPattern.ml

+ 87 - 30
.github/workflows/main.yml

@@ -24,7 +24,7 @@ jobs:
           rm C:\msys64\usr\bin\bash.exe
 
       - name: choco install nsis
-        uses: nick-invision/retry@v2
+        uses: nick-invision/retry@v3
         with:
           timeout_minutes: 10
           max_attempts: 10
@@ -114,7 +114,7 @@ jobs:
           [ $(ls -1 out | wc -l) -eq "3" ]
 
       - name: Upload artifact
-        uses: actions/upload-artifact@v3
+        uses: actions/upload-artifact@v4
         with:
           name: win${{env.ARCH}}Binaries
           path: out
@@ -136,7 +136,7 @@ jobs:
 
       - name: Cache opam
         id: cache-opam
-        uses: actions/cache@v3.0.11
+        uses: actions/cache@v4
         with:
           path: ~/.opam/
           key: ${{ runner.os }}-${{ matrix.ocaml }}-${{ hashFiles('./haxe.opam', './libs/') }}
@@ -149,9 +149,11 @@ jobs:
           tar -xf $RUNNER_TEMP/neko_latest.tar.gz -C $RUNNER_TEMP
           NEKOPATH=`echo $RUNNER_TEMP/neko-*-*`
           sudo mkdir -p /usr/local/bin
+          sudo mkdir -p /usr/local/include
           sudo mkdir -p /usr/local/lib/neko
           sudo ln -s $NEKOPATH/{neko,nekoc,nekoml,nekotools}  /usr/local/bin/
           sudo ln -s $NEKOPATH/libneko.*                      /usr/local/lib/
+          sudo ln -s $NEKOPATH/include/*                      /usr/local/include/
           sudo ln -s $NEKOPATH/*.ndll                         /usr/local/lib/neko/
           echo "NEKOPATH=$NEKOPATH" >> $GITHUB_ENV
 
@@ -213,13 +215,13 @@ jobs:
           EOL
 
       - name: Upload artifact
-        uses: actions/upload-artifact@v3
+        uses: actions/upload-artifact@v4
         with:
           name: linuxBinaries${{ (matrix.ocaml == '5.0.0' && '_ocaml5') || '' }}
           path: out
 
       - name: Upload xmldoc artifact
-        uses: actions/upload-artifact@v3
+        uses: actions/upload-artifact@v4
         if: matrix.ocaml == '4.08.1'
         with:
           name: xmldoc
@@ -251,7 +253,7 @@ jobs:
       - uses: actions/checkout@main
         with:
           submodules: recursive
-      - uses: actions/download-artifact@v3
+      - uses: actions/download-artifact@v4
         with:
           name: linuxBinaries${{ (matrix.ocaml == '5.0.0' && '_ocaml5') || '' }}
           path: linuxBinaries
@@ -264,9 +266,11 @@ jobs:
           tar -xf $RUNNER_TEMP/neko_latest.tar.gz -C $RUNNER_TEMP
           NEKOPATH=`echo $RUNNER_TEMP/neko-*-*`
           sudo mkdir -p /usr/local/bin
+          sudo mkdir -p /usr/local/include
           sudo mkdir -p /usr/local/lib/neko
           sudo ln -s $NEKOPATH/{neko,nekoc,nekoml,nekotools}  /usr/local/bin/
           sudo ln -s $NEKOPATH/libneko.*                      /usr/local/lib/
+          sudo ln -s $NEKOPATH/include/*                      /usr/local/include/
           sudo ln -s $NEKOPATH/*.ndll                         /usr/local/lib/neko/
           echo "NEKOPATH=$NEKOPATH" >> $GITHUB_ENV
 
@@ -321,13 +325,13 @@ jobs:
         with:
           submodules: recursive
 
-      - uses: actions/download-artifact@v3
+      - uses: actions/download-artifact@v4
         with:
           name: linuxBinaries
           path: linuxBinaries
 
       - name: Download xmldoc artifact
-        uses: actions/download-artifact@v3
+        uses: actions/download-artifact@v4
         with:
           name: xmldoc
           path: xmldoc
@@ -340,9 +344,11 @@ jobs:
           tar -xf $RUNNER_TEMP/neko_latest.tar.gz -C $RUNNER_TEMP
           NEKOPATH=`echo $RUNNER_TEMP/neko-*-*`
           sudo mkdir -p /usr/local/bin
+          sudo mkdir -p /usr/local/include
           sudo mkdir -p /usr/local/lib/neko
           sudo ln -s $NEKOPATH/{neko,nekoc,nekoml,nekotools}  /usr/local/bin/
           sudo ln -s $NEKOPATH/libneko.*                      /usr/local/lib/
+          sudo ln -s $NEKOPATH/include/*                      /usr/local/include/
           sudo ln -s $NEKOPATH/*.ndll                         /usr/local/lib/neko/
           echo "NEKOPATH=$NEKOPATH" >> $GITHUB_ENV
 
@@ -396,7 +402,7 @@ jobs:
       FORCE_COLOR: 1
     steps:
       - name: Login to GitHub Container Registry
-        uses: docker/login-action@v2
+        uses: docker/login-action@v3
         with:
           registry: ghcr.io
           username: ${{ github.actor }}
@@ -407,7 +413,7 @@ jobs:
 
       - name: Set up QEMU
         id: qemu
-        uses: docker/setup-qemu-action@v2
+        uses: docker/setup-qemu-action@v3
         with:
             image: tonistiigi/binfmt:latest
             platforms: all
@@ -439,17 +445,23 @@ jobs:
           EARTHLY_REMOTE_CACHE: "ghcr.io/${{env.CONTAINER_REG}}_cache:build-${{env.CONTAINER_TAG}}-arm64"
 
       - name: Upload artifact
-        uses: actions/upload-artifact@v3
+        uses: actions/upload-artifact@v4
         with:
           name: linuxArm64Binaries
           path: out/linux/arm64
 
   mac-build:
-    runs-on: macos-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        os: [macos-14, macos-13]
+    runs-on: ${{ matrix.os }}
     env:
-      PLATFORM: mac
+      PLATFORM: mac${{ matrix.os == 'macos-14' && '-arm64' || '' }}
       OPAMYES: 1
       MACOSX_DEPLOYMENT_TARGET: 10.13
+      OCAML_VERSION: 5.1.1
+      CTYPES: 0.21.1
     steps:
       - uses: actions/checkout@main
         with:
@@ -457,10 +469,10 @@ jobs:
 
       - name: Cache opam
         id: cache-opam
-        uses: actions/cache@v3.0.11
+        uses: actions/cache@v4
         with:
           path: ~/.opam/
-          key: ${{ runner.os }}-${{ hashFiles('./haxe.opam', './libs/') }}
+          key: ${{ matrix.os }}-${{ hashFiles('./haxe.opam', './libs/') }}
 
       - name: Install Neko from S3
         run: |
@@ -470,9 +482,11 @@ jobs:
           tar -xf $RUNNER_TEMP/neko_latest.tar.gz -C $RUNNER_TEMP
           NEKOPATH=`echo $RUNNER_TEMP/neko-*-*`
           sudo mkdir -p /usr/local/bin
+          sudo mkdir -p /usr/local/include
           sudo mkdir -p /usr/local/lib/neko
           sudo ln -s $NEKOPATH/{neko,nekoc,nekoml,nekotools}  /usr/local/bin/
           sudo ln -s $NEKOPATH/libneko.*                      /usr/local/lib/
+          sudo ln -s $NEKOPATH/include/*                      /usr/local/include/
           sudo ln -s $NEKOPATH/*.ndll                         /usr/local/lib/neko/
           echo "NEKOPATH=$NEKOPATH" >> $GITHUB_ENV
 
@@ -494,16 +508,16 @@ jobs:
           curl -L https://github.com/madler/zlib/releases/download/v$ZLIB_VERSION/zlib-$ZLIB_VERSION.tar.gz | tar xz
           cd zlib-$ZLIB_VERSION
           ./configure
-          make && make install
+          sudo make && sudo make install
           cd ..
           curl -L https://github.com/ARMmbed/mbedtls/archive/v$MBEDTLS_VERSION.tar.gz | tar xz
           cd mbedtls-$MBEDTLS_VERSION
-          make && make install
+          sudo make && sudo make install
           cd ..
           curl -L https://github.com/PCRE2Project/pcre2/releases/download/pcre2-$PCRE2_VERSION/pcre2-$PCRE2_VERSION.tar.gz | tar xz
           cd pcre2-$PCRE2_VERSION
           ./configure --enable-unicode --enable-pcre2-8 --enable-pcre2-16 --enable-pcre2-32 --enable-unicode-properties --enable-pcre2grep-libz --enable-pcre2grep-libbz2 --enable-jit
-          make && make install
+          sudo make && sudo make install
           cd ..
 
       - name: Install OCaml libraries
@@ -512,10 +526,10 @@ jobs:
           set -ex
           opam init # --disable-sandboxing
           opam update
-          opam switch create 4.08.1
+          opam switch create ${{env.OCAML_VERSION}}
           eval $(opam env)
           opam env
-          opam pin add ctypes 0.17.1 --yes
+          opam pin add ctypes ${{env.CTYPES}} --yes
           opam pin add haxe . --no-action
           opam install haxe --deps-only --assume-depexts
           opam list
@@ -536,10 +550,18 @@ jobs:
           otool -L ./haxe
           otool -L ./haxelib
 
-      - name: Upload artifact
-        uses: actions/upload-artifact@v3
+      - name: Upload artifact (x64)
+        if: runner.arch == 'X64'
+        uses: actions/upload-artifact@v4
         with:
-          name: macBinaries
+          name: macX64Binaries
+          path: out
+
+      - name: Upload artifact (arm)
+        if: runner.arch == 'ARM64'
+        uses: actions/upload-artifact@v4
+        with:
+          name: macArmBinaries
           path: out
 
 
@@ -561,7 +583,7 @@ jobs:
       - uses: actions/checkout@main
         with:
           submodules: recursive
-      - uses: actions/download-artifact@v3
+      - uses: actions/download-artifact@v4
         with:
           name: win${{env.ARCH}}Binaries
           path: win${{env.ARCH}}Binaries
@@ -578,7 +600,7 @@ jobs:
       - name: Print Neko version
         run: neko -version 2>&1
 
-      - uses: actions/setup-node@v3
+      - uses: actions/setup-node@v4
         with:
           node-version: 18.17.1
 
@@ -639,9 +661,42 @@ jobs:
         working-directory: ${{github.workspace}}/tests
 
 
-  mac-test:
+  mac-build-universal:
     needs: mac-build
     runs-on: macos-latest
+    steps:
+      - name: Checkout the repository
+        uses: actions/checkout@main
+      - uses: actions/download-artifact@v4
+        with:
+          name: macX64Binaries
+          path: macX64Binaries
+      - uses: actions/download-artifact@v4
+        with:
+          name: macArmBinaries
+          path: macArmBinaries
+
+      - name: Make universal binary
+        run: |
+          set -ex
+          tar -xf macX64Binaries/*_bin.tar.gz -C macX64Binaries --strip-components=1
+          tar -xf macArmBinaries/*_bin.tar.gz -C macArmBinaries --strip-components=1
+          lipo -create -output haxe macX64Binaries/haxe macArmBinaries/haxe
+          lipo -create -output haxelib macX64Binaries/haxelib macArmBinaries/haxelib
+          make -s package_unix package_installer_mac PACKAGE_INSTALLER_MAC_ARCH=universal
+          ls -l out
+          otool -L ./haxe
+          otool -L ./haxelib
+
+      - name: Upload artifact (universal)
+        uses: actions/upload-artifact@v4
+        with:
+          name: macBinaries
+          path: out
+
+  mac-test:
+    needs: mac-build-universal
+    runs-on: macos-13
     env:
       PLATFORM: mac
       TEST: ${{matrix.target}}
@@ -658,7 +713,7 @@ jobs:
       - uses: actions/checkout@main
         with:
           submodules: recursive
-      - uses: actions/download-artifact@v3
+      - uses: actions/download-artifact@v4
         with:
           name: macBinaries
           path: macBinaries
@@ -671,9 +726,11 @@ jobs:
           tar -xf $RUNNER_TEMP/neko_latest.tar.gz -C $RUNNER_TEMP
           NEKOPATH=`echo $RUNNER_TEMP/neko-*-*`
           sudo mkdir -p /usr/local/bin
+          sudo mkdir -p /usr/local/include
           sudo mkdir -p /usr/local/lib/neko
           sudo ln -s $NEKOPATH/{neko,nekoc,nekoml,nekotools}  /usr/local/bin/
           sudo ln -s $NEKOPATH/libneko.*                      /usr/local/lib/
+          sudo ln -s $NEKOPATH/include/*                      /usr/local/include/
           sudo ln -s $NEKOPATH/*.ndll                         /usr/local/lib/neko/
           echo "NEKOPATH=$NEKOPATH" >> $GITHUB_ENV
 
@@ -726,7 +783,7 @@ jobs:
         uses: actions/checkout@main
 
       - name: Download build artifacts
-        uses: actions/download-artifact@v3
+        uses: actions/download-artifact@v4
 
       - name: Install awscli
         run: |
@@ -795,7 +852,7 @@ jobs:
           sudo apt-get install -qqy libc6
 
       - name: Download Haxe
-        uses: actions/download-artifact@v3
+        uses: actions/download-artifact@v4
         with:
           name: linuxBinaries
           path: linuxBinaries
@@ -811,7 +868,7 @@ jobs:
           sudo ln -s `pwd`/linuxBinaries/std /usr/local/share/haxe/std
 
       - name: Download xmldoc artifact
-        uses: actions/download-artifact@v3
+        uses: actions/download-artifact@v4
         with:
           name: xmldoc
           path: xmldoc

+ 19 - 0
.github/workflows/target.yml

@@ -0,0 +1,19 @@
+name: Check pull request target branch
+on:
+  pull_request_target:
+    types:
+      - opened
+      - reopened
+      - synchronize
+      - edited
+jobs:
+  check-branches:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Check branches
+        run: |
+          if [ ${{ github.base_ref }} != "development" ]; then
+            echo "Merge requests should target `development`."
+            exit 1
+          fi
+

+ 1 - 6
.gitignore

@@ -41,6 +41,7 @@
 /std/tools/haxelib/haxelib.n
 /std/tools/haxelib/index.n
 
+/tests/**/dump
 /tests/unit/as3
 /tests/unit/cpp
 /tests/unit/java
@@ -54,7 +55,6 @@
 /tests/unit/php
 /tests/unit/cs
 /tests/unit/cs_unsafe
-/tests/unit/dump
 /tests/unit/db.db3
 
 /tests/unit/native_java/obj
@@ -69,7 +69,6 @@
 /tests/unit/node_modules/
 
 /tests/nullsafety/bin
-/tests/nullsafety/dump
 
 /haxe.sublime*
 .idea
@@ -85,9 +84,7 @@ tests/unit/unit.py
 tests/unit/unit.py.res1.txt
 tests/unit/unit.py.res2.bin
 tests/sys/bin/
-/tests/sys/dump/
 /tests/sys/test-res/
-tests/optimization/dump/
 tests/misc/projects/*/*.n
 tests/misc/*/*/*.lua
 tests/unit/bin/
@@ -100,7 +97,6 @@ tests/misc/projects/Issue4070/cpp/
 /tests/misc/eventLoop/eventLoop.js
 /tests/misc/eventLoop/eventLoop.n
 /tests/misc/eventLoop/eventLoop.swf
-/tests/misc/eventLoop/dump
 /tests/misc/eventLoop/eventLoop.py
 /tests/misc/eventLoop/php
 *.vscode/
@@ -127,7 +123,6 @@ dev-display.hxml
 tests/sourcemaps/bin
 /*_plugin.ml
 tests/benchs/export/
-tests/benchs/dump/
 tests/display/.unittest/
 tests/unit/.unittest/
 tests/threads/export/

+ 1 - 0
Earthfile

@@ -146,6 +146,7 @@ INSTALL_NEKO:
     ARG PREFIX=/usr/local
     RUN bash -c "ln -s \"$NEKOPATH\"/{neko,nekoc,nekoml,nekotools} \"$PREFIX/bin/\""
     RUN bash -c "ln -s \"$NEKOPATH\"/libneko.* \"$PREFIX/lib/\""
+    RUN bash -c "ln -s \"$NEKOPATH\"/*.h \"$PREFIX/include/\""
     RUN mkdir -p "$PREFIX/lib/neko/"
     RUN bash -c "ln -s \"$NEKOPATH\"/*.ndll \"$PREFIX/lib/neko/\""
     RUN ldconfig

+ 32 - 8
Makefile

@@ -59,7 +59,7 @@ PACKAGE_FILE_NAME=haxe_$(COMMIT_DATE)_$(COMMIT_SHA)
 HAXE_VERSION=$(shell $(CURDIR)/$(HAXE_OUTPUT) -version 2>&1 | awk '{print $$1;}')
 HAXE_VERSION_SHORT=$(shell echo "$(HAXE_VERSION)" | grep -oE "^[0-9]+\.[0-9]+\.[0-9]+")
 
-NEKO_VERSION=2.3.0
+NEKO_VERSION=2.4.0-rc.1
 NEKO_MAJOR_VERSION=$(shell echo "$(NEKO_VERSION)" | grep -oE "^[0-9]+")
 NEKO_VERSION_TAG=v$(shell echo "$(NEKO_VERSION)" | sed "s/\./-/g")
 
@@ -104,10 +104,24 @@ copy_haxetoolkit: /cygdrive/c/HaxeToolkit/haxe/haxe.exe
 	cp $< $@
 endif
 
+ifeq ($(SYSTEM_NAME),Mac)
+# This assumes that haxelib and neko will both be installed into INSTALL_DIR,
+# which is the case when installing using the mac installer package
+HAXELIB_LFLAGS= -Wl,-rpath,$(INSTALL_DIR)/lib
+endif
+
+haxelib_unix:
+	cd $(CURDIR)/extra/haxelib_src && \
+	HAXE_STD_PATH=$(CURDIR)/std $(CURDIR)/$(HAXE_OUTPUT) client.hxml && \
+	nekotools boot -c run.n
+	$(CC) $(CURDIR)/extra/haxelib_src/run.c -o $(HAXELIB_OUTPUT) -lneko $(HAXELIB_LFLAGS)
+
 # haxelib should depends on haxe, but we don't want to do that...
-haxelib:
-	(cd $(CURDIR)/extra/haxelib_src && $(CURDIR)/$(HAXE_OUTPUT) client.hxml && nekotools boot run.n)
-	mv extra/haxelib_src/run$(EXTENSION) $(HAXELIB_OUTPUT)
+ifeq ($(SYSTEM_NAME),Windows)
+haxelib: haxelib_$(PLATFORM)
+else
+haxelib: haxelib_unix
+endif
 
 tools: haxelib
 
@@ -167,19 +181,29 @@ xmldoc:
 $(INSTALLER_TMP_DIR):
 	mkdir -p $(INSTALLER_TMP_DIR)
 
-$(INSTALLER_TMP_DIR)/neko-osx64.tar.gz: $(INSTALLER_TMP_DIR)
-	wget -nv https://github.com/HaxeFoundation/neko/releases/download/$(NEKO_VERSION_TAG)/neko-$(NEKO_VERSION)-osx64.tar.gz -O installer/neko-osx64.tar.gz
+# Can be 'universal', 'arm64', or 'x86_64'
+ifndef PACKAGE_INSTALLER_MAC_ARCH
+PACKAGE_INSTALLER_MAC_ARCH:=$(shell uname -m)
+endif
+
+$(INSTALLER_TMP_DIR)/neko-osx.tar.gz: $(INSTALLER_TMP_DIR)
+	NEKO_ARCH_SUFFIX=$$(if [ "$(PACKAGE_INSTALLER_MAC_ARCH)" = "x86_64" ]; then \
+		echo 64; \
+	else \
+		echo "-$(PACKAGE_INSTALLER_MAC_ARCH)"; \
+	fi); \
+	wget -nv https://github.com/HaxeFoundation/neko/releases/download/$(NEKO_VERSION_TAG)/neko-$(NEKO_VERSION)-osx$$NEKO_ARCH_SUFFIX.tar.gz -O installer/neko-osx.tar.gz
 
 # Installer
 
-package_installer_mac: $(INSTALLER_TMP_DIR)/neko-osx64.tar.gz package_unix
+package_installer_mac: $(INSTALLER_TMP_DIR)/neko-osx.tar.gz package_unix
 	$(eval OUTFILE := $(shell pwd)/$(PACKAGE_OUT_DIR)/$(PACKAGE_FILE_NAME)_installer.tar.gz)
 	$(eval PACKFILE := $(shell pwd)/$(PACKAGE_OUT_DIR)/$(PACKAGE_FILE_NAME)_bin.tar.gz)
 	$(eval VERSION := $(shell $(CURDIR)/$(HAXE_OUTPUT) -version 2>&1))
 	bash -c "rm -rf $(INSTALLER_TMP_DIR)/{resources,pkg,tgz,haxe.tar.gz}"
 	mkdir $(INSTALLER_TMP_DIR)/resources
 	# neko - unpack to change the dir name
-	cd $(INSTALLER_TMP_DIR)/resources && tar -zxvf ../neko-osx64.tar.gz
+	cd $(INSTALLER_TMP_DIR)/resources && tar -zxvf ../neko-osx.tar.gz
 	mv $(INSTALLER_TMP_DIR)/resources/neko* $(INSTALLER_TMP_DIR)/resources/neko
 	cd $(INSTALLER_TMP_DIR)/resources && tar -zcvf neko.tar.gz neko
 	# haxe - unpack to change the dir name

+ 7 - 0
Makefile.win

@@ -53,6 +53,13 @@ PACKAGE_FILES=$(HAXE_OUTPUT) $(HAXELIB_OUTPUT) std \
 	"$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep libmbedtls.dll | sed -e 's/^\s*//')" \
 	"$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep libmbedx509.dll | sed -e 's/^\s*//')"
 
+# haxelib should depends on haxe, but we don't want to do that...
+haxelib_win:
+	cd $(CURDIR)/extra/haxelib_src && \
+	HAXE_STD_PATH=$$(cygpath -m $(CURDIR)/std) $(CURDIR)/$(HAXE_OUTPUT) client.hxml && \
+	nekotools boot run.n
+	mv extra/haxelib_src/run$(EXTENSION) $(HAXELIB_OUTPUT)
+
 echo_package_files:
 	echo $(PACKAGE_FILES)
 

+ 1 - 2
README.md

@@ -80,9 +80,8 @@ You can get help and talk with fellow Haxers from around the world via:
  * [Haxe on Stack Overflow](https://stackoverflow.com/questions/tagged/haxe)
  * [Haxe Gitter chatroom](https://gitter.im/HaxeFoundation/haxe/)
  * [Haxe Discord server](https://discordapp.com/invite/0uEuWH3spjck73Lo)
- * [#haxe on Twitter](https://twitter.com/hashtag/haxe?src=hash)
 
-:+1: Get notified of the latest Haxe news, follow us on [Twitter](https://twitter.com/haxelang), [Facebook](https://www.facebook.com/haxe.org) and don't forget to read the [Haxe roundups](https://haxe.io/).
+:+1: Get notified of the latest Haxe news, don't forget to read the [Haxe roundups](https://haxe.io/).
 
 ## Version compatibility
 

+ 61 - 0
extra/CHANGES.txt

@@ -1,3 +1,64 @@
+2024-07-18 4.3.5
+
+	General improvements:
+
+	all : macOS universal binaries (#11572)
+	display : migrated diagnostics to Json RPC (#11707)
+	macro : expose TVar VStatic flag in macros. (#11683)
+
+	Bugfixes:
+
+	all : fix `@:structInit` with getter + setter (#11662)
+	all : add missing recursion when checking abstract casts (#11676)
+	all : fail nicer if unify_min can't find a common type (#11684)
+	all : fix pretty errors failure (#11700)
+	all : disallow local statics when inlining (#11725)
+	display : unused pattern variables should be marked as unused (#7282)
+	display : diagnostics miss "used without being initialized" errors (#7931)
+	display : recursive inline is not supported on enum abstract constructor (#11177)
+	display : Void as value error disappears on second compilation (#11184)
+	display : false positives of "This cast has no effect, but some of its sub-expressions" (#11203)
+	cpp : inherit `@:unreflective` on generic classes
+	hl : fix bit shift + assignment in while loop header (#10783)
+	hl : fix do-while loop in genhl+hlopt (#11461)
+	hl/c : use uint64 instead of uint64_t for shift cast (#11721)
+	macro : don't choke on namePos for reification pattern matching (#11671)
+
+	Deprecation / future version handling:
+
+	macro : `Compiler.include()` warning when used outside init macros
+
+2024-03-04 4.3.4
+
+	General improvements:
+
+	all : allow @:using with Class and Enum (#11553)
+	display : expose list of metadata/defines (#11399)
+
+	Bugfixes:
+
+	all : typedef vs. GADT (#11446)
+	all : don't double-throw exceptions (#11175)
+	all : fix some abstract inlining failures (#11526)
+	all : fix JsonPrinter empty parent class (#11560)
+	all : dce: clean up operator handling (#11427)
+	all : analyzer: deal with unreachable block in binops (#11402)
+	all : analyzer: don't recursively check enum values when const propagating (#11429)
+	all : analyzer: fix check for inlined purity meta
+	display : fix errors from parser missing in diagnostics (#8687)
+	display : fix display services with static extension (#11285)
+	display : fix display services with safe navigation (#11205)
+	hl : hlopt rework try-catch control flow (#11581)
+	hl/c : fix reserved keywords (#11408)
+
+	Deprecation / future version handling:
+
+	all : don't infer string on concat, when using -D haxe-next (#11318)
+	all : handle optional arguments with bind, when using -D haxe-next (#11533)
+	macro : build order vs inheritance, when using -D haxe-next (#11582)
+	macro : deprecate some API from haxe.macro.Compiler (see #11540)
+	java/jvm : warn about --java ... -D jvm vs --jvm ...
+
 2023-09-17 4.3.3
 
 	General improvements:

+ 16 - 8
extra/github-actions/build-mac.yml

@@ -13,16 +13,16 @@
     curl -L https://github.com/madler/zlib/releases/download/v$ZLIB_VERSION/zlib-$ZLIB_VERSION.tar.gz | tar xz
     cd zlib-$ZLIB_VERSION
     ./configure
-    make && make install
+    sudo make && sudo make install
     cd ..
     curl -L https://github.com/ARMmbed/mbedtls/archive/v$MBEDTLS_VERSION.tar.gz | tar xz
     cd mbedtls-$MBEDTLS_VERSION
-    make && make install
+    sudo make && sudo make install
     cd ..
     curl -L https://github.com/PCRE2Project/pcre2/releases/download/pcre2-$PCRE2_VERSION/pcre2-$PCRE2_VERSION.tar.gz | tar xz
     cd pcre2-$PCRE2_VERSION
     ./configure --enable-unicode --enable-pcre2-8 --enable-pcre2-16 --enable-pcre2-32 --enable-unicode-properties --enable-pcre2grep-libz --enable-pcre2grep-libbz2 --enable-jit
-    make && make install
+    sudo make && sudo make install
     cd ..
 
 - name: Install OCaml libraries
@@ -31,10 +31,10 @@
     set -ex
     opam init # --disable-sandboxing
     opam update
-    opam switch create 4.08.1
+    opam switch create ${{env.OCAML_VERSION}}
     eval $(opam env)
     opam env
-    opam pin add ctypes 0.17.1 --yes
+    opam pin add ctypes ${{env.CTYPES}} --yes
     opam pin add haxe . --no-action
     opam install haxe --deps-only --assume-depexts
     opam list
@@ -55,8 +55,16 @@
     otool -L ./haxe
     otool -L ./haxelib
 
-- name: Upload artifact
-  uses: actions/upload-artifact@v3
+- name: Upload artifact (x64)
+  if: runner.arch == 'X64'
+  uses: actions/upload-artifact@v4
   with:
-    name: macBinaries
+    name: macX64Binaries
+    path: out
+
+- name: Upload artifact (arm)
+  if: runner.arch == 'ARM64'
+  uses: actions/upload-artifact@v4
+  with:
+    name: macArmBinaries
     path: out

+ 1 - 1
extra/github-actions/build-windows.yml

@@ -34,7 +34,7 @@
     [ $(ls -1 out | wc -l) -eq "3" ]
 
 - name: Upload artifact
-  uses: actions/upload-artifact@v3
+  uses: actions/upload-artifact@v4
   with:
     name: win${{env.ARCH}}Binaries
     path: out

+ 2 - 0
extra/github-actions/install-neko-unix.yml

@@ -6,9 +6,11 @@
     tar -xf $RUNNER_TEMP/neko_latest.tar.gz -C $RUNNER_TEMP
     NEKOPATH=`echo $RUNNER_TEMP/neko-*-*`
     sudo mkdir -p /usr/local/bin
+    sudo mkdir -p /usr/local/include
     sudo mkdir -p /usr/local/lib/neko
     sudo ln -s $NEKOPATH/{neko,nekoc,nekoml,nekotools}  /usr/local/bin/
     sudo ln -s $NEKOPATH/libneko.*                      /usr/local/lib/
+    sudo ln -s $NEKOPATH/include/*                      /usr/local/include/
     sudo ln -s $NEKOPATH/*.ndll                         /usr/local/lib/neko/
     echo "NEKOPATH=$NEKOPATH" >> $GITHUB_ENV
 

+ 1 - 1
extra/github-actions/install-nsis.yml

@@ -1,5 +1,5 @@
 - name: choco install nsis
-  uses: nick-invision/retry@v2
+  uses: nick-invision/retry@v3
   with:
     timeout_minutes: 10
     max_attempts: 10

+ 1 - 1
extra/github-actions/test-windows.yml

@@ -1,4 +1,4 @@
-- uses: actions/setup-node@v3
+- uses: actions/setup-node@v4
   with:
     node-version: 18.17.1
 

+ 58 - 19
extra/github-actions/workflows/main.yml

@@ -44,7 +44,7 @@ jobs:
 
       - name: Cache opam
         id: cache-opam
-        uses: actions/cache@v3.0.11
+        uses: actions/cache@v4
         with:
           path: ~/.opam/
           key: ${{ runner.os }}-${{ matrix.ocaml }}-${{ hashFiles('./haxe.opam', './libs/') }}
@@ -105,13 +105,13 @@ jobs:
           EOL
 
       - name: Upload artifact
-        uses: actions/upload-artifact@v3
+        uses: actions/upload-artifact@v4
         with:
           name: linuxBinaries${{ (matrix.ocaml == '5.0.0' && '_ocaml5') || '' }}
           path: out
 
       - name: Upload xmldoc artifact
-        uses: actions/upload-artifact@v3
+        uses: actions/upload-artifact@v4
         if: matrix.ocaml == '4.08.1'
         with:
           name: xmldoc
@@ -143,7 +143,7 @@ jobs:
       - uses: actions/checkout@main
         with:
           submodules: recursive
-      - uses: actions/download-artifact@v3
+      - uses: actions/download-artifact@v4
         with:
           name: linuxBinaries${{ (matrix.ocaml == '5.0.0' && '_ocaml5') || '' }}
           path: linuxBinaries
@@ -197,13 +197,13 @@ jobs:
         with:
           submodules: recursive
 
-      - uses: actions/download-artifact@v3
+      - uses: actions/download-artifact@v4
         with:
           name: linuxBinaries
           path: linuxBinaries
 
       - name: Download xmldoc artifact
-        uses: actions/download-artifact@v3
+        uses: actions/download-artifact@v4
         with:
           name: xmldoc
           path: xmldoc
@@ -256,7 +256,7 @@ jobs:
       FORCE_COLOR: 1
     steps:
       - name: Login to GitHub Container Registry
-        uses: docker/login-action@v2
+        uses: docker/login-action@v3
         with:
           registry: ghcr.io
           username: ${{ github.actor }}
@@ -267,7 +267,7 @@ jobs:
 
       - name: Set up QEMU
         id: qemu
-        uses: docker/setup-qemu-action@v2
+        uses: docker/setup-qemu-action@v3
         with:
             image: tonistiigi/binfmt:latest
             platforms: all
@@ -299,17 +299,23 @@ jobs:
           EARTHLY_REMOTE_CACHE: "ghcr.io/${{env.CONTAINER_REG}}_cache:build-${{env.CONTAINER_TAG}}-arm64"
 
       - name: Upload artifact
-        uses: actions/upload-artifact@v3
+        uses: actions/upload-artifact@v4
         with:
           name: linuxArm64Binaries
           path: out/linux/arm64
 
   mac-build:
-    runs-on: macos-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        os: [macos-14, macos-13]
+    runs-on: ${{ matrix.os }}
     env:
-      PLATFORM: mac
+      PLATFORM: mac${{ matrix.os == 'macos-14' && '-arm64' || '' }}
       OPAMYES: 1
       MACOSX_DEPLOYMENT_TARGET: 10.13
+      OCAML_VERSION: 5.1.1
+      CTYPES: 0.21.1
     steps:
       - uses: actions/checkout@main
         with:
@@ -317,10 +323,10 @@ jobs:
 
       - name: Cache opam
         id: cache-opam
-        uses: actions/cache@v3.0.11
+        uses: actions/cache@v4
         with:
           path: ~/.opam/
-          key: ${{ runner.os }}-${{ hashFiles('./haxe.opam', './libs/') }}
+          key: ${{ matrix.os }}-${{ hashFiles('./haxe.opam', './libs/') }}
 
       @import install-neko-unix.yml
       @import build-mac.yml
@@ -343,7 +349,7 @@ jobs:
       - uses: actions/checkout@main
         with:
           submodules: recursive
-      - uses: actions/download-artifact@v3
+      - uses: actions/download-artifact@v4
         with:
           name: win${{env.ARCH}}Binaries
           path: win${{env.ARCH}}Binaries
@@ -351,9 +357,42 @@ jobs:
       @import install-neko-windows.yml
       @import test-windows.yml
 
-  mac-test:
+  mac-build-universal:
     needs: mac-build
     runs-on: macos-latest
+    steps:
+      - name: Checkout the repository
+        uses: actions/checkout@main
+      - uses: actions/download-artifact@v4
+        with:
+          name: macX64Binaries
+          path: macX64Binaries
+      - uses: actions/download-artifact@v4
+        with:
+          name: macArmBinaries
+          path: macArmBinaries
+
+      - name: Make universal binary
+        run: |
+          set -ex
+          tar -xf macX64Binaries/*_bin.tar.gz -C macX64Binaries --strip-components=1
+          tar -xf macArmBinaries/*_bin.tar.gz -C macArmBinaries --strip-components=1
+          lipo -create -output haxe macX64Binaries/haxe macArmBinaries/haxe
+          lipo -create -output haxelib macX64Binaries/haxelib macArmBinaries/haxelib
+          make -s package_unix package_installer_mac PACKAGE_INSTALLER_MAC_ARCH=universal
+          ls -l out
+          otool -L ./haxe
+          otool -L ./haxelib
+
+      - name: Upload artifact (universal)
+        uses: actions/upload-artifact@v4
+        with:
+          name: macBinaries
+          path: out
+
+  mac-test:
+    needs: mac-build-universal
+    runs-on: macos-13
     env:
       PLATFORM: mac
       TEST: ${{matrix.target}}
@@ -370,7 +409,7 @@ jobs:
       - uses: actions/checkout@main
         with:
           submodules: recursive
-      - uses: actions/download-artifact@v3
+      - uses: actions/download-artifact@v4
         with:
           name: macBinaries
           path: macBinaries
@@ -390,7 +429,7 @@ jobs:
         uses: actions/checkout@main
 
       - name: Download build artifacts
-        uses: actions/download-artifact@v3
+        uses: actions/download-artifact@v4
 
       - name: Install awscli
         run: |
@@ -459,7 +498,7 @@ jobs:
           sudo apt-get install -qqy libc6
 
       - name: Download Haxe
-        uses: actions/download-artifact@v3
+        uses: actions/download-artifact@v4
         with:
           name: linuxBinaries
           path: linuxBinaries
@@ -475,7 +514,7 @@ jobs:
           sudo ln -s `pwd`/linuxBinaries/std /usr/local/share/haxe/std
 
       - name: Download xmldoc artifact
-        uses: actions/download-artifact@v3
+        uses: actions/download-artifact@v4
         with:
           name: xmldoc
           path: xmldoc

+ 2 - 2
haxe.opam

@@ -22,7 +22,7 @@ depends: [
   ("ocaml" {>= "5.0"} & ("camlp5" {build}))
     | ("ocaml" {>= "4.08" & < "5.0"} & ("camlp5" {build & = "8.00.03"}))
   "ocamlfind" {build}
-  "dune" {>= "1.11"}
+  "dune" {>= "1.11" & < "3.16"}
   "sedlex" {>= "2.0"}
   "xml-light"
   "extlib" {>= "1.7.8"}
@@ -31,7 +31,7 @@ depends: [
   "conf-libpcre2-8"
   "conf-zlib"
   "conf-neko"
-  "luv" {>= "0.5.12"}
+  "luv" {= "0.5.12"}
   "ipaddr"
   "terminal_size"
 ]

+ 2 - 2
libs/mbedtls/mbedtls.ml

@@ -43,8 +43,8 @@ external mbedtls_ssl_setup : mbedtls_ssl_context -> mbedtls_ssl_config -> mbedtl
 external mbedtls_ssl_write : mbedtls_ssl_context -> bytes -> int -> int -> mbedtls_result = "ml_mbedtls_ssl_write"
 
 external mbedtls_pk_init : unit -> mbedtls_pk_context = "ml_mbedtls_pk_init"
-external mbedtls_pk_parse_key : mbedtls_pk_context -> bytes -> string option -> mbedtls_result = "ml_mbedtls_pk_parse_key"
-external mbedtls_pk_parse_keyfile : mbedtls_pk_context -> string -> string option -> mbedtls_result = "ml_mbedtls_pk_parse_keyfile"
+external mbedtls_pk_parse_key : mbedtls_pk_context -> bytes -> string option -> mbedtls_ctr_drbg_context -> mbedtls_result = "ml_mbedtls_pk_parse_key"
+external mbedtls_pk_parse_keyfile : mbedtls_pk_context -> string -> string option -> mbedtls_ctr_drbg_context -> mbedtls_result = "ml_mbedtls_pk_parse_keyfile"
 external mbedtls_pk_parse_public_keyfile : mbedtls_pk_context -> string -> mbedtls_result = "ml_mbedtls_pk_parse_public_keyfile"
 external mbedtls_pk_parse_public_key : mbedtls_pk_context -> bytes -> mbedtls_result = "ml_mbedtls_pk_parse_public_key"
 

+ 51 - 52
libs/mbedtls/mbedtls_stubs.c

@@ -1,4 +1,3 @@
-#include <ctype.h>
 #include <string.h>
 #include <stdio.h>
 
@@ -18,13 +17,10 @@
 #include <caml/callback.h>
 #include <caml/custom.h>
 
-#include "mbedtls/debug.h"
 #include "mbedtls/error.h"
-#include "mbedtls/config.h"
 #include "mbedtls/ssl.h"
 #include "mbedtls/entropy.h"
 #include "mbedtls/ctr_drbg.h"
-#include "mbedtls/certs.h"
 #include "mbedtls/oid.h"
 
 #define PVoid_val(v) (*((void**) Data_custom_val(v)))
@@ -84,7 +80,7 @@ CAMLprim value ml_mbedtls_ctr_drbg_init(void) {
 
 CAMLprim value ml_mbedtls_ctr_drbg_random(value p_rng, value output, value output_len) {
 	CAMLparam3(p_rng, output, output_len);
-	CAMLreturn(Val_int(mbedtls_ctr_drbg_random(CtrDrbg_val(p_rng), String_val(output), Int_val(output_len))));
+	CAMLreturn(Val_int(mbedtls_ctr_drbg_random(CtrDrbg_val(p_rng), Bytes_val(output), Int_val(output_len))));
 }
 
 CAMLprim value ml_mbedtls_ctr_drbg_seed(value ctx, value p_entropy, value custom) {
@@ -124,7 +120,7 @@ CAMLprim value ml_mbedtls_entropy_init(void) {
 
 CAMLprim value ml_mbedtls_entropy_func(value data, value output, value len) {
 	CAMLparam3(data, output, len);
-	CAMLreturn(Val_int(mbedtls_entropy_func(PVoid_val(data), String_val(output), Int_val(len))));
+	CAMLreturn(Val_int(mbedtls_entropy_func(PVoid_val(data), Bytes_val(output), Int_val(len))));
 }
 
 // Certificate
@@ -171,7 +167,7 @@ CAMLprim value ml_mbedtls_x509_next(value chain) {
 
 CAMLprim value ml_mbedtls_x509_crt_parse(value chain, value bytes) {
 	CAMLparam2(chain, bytes);
-	const char* buf = String_val(bytes);
+	const unsigned char* buf = Bytes_val(bytes);
 	int len = caml_string_length(bytes);
 	CAMLreturn(Val_int(mbedtls_x509_crt_parse(X509Crt_val(chain), buf, len + 1)));
 }
@@ -191,8 +187,7 @@ CAMLprim value ml_mbedtls_x509_crt_parse_path(value chain, value path) {
 value caml_string_of_asn1_buf(mbedtls_asn1_buf* dat) {
 	CAMLparam0();
 	CAMLlocal1(s);
-	s = caml_alloc_string(dat->len);
-	memcpy(String_val(s), dat->p, dat->len);
+	s = caml_alloc_initialized_string(dat->len, (const char *)dat->p);
 	CAMLreturn(s);
 }
 
@@ -200,7 +195,11 @@ CAMLprim value hx_cert_get_alt_names(value chain) {
 	CAMLparam1(chain);
 	CAMLlocal1(obj);
 	mbedtls_x509_crt* cert = X509Crt_val(chain);
-	if (cert->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME == 0 || &cert->subject_alt_names == NULL) {
+#if MBEDTLS_VERSION_MAJOR >= 3
+	if (!mbedtls_x509_crt_has_ext_type(cert, MBEDTLS_X509_EXT_SUBJECT_ALT_NAME)) {
+#else
+	if ((cert->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME) == 0) {
+#endif
 		obj = Atom(0);
 	} else {
 		mbedtls_asn1_sequence* cur = &cert->subject_alt_names;
@@ -366,29 +365,39 @@ CAMLprim value ml_mbedtls_pk_init(void) {
 	CAMLreturn(obj);
 }
 
-CAMLprim value ml_mbedtls_pk_parse_key(value ctx, value key, value password) {
-	CAMLparam3(ctx, key, password);
-	const char* pwd = NULL;
+CAMLprim value ml_mbedtls_pk_parse_key(value ctx, value key, value password, value rng) {
+	CAMLparam4(ctx, key, password, rng);
+	const unsigned char* pwd = NULL;
 	size_t pwdlen = 0;
 	if (password != Val_none) {
-		pwd = String_val(Field(password, 0));
+		pwd = Bytes_val(Field(password, 0));
 		pwdlen = caml_string_length(Field(password, 0));
 	}
-	CAMLreturn(mbedtls_pk_parse_key(PkContext_val(ctx), String_val(key), caml_string_length(key) + 1, pwd, pwdlen));
+	#if MBEDTLS_VERSION_MAJOR >= 3
+	mbedtls_ctr_drbg_context *ctr_drbg = CtrDrbg_val(rng);
+	CAMLreturn(mbedtls_pk_parse_key(PkContext_val(ctx), Bytes_val(key), caml_string_length(key) + 1, pwd, pwdlen, mbedtls_ctr_drbg_random, NULL));
+	#else
+	CAMLreturn(mbedtls_pk_parse_key(PkContext_val(ctx), Bytes_val(key), caml_string_length(key) + 1, pwd, pwdlen));
+	#endif
 }
 
-CAMLprim value ml_mbedtls_pk_parse_keyfile(value ctx, value path, value password) {
-	CAMLparam3(ctx, path, password);
+CAMLprim value ml_mbedtls_pk_parse_keyfile(value ctx, value path, value password, value rng) {
+	CAMLparam4(ctx, path, password, rng);
 	const char* pwd = NULL;
 	if (password != Val_none) {
 		pwd = String_val(Field(password, 0));
 	}
+	#if MBEDTLS_VERSION_MAJOR >= 3
+	mbedtls_ctr_drbg_context *ctr_drbg = CtrDrbg_val(rng);
+	CAMLreturn(mbedtls_pk_parse_keyfile(PkContext_val(ctx), String_val(path), pwd, mbedtls_ctr_drbg_random, ctr_drbg));
+	#else
 	CAMLreturn(mbedtls_pk_parse_keyfile(PkContext_val(ctx), String_val(path), pwd));
+	#endif
 }
 
 CAMLprim value ml_mbedtls_pk_parse_public_key(value ctx, value key) {
 	CAMLparam2(ctx, key);
-	CAMLreturn(mbedtls_pk_parse_public_key(PkContext_val(ctx), String_val(key), caml_string_length(key) + 1));
+	CAMLreturn(mbedtls_pk_parse_public_key(PkContext_val(ctx), Bytes_val(key), caml_string_length(key) + 1));
 }
 
 CAMLprim value ml_mbedtls_pk_parse_public_keyfile(value ctx, value path) {
@@ -446,15 +455,14 @@ CAMLprim value ml_mbedtls_ssl_handshake(value ssl) {
 
 CAMLprim value ml_mbedtls_ssl_read(value ssl, value buf, value pos, value len) {
 	CAMLparam4(ssl, buf, pos, len);
-	CAMLreturn(Val_int(mbedtls_ssl_read(SslContext_val(ssl), String_val(buf) + Int_val(pos), Int_val(len))));
+	CAMLreturn(Val_int(mbedtls_ssl_read(SslContext_val(ssl), Bytes_val(buf) + Int_val(pos), Int_val(len))));
 }
 
 static int bio_write_cb(void* ctx, const unsigned char* buf, size_t len) {
 	CAMLparam0();
 	CAMLlocal3(r, s, vctx);
-	vctx = (value)ctx;
-	s = caml_alloc_string(len);
-	memcpy(String_val(s), buf, len);
+	vctx = *(value*)ctx;
+	s = caml_alloc_initialized_string(len, (const char*)buf);
 	r = caml_callback2(Field(vctx, 1), Field(vctx, 0), s);
 	CAMLreturn(Int_val(r));
 }
@@ -462,7 +470,7 @@ static int bio_write_cb(void* ctx, const unsigned char* buf, size_t len) {
 static int bio_read_cb(void* ctx, unsigned char* buf, size_t len) {
 	CAMLparam0();
 	CAMLlocal3(r, s, vctx);
-	vctx = (value)ctx;
+	vctx = *(value*)ctx;
 	s = caml_alloc_string(len);
 	r = caml_callback2(Field(vctx, 2), Field(vctx, 0), s);
 	memcpy(buf, String_val(s), len);
@@ -476,7 +484,11 @@ CAMLprim value ml_mbedtls_ssl_set_bio(value ssl, value p_bio, value f_send, valu
 	Store_field(ctx, 0, p_bio);
 	Store_field(ctx, 1, f_send);
 	Store_field(ctx, 2, f_recv);
-	mbedtls_ssl_set_bio(SslContext_val(ssl), (void*)ctx, bio_write_cb, bio_read_cb, NULL);
+	// TODO: this allocation is leaked
+	value *location = malloc(sizeof(value));
+	*location = ctx;
+	caml_register_generational_global_root(location);
+	mbedtls_ssl_set_bio(SslContext_val(ssl), (void*)location, bio_write_cb, bio_read_cb, NULL);
 	CAMLreturn(Val_unit);
 }
 
@@ -492,7 +504,7 @@ CAMLprim value ml_mbedtls_ssl_setup(value ssl, value conf) {
 
 CAMLprim value ml_mbedtls_ssl_write(value ssl, value buf, value pos, value len) {
 	CAMLparam4(ssl, buf, pos, len);
-	CAMLreturn(Val_int(mbedtls_ssl_write(SslContext_val(ssl), String_val(buf) + Int_val(pos), Int_val(len))));
+	CAMLreturn(Val_int(mbedtls_ssl_write(SslContext_val(ssl), Bytes_val(buf) + Int_val(pos), Int_val(len))));
 }
 
 // glue
@@ -520,36 +532,23 @@ CAMLprim value hx_cert_load_defaults(value certificate) {
 	#endif
 
 	#ifdef __APPLE__
-	CFMutableDictionaryRef search;
-	CFArrayRef result;
-	SecKeychainRef keychain;
-	SecCertificateRef item;
-	CFDataRef dat;
-	// Load keychain
-	if (SecKeychainOpen("/System/Library/Keychains/SystemRootCertificates.keychain", &keychain) == errSecSuccess) {
-		// Search for certificates
-		search = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
-		CFDictionarySetValue(search, kSecClass, kSecClassCertificate);
-		CFDictionarySetValue(search, kSecMatchLimit, kSecMatchLimitAll);
-		CFDictionarySetValue(search, kSecReturnRef, kCFBooleanTrue);
-		CFDictionarySetValue(search, kSecMatchSearchList, CFArrayCreate(NULL, (const void **)&keychain, 1, NULL));
-		if (SecItemCopyMatching(search, (CFTypeRef *)&result) == errSecSuccess) {
-			CFIndex n = CFArrayGetCount(result);
-			for (CFIndex i = 0; i < n; i++) {
-				item = (SecCertificateRef)CFArrayGetValueAtIndex(result, i);
-
-				// Get certificate in DER format
-				dat = SecCertificateCopyData(item);
-				if (dat) {
-					r = mbedtls_x509_crt_parse_der(chain, (unsigned char *)CFDataGetBytePtr(dat), CFDataGetLength(dat));
-					CFRelease(dat);
-					if (r != 0) {
-						CAMLreturn(Val_int(r));
-					}
+	CFArrayRef certs;
+	if (SecTrustCopyAnchorCertificates(&certs) == errSecSuccess) {
+		CFIndex count = CFArrayGetCount(certs);
+		for(CFIndex i = 0; i < count; i++) {
+			SecCertificateRef item = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i);
+
+			// Get certificate in DER format
+			CFDataRef data = SecCertificateCopyData(item);
+			if(data) {
+				r = mbedtls_x509_crt_parse_der(chain, (unsigned char *)CFDataGetBytePtr(data), CFDataGetLength(data));
+				CFRelease(data);
+				if (r != 0) {
+					CAMLreturn(Val_int(r));
 				}
 			}
 		}
-		CFRelease(keychain);
+		CFRelease(certs);
 	}
 	#endif
 

+ 16 - 1
src-json/define.json

@@ -66,6 +66,11 @@
 		"define": "debug",
 		"doc": "Activated when compiling with -debug."
 	},
+	{
+		"name": "DisableHxbCache",
+		"define": "disable-hxb-cache",
+		"doc": "Use in-memory cache instead of hxb powered cache."
+	},
 	{
 		"name": "DisableUnicodeStrings",
 		"define": "disable-unicode-strings",
@@ -160,6 +165,11 @@
 		"doc": "Record per-method execution times in macro/interp mode. Implies eval-stack.",
 		"platforms": ["eval"]
 	},
+	{
+		"name": "FailFast",
+		"define": "fail-fast",
+		"doc": "Abort compilation when first error occurs."
+	},
 	{
 		"name": "FilterTimes",
 		"define": "filter-times",
@@ -256,6 +266,11 @@
 		"platforms": ["hl"],
 		"params": ["version"]
 	},
+	{
+		"name": "HxbTimes",
+		"define": "hxb-times",
+		"doc": "Display hxb timing when used with `--times`."
+	},
 	{
 		"name": "HxcppApiLevel",
 		"define": "hxcpp-api-level",
@@ -781,7 +796,7 @@
 	{
 		"name": "MessageReporting",
 		"define": "message.reporting",
-		"doc": "Select message reporting mode for compiler output. (default: classic)",
+		"doc": "Select message reporting mode for compiler output. (default: pretty)",
 		"params": ["mode: classic | pretty | indent"]
 	},
 	{

+ 8 - 3
src/codegen/codegen.ml

@@ -315,7 +315,7 @@ module Dump = struct
 					print "\n");
 				print "}";
 			| Type.TEnumDecl e ->
-				print "%s%s%senum %s%s {\n" (s_metas e.e_meta "") (if e.e_private then "private " else "") (if e.e_extern then "extern " else "") (s_type_path path) (params e.e_params);
+				print "%s%s%senum %s%s {\n" (s_metas e.e_meta "") (if e.e_private then "private " else "") (if has_enum_flag e EnExtern then "extern " else "") (s_type_path path) (params e.e_params);
 				List.iter (fun n ->
 					let f = PMap.find n e.e_constrs in
 					print "\t%s%s;\n" f.ef_name (
@@ -389,9 +389,14 @@ module Dump = struct
 		List.iter (fun m ->
 			print "%s:\n" (Path.UniqueKey.lazy_path m.m_extra.m_file);
 			PMap.iter (fun _ mdep ->
-				let m2 = com.module_lut#find mdep.md_path in
+				let (ctx,m2) = match mdep.md_kind with
+					| MMacro when not com.is_macro_context ->
+						("[macro] ", (Option.get (com.get_macros())).module_lut#find mdep.md_path)
+					| _ ->
+						("", com.module_lut#find mdep.md_path)
+				in
 				let file = Path.UniqueKey.lazy_path m2.m_extra.m_file in
-				print "\t%s\n" file;
+				print "\t%s%s\n" ctx file;
 				let l = try Hashtbl.find dep file with Not_found -> [] in
 				Hashtbl.replace dep file (m :: l)
 			) m.m_extra.m_deps;

+ 1 - 1
src/codegen/genxml.ml

@@ -70,7 +70,7 @@ let tpath t =
 	real_path i.mt_path i.mt_meta
 
 let rec follow_param t =
-	match t with
+	match (follow_lazy t) with
 	| TMono r ->
 		(match r.tm_type with
 		| Some t -> follow_param t

+ 2 - 10
src/codegen/javaModern.ml

@@ -754,11 +754,7 @@ module Converter = struct
 		tp
 
 	let convert_enum (jc : jclass) (file : string) =
-		let p = {
-			pfile = file;
-			pmin = 0;
-			pmax = 0
-		} in
+		let p = file_pos file in
 		let meta = ref [] in
 		let add_meta m = meta := m :: !meta in
 		let data = ref [] in
@@ -920,11 +916,7 @@ module Converter = struct
 		cff
 
 	let convert_class ctx (jc : jclass) (file : string) =
-		let p = {
-			pfile = file;
-			pmin = 0;
-			pmax = 0
-		} in
+		let p = file_pos file in
 		let flags = ref [HExtern] in
 		let meta = ref [] in
 		let add_flag f = flags := f :: !flags in

+ 1 - 1
src/codegen/swfLoader.ml

@@ -147,7 +147,7 @@ let is_valid_path com pack name =
 
 let build_class com c file =
 	let path = (make_tpath c.hlc_name).path in
-	let pos = { pfile = file ^ "@" ^ s_type_path (path.tpackage,path.tname); pmin = 0; pmax = 0 } in
+	let pos = file_pos (file ^ "@" ^ s_type_path (path.tpackage,path.tname)) in
 	match path with
 	| { tpackage = ["flash";"utils"]; tname = ("Object"|"Function") } ->
 		let inf = {

+ 9 - 12
src/compiler/args.ml

@@ -154,8 +154,7 @@ let parse_args com =
 			com.debug <- true;
 		),"","add debug information to the compiled code");
 		("Miscellaneous",["--version"],["-version"],Arg.Unit (fun() ->
-			com.info s_version_full null_pos;
-			actx.did_something <- true;
+			raise (Helper.HelpMessage s_version_full);
 		),"","print version and exit");
 		("Miscellaneous", ["-h";"--help"], ["-help"], Arg.Unit (fun () ->
 			raise (Arg.Help "")
@@ -163,31 +162,27 @@ let parse_args com =
 		("Miscellaneous",["--help-defines"],[], Arg.Unit (fun() ->
 			let all,max_length = Define.get_documentation_list com.user_defines in
 			let all = List.map (fun (n,doc) -> Printf.sprintf " %-*s: %s" max_length n (limit_string doc (max_length + 3))) all in
-			List.iter (fun msg -> com.print (msg ^ "\n")) all;
-			actx.did_something <- true
+			raise (Helper.HelpMessage (ExtLib.String.join "\n" all));
 		),"","print help for all compiler specific defines");
 		("Miscellaneous",["--help-user-defines"],[], Arg.Unit (fun() ->
 			actx.did_something <- true;
 			com.callbacks#add_after_init_macros (fun() ->
 				let all,max_length = Define.get_user_documentation_list com.user_defines in
 				let all = List.map (fun (n,doc) -> Printf.sprintf " %-*s: %s" max_length n (limit_string doc (max_length + 3))) all in
-				List.iter (fun msg -> com.print (msg ^ "\n")) all;
-				raise Abort
+				raise (Helper.HelpMessage (ExtLib.String.join "\n" all));
 			)
 		),"","print help for all user defines");
 		("Miscellaneous",["--help-metas"],[], Arg.Unit (fun() ->
 			let all,max_length = Meta.get_documentation_list com.user_metas in
 			let all = List.map (fun (n,doc) -> Printf.sprintf " %-*s: %s" max_length n (limit_string doc (max_length + 3))) all in
-			List.iter (fun msg -> com.print (msg ^ "\n")) all;
-			actx.did_something <- true
+			raise (Helper.HelpMessage (ExtLib.String.join "\n" all));
 		),"","print help for all compiler metadatas");
 		("Miscellaneous",["--help-user-metas"],[], Arg.Unit (fun() ->
 			actx.did_something <- true;
 			com.callbacks#add_after_init_macros (fun() ->
 				let all,max_length = Meta.get_user_documentation_list com.user_metas in
 				let all = List.map (fun (n,doc) -> Printf.sprintf " %-*s: %s" max_length n (limit_string doc (max_length + 3))) all in
-				List.iter (fun msg -> com.print (msg ^ "\n")) all;
-				raise Abort
+				raise (Helper.HelpMessage (ExtLib.String.join "\n" all));
 			)
 		),"","print help for all user metadatas");
 	] in
@@ -298,7 +293,7 @@ let parse_args com =
 		),"<directory>","set current working directory");
 		("Compilation",["--haxelib-global"],[], Arg.Unit (fun () -> ()),"","pass --global argument to haxelib");
 		("Compilation",["-w"],[], Arg.String (fun s ->
-			let p = { pfile = "-w " ^ s; pmin = 0; pmax = 0 } in
+			let p = fake_pos ("-w " ^ s) in
 			let l = Warning.parse_options s p in
 			com.warning_options <- l :: com.warning_options
 		),"<warning list>","enable or disable specific warnings");
@@ -330,11 +325,13 @@ let parse_args com =
 					List.rev acc
 			in
 			let args = loop [] args in
-			Arg.parse_argv ~current (Array.of_list ("" :: args)) all_args_spec args_callback "";
+			Arg.parse_argv ~current (Array.of_list ("Haxe" :: args)) all_args_spec args_callback "";
 		with
 		| Arg.Help _ ->
 			raise (Helper.HelpMessage (usage_string all_args usage))
 		| Arg.Bad msg ->
+			(* Strip error prefix added by ocaml's arg parser *)
+			let msg = if ExtLib.String.starts_with msg "Haxe: " then (String.sub msg 6 ((String.length msg) - 6)) else msg in
 			let first_line = List.nth (Str.split (Str.regexp "\n") msg) 0 in
 			let new_msg = (Printf.sprintf "%s" first_line) in
 			let r = Str.regexp "unknown option [`']?\\([-A-Za-z]+\\)[`']?" in

+ 28 - 10
src/compiler/compilationCache.ml

@@ -35,6 +35,8 @@ class context_cache (index : int) (sign : Digest.t) = object(self)
 	val files : (Path.UniqueKey.t,cached_file) Hashtbl.t = Hashtbl.create 0
 	val modules : (path,module_def) Hashtbl.t = Hashtbl.create 0
 	val binary_cache : (path,HxbData.module_cache) Hashtbl.t = Hashtbl.create 0
+	val tmp_binary_cache : (path,HxbData.module_cache) Hashtbl.t = Hashtbl.create 0
+	val string_pool  = StringPool.create ()
 	val removed_files = Hashtbl.create 0
 	val mutable json = JNull
 	val mutable initialized = false
@@ -66,15 +68,25 @@ class context_cache (index : int) (sign : Digest.t) = object(self)
 	method find_module_opt path =
 		Hashtbl.find_opt modules path
 
+	method get_hxb_module path =
+		try Hashtbl.find tmp_binary_cache path
+		with Not_found ->
+			let mc = Hashtbl.find binary_cache path in
+			let m_extra = { mc.mc_extra with m_deps = mc.mc_extra.m_deps } in
+			let mc = { mc with mc_extra = m_extra } in
+			Hashtbl.add tmp_binary_cache path mc;
+			mc
+
 	method find_module_extra path =
-		try (Hashtbl.find modules path).m_extra with Not_found -> (Hashtbl.find binary_cache path).mc_extra
+		try (Hashtbl.find modules path).m_extra
+		with Not_found -> (self#get_hxb_module path).mc_extra
 
-	method cache_module config warn anon_identification path m =
+	method cache_hxb_module config warn anon_identification path m =
 		match m.m_extra.m_kind with
 		| MImport ->
 			Hashtbl.add modules m.m_path m
 		| _ ->
-			let writer = HxbWriter.create config warn anon_identification in
+			let writer = HxbWriter.create config (Some string_pool) warn anon_identification in
 			HxbWriter.write_module writer m;
 			let chunks = HxbWriter.get_chunks writer in
 			Hashtbl.replace binary_cache path {
@@ -84,8 +96,15 @@ class context_cache (index : int) (sign : Digest.t) = object(self)
 				mc_extra = { m.m_extra with m_cache_state = MSGood }
 			}
 
+	method cache_module_in_memory path m =
+		Hashtbl.replace modules path m
+
+	method clear_temp_cache =
+		Hashtbl.clear tmp_binary_cache
+
 	method clear_cache =
-		Hashtbl.clear modules
+		Hashtbl.clear modules;
+		self#clear_temp_cache
 
 	(* initialization *)
 
@@ -98,7 +117,8 @@ class context_cache (index : int) (sign : Digest.t) = object(self)
 	method get_modules = modules
 
 	method get_hxb = binary_cache
-	method get_hxb_module path = Hashtbl.find binary_cache path
+	method get_string_pool = string_pool
+	method get_string_pool_arr = string_pool.items.arr
 
 	(* TODO handle hxb cache there too *)
 	method get_removed_files = removed_files
@@ -152,6 +172,9 @@ class cache = object(self)
 
 	(* contexts *)
 
+	method clear_temp_cache =
+		Hashtbl.iter (fun _ ctx -> ctx#clear_temp_cache) contexts
+
 	method get_context sign =
 		try
 			Hashtbl.find contexts sign
@@ -310,8 +333,3 @@ class cache = object(self)
 end
 
 type t = cache
-
-type context_options =
-	| NormalContext
-	| MacroContext
-	| NormalAndMacroContext

+ 12 - 4
src/compiler/compilationContext.ml

@@ -80,16 +80,24 @@ let message ctx msg =
 	ctx.messages <- msg :: ctx.messages
 
 let error ctx ?(depth=0) ?(from_macro = false) msg p =
-	message ctx (make_compiler_message ~from_macro msg p depth DKCompilerMessage Error);
-	ctx.has_error <- true
+	message ctx (make_compiler_message ~from_macro msg p depth DKCompilerMessage Error)
+
+let after_error ctx =
+	ctx.has_error <- true;
+	if Common.fail_fast ctx.com then raise Abort
 
 let error_ext ctx (err : Error.error) =
 	Error.recurse_error (fun depth err ->
 		error ~depth ~from_macro:err.err_from_macro ctx (Error.error_msg err.err_message) err.err_pos
-	) err
+	) err;
+	after_error ctx
+
+let error ctx ?(depth=0) ?(from_macro = false) msg p =
+	error ctx ~depth ~from_macro msg p;
+	after_error ctx
 
 let create_native_lib file extern kind = {
 	lib_file = file;
 	lib_extern = extern;
 	lib_kind = kind;
-}
+}

+ 13 - 8
src/compiler/compiler.ml

@@ -190,6 +190,7 @@ module Setup = struct
 	let get_std_class_paths () =
 		try
 			let p = Sys.getenv "HAXE_STD_PATH" in
+			let p = Path.remove_trailing_slash p in
 			let rec loop = function
 				| drive :: path :: l ->
 					if String.length drive = 1 && ((drive.[0] >= 'a' && drive.[0] <= 'z') || (drive.[0] >= 'A' && drive.[0] <= 'Z')) then
@@ -274,7 +275,7 @@ let check_defines com =
 		PMap.iter (fun k _ ->
 			try
 				let reason = Hashtbl.find Define.deprecation_lut k in
-				let p = { pfile = "-D " ^ k; pmin = -1; pmax = -1 } in
+				let p = fake_pos ("-D " ^ k) in
 				com.warning WDeprecatedDefine [] reason p
 			with Not_found ->
 				()
@@ -345,7 +346,9 @@ let compile ctx actx callbacks =
 	let com = ctx.com in
 	(* Set up display configuration *)
 	DisplayProcessing.process_display_configuration ctx;
+	let restore = disable_report_mode com in
 	let display_file_dot_path = DisplayProcessing.process_display_file com actx in
+	restore ();
 	let mctx = match com.platform with
 		| CustomTarget name ->
 			begin try
@@ -417,8 +420,6 @@ let compile_safe ctx f =
 try
 	f ()
 with
-	| Abort ->
-		()
 	| Error.Fatal_error err ->
 		error_ext ctx err
 	| Lexer.Error (m,p) ->
@@ -430,8 +431,8 @@ with
 			ctx.has_error <- false;
 			ctx.messages <- [];
 		end else begin
-			error ctx (Printf.sprintf "You cannot access the %s package while %s (for %s)" pack (if pf = "macro" then "in a macro" else "targeting " ^ pf) (s_type_path m) ) p;
-			List.iter (error ~depth:1 ctx (Error.compl_msg "referenced here")) (List.rev pl);
+			let sub = List.map (fun p -> Error.make_error ~depth:1 (Error.Custom (Error.compl_msg "referenced here")) p) pl in
+			error_ext ctx (Error.make_error (Error.Custom (Printf.sprintf "You cannot access the %s package while %s (for %s)" pack (if pf = "macro" then "in a macro" else "targeting " ^ pf) (s_type_path m))) ~sub p)
 		end
 	| Error.Error err ->
 		error_ext ctx err
@@ -440,7 +441,7 @@ with
 	| Failure msg when not Helper.is_debug_run ->
 		error ctx ("Error: " ^ msg) null_pos
 	| Helper.HelpMessage msg ->
-		com.info msg null_pos
+		print_endline msg
 	| Parser.TypePath (p,c,is_import,pos) ->
 		DisplayOutput.handle_type_path_exception ctx p c is_import pos
 	| Parser.SyntaxCompletion(kind,subj) ->
@@ -448,12 +449,15 @@ with
 		error ctx ("Error: No completion point was found") null_pos
 	| DisplayException.DisplayException dex ->
 		DisplayOutput.handle_display_exception ctx dex
-	| Out_of_memory | EvalTypes.Sys_exit _ | Hlinterp.Sys_exit _ | DisplayProcessingGlobals.Completion _ as exc ->
+	| Abort | Out_of_memory | EvalTypes.Sys_exit _ | Hlinterp.Sys_exit _ | DisplayProcessingGlobals.Completion _ as exc ->
 		(* We don't want these to be caught by the catchall below *)
 		raise exc
 	| e when (try Sys.getenv "OCAMLRUNPARAM" <> "b" with _ -> true) && not Helper.is_debug_run ->
 		error ctx (Printexc.to_string e) null_pos
 
+let compile_safe ctx f =
+	try compile_safe ctx f with Abort -> ()
+
 let finalize ctx =
 	ctx.comm.flush ctx;
 	List.iter (fun lib -> lib#close) ctx.com.hxb_libs;
@@ -597,7 +601,8 @@ module HighLevel = struct
 				loop acc l
 			| "--cwd" :: dir :: l | "-C" :: dir :: l ->
 				(* we need to change it immediately since it will affect hxml loading *)
-				(try Unix.chdir dir with _ -> raise (Arg.Bad ("Invalid directory: " ^ dir)));
+				(* Exceptions are ignored there to let arg parsing do the error handling in expected order *)
+				(try Unix.chdir dir with _ -> ());
 				(* Push the --cwd arg so the arg processor know we did something. *)
 				loop (dir :: "--cwd" :: acc) l
 			| "--connect" :: hp :: l ->

+ 35 - 30
src/compiler/displayProcessing.ml

@@ -48,7 +48,7 @@ let handle_display_argument_old com file_pos actx =
 			| "diagnostics" ->
 				com.report_mode <- RMLegacyDiagnostics [file_unique];
 				let dm = create DMNone in
-				{dm with dms_display_file_policy = DFPOnly; dms_per_file = true; dms_populate_cache = !ServerConfig.populate_cache_from_display}
+				{dm with dms_display_file_policy = DFPOnly; dms_per_file = true; dms_populate_cache = false}
 			| "statistics" ->
 				com.report_mode <- RMStatistics;
 				let dm = create DMNone in
@@ -156,36 +156,41 @@ let process_display_file com actx =
 				actx.classes <- [];
 				com.main.main_class <- None;
 			end;
-			let real = Path.get_real_path (DisplayPosition.display_position#get).pfile in
-			let path = match get_module_path_from_file_path com real with
-			| Some path ->
-				if com.display.dms_kind = DMPackage then DisplayException.raise_package (fst 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] ->
-						actx.classes <- path :: actx.classes;
-						DPKNormal path
-					| [name;target] ->
-						let path = fst path, name in
-						actx.classes <- path :: actx.classes;
-						DPKNormal path
-					| e ->
-						die "" __LOC__
+			let dpk = List.map (fun file_key ->
+				let real = Path.get_real_path (Path.UniqueKey.to_string file_key) in
+				let dpk = match get_module_path_from_file_path com real with
+				| Some path ->
+					if com.display.dms_kind = DMPackage then DisplayException.raise_package (fst path);
+					let dpk = 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] ->
+							actx.classes <- path :: actx.classes;
+							DPKNormal path
+						| [name;target] ->
+							let path = fst path, name in
+							actx.classes <- path :: actx.classes;
+							DPKNormal path
+						| _ ->
+							failwith ("Invalid display file '" ^ real ^ "'")
+					in
+					dpk
+				| 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
+					| file :: _ when file.[0] >= 'a' && file.[0] <= 'z' -> failwith ("Display file '" ^ file ^ "' should not start with a lowercase letter")
+					| _ -> ());
+					DPKDirect real
 				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
-				| file :: _ when file.[0] >= 'a' && file.[0] <= 'z' -> failwith ("Display file '" ^ file ^ "' should not start with a lowercase letter")
-				| _ -> ());
-				DPKDirect real
-			in
-			Common.log com ("Display file : " ^ real);
+				Common.log com ("Display file : " ^ real);
+				dpk
+			) DisplayPosition.display_position#get_files in
 			Common.log com ("Classes found : ["  ^ (String.concat "," (List.map s_type_path actx.classes)) ^ "]");
-			path
+			match dpk with
+				| [dfile] -> dfile
+				| _ -> DPKNone
 
 (* 3. Loaders for display file that might be called *)
 
@@ -244,7 +249,7 @@ let load_display_file_standalone (ctx : Typecore.typer) file =
 let load_display_content_standalone (ctx : Typecore.typer) input =
 	let com = ctx.com in
 	let file = file_input_marker in
-	let p = {pfile = file; pmin = 0; pmax = 0} in
+	let p = file_pos file in
 	let parsed = TypeloadParse.parse_file_from_string com file p input in
 	let pack,decls = TypeloadParse.handle_parser_result com p parsed in
 	ignore(TypeloadModule.type_module ctx.com ctx.g (pack,"?DISPLAY") file ~dont_check_path:true decls p)

+ 49 - 21
src/compiler/generate.ml

@@ -21,7 +21,17 @@ let check_auxiliary_output com actx =
 			Genjson.generate com.types file
 	end
 
-let export_hxb com config cc platform zip m =
+let create_writer com config string_pool =
+	let anon_identification = new tanon_identification in
+	let warn w s p = com.Common.warning w com.warning_options s p in
+	let writer = HxbWriter.create config string_pool warn anon_identification in
+	writer,(fun () ->
+		let out = IO.output_string () in
+		HxbWriter.export writer out;
+		IO.close_out out
+	)
+
+let export_hxb from_cache com config string_pool cc platform zip m =
 	let open HxbData in
 	match m.m_extra.m_kind with
 		| MCode | MMacro | MFake | MExtern -> begin
@@ -29,8 +39,8 @@ let export_hxb com config cc platform zip m =
 			let l = platform :: (fst m.m_path @ [snd m.m_path]) in
 			let path = (String.concat "/" l) ^ ".hxb" in
 
-			try
-				let hxb_cache = cc#get_hxb_module m.m_path in
+			if from_cache then begin
+				let hxb_cache = try cc#get_hxb_module m.m_path with Not_found -> raise Abort in
 				let out = IO.output_string () in
 				write_header out;
 				List.iter (fun (kind,data) ->
@@ -39,14 +49,12 @@ let export_hxb com config cc platform zip m =
 				) hxb_cache.mc_chunks;
 				let data = IO.close_out out in
 				zip#add_entry data path;
-			with Not_found ->
-				let anon_identification = new tanon_identification in
-				let warn w s p = com.Common.warning w com.warning_options s p in
-				let writer = HxbWriter.create config warn anon_identification in
+			end else begin
+				let writer,close = create_writer com config string_pool in
 				HxbWriter.write_module writer m;
-				let out = IO.output_string () in
-				HxbWriter.export writer out;
-				zip#add_entry (IO.close_out out) path;
+				let bytes = close () in
+				zip#add_entry bytes path;
+			end
 		end
 	| _ ->
 		()
@@ -54,41 +62,61 @@ let export_hxb com config cc platform zip m =
 let check_hxb_output ctx config =
 	let open HxbWriterConfig in
 	let com = ctx.com in
+	let write_string_pool config zip name pool =
+		let writer,close = create_writer com config (Some pool) in
+		let a = StringPool.finalize writer.cp in
+		HxbWriter.HxbWriter.write_string_pool writer STR a;
+		let bytes = close () in
+		zip#add_entry bytes name;
+	in
 	let match_path_list l sl_path =
 		List.exists (fun sl -> Ast.match_path true sl_path sl) l
 	in
-	let try_write () =
+	let try_write from_cache =
 		let path = config.HxbWriterConfig.archive_path in
 		let path = Str.global_replace (Str.regexp "\\$target") (platform_name ctx.com.platform) path in
 		let t = Timer.timer ["generate";"hxb"] in
 		Path.mkdir_from_path path;
 		let zip = new Zip_output.zip_output path 6 in
-		let export com config =
+		let export com config string_pool =
 			let cc = CommonCache.get_cache com in
 			let target = Common.platform_name_macro com in
+
 			List.iter (fun m ->
 				let t = Timer.timer ["generate";"hxb";s_type_path m.m_path] in
 				let sl_path = fst m.m_path @ [snd m.m_path] in
 				if not (match_path_list config.exclude sl_path) || match_path_list config.include' sl_path then
-					Std.finally t (export_hxb com config cc target zip) m
+					Std.finally t (export_hxb from_cache com config string_pool cc target zip) m
 			) com.modules;
 		in
 		Std.finally (fun () ->
 			zip#close;
 			t()
 		) (fun () ->
-			if  config.target_config.generate then
-				export com config.target_config;
-			begin match com.get_macros() with
-				| Some mcom when config.macro_config.generate ->
-					export mcom config.macro_config
-				| _ ->
-					()
+			let string_pool = if config.share_string_pool then Some (StringPool.create ()) else None in
+			if config.target_config.generate then begin
+				export com config.target_config string_pool;
+			end;
+
+			if config.macro_config.generate then begin
+				match com.get_macros() with
+					| Some mcom ->
+						let use_separate_pool = config.share_string_pool && from_cache in
+						let string_pool = if use_separate_pool then Some (StringPool.create ()) else string_pool in
+						export mcom config.macro_config string_pool;
+						if use_separate_pool then write_string_pool config.macro_config zip "StringPool.macro.hxb" (Option.get string_pool)
+					| _ ->
+						()
 			end;
+
+			if config.share_string_pool then
+				write_string_pool config.target_config zip "StringPool.hxb" (Option.get string_pool);
 		) ()
 	in
 	try
-		try_write ()
+		(* This Abort case shouldn't happen, unless some modules are not stored in hxb cache (which should not be the case currently) *)
+		if ctx.comm.is_server then try try_write true with Abort -> try_write false
+		else try_write false
 	with Sys_error s ->
 		CompilationContext.error ctx (Printf.sprintf "Could not write to %s: %s" config.archive_path s) null_pos
 

+ 4 - 4
src/compiler/hxb/hxbData.ml

@@ -24,10 +24,10 @@ exception HxbFailure of string
 type chunk_kind =
 	| STR (* string pool *)
 	| DOC (* doc pool *)
-	| MDF (* module foward *)
+	| MDF (* module forward *)
 	| MTF (* module types forward *)
 	(* Module type references *)
-	| MDR (* module references *)
+	| IMP (* imports *)
 	| CLR (* class references *)
 	| ENR (* enum references *)
 	| ABR (* abstract references *)
@@ -68,7 +68,7 @@ let string_of_chunk_kind = function
 	| DOC -> "DOC"
 	| MDF -> "MDF"
 	| MTF -> "MTF"
-	| MDR -> "MDR"
+	| IMP -> "IMP"
 	| CLR -> "CLR"
 	| ENR -> "ENR"
 	| ABR -> "ABR"
@@ -95,7 +95,7 @@ let chunk_kind_of_string = function
 	| "DOC" -> DOC
 	| "MDF" -> MDF
 	| "MTF" -> MTF
-	| "MDR" -> MDR
+	| "IMP" -> IMP
 	| "CLR" -> CLR
 	| "ENR" -> ENR
 	| "ABR" -> ABR

+ 16 - 2
src/compiler/hxb/hxbLib.ml

@@ -2,7 +2,7 @@ open Globals
 open Common
 open ExtString
 
-class hxb_library file_path = object(self)
+class hxb_library file_path hxb_times = object(self)
 	inherit abstract_hxb_lib
 	val zip = lazy (Zip.open_in file_path)
 
@@ -10,12 +10,23 @@ class hxb_library file_path = object(self)
 	val modules = Hashtbl.create 0
 	val mutable closed = false
 	val mutable loaded = false
+	val mutable string_pool : string array option = None
+	val mutable macro_string_pool : string array option = None
 
 	method load =
 		if not loaded then begin
 			loaded <- true;
 			let close = Timer.timer ["hxblib";"read"] in
 			List.iter (function
+				| ({ Zip.filename = "StringPool.hxb" | "StringPool.macro.hxb" as filename} as entry) ->
+					let reader = new HxbReader.hxb_reader (["hxb";"internal"],"StringPool") (HxbReader.create_hxb_reader_stats()) None hxb_times in
+					let zip = Lazy.force zip in
+					let data = Bytes.unsafe_of_string (Zip.read_entry zip entry) in
+					ignore(reader#read (new HxbReaderApi.hxb_reader_api_null) data STR);
+					if filename = "StringPool.hxb" then
+						string_pool <- reader#get_string_pool
+					else
+						macro_string_pool <- reader#get_string_pool
 				| ({ Zip.is_directory = false; Zip.filename = filename } as entry) when String.ends_with filename ".hxb" ->
 					let pack = String.nsplit filename "/" in
 					begin match List.rev pack with
@@ -49,6 +60,9 @@ class hxb_library file_path = object(self)
 		end
 
 	method get_file_path = file_path
+	method get_string_pool target =
+		if target = "macro" && Option.is_some macro_string_pool then macro_string_pool
+		else string_pool
 end
 
 
@@ -60,4 +74,4 @@ let create_hxb_lib com file_path =
 	with Not_found ->
 		failwith ("hxb lib " ^ file_path ^ " not found")
 	in
-	new hxb_library file
+	new hxb_library file (Common.defined com Define.HxbTimes)

+ 52 - 13
src/compiler/hxb/hxbReader.ml

@@ -142,18 +142,22 @@ let read_leb128 ch =
 
 let dump_stats name stats =
 	print_endline (Printf.sprintf "hxb_reader stats for %s" name);
-	print_endline (Printf.sprintf "  modules partially restored: %i" (!(stats.modules_fully_restored) - !(stats.modules_partially_restored)));
+	print_endline (Printf.sprintf "  modules partially restored: %i" (!(stats.modules_partially_restored) - !(stats.modules_fully_restored)));
 	print_endline (Printf.sprintf "  modules fully restored: %i" !(stats.modules_fully_restored));
 
 class hxb_reader
 	(mpath : path)
 	(stats : hxb_reader_stats)
+	(string_pool : string array option)
+	(timers_enabled : bool)
 = object(self)
 	val mutable api = Obj.magic ""
+	val mutable minimal_restore = false
 	val mutable current_module = null_module
 
 	val mutable ch = BytesWithPosition.create (Bytes.create 0)
-	val mutable string_pool = Array.make 0 ""
+	val mutable has_string_pool = (string_pool <> None)
+	val mutable string_pool = (match string_pool with None -> Array.make 0 "" | Some pool -> pool)
 	val mutable doc_pool = Array.make 0 ""
 
 	val mutable classes = Array.make 0 null_class
@@ -180,6 +184,12 @@ class hxb_reader
 			dump_backtrace();
 			error (Printf.sprintf "[HXB] [%s] Cannot resolve type %s" (s_type_path current_module.m_path) (s_type_path ((pack @ [mname]),tname)))
 
+	method get_string_pool =
+		if has_string_pool then
+			Some (string_pool)
+		else
+			None
+
 	(* Primitives *)
 
 	method read_i32 =
@@ -734,6 +744,9 @@ class hxb_reader
 			local_type_parameters.(k).ttp_type
 		| 4 ->
 			t_dynamic
+		| 5 ->
+			let path = self#read_path in
+			(mk_type_param { null_class with cl_path = path } TPHUnbound None None).ttp_type
 		| 10 ->
 			let c = self#read_class_ref in
 			c.cl_type
@@ -963,7 +976,7 @@ class hxb_reader
 			| 5 -> VUser TVOLocalFunction
 			| 6 -> VGenerated
 			| 7 -> VInlined
-			| 8 -> VInlinedConstructorVariable
+			| 8 -> VInlinedConstructorVariable (self#read_list (fun () -> self#read_string))
 			| 9 -> VExtractorVariable
 			| 10 -> VAbstractThis
 			| _ -> assert false
@@ -1446,7 +1459,6 @@ class hxb_reader
 		in
 		loop CfrMember (read_uleb128 ch) c.cl_ordered_fields;
 		loop CfrStatic (read_uleb128 ch) c.cl_ordered_statics;
-		(match c.cl_kind with KModuleFields md -> md.m_statics <- Some c; | _ -> ());
 
 	method read_enum_fields (e : tenum) =
 		type_type_parameters <- Array.of_list e.e_params;
@@ -1503,6 +1515,9 @@ class hxb_reader
 		c.cl_implements <- self#read_list read_relation;
 		c.cl_dynamic <- self#read_option (fun () -> self#read_type_instance);
 		c.cl_array_access <- self#read_option (fun () -> self#read_type_instance);
+		(match c.cl_kind with
+			| KModuleFields md -> md.m_statics <- Some c;
+			| _ -> ());
 
 	method read_abstract (a : tabstract) =
 		self#read_common_module_type (Obj.magic a);
@@ -1515,6 +1530,7 @@ class hxb_reader
 		end;
 		a.a_from <- self#read_list (fun () -> self#read_type_instance);
 		a.a_to <- self#read_list (fun () -> self#read_type_instance);
+		a.a_extern <- self#read_bool;
 		a.a_enum <- self#read_bool;
 
 	method read_abstract_fields (a : tabstract) =
@@ -1557,7 +1573,7 @@ class hxb_reader
 
 	method read_enum (e : tenum) =
 		self#read_common_module_type (Obj.magic e);
-		e.e_extern <- self#read_bool;
+		e.e_flags <- read_uleb128 ch;
 		e.e_names <- self#read_list (fun () -> self#read_string);
 
 	method read_typedef (td : tdef) =
@@ -1817,7 +1833,7 @@ class hxb_reader
 				error ("Unexpected type where typedef was expected: " ^ (s_type_path (pack,tname)))
 		))
 
-	method read_mdr =
+	method read_imports =
 		let length = read_uleb128 ch in
 		for _ = 0 to length - 1 do
 			let path = self#read_path in
@@ -1870,7 +1886,7 @@ class hxb_reader
 				let read_field () =
 					let name = self#read_string in
 					let pos,name_pos = self#read_pos_pair in
-					let index = read_byte ch in
+					let index = read_uleb128 ch in
 
 					{ null_enum_field with
 						ef_name = name;
@@ -1923,15 +1939,18 @@ class hxb_reader
 		match kind with
 		| STR ->
 			string_pool <- self#read_string_pool;
+			has_string_pool <- true;
 		| DOC ->
 			doc_pool <- self#read_string_pool;
 		| MDF ->
+			assert(has_string_pool);
 			current_module <- self#read_mdf;
+			incr stats.modules_partially_restored;
 		| MTF ->
 			current_module.m_types <- self#read_mtf;
 			api#add_module current_module;
-		| MDR ->
-			self#read_mdr;
+		| IMP ->
+			if not minimal_restore then self#read_imports;
 		| CLR ->
 			self#read_clr;
 		| ENR ->
@@ -1973,18 +1992,37 @@ class hxb_reader
 		| EOM ->
 			incr stats.modules_fully_restored;
 
+	method private get_backtrace () = Printexc.get_raw_backtrace ()
+	method private get_callstack () = Printexc.get_callstack 200
+
+	method private failwith chunk msg backtrace =
+		let msg =
+			(Printf.sprintf "Compiler failure while reading hxb chunk %s of %s: %s\n" (string_of_chunk_kind chunk) (s_type_path mpath) (msg))
+			^ "Please submit an issue at https://github.com/HaxeFoundation/haxe/issues/new\n"
+			^ "Attach the following information:"
+		in
+		let backtrace = Printexc.raw_backtrace_to_string backtrace in
+		let s = Printf.sprintf "%s\nHaxe: %s\n%s" msg s_version_full backtrace in
+		failwith s
+
 	method private read_chunk_data kind =
 		let path = String.concat "_" (ExtLib.String.nsplit (s_type_path mpath) ".") in
 		let id = ["hxb";"read";string_of_chunk_kind kind;path] in
-		let close = Timer.timer id in
-		self#read_chunk_data' kind;
+		let close = if timers_enabled then Timer.timer id else fun() -> () in
+		try
+			self#read_chunk_data' kind
+		with Invalid_argument msg -> begin
+			close();
+			self#failwith kind msg (self#get_backtrace ())
+		end;
 		close()
 
 	method read_chunks (new_api : hxb_reader_api) (chunks : cached_chunks) =
-		fst (self#read_chunks_until new_api chunks EOM)
+		fst (self#read_chunks_until new_api chunks EOM false)
 
-	method read_chunks_until (new_api : hxb_reader_api) (chunks : cached_chunks) end_chunk =
+	method read_chunks_until (new_api : hxb_reader_api) (chunks : cached_chunks) end_chunk minimal_restore' =
 		api <- new_api;
+		minimal_restore <- minimal_restore';
 		let rec loop = function
 			| (kind,data) :: chunks ->
 				ch <- BytesWithPosition.create data;
@@ -1997,6 +2035,7 @@ class hxb_reader
 
 	method read (new_api : hxb_reader_api) (bytes : bytes) =
 		api <- new_api;
+		minimal_restore <- false;
 		ch <- BytesWithPosition.create bytes;
 		if (Bytes.to_string (read_bytes ch 3)) <> "hxb" then
 			raise (HxbFailure "magic");

+ 12 - 0
src/compiler/hxb/hxbReaderApi.ml

@@ -10,3 +10,15 @@ class virtual hxb_reader_api = object(self)
 	method virtual get_var_id : int -> int
 	method virtual read_expression_eagerly : tclass_field -> bool
 end
+
+class hxb_reader_api_null = object(self)
+	inherit hxb_reader_api
+
+	method make_module _ = assert false
+	method add_module _ = assert false
+	method resolve_type _ _ _ = assert false
+	method resolve_module _ = assert false
+	method basic_types = assert false
+	method get_var_id _ = assert false
+	method read_expression_eagerly _ = assert false
+end

+ 124 - 98
src/compiler/hxb/hxbWriter.ml

@@ -56,41 +56,6 @@ module StringHashtbl = Hashtbl.Make(struct
 		Hashtbl.hash s
 end)
 
-module StringPool = struct
-	type t = {
-		lut : int StringHashtbl.t;
-		items : string DynArray.t;
-		mutable closed : bool;
-	}
-
-	let create () = {
-		lut = StringHashtbl.create 16;
-		items = DynArray.create ();
-		closed = false;
-	}
-
-	let add sp s =
-		assert (not sp.closed);
-		let index = DynArray.length sp.items in
-		StringHashtbl.add sp.lut s index;
-		DynArray.add sp.items s;
-		index
-
-	let get sp s =
-		StringHashtbl.find sp.lut s
-
-	let get_or_add sp s =
-		try
-			get sp s
-		with Not_found ->
-			add sp s
-
-	let finalize sp =
-		assert (not sp.closed);
-		sp.closed <- true;
-		DynArray.to_list sp.items,DynArray.length sp.items
-end
-
 module Pool = struct
 	type ('key,'value) t = {
 		lut : ('key,int) Hashtbl.t;
@@ -445,10 +410,14 @@ type hxb_writer = {
 	anon_id : Type.t Tanon_identification.tanon_identification;
 	mutable current_module : module_def;
 	chunks : Chunk.t DynArray.t;
+	has_own_string_pool : bool;
 	cp : StringPool.t;
 	docs : StringPool.t;
 	mutable chunk : Chunk.t;
 
+	mutable in_expr : bool;
+	mutable sig_deps : module_def list;
+
 	classes : (path,tclass) Pool.t;
 	enums : (path,tenum) Pool.t;
 	typedefs : (path,tdef) Pool.t;
@@ -469,11 +438,25 @@ type hxb_writer = {
 	mutable local_type_parameters : (typed_type_param,unit) IdentityPool.t;
 	mutable field_stack : unit list;
 	mutable wrote_local_type_param : bool;
+	mutable needs_local_context : bool;
 	unbound_ttp : (typed_type_param,unit) IdentityPool.t;
 	t_instance_chunk : Chunk.t;
 }
 
 module HxbWriter = struct
+	let get_backtrace () = Printexc.get_raw_backtrace ()
+	let get_callstack () = Printexc.get_callstack 200
+
+	let failwith writer msg backtrace =
+		let msg =
+			(Printf.sprintf "Compiler failure while writing hxb chunk %s of %s: %s\n" (string_of_chunk_kind writer.chunk.kind) (s_type_path writer.current_module.m_path) (msg))
+			^ "Please submit an issue at https://github.com/HaxeFoundation/haxe/issues/new\n"
+			^ "Attach the following information:"
+		in
+		let backtrace = Printexc.raw_backtrace_to_string backtrace in
+		let s = Printf.sprintf "%s\nHaxe: %s\n%s" msg s_version_full backtrace in
+		failwith s
+
 	let in_nested_scope writer = match writer.field_stack with
 		| [] -> false (* can happen for cl_init and in EXD *)
 		| [_] -> false
@@ -485,7 +468,7 @@ module HxbWriter = struct
 		let initial_size = match kind with
 			| EOT | EOF | EOM -> 0
 			| MDF -> 16
-			| MTF | MDR | CLR | END | ABD | ENR | ABR | TDR | EFR | CFR | AFD -> 64
+			| MTF | IMP | CLR | END | ABD | ENR | ABR | TDR | EFR | CFR | AFD -> 64
 			| OFR | OFD | OBD | CLD | TDD | EFD -> 128
 			| STR | DOC -> 256
 			| CFD | EXD -> 512
@@ -527,7 +510,7 @@ module HxbWriter = struct
 	let write_full_path writer (pack : string list) (mname : string) (tname : string) =
 		Chunk.write_list writer.chunk pack (Chunk.write_string writer.chunk);
 		if mname = "" || tname = "" then
-			die (Printf.sprintf "write_full_path: pack = %s, mname = %s, tname = %s" (String.concat "." pack) mname tname) __LOC__;
+			failwith writer (Printf.sprintf "write_full_path: pack = %s, mname = %s, tname = %s" (String.concat "." pack) mname tname) (get_callstack ());
 		Chunk.write_string writer.chunk mname;
 		Chunk.write_string writer.chunk tname
 
@@ -886,20 +869,28 @@ module HxbWriter = struct
 
 	(* References *)
 
+	let maybe_add_sig_dep writer m =
+		if not writer.in_expr && m.m_path <> writer.current_module.m_path && not (List.exists (fun m' -> m'.m_path = m.m_path) writer.sig_deps) then
+			writer.sig_deps <- m :: writer.sig_deps
+
 	let write_class_ref writer (c : tclass) =
 		let i = Pool.get_or_add writer.classes c.cl_path c in
+		maybe_add_sig_dep writer c.cl_module;
 		Chunk.write_uleb128 writer.chunk i
 
 	let write_enum_ref writer (en : tenum) =
 		let i = Pool.get_or_add writer.enums en.e_path en in
+		maybe_add_sig_dep writer en.e_module;
 		Chunk.write_uleb128 writer.chunk i
 
 	let write_typedef_ref writer (td : tdef) =
 		let i = Pool.get_or_add writer.typedefs td.t_path td in
+		maybe_add_sig_dep writer td.t_module;
 		Chunk.write_uleb128 writer.chunk i
 
 	let write_abstract_ref writer (a : tabstract) =
 		let i = Pool.get_or_add writer.abstracts a.a_path a in
+		maybe_add_sig_dep writer a.a_module;
 		Chunk.write_uleb128 writer.chunk i
 
 	let write_tmono_ref writer (mono : tmono) =
@@ -980,20 +971,22 @@ module HxbWriter = struct
 			Chunk.write_uleb128 writer.chunk (Pool.add writer.enum_fields key (en,ef))
 
 	let write_var_kind writer vk =
-		let b = match vk with
-			| VUser TVOLocalVariable -> 0
-			| VUser TVOArgument -> 1
-			| VUser TVOForVariable -> 2
-			| VUser TVOPatternVariable -> 3
-			| VUser TVOCatchVariable -> 4
-			| VUser TVOLocalFunction -> 5
-			| VGenerated -> 6
-			| VInlined -> 7
-			| VInlinedConstructorVariable -> 8
-			| VExtractorVariable -> 9
-			| VAbstractThis -> 10
-		in
-		Chunk.write_u8 writer.chunk b
+		let b,sl = match vk with
+			| VUser TVOLocalVariable -> 0, []
+			| VUser TVOArgument -> 1, []
+			| VUser TVOForVariable -> 2, []
+			| VUser TVOPatternVariable -> 3, []
+			| VUser TVOCatchVariable -> 4, []
+			| VUser TVOLocalFunction -> 5, []
+			| VGenerated -> 6, []
+			| VInlined -> 7, []
+			| VInlinedConstructorVariable sl -> 8, sl
+			| VExtractorVariable -> 9, []
+			| VAbstractThis -> 10, []
+		in begin
+			Chunk.write_u8 writer.chunk b;
+			if (b == 8) then Chunk.write_list writer.chunk sl (Chunk.write_string writer.chunk);
+		end
 
 	let write_var writer fctx v =
 		Chunk.write_uleb128 writer.chunk v.v_id;
@@ -1004,12 +997,11 @@ module HxbWriter = struct
 		write_pos writer v.v_pos
 
 	let rec write_anon writer (an : tanon) =
-		let needs_local_context = ref false in
 		let write_fields () =
 			let restore = start_temporary_chunk writer 256 in
 			let i = ref 0 in
 			PMap.iter (fun _ cf ->
-				write_anon_field_ref writer needs_local_context cf;
+				write_anon_field_ref writer cf;
 				incr i;
 			) an.a_fields;
 			let bytes = restore (fun new_chunk -> Chunk.get_bytes new_chunk) in
@@ -1033,8 +1025,7 @@ module HxbWriter = struct
 			assert false
 		| AbstractStatics _ ->
 			assert false
-		end;
-		!needs_local_context
+		end
 
 	and write_anon_ref writer (an : tanon) =
 		let pfm = Option.get (writer.anon_id#identify_anon ~strict:true an) in
@@ -1044,9 +1035,10 @@ module HxbWriter = struct
 			Chunk.write_uleb128 writer.chunk index
 		with Not_found ->
 			let restore = start_temporary_chunk writer 256 in
-			let needs_local_context = write_anon writer an in
+			writer.needs_local_context <- false;
+			write_anon writer an;
 			let bytes = restore (fun new_chunk -> Chunk.get_bytes new_chunk) in
-			if needs_local_context then begin
+			if writer.needs_local_context then begin
 				let index = Pool.add writer.anons pfm.pfm_path None in
 				Chunk.write_u8 writer.chunk 1;
 				Chunk.write_uleb128 writer.chunk index;
@@ -1057,7 +1049,7 @@ module HxbWriter = struct
 				Chunk.write_uleb128 writer.chunk index;
 			end
 
-	and write_anon_field_ref writer needs_local_context cf =
+	and write_anon_field_ref writer cf =
 		try
 			let index = HashedIdentityPool.get writer.anon_fields cf.cf_name cf in
 			Chunk.write_u8 writer.chunk 0;
@@ -1067,14 +1059,12 @@ module HxbWriter = struct
 			let old = writer.wrote_local_type_param in
 			writer.wrote_local_type_param <- false;
 			ignore(write_class_field_and_overloads_data writer true cf);
-			let wrote_local_type_param = writer.wrote_local_type_param in
-			writer.wrote_local_type_param <- old;
 			let bytes = restore (fun new_chunk -> Chunk.get_bytes new_chunk) in
-			if wrote_local_type_param then begin
+			if writer.needs_local_context || writer.wrote_local_type_param then begin
 				(* If we access something from the method scope, we have to write the anon field immediately.
 				   This should be fine because in such cases the field cannot be referenced elsewhere. *)
 				let index = HashedIdentityPool.add writer.anon_fields cf.cf_name cf None in
-				needs_local_context := true;
+				writer.needs_local_context <- true;
 				Chunk.write_u8 writer.chunk 1;
 				Chunk.write_uleb128 writer.chunk index;
 				Chunk.write_bytes writer.chunk bytes
@@ -1082,7 +1072,8 @@ module HxbWriter = struct
 				let index = HashedIdentityPool.add writer.anon_fields cf.cf_name cf (Some bytes) in
 				Chunk.write_u8 writer.chunk 0;
 				Chunk.write_uleb128 writer.chunk index;
-			end
+			end;
+			writer.wrote_local_type_param <- old
 
 	(* Type instances *)
 
@@ -1105,14 +1096,18 @@ module HxbWriter = struct
 				writer.wrote_local_type_param <- true;
 				Chunk.write_u8 writer.chunk 3;
 				Chunk.write_uleb128 writer.chunk index;
+			| TPHUnbound ->
+				raise Not_found
 		end with Not_found ->
 			(try ignore(IdentityPool.get writer.unbound_ttp ttp) with Not_found -> begin
 				ignore(IdentityPool.add writer.unbound_ttp ttp ());
-				let p = { null_pos with pfile = (Path.UniqueKey.lazy_path writer.current_module.m_extra.m_file) } in
+				let p = file_pos (Path.UniqueKey.lazy_path writer.current_module.m_extra.m_file) in
 				let msg = Printf.sprintf "Unbound type parameter %s" (s_type_path ttp.ttp_class.cl_path) in
 				writer.warn WUnboundTypeParameter msg p
 			end);
-			Chunk.write_u8 writer.chunk 4; (* TDynamic None *)
+			writer.wrote_local_type_param <- true;
+			Chunk.write_u8 writer.chunk 5;
+			write_path writer ttp.ttp_class.cl_path;
 		end
 
 	(*
@@ -1564,7 +1559,7 @@ module HxbWriter = struct
 			| TField(e1,FAnon cf) ->
 				Chunk.write_u8 writer.chunk 104;
 				loop e1;
-				write_anon_field_ref writer (ref false) cf;
+				write_anon_field_ref writer cf;
 				true;
 			| TField(e1,FClosure(Some(c,tl),cf)) ->
 				Chunk.write_u8 writer.chunk 105;
@@ -1576,7 +1571,7 @@ module HxbWriter = struct
 			| TField(e1,FClosure(None,cf)) ->
 				Chunk.write_u8 writer.chunk 106;
 				loop e1;
-				write_anon_field_ref writer (ref false) cf;
+				write_anon_field_ref writer cf;
 				true;
 			| TField(e1,FEnum(en,ef)) ->
 				Chunk.write_u8 writer.chunk 107;
@@ -1670,6 +1665,7 @@ module HxbWriter = struct
 				| TPHEnumConstructor -> 3
 				| TPHAnonField -> 4
 				| TPHLocal -> 5
+				| TPHUnbound -> 6
 			in
 			Chunk.write_u8 writer.chunk i
 		in
@@ -1766,11 +1762,11 @@ module HxbWriter = struct
 					write_type_parameters writer ltp
 				end;
 				Chunk.write_option writer.chunk fctx.texpr_this (fun e -> write_type_instance writer e.etype);
-				let items,length = StringPool.finalize fctx.t_pool in
-				Chunk.write_uleb128 writer.chunk length;
-				List.iter (fun bytes ->
+				let a = StringPool.finalize fctx.t_pool in
+				Chunk.write_uleb128 writer.chunk a.length;
+				StringDynArray.iter a (fun bytes ->
 					Chunk.write_bytes writer.chunk (Bytes.unsafe_of_string bytes)
-				) items;
+				);
 				Chunk.write_uleb128 writer.chunk (DynArray.length fctx.vars);
 				DynArray.iter (fun (v,v_id) ->
 					v.v_id <- v_id;
@@ -1805,15 +1801,21 @@ module HxbWriter = struct
 			| Some e when not write_expr_immediately ->
 				Chunk.write_u8 writer.chunk 2;
 				let fctx,close = start_texpr writer e.epos in
+				let old = writer.in_expr in
+				writer.in_expr <- true;
 				write_texpr writer fctx e;
 				Chunk.write_option writer.chunk cf.cf_expr_unoptimized (write_texpr writer fctx);
+				writer.in_expr <- old;
 				let expr_chunk = close() in
 				Some expr_chunk
 			| Some e ->
 				Chunk.write_u8 writer.chunk 1;
 				let fctx,close = start_texpr writer e.epos in
+				let old = writer.in_expr in
+				writer.in_expr <- true;
 				write_texpr writer fctx e;
 				Chunk.write_option writer.chunk cf.cf_expr_unoptimized (write_texpr writer fctx);
+				writer.in_expr <- old;
 				let expr_pre_chunk,expr_chunk = close() in
 				Chunk.export_data expr_pre_chunk writer.chunk;
 				Chunk.export_data expr_chunk writer.chunk;
@@ -1911,6 +1913,7 @@ module HxbWriter = struct
 		end;
 		Chunk.write_list writer.chunk a.a_from (write_type_instance writer);
 		Chunk.write_list writer.chunk a.a_to (write_type_instance writer);
+		Chunk.write_bool writer.chunk a.a_extern;
 		Chunk.write_bool writer.chunk a.a_enum
 
 	let write_abstract_fields writer (a : tabstract) =
@@ -1947,7 +1950,7 @@ module HxbWriter = struct
 	let write_enum writer (e : tenum) =
 		select_type writer e.e_path;
 		write_common_module_type writer (Obj.magic e);
-		Chunk.write_bool writer.chunk e.e_extern;
+		Chunk.write_uleb128 writer.chunk e.e_flags;
 		Chunk.write_list writer.chunk e.e_names (Chunk.write_string writer.chunk)
 
 	let write_typedef writer (td : tdef) =
@@ -2028,13 +2031,21 @@ module HxbWriter = struct
 			Chunk.write_list writer.chunk (PMap.foldi (fun s f acc -> (s,f) :: acc) e.e_constrs []) (fun (s,ef) ->
 				Chunk.write_string writer.chunk s;
 				write_pos_pair writer ef.ef_pos ef.ef_name_pos;
-				Chunk.write_u8 writer.chunk ef.ef_index
+				Chunk.write_uleb128 writer.chunk ef.ef_index
 			);
 		| TAbstractDecl a ->
 			()
 		| TTypeDecl t ->
 			()
 
+	let write_string_pool writer kind a =
+		start_chunk writer kind;
+		Chunk.write_uleb128 writer.chunk a.StringDynArray.length;
+		StringDynArray.iter a (fun s ->
+			let b = Bytes.unsafe_of_string s in
+			Chunk.write_bytes_length_prefixed writer.chunk b;
+		)
+
 	let write_module writer (m : module_def) =
 		writer.current_module <- m;
 
@@ -2234,43 +2245,49 @@ module HxbWriter = struct
 		end;
 
 		begin
-			let deps = DynArray.create () in
+			let imports = DynArray.create () in
 			PMap.iter (fun _ mdep ->
-				match mdep.md_kind with
-				| MCode | MExtern when mdep.md_sign = m.m_extra.m_sign ->
-					DynArray.add deps mdep.md_path;
+				match mdep.md_kind, mdep.md_origin with
+				| (MCode | MExtern), MDepFromImport when mdep.md_sign = m.m_extra.m_sign ->
+					DynArray.add imports mdep.md_path;
 				| _ ->
 					()
 			) m.m_extra.m_deps;
-			if DynArray.length deps > 0 then begin
-				start_chunk writer MDR;
-				Chunk.write_uleb128 writer.chunk (DynArray.length deps);
+
+			if DynArray.length imports > 0 then begin
+				start_chunk writer IMP;
+				Chunk.write_uleb128 writer.chunk (DynArray.length imports);
 				DynArray.iter (fun path ->
 					write_path writer path
-				) deps
-			end
+				) imports
+			end;
 		end;
 
+		(* Note: this is only a start, and is still including a lot of dependencies *)
+		(* that are not actually needed for signature only. *)
+		let sig_deps = ref PMap.empty in
+		List.iter (fun mdep ->
+			let dep = {md_sign = mdep.m_extra.m_sign; md_path = mdep.m_path; md_kind = mdep.m_extra.m_kind; md_origin = MDepFromTyping} in
+			sig_deps := PMap.add mdep.m_id dep !sig_deps;
+		) writer.sig_deps;
+		PMap.iter (fun id mdep -> match mdep.md_kind, mdep.md_origin with
+			| (MCode | MExtern), MDepFromMacro when mdep.md_sign = m.m_extra.m_sign -> sig_deps := PMap.add id mdep !sig_deps;
+			| _ -> ()
+		) m.m_extra.m_deps;
+		m.m_extra.m_sig_deps <- Some !sig_deps;
+
 		start_chunk writer EOT;
 		start_chunk writer EOF;
 		start_chunk writer EOM;
 
-		let finalize_string_pool kind items length =
-			start_chunk writer kind;
-			Chunk.write_uleb128 writer.chunk length;
-			List.iter (fun s ->
-				let b = Bytes.unsafe_of_string s in
-				Chunk.write_bytes_length_prefixed writer.chunk b;
-			) items
-		in
-		begin
-			let items,length = StringPool.finalize writer.cp in
-			finalize_string_pool STR items length
+		if writer.has_own_string_pool then begin
+			let a = StringPool.finalize writer.cp in
+			write_string_pool writer STR a
 		end;
 		begin
-			let items,length = StringPool.finalize writer.docs in
-			if length > 0 then
-				finalize_string_pool DOC items length
+			let a = StringPool.finalize writer.docs in
+			if a.length > 0 then
+				write_string_pool writer DOC a
 		end
 
 	let get_sorted_chunks writer =
@@ -2281,8 +2298,13 @@ module HxbWriter = struct
 		l
 end
 
-let create config warn anon_id =
-	let cp = StringPool.create () in
+let create config string_pool warn anon_id =
+	let cp,has_own_string_pool = match string_pool with
+		| None ->
+			StringPool.create(),true
+		| Some pool ->
+			pool,false
+	in
 	{
 		config;
 		warn;
@@ -2290,6 +2312,9 @@ let create config warn anon_id =
 		current_module = null_module;
 		chunks = DynArray.create ();
 		cp = cp;
+		has_own_string_pool;
+		sig_deps = [];
+		in_expr = false;
 		docs = StringPool.create ();
 		chunk = Obj.magic ();
 		classes = Pool.create ();
@@ -2311,6 +2336,7 @@ let create config warn anon_id =
 		local_type_parameters = IdentityPool.create ();
 		field_stack = [];
 		wrote_local_type_param = false;
+		needs_local_context = false;
 		unbound_ttp = IdentityPool.create ();
 		t_instance_chunk = Chunk.create EOM cp 32;
 	}

+ 3 - 1
src/compiler/hxb/hxbWriterConfig.ml

@@ -11,6 +11,7 @@ type writer_target_config = {
 
 type t = {
 	mutable archive_path : string;
+	mutable share_string_pool : bool;
 	target_config : writer_target_config;
 	macro_config : writer_target_config;
 }
@@ -25,6 +26,7 @@ let create_target_config () = {
 
 let create () = {
 	archive_path = "";
+	share_string_pool = true; (* Do we want this as default? *)
 	target_config = create_target_config ();
 	macro_config = create_target_config ()
 }
@@ -115,4 +117,4 @@ let process_argument file =
 		| _ ->
 			config.archive_path <- file;
 	end;
-	Some config
+	Some config

+ 79 - 67
src/compiler/messageReporting.ml

@@ -4,63 +4,57 @@ open Common
 open CompilationContext
 
 let resolve_source file l1 p1 l2 p2 =
-	let ch = open_in_bin file in
-	let curline = ref 1 in
-	let lines = ref [] in
-	let rec loop p line =
-		let inc i line =
-			if (!curline >= l1) && (!curline <= l2) then lines := (!curline, line) :: !lines;
-			curline := !curline + 1;
-			(i, "")
-		in
-
-		let input_char_or_done ch line =
-			try input_char ch with End_of_file -> begin
-				ignore(inc 0 line);
-				raise End_of_file
-			end
-		in
+	if l1 = l2 && p1 = p2 && l1 = 1 && p1 = 1 then []
+	else begin
+		let ch = open_in_bin file in
+		let curline = ref 1 in
+		let lines = ref [] in
+		let rec loop p line =
+			let inc i line =
+				if (!curline >= l1) && (!curline <= l2) then lines := (!curline, line) :: !lines;
+				incr curline;
+				(i, "")
+			in
 
-		let read_char line = match input_char_or_done ch line with
-			| '\n' -> inc 1 line
-			| '\r' ->
-				ignore(input_char_or_done ch line);
-				inc 2 line
-			| c -> begin
-				let line = ref (line ^ (String.make 1 c)) in
-				let rec skip n =
-					if n > 0 then begin
-						let c = input_char_or_done ch !line in
-						line := !line ^ (String.make 1 c);
-						skip (n - 1)
-					end
-				in
+			let input_char_or_done ch line =
+				try input_char ch with End_of_file -> begin
+					ignore(inc 0 line);
+					raise End_of_file
+				end
+			in
 
-				let code = int_of_char c in
-				if code < 0xC0 then ()
-				else if code < 0xE0 then skip 1
-				else if code < 0xF0 then skip 2
-				else skip 3;
+			let read_char line = match input_char_or_done ch line with
+				| '\n' -> inc 1 line
+				| '\r' ->
+					ignore(input_char_or_done ch line);
+					inc 2 line
+				| c -> begin
+					let line = ref (line ^ (String.make 1 c)) in
+					let rec skip n =
+						if n > 0 then begin
+							let c = input_char_or_done ch !line in
+							line := !line ^ (String.make 1 c);
+							skip (n - 1)
+						end
+					in
+
+					let code = int_of_char c in
+					if code < 0xC0 then ()
+					else if code < 0xE0 then skip 1
+					else if code < 0xF0 then skip 2
+					else skip 3;
+
+					(1, !line)
+				end
+			in
 
-				(1, !line)
-			end
+			let (delta, line) = read_char line in
+			loop (p + delta) line
 		in
 
-		let (delta, line) = read_char line in
-		loop (p + delta) line
-	in
-
-	try loop 0 ""; with End_of_file -> close_in ch;
-	List.rev !lines
-
-let resolve_file ctx f =
-	let ext = StringHelper.extension f in
-	let second_ext = StringHelper.extension (StringHelper.remove_extension f) in
-	let platform_ext = "." ^ (platform_name_macro ctx) in
-	if platform_ext = second_ext then
-		(StringHelper.remove_extension (StringHelper.remove_extension f)) ^ ext
-	else
-		f
+		try loop 0 ""; with End_of_file -> close_in ch;
+		List.rev !lines
+	end
 
 let error_printer file line = Printf.sprintf "%s:%d:" file line
 
@@ -95,12 +89,11 @@ let compiler_pretty_message_string com ectx cm =
 				let epos = if is_unknown_file cm.cm_pos.pfile then "(unknown position)" else cm.cm_pos.pfile in
 				(-1, -1, -1, -1, epos, [])
 			end else try begin
-				let f = resolve_file com cm.cm_pos.pfile in
-				let f = Common.find_file com f in
 				let l1, p1, l2, p2 = Lexer.get_pos_coords cm.cm_pos in
-				let lines = resolve_source f l1 p1 l2 p2 in
+				let lines = resolve_source cm.cm_pos.pfile l1 p1 l2 p2 in
 				let epos =
-					if ectx.absolute_positions then TPrinting.Printer.s_pos cm.cm_pos
+					if lines = [] then cm.cm_pos.pfile
+					else if ectx.absolute_positions then TPrinting.Printer.s_pos cm.cm_pos
 					else Lexer.get_error_pos error_printer cm.cm_pos
 				in
 				(l1, p1, l2, p2, epos, lines)
@@ -180,6 +173,20 @@ let compiler_pretty_message_string com ectx cm =
 				(* File + line pointer *)
 				epos;
 
+		(* Macros can send all sorts of bad positions; avoid failing too hard *)
+		let safe_sub s pos len =
+			if len < 0 then ""
+			else
+				let pos = if pos < 0 then 0 else pos in
+				let slen = String.length s in
+				if pos >= slen then ""
+				else
+					let len = if (pos + len) > slen then slen - pos else len in
+					try String.sub s pos len with
+					(* Should not happen anymore, but still better than a crash if I missed some case... *)
+					| Invalid_argument _ -> (Printf.sprintf "[%s;%i;%i]" s pos len)
+		in
+
 		(* Error source *)
 		if display_source then out := List.fold_left (fun out (l, line) ->
 			let nb_len = String.length (string_of_int l) in
@@ -198,18 +205,18 @@ let compiler_pretty_message_string com ectx cm =
 					if l = 0 then
 						c_dim ^ line ^ c_reset
 					else if l1 = l2 then
-						(if p1 > 1 then c_dim ^ (String.sub line 0 (p1-1)) else "")
-						^ c_reset ^ c_bold ^ (String.sub line (p1-1) (p2-p1))
-						^ c_reset ^ c_dim ^ (String.sub line (p2-1) (len - p2 + 1))
+						(if p1 > 1 then c_dim ^ (safe_sub line 0 (p1-1)) else "")
+						^ c_reset ^ c_bold ^ (safe_sub line (p1-1) (p2-p1))
+						^ c_reset ^ c_dim ^ (safe_sub line (p2-1) (len - p2 + 1))
 						^ c_reset
 					else begin
 						(if (l = l1) then
-							(if p1 > 1 then c_dim ^ (String.sub line 0 (p1-1)) else "")
-							^ c_reset ^ c_bold ^ (String.sub line (p1-1) (len-p1+1))
+							c_dim ^ (safe_sub line 0 (p1-1))
+							^ c_reset ^ c_bold ^ (safe_sub line (p1-1) (len-p1+1))
 							^ c_reset
 						else if (l = l2) then
-							(if p2 > 1 then c_bold ^ (String.sub line 0 (p2-1)) else "")
-							^ c_reset ^ c_dim ^ (String.sub line (p2-1) (len-p2+1))
+							c_bold ^ (safe_sub line 0 (p2-1))
+							^ c_reset ^ c_dim ^ (safe_sub line (p2-1) (len-p2+1))
 							^ c_reset
 						else c_bold ^ line ^ c_reset)
 					end
@@ -342,7 +349,7 @@ let format_messages com messages =
 	let absolute_positions = Define.defined com.defines Define.MessageAbsolutePositions in
 	let ectx = create_error_context absolute_positions in
 	ectx.max_lines <- get_max_line ectx.max_lines messages;
-	let message_formatter = get_formatter com Define.MessageReporting "classic" in
+	let message_formatter = get_formatter com Define.MessageReporting "pretty" in
 	let lines = List.rev (
 		List.fold_left (fun lines cm -> match (message_formatter ectx cm) with
 			| None -> lines
@@ -356,14 +363,19 @@ let display_messages ctx on_message = begin
 	let ectx = create_error_context absolute_positions in
 	ectx.max_lines <- get_max_line ectx.max_lines ctx.messages;
 
+	let error msg =
+		ctx.has_error <- true;
+		on_message MessageSeverity.Error msg
+	in
+
 	let get_formatter _ def default =
 		try get_formatter ctx.com def default
 		with | ConfigError s ->
-			error ctx s null_pos;
+			error s;
 			compiler_message_string
 	in
 
-	let message_formatter = get_formatter ctx.com Define.MessageReporting "classic" in
+	let message_formatter = get_formatter ctx.com Define.MessageReporting "pretty" in
 	let log_formatter = get_formatter ctx.com Define.MessageLogFormat "indent" in
 
 	let log_messages = ref (Define.defined ctx.com.defines Define.MessageLogFile) in
@@ -393,7 +405,7 @@ let display_messages ctx on_message = begin
 		end with
 			| Failure e | Sys_error e -> begin
 				let def = Define.get_define_key Define.MessageLogFile in
-				error ctx (Printf.sprintf "Error opening log file: %s. Logging to file disabled (-D %s)" e def) null_pos;
+				error (Printf.sprintf "Error opening log file: %s. Logging to file disabled (-D %s)" e def);
 				log_messages := false;
 			end
 	end;

+ 51 - 36
src/compiler/server.ml

@@ -291,7 +291,7 @@ let check_module sctx com m_path m_extra p =
 				end
 		in
 		let has_policy policy = List.mem policy m_extra.m_check_policy || match policy with
-			| NoCheckShadowing | NoCheckFileTimeModification when !ServerConfig.do_not_check_modules && !Parser.display_mode <> DMNone -> true
+			| NoFileSystemCheck when !ServerConfig.do_not_check_modules && !Parser.display_mode <> DMNone -> true
 			| _ -> false
 		in
 		let check_file () =
@@ -310,6 +310,11 @@ let check_module sctx com m_path m_extra p =
 			(com.cs#get_context sign)#find_module_extra mpath
 		in
 		let check_dependencies () =
+			let full_restore =
+				com.is_macro_context
+				|| com.display.dms_full_typing
+				|| DisplayPosition.display_position#is_in_file (Path.UniqueKey.lazy_key m_extra.m_file)
+			in
 			PMap.iter (fun _ mdep ->
 				let sign = mdep.md_sign in
 				let mpath = mdep.md_path in
@@ -321,13 +326,13 @@ let check_module sctx com m_path m_extra p =
 				match check mpath m2_extra with
 				| None -> ()
 				| Some reason -> raise (Dirty (DependencyDirty(mpath,reason)))
-			) m_extra.m_deps;
+			) (if full_restore then m_extra.m_deps else Option.default m_extra.m_deps m_extra.m_sig_deps)
 		in
 		let check () =
 			try
-				if not (has_policy NoCheckShadowing) then check_module_path();
-				if not (has_policy NoCheckFileTimeModification) || Path.file_extension (Path.UniqueKey.lazy_path m_extra.m_file) <> "hx" then check_file();
-				if not (has_policy NoCheckDependencies) then check_dependencies();
+				check_module_path();
+				if not (has_policy NoFileSystemCheck) || Path.file_extension (Path.UniqueKey.lazy_path m_extra.m_file) <> "hx" then check_file();
+				check_dependencies();
 				None
 			with
 			| Dirty reason ->
@@ -386,6 +391,20 @@ let check_module sctx com m_path m_extra p =
 	end;
 	state
 
+let get_hxb_module com cc path =
+	try
+		let mc = cc#get_hxb_module path in
+		if not com.is_macro_context && not com.display.dms_full_typing && not (DisplayPosition.display_position#is_in_file (Path.UniqueKey.lazy_key mc.mc_extra.m_file)) then begin
+			mc.mc_extra.m_cache_state <- MSGood;
+			BinaryModule mc
+		end else
+			begin match mc.mc_extra.m_cache_state with
+				| MSBad reason -> BadModule reason
+				| _ -> BinaryModule mc
+			end
+	with Not_found ->
+		NoModule
+
 class hxb_reader_api_server
 	(com : Common.context)
 	(cc : context_cache)
@@ -399,7 +418,9 @@ class hxb_reader_api_server
 			m_path = path;
 			m_types = [];
 			m_statics = None;
-			m_extra = mc.mc_extra
+			(* Creating a new m_extra because if we keep the same reference, display requests *)
+			(* can alter it with bad data (for example adding dependencies that are not cached) *)
+			m_extra = { mc.mc_extra with m_deps = mc.mc_extra.m_deps }
 		}
 
 	method add_module (m : module_def) =
@@ -415,37 +436,31 @@ class hxb_reader_api_server
 		| GoodModule m ->
 			m
 		| BinaryModule mc ->
-			let reader = new HxbReader.hxb_reader path com.hxb_reader_stats in
+			let reader = new HxbReader.hxb_reader path com.hxb_reader_stats (Some cc#get_string_pool_arr) (Common.defined com Define.HxbTimes) in
+			let is_display_file = DisplayPosition.display_position#is_in_file (Path.UniqueKey.lazy_key mc.mc_extra.m_file) in
+			let full_restore = com.is_macro_context || com.display.dms_full_typing || is_display_file in
 			let f_next chunks until =
 				let t_hxb = Timer.timer ["server";"module cache";"hxb read"] in
-				let r = reader#read_chunks_until (self :> HxbReaderApi.hxb_reader_api) chunks until in
+				let r = reader#read_chunks_until (self :> HxbReaderApi.hxb_reader_api) chunks until (not full_restore) in
 				t_hxb();
 				r
 			in
-			let m,chunks = f_next mc.mc_chunks EOF in
+			let m,chunks = f_next mc.mc_chunks EOT in
 
 			(* We try to avoid reading expressions as much as possible, so we only do this for
 				 our current display file if we're in display mode. *)
-			let is_display_file = DisplayPosition.display_position#is_in_file (Path.UniqueKey.lazy_key m.m_extra.m_file) in
-			if is_display_file || com.display.dms_full_typing then ignore(f_next chunks EOM)
-			else delay (fun () -> ignore(f_next chunks EOM));
+			if full_restore then ignore(f_next chunks EOM)
+			else delay (fun () -> ignore(f_next chunks EOF));
 			m
 		| BadModule reason ->
-			die (Printf.sprintf "Unexpected BadModule %s" (s_type_path path)) __LOC__
+			die (Printf.sprintf "Unexpected BadModule %s (%s)" (s_type_path path) (Printer.s_module_skip_reason reason)) __LOC__
 		| NoModule ->
 			die (Printf.sprintf "Unexpected NoModule %s" (s_type_path path)) __LOC__
 
 	method find_module (m_path : path) =
 		try
 			GoodModule (com.module_lut#find m_path)
-		with Not_found -> try
-			let mc = cc#get_hxb_module m_path in
-			begin match mc.mc_extra.m_cache_state with
-				| MSBad reason -> BadModule reason
-				| _ -> BinaryModule mc
-			end
-		with Not_found ->
-			NoModule
+		with Not_found -> get_hxb_module com cc m_path
 
 	method basic_types =
 		com.basic
@@ -488,6 +503,11 @@ let rec add_modules sctx com delay (m : module_def) (from_binary : bool) (p : po
 				if not from_binary || m != m then
 					com.module_lut#add m.m_path m;
 				handle_cache_bound_objects com m.m_extra.m_cache_bound_objects;
+				let full_restore =
+					com.is_macro_context
+					|| com.display.dms_full_typing
+					|| DisplayPosition.display_position#is_in_file (Path.UniqueKey.lazy_key m.m_extra.m_file)
+				in
 				PMap.iter (fun _ mdep ->
 					let mpath = mdep.md_path in
 					if mdep.md_sign = own_sign then begin
@@ -506,7 +526,7 @@ let rec add_modules sctx com delay (m : module_def) (from_binary : bool) (p : po
 						in
 						add_modules (tabs ^ "  ") m0 m2
 					end
-				) m.m_extra.m_deps
+				) (if full_restore then m.m_extra.m_deps else Option.default m.m_extra.m_deps m.m_extra.m_sig_deps)
 			)
 		end
 	in
@@ -540,14 +560,7 @@ and type_module sctx com delay mpath p =
 				| MSBad reason -> BadModule reason
 				| _ -> GoodModule m
 			end;
-		with Not_found -> try
-			let mc = cc#get_hxb_module m_path in
-			begin match mc.mc_extra.m_cache_state with
-				| MSBad reason -> BadModule reason
-				| _ -> BinaryModule mc
-			end
-		with Not_found ->
-			NoModule
+		with Not_found -> get_hxb_module com cc m_path
 	in
 	(* Should not raise anything! *)
 	let m = match find_module_in_cache cc mpath p with
@@ -565,7 +578,9 @@ and type_module sctx com delay mpath p =
 			   checking dependencies. This means that the actual decoding never has any reason to fail. *)
 			begin match check_module sctx mpath mc.mc_extra p with
 				| None ->
-					let reader = new HxbReader.hxb_reader mpath com.hxb_reader_stats in
+					let reader = new HxbReader.hxb_reader mpath com.hxb_reader_stats (Some cc#get_string_pool_arr) (Common.defined com Define.HxbTimes) in
+					let is_display_file = DisplayPosition.display_position#is_in_file (Path.UniqueKey.lazy_key mc.mc_extra.m_file) in
+					let full_restore = com.is_macro_context || com.display.dms_full_typing || is_display_file in
 					let api = match com.hxb_reader_api with
 						| Some api ->
 							api
@@ -576,16 +591,15 @@ and type_module sctx com delay mpath p =
 					in
 					let f_next chunks until =
 						let t_hxb = Timer.timer ["server";"module cache";"hxb read"] in
-						let r = reader#read_chunks_until api chunks until in
+						let r = reader#read_chunks_until api chunks until (not full_restore) in
 						t_hxb();
 						r
 					in
-					let m,chunks = f_next mc.mc_chunks EOF in
+					let m,chunks = f_next mc.mc_chunks EOT in
 					(* We try to avoid reading expressions as much as possible, so we only do this for
 					   our current display file if we're in display mode. *)
-					let is_display_file = DisplayPosition.display_position#is_in_file (Path.UniqueKey.lazy_key m.m_extra.m_file) in
-					if is_display_file || com.display.dms_full_typing then ignore(f_next chunks EOM)
-					else delay (fun () -> ignore(f_next chunks EOM));
+					if full_restore then ignore(f_next chunks EOM)
+					else delay (fun () -> ignore(f_next chunks EOF));
 					add_modules true m;
 				| Some reason ->
 					skip mpath reason
@@ -626,6 +640,7 @@ let after_save sctx ctx =
 		maybe_cache_context sctx ctx.com
 
 let after_compilation sctx ctx =
+	sctx.cs#clear_temp_cache;
 	()
 
 let mk_length_prefixed_communication allow_nonblock chin chout =

+ 1 - 3
src/compiler/serverConfig.ml

@@ -1,11 +1,9 @@
 let do_not_check_modules = ref false
-let populate_cache_from_display = ref true
 let legacy_completion = ref false
 
 let max_completion_items = ref 0
 
 let reset () =
 	do_not_check_modules := false;
-	populate_cache_from_display := true;
 	legacy_completion := false;
-	max_completion_items := 0
+	max_completion_items := 0

+ 6 - 5
src/context/abstractCast.ml

@@ -244,7 +244,7 @@ let find_multitype_specialization com a pl p =
 	cf, follow m
 
 let handle_abstract_casts ctx e =
-	let rec loop ctx e = match e.eexpr with
+	let rec loop e = match e.eexpr with
 		| TNew({cl_kind = KAbstractImpl a} as c,pl,el) ->
 			if not (Meta.has Meta.MultiType a.a_meta) then begin
 				(* This must have been a @:generic expansion with a { new } constraint (issue #4364). In this case
@@ -296,10 +296,11 @@ let handle_abstract_casts ctx e =
 					| TCast(e2,None) ->
 						{e1 with eexpr = TCast(find_field e2,None)}
 					| TField(e2,fa) ->
+						let e2 = loop e2 in
 						let a,pl,e2 = find_abstract e2 e2.etype in
 						let m = Abstract.get_underlying_type a pl in
 						let fname = field_name fa in
-						let el = List.map (loop ctx) el in
+						let el = List.map loop el in
 						begin try
 							let fa = quick_field m fname in
 							let get_fun_type t = match follow t with
@@ -353,11 +354,11 @@ let handle_abstract_casts ctx e =
 				in
 				find_field e1
 			with Not_found ->
-				Type.map_expr (loop ctx) e
+				Type.map_expr loop e
 			end
 		| _ ->
-			Type.map_expr (loop ctx) e
+			Type.map_expr loop e
 	in
-	loop ctx e
+	loop e
 ;;
 Typecore.cast_or_unify_raise_ref := cast_or_unify_raise

+ 12 - 1
src/context/common.ml

@@ -230,6 +230,13 @@ class file_keys = object(self)
 			let key = Path.UniqueKey.create file in
 			Hashtbl.add cache file key;
 			key
+
+	val virtual_counter = ref 0
+
+	method generate_virtual step =
+		incr virtual_counter;
+		Printf.sprintf "file_%i_%i" step !virtual_counter
+
 end
 
 type shared_display_information = {
@@ -338,6 +345,7 @@ class virtual abstract_hxb_lib = object(self)
 	method virtual get_bytes : string -> path -> bytes option
 	method virtual close : unit
 	method virtual get_file_path : string
+	method virtual get_string_pool : string -> string array option
 end
 
 type context_main = {
@@ -435,7 +443,7 @@ let ignore_error com =
 	b
 
 let module_warning com m w options msg p =
-	DynArray.add m.m_extra.m_cache_bound_objects (Warning(w,msg,p));
+	if com.display.dms_full_typing then DynArray.add m.m_extra.m_cache_bound_objects (Warning(w,msg,p));
 	com.warning w options msg p
 
 (* Defines *)
@@ -469,6 +477,7 @@ let convert_define k =
 	String.concat "_" (ExtString.String.nsplit k "-")
 
 let is_next com = defined com HaxeNext
+let fail_fast com = defined com FailFast
 
 let external_defined ctx k =
 	Define.raw_defined ctx.defines (convert_define k)
@@ -826,6 +835,7 @@ let create compilation_step cs version args display_mode =
 		pass_debug_messages = DynArray.create();
 		basic = {
 			tvoid = mk_mono();
+			tany = mk_mono();
 			tint = mk_mono();
 			tfloat = mk_mono();
 			tbool = mk_mono();
@@ -873,6 +883,7 @@ let clone com is_macro_context =
 		cache = None;
 		basic = { t with
 			tvoid = mk_mono();
+			tany = mk_mono();
 			tint = mk_mono();
 			tfloat = mk_mono();
 			tbool = mk_mono();

+ 28 - 16
src/context/commonCache.ml

@@ -11,7 +11,7 @@ class lib_build_task cs file ftime lib = object(self)
 		let h = Hashtbl.create 0 in
 		List.iter (fun path ->
 			if not (Hashtbl.mem h path) then begin
-				let p = { pfile = file ^ " @ " ^ Globals.s_type_path path; pmin = 0; pmax = 0; } in
+				let p = file_pos (file ^ " @ " ^ Globals.s_type_path path) in
 				try begin match lib#build path p with
 				| Some r -> Hashtbl.add h path r
 				| None -> ()
@@ -84,27 +84,39 @@ let get_cache_sign com = match com.Common.cache with
 let rec cache_context cs com =
 	let cc = get_cache com in
 	let sign = Define.get_signature com.defines in
-	let anon_identification = new Tanon_identification.tanon_identification in
-	let config = match com.hxb_writer_config with
-		| None ->
-			HxbWriterConfig.create_target_config ()
-		| Some config ->
-			if com.is_macro_context then config.macro_config else config.target_config
-	in
-	let cache_module m =
-		(* If we have a signature mismatch, look-up cache for module. Physical equality check is fine as a heueristic. *)
-		let cc = if m.m_extra.m_sign = sign then cc else cs#get_context m.m_extra.m_sign in
-		let warn w s p = com.warning w com.warning_options s p in
-		cc#cache_module config warn anon_identification m.m_path m;
+
+	let cache_module =
+		if Define.defined com.defines DisableHxbCache then
+			let cache_module m =
+				(* If we have a signature mismatch, look-up cache for module. Physical equality check is fine as a heuristic. *)
+				let cc = if m.m_extra.m_sign = sign then cc else cs#get_context m.m_extra.m_sign in
+				cc#cache_module_in_memory m.m_path m;
+			in
+			cache_module
+		else
+			let anon_identification = new Tanon_identification.tanon_identification in
+			let warn w s p = com.warning w com.warning_options s p in
+			let config = match com.hxb_writer_config with
+				| None ->
+					HxbWriterConfig.create_target_config ()
+				| Some config ->
+					if com.is_macro_context then config.macro_config else config.target_config
+			in
+			let cache_module m =
+				(* If we have a signature mismatch, look-up cache for module. Physical equality check is fine as a heuristic. *)
+				let cc = if m.m_extra.m_sign = sign then cc else cs#get_context m.m_extra.m_sign in
+				cc#cache_hxb_module config warn anon_identification m.m_path m;
+			in
+			cache_module
 	in
+
 	List.iter cache_module com.modules;
 	begin match com.get_macros() with
 		| None -> ()
 		| Some com -> cache_context cs com
 	end;
-	if Define.raw_defined com.defines "hxb.stats" then begin
-		HxbReader.dump_stats (platform_name com.platform) com.hxb_reader_stats;
-	end
+	if Define.raw_defined com.defines "hxb.stats" then
+		HxbReader.dump_stats (platform_name com.platform) com.hxb_reader_stats
 
 let maybe_add_context_sign cs com desc =
 	let sign = Define.get_signature com.defines in

+ 13 - 21
src/context/display/displayJson.ml

@@ -99,13 +99,13 @@ class display_handler (jsonrpc : jsonrpc_handler) com (cs : CompilationCache.t)
 			com.file_contents <- file_contents;
 
 			match files with
-			| [] | [_] -> DisplayPosition.display_position#set { pfile = file; pmin = pos; pmax = pos; };
+			| [] -> DisplayPosition.display_position#set { pfile = file; pmin = pos; pmax = pos; };
 			| _ -> DisplayPosition.display_position#set_files files;
 		end
 end
 
 class hxb_reader_api_com
-	~(headers_only : bool)
+	~(minimal_restore : bool)
 	(com : Common.context)
 	(cc : CompilationCache.context_cache)
 = object(self)
@@ -116,7 +116,9 @@ class hxb_reader_api_com
 			m_path = path;
 			m_types = [];
 			m_statics = None;
-			m_extra = mc.mc_extra
+			(* Creating a new m_extra because if we keep the same reference, display requests *)
+			(* can alter it with bad data (for example adding dependencies that are not cached) *)
+			m_extra = { mc.mc_extra with m_deps = mc.mc_extra.m_deps }
 		}
 
 	method add_module (m : module_def) =
@@ -137,8 +139,8 @@ class hxb_reader_api_com
 			cc#find_module m_path
 		with Not_found ->
 			let mc = cc#get_hxb_module m_path in
-			let reader = new HxbReader.hxb_reader mc.mc_path com.hxb_reader_stats in
-			fst (reader#read_chunks_until (self :> HxbReaderApi.hxb_reader_api) mc.mc_chunks (if headers_only then MTF else EOM))
+			let reader = new HxbReader.hxb_reader mc.mc_path com.hxb_reader_stats (Some cc#get_string_pool_arr) (Common.defined com Define.HxbTimes) in
+			fst (reader#read_chunks_until (self :> HxbReaderApi.hxb_reader_api) mc.mc_chunks (if minimal_restore then MTF else EOM) minimal_restore)
 
 	method basic_types =
 		com.basic
@@ -150,8 +152,8 @@ class hxb_reader_api_com
 		false
 end
 
-let find_module ~(headers_only : bool) com cc path =
-	(new hxb_reader_api_com ~headers_only com cc)#find_module path
+let find_module ~(minimal_restore : bool) com cc path =
+	(new hxb_reader_api_com ~minimal_restore com cc)#find_module path
 
 type handler_context = {
 	com : Common.context;
@@ -208,12 +210,8 @@ let handler =
 		"display/diagnostics", (fun hctx ->
 			hctx.display#set_display_file false false;
 			hctx.display#enable_display DMNone;
+			hctx.com.display <- { hctx.com.display with dms_display_file_policy = DFPAlso; dms_per_file = true; dms_populate_cache = true };
 			hctx.com.report_mode <- RMDiagnostics (List.map (fun (f,_) -> f) hctx.com.file_contents);
-
-			(match hctx.com.file_contents with
-			| [file, None] ->
-				hctx.com.display <- { hctx.com.display with dms_display_file_policy = DFPAlso; dms_per_file = true; dms_populate_cache = !ServerConfig.populate_cache_from_display};
-			| _ -> ());
 		);
 		"display/implementation", (fun hctx ->
 			hctx.display#set_display_file false true;
@@ -350,11 +348,11 @@ let handler =
 			let cs = hctx.display#get_cs in
 			let cc = cs#get_context sign in
 			let m = try
-				find_module ~headers_only:true hctx.com cc path
+				find_module ~minimal_restore:true hctx.com cc path
 			with Not_found ->
 				hctx.send_error [jstring "No such module"]
 			in
-			hctx.send_result (generate_module (cc#get_hxb) (find_module ~headers_only:true hctx.com cc) m)
+			hctx.send_result (generate_module (cc#get_hxb) (find_module ~minimal_restore:true hctx.com cc) m)
 		);
 		"server/type", (fun hctx ->
 			let sign = Digest.from_hex (hctx.jsonrpc#get_string_param "signature") in
@@ -362,7 +360,7 @@ let handler =
 			let typeName = hctx.jsonrpc#get_string_param "typeName" in
 			let cc = hctx.display#get_cs#get_context sign in
 			let m = try
-				find_module ~headers_only:true hctx.com cc path
+				find_module ~minimal_restore:true hctx.com cc path
 			with Not_found ->
 				hctx.send_error [jstring "No such module"]
 			in
@@ -462,12 +460,6 @@ let handler =
 				l := jstring ("Legacy completion " ^ (if b then "enabled" else "disabled")) :: !l;
 				()
 			) ();
-			hctx.jsonrpc#get_opt_param (fun () ->
-				let b = hctx.jsonrpc#get_bool_param "populateCacheFromDisplay" in
-				ServerConfig.populate_cache_from_display := b;
-				l := jstring ("Compilation cache refill from display " ^ (if b then "enabled" else "disabled")) :: !l;
-				()
-			) ();
 			hctx.send_result (jarray !l)
 		);
 		"server/memory",(fun hctx ->

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

@@ -189,7 +189,7 @@ let handle_path_display ctx path p =
 			(* 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 = (Path.UniqueKey.lazy_path mt.m_extra.m_file); pmin = 0; pmax = 0} in
+			let p = file_pos (Path.UniqueKey.lazy_path mt.m_extra.m_file) in
 			raise_positions [p]
 		| (IDKModule(sl,s),_),DMHover ->
 			let m = ctx.g.do_load_module ctx (sl,s) p in

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

@@ -177,7 +177,7 @@ let check_display_file ctx cs =
 				| NoModule | BadModule _ -> raise Not_found
 				| BinaryModule mc ->
 					let api = (new TypeloadModule.hxb_reader_api_typeload ctx.com ctx.g TypeloadModule.load_module' p :> HxbReaderApi.hxb_reader_api) in
-					let reader = new HxbReader.hxb_reader path ctx.com.hxb_reader_stats in
+					let reader = new HxbReader.hxb_reader path ctx.com.hxb_reader_stats (Some cc#get_string_pool_arr) (Common.defined ctx.com Define.HxbTimes) in
 					let m = reader#read_chunks api mc.mc_chunks in
 					m
 				| GoodModule m ->

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

@@ -114,7 +114,7 @@ let collect_module_symbols mname with_locals (pack,decls) =
 	) decls;
 	begin match mname with
 	| Some(file,mname) when not (Hashtbl.mem type_decls mname) ->
-		add mname Module {pfile = file; pmin = 0; pmax = 0} (String.concat "." pack) false
+		add mname Module (file_pos file) (String.concat "." pack) false
 	| _ ->
 		()
 	end;

+ 3 - 3
src/context/display/importHandling.ml

@@ -81,7 +81,7 @@ let init_import ctx path mode p =
 	| (tname,p2) :: rest ->
 		let p1 = (match pack with [] -> p2 | (_,p1) :: _ -> p1) in
 		let p_type = punion p1 p2 in
-		let md = ctx.g.do_load_module ctx (List.map fst pack,tname) p_type in
+		let md = ctx.g.do_load_module ~origin:MDepFromImport ctx (List.map fst pack,tname) p_type in
 		let types = md.m_types in
 		let not_private mt = not (t_infos mt).mt_private in
 		let error_private p = raise_typing_error "Importing private declarations from a module is not allowed" p in
@@ -166,7 +166,7 @@ let init_import ctx path mode p =
 							check_alias tsub name pname;
 							Some name
 					in
-					ctx.m.import_resolution#add (module_type_resolution tsub alias p2);
+					ctx.m.import_resolution#add (module_type_resolution tsub alias p);
 				with Not_found ->
 					(* this might be a static property, wait later to check *)
 					let find_main_type_static () =
@@ -267,7 +267,7 @@ let handle_using ctx path p =
 	in
 	let types = (match t.tsub with
 		| None ->
-			let md = ctx.g.do_load_module ctx (t.tpackage,t.tname) p in
+			let md = ctx.g.do_load_module ~origin:MDepFromImport ctx (t.tpackage,t.tname) p in
 			let types = List.filter (fun t -> not (t_infos t).mt_private) md.m_types in
 			Option.map_default (fun c -> (TClassDecl c) :: types) types md.m_statics
 		| Some _ ->

+ 63 - 8
src/context/memory.ml

@@ -113,6 +113,9 @@ let get_memory_json (cs : CompilationCache.t) mreq =
 			"context",cc#get_json;
 			"size",jint (mem_size cc);
 		]) contexts in
+		let mem_size_2 v exclude =
+			Objsize.size_with_headers (Objsize.objsize v exclude [])
+		in
 		jobject [
 			"contexts",jarray j_contexts;
 			"memory",jobject [
@@ -121,14 +124,66 @@ let get_memory_json (cs : CompilationCache.t) mreq =
 				"haxelibCache",jint (mem_size cache_mem.(1));
 				"directoryCache",jint (mem_size cache_mem.(2));
 				"nativeLibCache",jint (mem_size cache_mem.(3));
-				"additionalSizes",jarray [
-					jobject ["name",jstring "macro interpreter";"size",jint (mem_size (MacroContext.macro_interp_cache))];
-					(* jobject ["name",jstring "macro stdlib";"size",jint (mem_size (EvalContext.GlobalState.stdlib))];
-					jobject ["name",jstring "macro macro_lib";"size",jint (mem_size (EvalContext.GlobalState.macro_lib))]; *)
-					jobject ["name",jstring "last completion result";"size",jint (mem_size (DisplayException.last_completion_result))];
-					jobject ["name",jstring "Lexer file cache";"size",jint (mem_size (Lexer.all_files))];
-					jobject ["name",jstring "GC heap words";"size",jint (int_of_float size)];
-				];
+				"additionalSizes",jarray (
+					(match !MacroContext.macro_interp_cache with
+					| Some interp ->
+						jobject ["name",jstring "macro interpreter";"size",jint (mem_size MacroContext.macro_interp_cache);"child",jarray [
+							jobject ["name",jstring "builtins";"size",jint (mem_size_2 interp.builtins [Obj.repr interp])];
+							jobject ["name",jstring "debug";"size",jint (mem_size_2 interp.debug [Obj.repr interp])];
+							jobject ["name",jstring "curapi";"size",jint (mem_size_2 interp.curapi [Obj.repr interp])];
+							jobject ["name",jstring "type_cache";"size",jint (mem_size_2 interp.type_cache [Obj.repr interp])];
+							jobject ["name",jstring "overrides";"size",jint (mem_size_2 interp.overrides [Obj.repr interp])];
+							jobject ["name",jstring "array_prototype";"size",jint (mem_size_2 interp.array_prototype [Obj.repr interp])];
+							jobject ["name",jstring "string_prototype";"size",jint (mem_size_2 interp.string_prototype [Obj.repr interp])];
+							jobject ["name",jstring "vector_prototype";"size",jint (mem_size_2 interp.vector_prototype [Obj.repr interp])];
+							jobject ["name",jstring "instance_prototypes";"size",jint (mem_size_2 interp.instance_prototypes [Obj.repr interp])];
+							jobject ["name",jstring "static_prototypes";"size",jint (mem_size_2 interp.static_prototypes [Obj.repr interp])];
+							jobject ["name",jstring "constructors";"size",jint (mem_size_2 interp.constructors [Obj.repr interp])];
+							jobject ["name",jstring "file_keys";"size",jint (mem_size_2 interp.file_keys [Obj.repr interp])];
+							jobject ["name",jstring "toplevel";"size",jint (mem_size_2 interp.toplevel [Obj.repr interp])];
+							jobject ["name",jstring "eval";"size",jint (mem_size_2 interp.eval [Obj.repr interp]);"child", jarray [
+								(match interp.eval.env with
+								| Some env ->
+									jobject ["name",jstring "env";"size",jint (mem_size_2 interp.eval.env [Obj.repr interp; Obj.repr interp.eval]);"child", jarray [
+										jobject ["name",jstring "env_info";"size",jint (mem_size_2 env.env_info [Obj.repr interp; Obj.repr interp.eval; Obj.repr env])];
+										jobject ["name",jstring "env_debug";"size",jint (mem_size_2 env.env_debug [Obj.repr interp; Obj.repr interp.eval; Obj.repr env])];
+										jobject ["name",jstring "env_locals";"size",jint (mem_size_2 env.env_locals [Obj.repr interp; Obj.repr interp.eval; Obj.repr env])];
+										jobject ["name",jstring "env_captures";"size",jint (mem_size_2 env.env_captures [Obj.repr interp; Obj.repr interp.eval; Obj.repr env])];
+										jobject ["name",jstring "env_extra_locals";"size",jint (mem_size_2 env.env_extra_locals [Obj.repr interp; Obj.repr interp.eval; Obj.repr env])];
+										jobject ["name",jstring "env_parent";"size",jint (mem_size_2 env.env_parent [Obj.repr interp; Obj.repr interp.eval; Obj.repr env])];
+										jobject ["name",jstring "env_eval";"size",jint (mem_size_2 env.env_eval [Obj.repr interp; Obj.repr interp.eval; Obj.repr env])];
+									]];
+								| None ->
+									jobject ["name",jstring "env";"size",jint (mem_size_2 interp.eval.env [Obj.repr interp; Obj.repr interp.eval])];
+								);
+								jobject ["name",jstring "thread";"size",jint (mem_size_2 interp.eval.thread [Obj.repr interp; Obj.repr interp.eval]);"child", jarray [
+									jobject ["name",jstring "tthread";"size",jint (mem_size_2 interp.eval.thread.tthread [Obj.repr interp; Obj.repr interp.eval; Obj.repr interp.eval.thread])];
+									jobject ["name",jstring "tdeque";"size",jint (mem_size_2 interp.eval.thread.tdeque [Obj.repr interp; Obj.repr interp.eval; Obj.repr interp.eval.thread])];
+									jobject ["name",jstring "tevents";"size",jint (mem_size_2 interp.eval.thread.tevents [Obj.repr interp; Obj.repr interp.eval; Obj.repr interp.eval.thread])];
+									jobject ["name",jstring "tstorage";"size",jint (mem_size_2 interp.eval.thread.tstorage [Obj.repr interp; Obj.repr interp.eval; Obj.repr interp.eval.thread])];
+								]];
+								jobject ["name",jstring "debug_state";"size",jint (mem_size_2 interp.eval.debug_state [Obj.repr interp; Obj.repr interp.eval])];
+								jobject ["name",jstring "breakpoint";"size",jint (mem_size_2 interp.eval.breakpoint [Obj.repr interp; Obj.repr interp.eval])];
+								jobject ["name",jstring "caught_types";"size",jint (mem_size_2 interp.eval.caught_types [Obj.repr interp; Obj.repr interp.eval])];
+								jobject ["name",jstring "caught_exception";"size",jint (mem_size_2 interp.eval.caught_exception [Obj.repr interp; Obj.repr interp.eval])];
+								jobject ["name",jstring "last_return";"size",jint (mem_size_2 interp.eval.last_return [Obj.repr interp; Obj.repr interp.eval])];
+								jobject ["name",jstring "debug_channel";"size",jint (mem_size_2 interp.eval.debug_channel [Obj.repr interp; Obj.repr interp.eval])];
+							]];
+							jobject ["name",jstring "evals";"size",jint (mem_size_2 interp.evals [Obj.repr interp])];
+							jobject ["name",jstring "exception_stack";"size",jint (mem_size_2 interp.exception_stack [Obj.repr interp])];
+						]];
+					| None ->
+						jobject ["name",jstring "macro interpreter";"size",jint (mem_size MacroContext.macro_interp_cache)];
+					)
+					::
+					[
+						(* jobject ["name",jstring "macro stdlib";"size",jint (mem_size (EvalContext.GlobalState.stdlib))];
+						jobject ["name",jstring "macro macro_lib";"size",jint (mem_size (EvalContext.GlobalState.macro_lib))]; *)
+						jobject ["name",jstring "last completion result";"size",jint (mem_size (DisplayException.last_completion_result))];
+						jobject ["name",jstring "Lexer file cache";"size",jint (mem_size (Lexer.all_files))];
+						jobject ["name",jstring "GC heap words";"size",jint (int_of_float size)];
+					]
+				);
 			]
 		]
 	| MContext sign ->

+ 1 - 1
src/context/typecore.ml

@@ -127,7 +127,7 @@ type typer_globals = {
 	(* api *)
 	do_macro : typer -> macro_mode -> path -> string -> expr list -> pos -> macro_result;
 	do_load_macro : typer -> bool -> path -> string -> pos -> ((string * bool * t) list * t * tclass * Type.tclass_field);
-	do_load_module : typer -> path -> pos -> module_def;
+	do_load_module : ?origin:module_dep_origin -> typer -> path -> pos -> module_def;
 	do_load_type_def : typer -> pos -> type_path -> module_type;
 	get_build_info : typer -> module_type -> pos -> build_info;
 	do_format_string : typer -> string -> pos -> Ast.expr;

+ 1 - 1
src/core/define.ml

@@ -152,7 +152,7 @@ let get_signature def =
 			   Parser.parse_macro_ident as well (issue #5682).
 			   Note that we should removed flags like use_rtti_doc here.
 			*)
-			| "display" | "use_rtti_doc" | "macro_times" | "display_details" | "no_copt" | "display_stdin" | "hxb.stats"
+			| "display" | "use_rtti_doc" | "macro_times" | "display_details" | "no_copt" | "display_stdin" | "disable-hxb-cache" | "hxb.stats" | "fail_fast"
 			| "message.reporting" | "message.log_file" | "message.log_format" | "message.no_color"
 			| "dump" | "dump_dependencies" | "dump_ignore_var_ids" -> acc
 			| _ -> (k ^ "=" ^ v) :: acc

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

@@ -203,7 +203,7 @@ module CompletionModuleType = struct
 			| TClassDecl c ->
 				(has_class_flag c CExtern),has_class_flag c CFinal,has_class_flag c CAbstract,(if (has_class_flag c CInterface) then Interface else Class),ctor c
 			| TEnumDecl en ->
-				en.e_extern,false,false,Enum,No
+				(has_enum_flag en EnExtern),false,false,Enum,No
 			| TTypeDecl td ->
 				let kind,ctor = match follow td.t_type with
 					| TAnon _ -> Struct,No

+ 5 - 1
src/core/display/displayPosition.ml

@@ -23,11 +23,15 @@ class display_position_container =
 		method set p =
 			pos <- p;
 			last_pos <- p;
-			file_key <- None
+			file_key <- None;
+			file_keys <- if p.pfile = DisplayProcessingGlobals.file_input_marker then [] else [Path.UniqueKey.create p.pfile]
 
 		method set_files files =
 			file_keys <- files
 
+		method get_files =
+			file_keys
+
 		(**
 			Get current display position
 		*)

+ 27 - 0
src/core/ds/stringDynArray.ml

@@ -0,0 +1,27 @@
+type t = {
+	mutable arr : string array;
+	mutable length : int;
+}
+
+let create length = {
+	arr = Array.make length "";
+	length = 0;
+}
+
+let length d =
+	d.length
+
+let add d s =
+	let length = Array.length d.arr in
+	if d.length = length then begin
+		let new_arr = Array.make (length * 2) "" in
+		Array.blit d.arr 0 new_arr 0 length;
+		d.arr <- new_arr;
+	end;
+	d.arr.(d.length) <- s;
+	d.length <- d.length + 1
+
+let iter d f =
+	for i = 0 to d.length - 1 do
+		f (Array.unsafe_get d.arr i)
+	done

+ 43 - 0
src/core/ds/stringPool.ml

@@ -0,0 +1,43 @@
+module StringHashtbl = Hashtbl.Make(struct
+	type t = string
+
+	let equal =
+		String.equal
+
+	let hash s =
+		(* What's the best here? *)
+		Hashtbl.hash s
+end)
+
+type t = {
+	lut : int StringHashtbl.t;
+	items : StringDynArray.t;
+	mutable closed : bool;
+}
+
+let create () = {
+	lut = StringHashtbl.create 16;
+	items = StringDynArray.create 16;
+	closed = false;
+}
+
+let add sp s =
+	assert (not sp.closed);
+	let index = StringDynArray.length sp.items in
+	StringHashtbl.add sp.lut s index;
+	StringDynArray.add sp.items s;
+	index
+
+let get sp s =
+	StringHashtbl.find sp.lut s
+
+let get_or_add sp s =
+	try
+		get sp s
+	with Not_found ->
+		add sp s
+
+let finalize sp =
+	assert (not sp.closed);
+	sp.closed <- true;
+	sp.items

+ 7 - 0
src/core/error.ml

@@ -328,6 +328,13 @@ let raise_msg ?(depth = 0) msg p = raise_error_msg ~depth (Custom msg) p
 let raise_typing_error ?(depth = 0) msg p = raise_msg ~depth msg p
 let raise_typing_error_ext err = raise_error err
 
+let raise_std_not_found () =
+	try
+		let std_path = Sys.getenv "HAXE_STD_PATH" in
+		raise_typing_error ("Standard library not found. Please check your `HAXE_STD_PATH` environment variable (current value: \"" ^ std_path ^ "\")") null_pos
+	with Not_found ->
+		raise_typing_error "Standard library not found. You may need to set your `HAXE_STD_PATH` environment variable" null_pos
+
 let error_require r p =
 	if r = "" then
 		raise_typing_error "This field is not available with the current compilation flags" p

+ 3 - 1
src/core/globals.ml

@@ -30,7 +30,9 @@ let version_minor = (version mod 1000) / 100
 let version_revision = (version mod 100)
 let version_pre = Some "alpha.1"
 
-let null_pos = { pfile = "?"; pmin = -1; pmax = -1 }
+let file_pos file = { pfile = file; pmin = 0; pmax = 0 }
+let fake_pos p = { pfile = p; pmin = -1; pmax = -1 }
+let null_pos = fake_pos "?"
 
 let no_color = false
 let c_reset = if no_color then "" else "\x1b[0m"

+ 1 - 1
src/core/json/genjson.ml

@@ -637,7 +637,7 @@ let generate_enum ctx e =
 	in
 	[
 		"constructors",generate_enum_constructors ();
-		"isExtern",jbool e.e_extern;
+		"isExtern",jbool (has_enum_flag e EnExtern)
 	]
 
 let generate_typedef ctx td =

+ 25 - 7
src/core/tFunctions.ml

@@ -44,6 +44,18 @@ let remove_class_field_flag cf (flag : flag_tclass_field) =
 let has_class_field_flag cf (flag : flag_tclass_field) =
 	has_flag cf.cf_flags (int_of_class_field_flag flag)
 
+let int_of_enum_flag (flag : flag_tenum) =
+	Obj.magic flag
+
+let add_enum_flag e (flag : flag_tenum) =
+	e.e_flags <- set_flag e.e_flags (int_of_enum_flag flag)
+
+let remove_enum_flag e (flag : flag_tenum) =
+	e.e_flags <- unset_flag e.e_flags (int_of_enum_flag flag)
+
+let has_enum_flag e (flag : flag_tenum) =
+	has_flag e.e_flags (int_of_enum_flag flag)
+
 let int_of_var_flag (flag : flag_tvar) =
 	Obj.magic flag
 
@@ -171,6 +183,7 @@ let module_extra file sign time kind added policy =
 		m_time = time;
 		m_processed = 0;
 		m_deps = PMap.empty;
+		m_sig_deps = None;
 		m_kind = kind;
 		m_cache_bound_objects = DynArray.create ();
 		m_features = Hashtbl.create 0;
@@ -246,7 +259,7 @@ let null_enum = {
 	e_using = [];
 	e_restore = (fun () -> ());
 	e_type = t_dynamic;
-	e_extern = false;
+	e_flags = 0;
 	e_constrs = PMap.empty;
 	e_names = [];
 }
@@ -286,15 +299,20 @@ let null_abstract = {
 	a_read = None;
 	a_write = None;
 	a_call = None;
+	a_extern = false;
 	a_enum = false;
 }
 
-let add_dependency ?(skip_postprocess=false) m mdep =
-	if m != null_module && mdep != null_module && (m.m_path != mdep.m_path || m.m_extra.m_sign != mdep.m_extra.m_sign) then begin
-		m.m_extra.m_deps <- PMap.add mdep.m_id ({md_sign = mdep.m_extra.m_sign; md_path = mdep.m_path; md_kind = mdep.m_extra.m_kind}) m.m_extra.m_deps;
-		(* In case the module is cached, we'll have to run post-processing on it again (issue #10635) *)
-		if not skip_postprocess then m.m_extra.m_processed <- 0
-	end
+let add_dependency ?(skip_postprocess=false) m mdep = function
+	(* These module dependency origins should not add as a dependency *)
+	| MDepFromMacroInclude -> ()
+
+	| origin ->
+		if m != null_module && mdep != null_module && (m.m_path != mdep.m_path || m.m_extra.m_sign != mdep.m_extra.m_sign) then begin
+			m.m_extra.m_deps <- PMap.add mdep.m_id ({md_sign = mdep.m_extra.m_sign; md_path = mdep.m_path; md_kind = mdep.m_extra.m_kind; md_origin = origin}) m.m_extra.m_deps;
+			(* In case the module is cached, we'll have to run post-processing on it again (issue #10635) *)
+			if not skip_postprocess then m.m_extra.m_processed <- 0
+		end
 
 let arg_name (a,_) = a.v_name
 

+ 2 - 46
src/core/tOther.ml

@@ -274,52 +274,7 @@ let mk_enum m path pos name_pos =
 		e_using = [];
 		e_restore = (fun () -> ());
 		e_private = false;
-		e_extern = false;
-		e_constrs = PMap.empty;
-		e_names = [];
-		e_type = mk_mono();
-	}
-
-let mk_abstract m path pos name_pos =
-	{
-		a_path = path;
-		a_private = false;
-		a_module = m;
-		a_pos = pos;
-		a_name_pos = name_pos;
-		a_doc = None;
-		a_params = [];
-		a_using = [];
-		a_restore = (fun () -> ());
-		a_meta = [];
-		a_from = [];
-		a_to = [];
-		a_from_field = [];
-		a_to_field = [];
-		a_ops = [];
-		a_unops = [];
-		a_impl = None;
-		a_array = [];
-		a_this = mk_mono();
-		a_read = None;
-		a_write = None;
-		a_enum = false;
-		a_call = None;
-	}
-
-let mk_enum m path pos name_pos =
-	{
-		e_path = path;
-		e_module = m;
-		e_pos = pos;
-		e_name_pos = name_pos;
-		e_doc = None;
-		e_meta = [];
-		e_params = [];
-		e_using = [];
-		e_restore = (fun () -> ());
-		e_private = false;
-		e_extern = false;
+		e_flags = 0;
 		e_constrs = PMap.empty;
 		e_names = [];
 		e_type = mk_mono();
@@ -348,6 +303,7 @@ let mk_abstract m path pos name_pos =
 		a_this = mk_mono();
 		a_read = None;
 		a_write = None;
+		a_extern = false;
 		a_enum = false;
 		a_call = None;
 	}

+ 10 - 2
src/core/tPrinting.ml

@@ -461,6 +461,7 @@ module Printer = struct
 		| TPHEnumConstructor -> "TPHEnumConstructor"
 		| TPHAnonField -> "TPHAnonField"
 		| TPHLocal -> "TPHLocal"
+		| TPHUnbound -> "TPHUnbound"
 
 	let s_type_param tabs ttp =
 		s_record_fields tabs [
@@ -549,7 +550,7 @@ module Printer = struct
 			"e_meta",s_metadata en.e_meta;
 			"e_params",s_type_params (tabs ^ "\t") en.e_params;
 			"e_type",s_type_kind en.e_type;
-			"e_extern",string_of_bool en.e_extern;
+			"e_extern",string_of_bool (has_enum_flag en EnExtern);
 			"e_constrs",s_list "\n\t" (s_tenum_field (tabs ^ "\t")) (PMap.fold (fun ef acc -> ef :: acc) en.e_constrs []);
 			"e_names",String.concat ", " en.e_names
 		]
@@ -601,7 +602,7 @@ module Printer = struct
 			| TVOLocalFunction -> "TVOLocalFunction") ^ ")"
 		| VGenerated -> "VGenerated"
 		| VInlined -> "VInlined"
-		| VInlinedConstructorVariable -> "VInlinedConstructorVariable"
+		| VInlinedConstructorVariable sl -> "VInlinedConstructorVariable" ^ "(" ^ (String.concat ", " sl) ^ ")"
 		| VExtractorVariable -> "VExtractorVariable"
 		| VAbstractThis -> "VAbstractThis"
 
@@ -612,6 +613,13 @@ module Printer = struct
 		| MExtern -> "MExtern"
 		| MImport -> "MImport"
 
+	let s_module_origin = function
+		| MDepFromImport -> "MDepFromImport"
+		| MDepFromTyping -> "MDepFromTyping"
+		| MDepFromMacro -> "MDepFromMacro"
+		| MDepFromMacroInclude -> "MDepFromMacroInclude"
+		| MDepFromMacroDefine -> "MDepFromMacroDefine"
+
 	let s_module_tainting_reason = function
 		| CheckDisplayFile -> "check_display_file"
 		| ServerInvalidate -> "server/invalidate"

+ 23 - 5
src/core/tType.ml

@@ -26,10 +26,9 @@ and method_kind =
 	| MethMacro
 
 type module_check_policy =
-	| NoCheckFileTimeModification
+	| NoFileSystemCheck
+	| CheckFileModificationTime
 	| CheckFileContentModification
-	| NoCheckDependencies
-	| NoCheckShadowing
 
 type module_tainting_reason =
 	| CheckDisplayFile
@@ -55,6 +54,7 @@ type type_param_host =
 	| TPHEnumConstructor
 	| TPHAnonField
 	| TPHLocal
+	| TPHUnbound
 
 type cache_bound_object =
 	| Resource of string * string
@@ -144,7 +144,7 @@ and tvar_kind =
 	| VUser of tvar_origin
 	| VGenerated
 	| VInlined
-	| VInlinedConstructorVariable
+	| VInlinedConstructorVariable of string list
 	| VExtractorVariable
 	| VAbstractThis
 
@@ -334,7 +334,7 @@ and tenum = {
 	mutable e_restore : unit -> unit;
 	(* do not insert any fields above *)
 	mutable e_type : t;
-	mutable e_extern : bool;
+	mutable e_flags : int;
 	mutable e_constrs : (string , tenum_field) PMap.t;
 	mutable e_names : string list;
 }
@@ -378,6 +378,7 @@ and tabstract = {
 	mutable a_read : tclass_field option;
 	mutable a_write : tclass_field option;
 	mutable a_call : tclass_field option;
+	mutable a_extern : bool;
 	mutable a_enum : bool;
 }
 
@@ -401,10 +402,20 @@ and module_def_display = {
 	mutable m_import_positions : (pos,bool ref) PMap.t;
 }
 
+and module_dep_origin =
+	| MDepFromTyping
+	| MDepFromImport
+	| MDepFromMacro
+	(* Compiler.include loads module with this special origin, which tells add_dependency not to add as a proper dependency. *)
+	| MDepFromMacroInclude
+	(* Modules created via Compiler.defineType or Compiler.defineModule will be added as dependency to their "parent" module with this origin. *)
+	| MDepFromMacroDefine
+
 and module_dep = {
 	md_sign : Digest.t;
 	md_kind : module_kind;
 	md_path : path;
+	md_origin : module_dep_origin
 }
 
 and module_def_extra = {
@@ -418,6 +429,7 @@ and module_def_extra = {
 	mutable m_checked : int;
 	mutable m_processed : int;
 	mutable m_deps : (int,module_dep) PMap.t;
+	mutable m_sig_deps : (int,module_dep) PMap.t option;
 	mutable m_kind : module_kind;
 	mutable m_cache_bound_objects : cache_bound_object DynArray.t;
 	mutable m_features : (string,bool) Hashtbl.t;
@@ -454,6 +466,7 @@ exception Type_exception of t
 
 type basic_types = {
 	mutable tvoid : t;
+	mutable tany : t;
 	mutable tint : t;
 	mutable tfloat : t;
 	mutable tbool : t;
@@ -474,6 +487,7 @@ type flag_tclass =
 	| CAbstract
 	| CFunctionalInterface
 	| CUsed (* Marker for DCE *)
+	| CExcluded (* Marker for exclude macro, turned into CExtern during filters *)
 
 type flag_tclass_field =
 	| CfPublic
@@ -497,6 +511,10 @@ let flag_tclass_field_names = [
 	"CfPublic";"CfStatic";"CfExtern";"CfFinal";"CfModifiesThis";"CfOverride";"CfAbstract";"CfOverload";"CfImpl";"CfEnum";"CfGeneric";"CfDefault";"CfPostProcessed";"CfUsed";"CfMaybeUsed"
 ]
 
+type flag_tenum =
+	| EnExtern
+	| EnExcluded (* Marker for exclude macro, turned into EnExtern during filters *)
+
 type flag_tvar =
 	| VCaptured
 	| VFinal

+ 45 - 6
src/core/tUnification.ml

@@ -31,6 +31,15 @@ type eq_kind =
 	| EqDoNotFollowNull (* like EqStrict, but does not follow Null<T> *)
 	| EqStricter
 
+type type_param_unification_context = {
+	known_type_params : typed_type_param list;
+	mutable type_param_pairs : (typed_type_param * typed_type_param) list;
+}
+
+type type_param_mode =
+	| TpDefault
+	| TpDefinition of type_param_unification_context
+
 type unification_context = {
 	allow_transitive_cast   : bool;
 	allow_abstract_cast     : bool; (* allows a non-transitive abstract cast (from,to,@:from,@:to) *)
@@ -39,6 +48,7 @@ type unification_context = {
 	equality_kind           : eq_kind;
 	equality_underlying     : bool;
 	strict_field_kind       : bool;
+	type_param_mode         : type_param_mode;
 }
 
 type unify_min_result =
@@ -64,6 +74,7 @@ let default_unification_context = {
 	equality_kind           = EqStrict;
 	equality_underlying     = false;
 	strict_field_kind       = false;
+	type_param_mode         = TpDefault;
 }
 
 (* Unify like targets (e.g. Java) probably would. *)
@@ -75,6 +86,7 @@ let native_unification_context = {
 	equality_underlying   = false;
 	allow_arg_name_mismatch = true;
 	strict_field_kind       = false;
+	type_param_mode         = TpDefault;
 }
 
 module Monomorph = struct
@@ -317,7 +329,7 @@ let rec follow_and_close t = match follow t with
 	| t ->
 		t
 
-let link e a b =
+let link uctx e a b =
 	(* tell if setting a == b will create a type-loop *)
 	let rec loop t =
 		if t == a then
@@ -325,6 +337,13 @@ let link e a b =
 		else match t with
 		| TMono t -> (match t.tm_type with None -> false | Some t -> loop t)
 		| TEnum (_,tl) -> List.exists loop tl
+		| TInst ({cl_kind = KTypeParameter ttp}, tl) ->
+			begin match uctx.type_param_mode with
+				| TpDefault ->
+					List.exists loop tl
+				| TpDefinition tctx ->
+					not (List.memq ttp tctx.known_type_params)
+			end
 		| TInst (_,tl) | TType (_,tl) | TAbstract (_,tl) -> List.exists loop tl
 		| TFun (tl,t) -> List.exists (fun (_,_,t) -> loop t) tl || loop t
 		| TDynamic None ->
@@ -519,6 +538,7 @@ let rec_stack stack value fcheck frun ferror =
 let rec_stack_default stack value fcheck frun def =
 	if not (rec_stack_exists fcheck stack) then rec_stack_loop stack value frun () else def
 
+
 let rec type_eq uctx a b =
 	let param = uctx.equality_kind in
 	let can_follow_null = match param with
@@ -542,11 +562,11 @@ let rec type_eq uctx a b =
 	| _ , TLazy f -> type_eq uctx a (lazy_type f)
 	| TMono t , _ ->
 		(match t.tm_type with
-		| None -> if param = EqCoreType || param = EqStricter || not (link t a b) then error [cannot_unify a b]
+		| None -> if param = EqCoreType || param = EqStricter || not (link uctx t a b) then error [cannot_unify a b]
 		| Some t -> type_eq uctx t b)
 	| _ , TMono t ->
 		(match t.tm_type with
-		| None -> if param = EqCoreType || param = EqStricter || not (link t b a) then error [cannot_unify a b]
+		| None -> if param = EqCoreType || param = EqStricter || not (link uctx t b a) then error [cannot_unify a b]
 		| Some t -> type_eq uctx a t)
 	| TDynamic None, TDynamic None ->
 		()
@@ -575,6 +595,9 @@ let rec type_eq uctx a b =
 	| TEnum (e1,tl1) , TEnum (e2,tl2) ->
 		if e1 != e2 && not (param = EqCoreType && e1.e_path = e2.e_path) then error [cannot_unify a b];
 		type_eq_params uctx a b tl1 tl2
+	| TInst ({cl_kind = KTypeParameter ttp1},tl1) , TInst ({cl_kind = KTypeParameter ttp2},tl2) when param <> EqCoreType ->
+		assign_type_params uctx ttp1 ttp2;
+		type_eq_params uctx a b tl1 tl2
 	| TInst (c1,tl1) , TInst (c2,tl2) ->
 		if c1 != c2 && not (param = EqCoreType && c1.cl_path = c2.cl_path) && (match c1.cl_kind, c2.cl_kind with KExpr _, KExpr _ -> false | _ -> true) then error [cannot_unify a b];
 		type_eq_params uctx a b tl1 tl2
@@ -636,6 +659,19 @@ let rec type_eq uctx a b =
 	| _ , _ ->
 		error [cannot_unify a b]
 
+and assign_type_params uctx ttp1 ttp2 =
+	if ttp1 != ttp2 then begin match uctx.type_param_mode with
+		| TpDefault ->
+			error []
+		| TpDefinition tctx ->
+			begin try
+				let ttp3 = List.assq ttp2 tctx.type_param_pairs in
+				if ttp1 != ttp3 then error []
+			with Not_found ->
+				tctx.type_param_pairs <- (ttp2,ttp1) :: tctx.type_param_pairs
+			end
+	end
+
 and type_eq_params uctx a b tl1 tl2 =
 	let i = ref 0 in
 	List.iter2 (fun t1 t2 ->
@@ -686,11 +722,11 @@ let rec unify (uctx : unification_context) a b =
 	| _ , TLazy f -> unify uctx a (lazy_type f)
 	| TMono t , _ ->
 		(match t.tm_type with
-		| None -> if uctx.equality_kind = EqStricter || not (link t a b) then error [cannot_unify a b]
+		| None -> if uctx.equality_kind = EqStricter || not (link uctx t a b) then error [cannot_unify a b]
 		| Some t -> unify uctx t b)
 	| _ , TMono t ->
 		(match t.tm_type with
-		| None -> if uctx.equality_kind = EqStricter || not (link t b a) then error [cannot_unify a b]
+		| None -> if uctx.equality_kind = EqStricter || not (link uctx t b a) then error [cannot_unify a b]
 		| Some t -> unify uctx a t)
 	| TType (t,tl) , _ ->
 		rec_stack unify_stack (a,b)
@@ -732,6 +768,9 @@ let rec unify (uctx : unification_context) a b =
 		unify_to {uctx with allow_transitive_cast = false} a b ab tl
 	| TAbstract (a1,tl1) , TAbstract (a2,tl2) ->
 		unify_abstracts uctx a b a1 tl1 a2 tl2
+	| TInst ({cl_kind = KTypeParameter ttp1},tl1) , TInst ({cl_kind = KTypeParameter ttp2},tl2) when uctx.type_param_mode != TpDefault ->
+		assign_type_params uctx ttp1 ttp2;
+		unify_type_params uctx a b tl1 tl2;
 	| TInst (c1,tl1) , TInst (c2,tl2) ->
 		let rec loop c tl =
 			if c == c2 then begin
@@ -1232,7 +1271,7 @@ module UnifyMinT = struct
 				begin match common_types with
 				| [] ->
 					begin match !first_error with
-					| None -> die "" __LOC__
+					| None -> UnifyMinError([Unify_custom "Could not determine common type, please add a type-hint"],0)
 					| Some(l,p) -> UnifyMinError(l,p)
 					end
 				| hd :: _ ->

+ 1 - 0
src/core/texpr.ml

@@ -612,6 +612,7 @@ let type_constant basic c p =
 	match c with
 	| Int (s,_) ->
 		if String.length s > 10 && String.sub s 0 2 = "0x" then raise_typing_error "Invalid hexadecimal integer" p;
+		if String.length s > 34 && String.sub s 0 2 = "0b" then raise_typing_error "Invalid binary integer" p;
 		(try mk (TConst (TInt (Int32.of_string s))) basic.tint p
 		with _ -> mk (TConst (TFloat s)) basic.tfloat p)
 	| Float (f,_) -> mk (TConst (TFloat f)) basic.tfloat p

+ 2 - 2
src/filters/exceptions.ml

@@ -39,7 +39,7 @@ let haxe_exception_static_call ctx method_name args p =
 		| TFun(_,t) -> t
 		| _ -> raise_typing_error ("haxe.Exception." ^ method_name ^ " is not a function and cannot be called") p
 	in
-	add_dependency ctx.typer.c.curclass.cl_module ctx.haxe_exception_class.cl_module;
+	add_dependency ctx.typer.c.curclass.cl_module ctx.haxe_exception_class.cl_module MDepFromTyping;
 	make_static_call ctx.typer ctx.haxe_exception_class method_field (fun t -> t) args return_type p
 
 (**
@@ -605,7 +605,7 @@ let insert_save_stacks tctx =
 				in
 				let catch_local = mk (TLocal catch_var) catch_var.v_type catch_var.v_pos in
 				begin
-					add_dependency tctx.c.curclass.cl_module native_stack_trace_cls.cl_module;
+					add_dependency tctx.c.curclass.cl_module native_stack_trace_cls.cl_module MDepFromTyping;
 					make_static_call tctx native_stack_trace_cls method_field (fun t -> t) [catch_local] return_type catch_var.v_pos
 				end
 			else

+ 21 - 10
src/filters/filters.ml

@@ -103,7 +103,7 @@ let check_local_vars_init ctx e =
 		| TVar (v,eo) ->
 			begin
 				match eo with
-				| None when v.v_kind = VInlinedConstructorVariable ->
+				| None when (match v.v_kind with VInlinedConstructorVariable _ -> true | _ -> false) ->
 					()
 				| None ->
 					declared := v.v_id :: !declared;
@@ -286,6 +286,16 @@ let check_abstract_as_value e =
 
 (* PASS 2 begin *)
 
+(* Applies exclude macro (which turns types into externs) *)
+
+let apply_macro_exclude com t = match t with
+	| TClassDecl c when has_class_flag c CExcluded ->
+		add_class_flag c CExtern
+	| TEnumDecl e when has_enum_flag e EnExcluded ->
+		add_enum_flag e EnExtern
+	| _ ->
+		()
+
 (* Removes extern and macro fields, also checks for Void fields *)
 
 let remove_extern_fields com t = match t with
@@ -407,7 +417,7 @@ let check_reserved_type_paths com t =
 	in
 	match t with
 	| TClassDecl c when not (has_class_flag c CExtern) -> check c.cl_path c.cl_pos
-	| TEnumDecl e when not e.e_extern -> check e.e_path e.e_pos
+	| TEnumDecl e when not (has_enum_flag e EnExtern) -> check e.e_path e.e_pos
 	| _ -> ()
 
 (* PASS 3 end *)
@@ -453,6 +463,7 @@ let destruction tctx detail_times main locals =
 		(* PASS 2: type filters pre-DCE *)
 		List.iter (fun t ->
 			FiltersCommon.remove_generic_base t;
+			apply_macro_exclude com t;
 			remove_extern_fields com t;
 			(* check @:remove metadata before DCE so it is ignored there (issue #2923) *)
 			check_remove_metadata t;
@@ -507,20 +518,20 @@ let destruction tctx detail_times main locals =
 	com.callbacks#run com.error_ext com.callbacks#get_after_filters;
 	enter_stage com CFilteringDone
 
-let update_cache_dependencies com t =
+let update_cache_dependencies ~close_monomorphs com t =
 	let visited_anons = ref [] in
 	let rec check_t m t = match t with
 		| TInst(c,tl) ->
-			add_dependency m c.cl_module;
+			add_dependency m c.cl_module MDepFromTyping;
 			List.iter (check_t m) tl;
 		| TEnum(en,tl) ->
-			add_dependency m en.e_module;
+			add_dependency m en.e_module MDepFromTyping;
 			List.iter (check_t m) tl;
 		| TType(t,tl) ->
-			add_dependency m t.t_module;
+			add_dependency m t.t_module MDepFromTyping;
 			List.iter (check_t m) tl;
 		| TAbstract(a,tl) ->
-			add_dependency m a.a_module;
+			add_dependency m a.a_module MDepFromTyping;
 			List.iter (check_t m) tl;
 		| TFun(targs,tret) ->
 			List.iter (fun (_,_,t) -> check_t m t) targs;
@@ -535,8 +546,8 @@ let update_cache_dependencies com t =
 				| Some t ->
 					check_t m t
 				| _ ->
-					(* Bind any still open monomorph that's part of a signature to Dynamic now (issue #10653) *)
-					Monomorph.do_bind r t_dynamic;
+					(* Bind any still open monomorph that's part of a signature to Any now (issue #10653) *)
+					if close_monomorphs then Monomorph.do_bind r com.basic.tany;
 		end
 		| TLazy f ->
 			check_t m (lazy_type f)
@@ -743,7 +754,7 @@ let run tctx main before_destruction =
 	enter_stage com CSaveStart;
 	with_timer detail_times "save state" None (fun () ->
 		List.iter (fun mt ->
-			update_cache_dependencies com mt;
+			update_cache_dependencies ~close_monomorphs:true com mt;
 			save_class_state com mt
 		) new_types;
 	);

+ 3 - 3
src/filters/localStatic.ml

@@ -1,4 +1,3 @@
-open Common
 open Type
 open Typecore
 open Error
@@ -14,8 +13,9 @@ let promote_local_static lsctx run v eo =
 	let c = lsctx.ctx.c.curclass in
 	begin try
 		let cf = PMap.find name c.cl_statics in
-		display_error lsctx.ctx.com (Printf.sprintf "The expanded name of this local (%s) conflicts with another static field" name) v.v_pos;
-		raise_typing_error ~depth:1 "Conflicting field was found here" cf.cf_name_pos;
+		raise_typing_error_ext (make_error (Custom (Printf.sprintf "The expanded name of this local (%s) conflicts with another static field" name)) ~sub:[
+			make_error ~depth:1 (Custom "Conflicting field was found here") cf.cf_name_pos
+		] v.v_pos);
 	with Not_found ->
 		let cf = mk_field name ~static:true v.v_type v.v_pos v.v_pos in
 		cf.cf_meta <- v.v_meta;

+ 18 - 7
src/generators/gencpp.ml

@@ -717,7 +717,7 @@ let is_extern_class class_def =
 ;;
 
 let is_extern_enum enum_def =
-   (enum_def.e_extern) || (has_meta_key enum_def.e_meta Meta.Extern)
+   (has_enum_flag enum_def EnExtern) || (has_meta_key enum_def.e_meta Meta.Extern)
 ;;
 
 let is_native_class class_def =
@@ -4760,7 +4760,18 @@ let gen_member_def ctx class_def is_static is_interface field =
          output "\n";
       | _ when has_class_field_flag field CfAbstract ->
          let ctx_arg_list ctx arg_list prefix =
-            String.concat "," (List.map (fun (n,o,t) -> (ctx_arg ctx n None t prefix) ) arg_list)
+            let get_default_value name =
+               try
+                  match Meta.get Meta.Value field.cf_meta with
+                  | (_,[ (EObjectDecl decls, _) ],_) ->
+                     Some ((List.find (fun ((n,_,_), _) -> n = name) decls) |> snd |> (type_constant_value ctx.ctx_common.basic));
+                  | _ ->
+                     None
+               with Not_found ->
+                  None
+            in
+
+            String.concat "," (List.map (fun (n,o,t) -> (ctx_arg ctx n (get_default_value n) t prefix) ) arg_list)
          in
          let tl,tr = match follow field.cf_type with
             | TFun(tl,tr) -> tl,tr
@@ -7069,7 +7080,7 @@ let create_super_dependencies common_ctx =
          | _ ->() );
          List.iter (fun imp -> if not (has_class_flag (fst imp) CExtern) then deps := (fst imp).cl_path :: !deps) (real_non_native_interfaces class_def.cl_implements);
          Hashtbl.add result class_def.cl_path !deps;
-      | TEnumDecl enum_def when not enum_def.e_extern ->
+      | TEnumDecl enum_def when not (has_enum_flag enum_def EnExtern) ->
          Hashtbl.add result enum_def.e_path [];
       | _ -> () );
       ) common_ctx.types;
@@ -8463,14 +8474,14 @@ let generate_cppia ctx =
          else begin
             generate_script_class common_ctx script class_def
          end
-      | TEnumDecl enum_def when enum_def.e_extern -> ()
+      | TEnumDecl enum_def when has_enum_flag enum_def EnExtern -> ()
       | TEnumDecl enum_def ->
          let is_internal = is_internal_class enum_def.e_path in
          if (is_internal) then
             (if (debug>=4) then print_endline (" internal enum " ^ (join_class_path enum_def.e_path ".") ))
          else begin
             let meta = Texpr.build_metadata common_ctx.basic object_def in
-            if (enum_def.e_extern) then
+            if (has_enum_flag enum_def EnExtern) then
                (if (debug>=4) then print_endline ("external enum " ^  (join_class_path enum_def.e_path ".") ));
             generate_script_enum common_ctx script enum_def meta
          end
@@ -8557,7 +8568,7 @@ let generate_source ctx =
             if not ((has_class_flag class_def CInterface) && (is_native_gen_class class_def)) then
                exe_classes := (class_def.cl_path, deps, object_def)  ::  !exe_classes;
          end
-      | TEnumDecl enum_def when enum_def.e_extern -> ()
+      | TEnumDecl enum_def when has_enum_flag enum_def EnExtern -> ()
       | TEnumDecl enum_def ->
          let name =  class_text enum_def.e_path in
          let is_internal = is_internal_class enum_def.e_path in
@@ -8576,7 +8587,7 @@ let generate_source ctx =
             makeId name 0;
 
             let meta = Texpr.build_metadata common_ctx.basic object_def in
-            if (enum_def.e_extern) then
+            if (has_enum_flag enum_def EnExtern) then
                (if (debug>1) then print_endline ("external enum " ^ name ));
             boot_enums := enum_def.e_path :: !boot_enums;
             jobs := (fun () -> generate_enum_files ctx enum_def super_deps meta ) :: !jobs;

+ 160 - 93
src/generators/genhl.ml

@@ -95,9 +95,9 @@ type context = {
 	cfunctions : fundecl DynArray.t;
 	cconstants : (constval, (global * int array)) lookup;
 	optimize : bool;
+	w_null_compare : bool;
 	overrides : (string * path, bool) Hashtbl.t;
 	defined_funs : (int,unit) Hashtbl.t;
-	is_macro : bool;
 	mutable dump_out : (unit IO.output) option;
 	mutable cached_types : (string list, ttype) PMap.t;
 	mutable m : method_context;
@@ -263,7 +263,7 @@ let global_type ctx g =
 	DynArray.get ctx.cglobals.arr g
 
 let is_overridden ctx c f =
-	ctx.is_macro || Hashtbl.mem ctx.overrides (f.cf_name,c.cl_path)
+	Hashtbl.mem ctx.overrides (f.cf_name,c.cl_path)
 
 let alloc_float ctx f =
 	lookup ctx.cfloats f (fun() -> f)
@@ -339,7 +339,7 @@ let make_debug ctx arr =
 		with Not_found ->
 			p.pfile
 	in
-	let pos = ref (0,0) in
+	let pos = ref (0,0,Globals.null_pos) in
 	let cur_file = ref 0 in
 	let cur_line = ref 0 in
 	let cur = ref Globals.null_pos in
@@ -347,12 +347,12 @@ let make_debug ctx arr =
 	for i = 0 to DynArray.length arr - 1 do
 		let p = DynArray.unsafe_get arr i in
 		if p != !cur then begin
-			let file = if p.pfile == (!cur).pfile then !cur_file else lookup ctx.cdebug_files p.pfile (fun() -> if ctx.is_macro then p.pfile else get_relative_path p) in
-			let line = if ctx.is_macro then p.pmin lor ((p.pmax - p.pmin) lsl 20) else Lexer.get_error_line p in
+			let file = if p.pfile == (!cur).pfile then !cur_file else lookup ctx.cdebug_files p.pfile (fun() -> get_relative_path p) in
+			let line = Lexer.get_error_line p in
 			if line <> !cur_line || file <> !cur_file then begin
 				cur_file := file;
 				cur_line := line;
-				pos := (file,line);
+				pos := (file,line,p);
 			end;
 			cur := p;
 		end;
@@ -569,10 +569,17 @@ and class_type ?(tref=None) ctx c pl statics =
 		let t = HVirtual vp in
 		ctx.cached_types <- PMap.add key_path t ctx.cached_types;
 		let rec loop c =
-			let fields = List.fold_left (fun acc (i,_) -> loop i @ acc) [] c.cl_implements in
-			PMap.fold (fun cf acc -> cfield_type ctx cf :: acc) c.cl_fields fields
+			let rec concat_uniq fields pfields =
+				match pfields with
+				| (n,_,_) as pf::pfl -> if List.exists (fun (n1,_,_) -> n1 = n) fields then concat_uniq fields pfl else concat_uniq (pf::fields) pfl
+				| [] -> fields
+			in
+			let pfields = List.fold_left (fun acc (i,_) -> loop i @ acc) [] c.cl_implements in
+			let fields = PMap.fold (fun cf acc -> cfield_type ctx cf :: acc) c.cl_fields [] in
+			concat_uniq fields pfields
 		in
 		let fields = loop c in
+		let fields = List.sort (fun (n1,_,_) (n2,_,_) -> compare n1 n2) fields in
 		vp.vfields <- Array.of_list fields;
 		Array.iteri (fun i (n,_,_) -> vp.vindex <- PMap.add n i vp.vindex) vp.vfields;
 		t
@@ -951,34 +958,39 @@ let write_mem ctx bytes index t r =
 	| _ ->
 		die "" __LOC__
 
+let common_type_number ctx t1 t2 p =
+	if t1 == t2 then t1 else
+	match t1, t2 with
+	| HUI8, (HUI16 | HI32 | HI64 | HF32 | HF64) -> t2
+	| HUI16, (HI32 | HI64 | HF32 | HF64) -> t2
+	| (HI32 | HI64), HF32 -> t2 (* possible loss of precision *)
+	| (HI32 | HI64 | HF32), HF64 -> t2
+	| (HUI8|HUI16|HI32|HI64|HF32|HF64), (HUI8|HUI16|HI32|HI64|HF32|HF64) -> t1
+	| _ ->
+		die "" __LOC__
+
 let common_type ctx e1 e2 for_eq p =
 	let t1 = to_type ctx e1.etype in
 	let t2 = to_type ctx e2.etype in
-	let rec loop t1 t2 =
-		if t1 == t2 then t1 else
-		match t1, t2 with
-		| HUI8, (HUI16 | HI32 | HI64 | HF32 | HF64) -> t2
-		| HUI16, (HI32 | HI64 | HF32 | HF64) -> t2
-		| (HI32 | HI64), HF32 -> t2 (* possible loss of precision *)
-		| (HI32 | HI64 | HF32), HF64 -> t2
-		| (HUI8|HUI16|HI32|HI64|HF32|HF64), (HUI8|HUI16|HI32|HI64|HF32|HF64) -> t1
-		| (HUI8|HUI16|HI32|HI64|HF32|HF64), (HNull t2) -> if for_eq then HNull (loop t1 t2) else loop t1 t2
-		| (HNull t1), (HUI8|HUI16|HI32|HI64|HF32|HF64) -> if for_eq then HNull (loop t1 t2) else loop t1 t2
-		| (HNull t1), (HNull t2) -> if for_eq then HNull (loop t1 t2) else loop t1 t2
-		| HDyn, (HUI8|HUI16|HI32|HI64|HF32|HF64) -> HF64
-		| (HUI8|HUI16|HI32|HI64|HF32|HF64), HDyn -> HF64
-		| HDyn, _ -> HDyn
-		| _, HDyn -> HDyn
-		| _ when for_eq && safe_cast t1 t2 -> t2
-		| _ when for_eq && safe_cast t2 t1 -> t1
-		| HBool, HNull HBool when for_eq -> t2
-		| HNull HBool, HBool when for_eq -> t1
-		| HObj _, HVirtual _ | HVirtual _, HObj _ | HVirtual _ , HVirtual _ -> HDyn
-		| HFun _, HFun _ -> HDyn
-		| _ ->
-			abort ("Don't know how to compare " ^ tstr t1 ^ " and " ^ tstr t2) p
-	in
-	loop t1 t2
+	if t1 == t2 then t1 else
+	match t1, t2 with
+	| (HUI8|HUI16|HI32|HI64|HF32|HF64), (HUI8|HUI16|HI32|HI64|HF32|HF64) -> common_type_number ctx t1 t2 p
+	| (HUI8|HUI16|HI32|HI64|HF32|HF64 as t1), (HNull t2)
+	| (HNull t1), (HUI8|HUI16|HI32|HI64|HF32|HF64 as t2)
+	| (HNull t1), (HNull t2)
+		-> if for_eq then HNull (common_type_number ctx t1 t2 p) else common_type_number ctx t1 t2 p
+	| HDyn, (HUI8|HUI16|HI32|HI64|HF32|HF64) -> HF64
+	| (HUI8|HUI16|HI32|HI64|HF32|HF64), HDyn -> HF64
+	| HDyn, _ -> HDyn
+	| _, HDyn -> HDyn
+	| _ when for_eq && safe_cast t1 t2 -> t2
+	| _ when for_eq && safe_cast t2 t1 -> t1
+	| HBool, HNull HBool when for_eq -> t2
+	| HNull HBool, HBool when for_eq -> t1
+	| HObj _, HVirtual _ | HVirtual _, HObj _ | HVirtual _ , HVirtual _ -> HDyn
+	| HFun _, HFun _ -> HDyn
+	| _ ->
+		abort ("Can't find common type " ^ tstr t1 ^ " and " ^ tstr t2) p
 
 let captured_index ctx v =
 	if not (has_var_flag v VCaptured) then None else try Some (PMap.find v.v_id ctx.m.mcaptured.c_map) with Not_found -> None
@@ -991,14 +1003,17 @@ let real_name v =
 	in
 	match loop v.v_meta with
 	| "_gthis" -> "this"
-	| name -> name
+	| name -> match v.v_kind with
+		| VInlinedConstructorVariable sl -> String.concat "." sl
+		| _ -> name
 
-let is_gen_local ctx v = match v.v_kind with
+let not_debug_var ctx v = match v.v_kind with
 	| VUser _ -> false
+	| VInlinedConstructorVariable _ -> false
 	| _ -> true
 
-let add_assign ctx v =
-	if is_gen_local ctx v then () else
+let add_assign ?(force=false) ctx v =
+	if not force && not_debug_var ctx v then () else
 	let name = real_name v in
 	ctx.m.massign <- (alloc_string ctx name, current_pos ctx - 1) :: ctx.m.massign
 
@@ -1460,7 +1475,7 @@ and jump_expr ctx e jcond =
 		jump_expr ctx e jcond
 	| TUnop (Not,_,e) ->
 		jump_expr ctx e (not jcond)
-	| TBinop (OpEq,{ eexpr = TConst(TNull) },e) | TBinop (OpEq,e,{ eexpr = TConst(TNull) }) ->
+	| TBinop ((OpEq | OpGte | OpLte),{ eexpr = TConst(TNull) },e) | TBinop ((OpEq | OpGte | OpLte),e,{ eexpr = TConst(TNull) }) ->
 		let r = eval_expr ctx e in
 		if is_nullable(rtype ctx r) then
 			jump ctx (fun i -> if jcond then OJNull (r,i) else OJNotNull (r,i))
@@ -1476,24 +1491,99 @@ and jump_expr ctx e jcond =
 			jump ctx (fun i -> OJAlways i)
 		else
 			(fun i -> ())
-	| TBinop (OpEq | OpNotEq | OpGt | OpGte | OpLt | OpLte as jop, e1, e2) ->
-		let t = common_type ctx e1 e2 (match jop with OpEq | OpNotEq -> true | _ -> false) e.epos in
-		let r1 = eval_to ctx e1 t in
-		hold ctx r1;
-		let r2 = eval_to ctx e2 t in
-		free ctx r1;
-		let unsigned = unsigned_op e1 e2 in
-		jump ctx (fun i ->
-			let lt a b = if unsigned then OJULt (a,b,i) else if not jcond && is_float t then OJNotGte (a,b,i) else OJSLt (a,b,i) in
-			let gte a b = if unsigned then OJUGte (a,b,i) else if not jcond && is_float t then OJNotLt (a,b,i) else OJSGte (a,b,i) in
+	| TBinop (OpEq | OpNotEq as jop, e1, e2) ->
+		let jumpeq r1 r2 = jump ctx (fun i ->
 			match jop with
 			| OpEq -> if jcond then OJEq (r1,r2,i) else OJNotEq (r1,r2,i)
 			| OpNotEq -> if jcond then OJNotEq (r1,r2,i) else OJEq (r1,r2,i)
-			| OpGt -> if jcond then lt r2 r1 else gte r2 r1
-			| OpGte -> if jcond then gte r1 r2 else lt r1 r2
-			| OpLt -> if jcond then lt r1 r2 else gte r1 r2
-			| OpLte -> if jcond then gte r2 r1 else lt r2 r1
 			| _ -> die "" __LOC__
+		) in
+		let nullisfalse = match jop with
+			| OpEq -> jcond
+			| OpNotEq -> not jcond
+			| _ -> die "" __LOC__
+		in
+		let t1 = to_type ctx e1.etype in
+		let t2 = to_type ctx e2.etype in
+		(match t1, t2 with
+		| HNull (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti1), (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti2)
+		| (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti1), HNull (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti2)
+		| HNull (HBool as ti1), (HBool as ti2)
+		| (HBool as ti1), HNull (HBool as ti2)
+			->
+			let t1,t2,e1,e2 = if is_nullt t2 then t2,t1,e2,e1 else t1,t2,e1,e2 in
+			let r1 = eval_expr ctx e1 in
+			hold ctx r1;
+			let jnull = if is_nullt t1 then jump ctx (fun i -> OJNull (r1, i)) else (fun i -> ()) in
+			let t = common_type_number ctx ti1 ti2 e.epos in (* HBool has t==ti1==ti2 *)
+			let a = cast_to ctx r1 t e1.epos in
+			hold ctx a;
+			let b = eval_to ctx e2 t in
+			free ctx a;
+			free ctx r1;
+			let j = jumpeq a b in
+			if nullisfalse then (jnull(););
+			(fun() -> if not nullisfalse then (jnull();); j());
+		| _ ->
+			let t = common_type ctx e1 e2 true e.epos in
+			let a = eval_to ctx e1 t in
+			hold ctx a;
+			let b = eval_to ctx e2 t in
+			free ctx a;
+			let j = jumpeq a b in
+			(fun() -> j());
+		)
+	| TBinop (OpGt | OpGte | OpLt | OpLte as jop, e1, e2) ->
+		let t1 = to_type ctx e1.etype in
+		let t2 = to_type ctx e2.etype in
+		let unsigned = unsigned_op e1 e2 in
+		let jumpcmp t r1 r2 = jump ctx (fun i ->
+			let lt a b = if unsigned then OJULt (a,b,i) else if not jcond && is_float t then OJNotGte (a,b,i) else OJSLt (a,b,i) in
+			let gte a b = if unsigned then OJUGte (a,b,i) else if not jcond && is_float t then OJNotLt (a,b,i) else OJSGte (a,b,i) in
+			match jop with
+				| OpGt -> if jcond then lt r2 r1 else gte r2 r1
+				| OpGte -> if jcond then gte r1 r2 else lt r1 r2
+				| OpLt -> if jcond then lt r1 r2 else gte r1 r2
+				| OpLte -> if jcond then gte r2 r1 else lt r2 r1
+				| _ -> die "" __LOC__
+		) in
+		(match t1, t2 with
+		| (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti1), (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti2)
+		| HNull (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti1), (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti2)
+		| (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti1), HNull (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti2)
+		| HNull (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti1), HNull (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 as ti2)
+			->
+			if ctx.w_null_compare && (is_nullt t1 || is_nullt t2) then
+				ctx.com.warning WGenerator [] (Printf.sprintf "Null compare: %s %s %s" (tstr t1) (s_binop jop) (tstr t2)) e.epos;
+			let r1 = eval_expr ctx e1 in
+			hold ctx r1;
+			let jnull1 = if is_nullt t1 then jump ctx (fun i -> OJNull (r1, i)) else (fun i -> ()) in
+			let r2 = eval_expr ctx e2 in
+			hold ctx r2;
+			let jnull2 = if is_nullt t2 then jump ctx (fun i -> OJNull (r2, i)) else (fun i -> ()) in
+			let t = common_type_number ctx ti1 ti2 e.epos in
+			let a = cast_to ctx r1 t e1.epos in
+			hold ctx a;
+			let b = cast_to ctx r2 t e2.epos in
+			free ctx a;
+			free ctx r1;
+			free ctx r2;
+			let j = jumpcmp t a b in
+			if jcond then (jnull1(); jnull2(););
+			(fun() -> if not jcond then (jnull1(); jnull2();); j());
+		| HObj { pname = "String" }, HObj { pname = "String" }
+		| HDyn, _
+		| _, HDyn
+			->
+			let t = common_type ctx e1 e2 false e.epos in
+			let a = eval_to ctx e1 t in
+			hold ctx a;
+			let b = eval_to ctx e2 t in
+			free ctx a;
+			let j = jumpcmp t a b in
+			(fun() -> j());
+		| _ ->
+			abort ("Don't know how to compare " ^ tstr t1 ^ " and " ^ tstr t2) e.epos
 		)
 	| TBinop (OpBoolAnd, e1, e2) ->
 		let j = jump_expr ctx e1 false in
@@ -2338,23 +2428,9 @@ and eval_expr ctx e =
 			jexit());
 		out
 	| TBinop (bop, e1, e2) ->
-		let is_unsigned() = unsigned_op e1 e2 in
-		let boolop r f =
-			let j = jump ctx f in
-			op ctx (OBool (r,false));
-			op ctx (OJAlways 1);
-			j();
-			op ctx (OBool (r, true));
-		in
-		let binop r a b =
+		let arithbinop r a b =
 			let rec loop bop =
 				match bop with
-				| OpLte -> boolop r (fun d -> if is_unsigned() then OJUGte (b,a,d) else OJSLte (a,b,d))
-				| OpGt -> boolop r (fun d -> if is_unsigned() then OJULt (b,a,d) else OJSGt (a,b,d))
-				| OpGte -> boolop r (fun d -> if is_unsigned() then OJUGte (a,b,d) else OJSGte (a,b,d))
-				| OpLt -> boolop r (fun d -> if is_unsigned() then OJULt (a,b,d) else OJSLt (a,b,d))
-				| OpEq -> boolop r (fun d -> OJEq (a,b,d))
-				| OpNotEq -> boolop r (fun d -> OJNotEq (a,b,d))
 				| OpAdd ->
 					(match rtype ctx r with
 					| HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 ->
@@ -2401,23 +2477,13 @@ and eval_expr ctx e =
 			loop bop
 		in
 		(match bop with
-		| OpLte | OpGt | OpGte | OpLt ->
+		| OpLte | OpGt | OpGte | OpLt | OpEq | OpNotEq ->
 			let r = alloc_tmp ctx HBool in
-			let t = common_type ctx e1 e2 false e.epos in
-			let a = eval_to ctx e1 t in
-			hold ctx a;
-			let b = eval_to ctx e2 t in
-			free ctx a;
-			binop r a b;
-			r
-		| OpEq | OpNotEq ->
-			let r = alloc_tmp ctx HBool in
-			let t = common_type ctx e1 e2 true e.epos in
-			let a = eval_to ctx e1 t in
-			hold ctx a;
-			let b = eval_to ctx e2 t in
-			free ctx a;
-			binop r a b;
+			let j = jump_expr ctx e false in
+			op ctx (OBool (r, true));
+			op ctx (OJAlways 1);
+			j();
+			op ctx (OBool (r, false));
 			r
 		| OpAdd | OpSub | OpMult | OpDiv | OpMod | OpShl | OpShr | OpUShr | OpAnd | OpOr | OpXor ->
 			let t = (match to_type ctx e.etype with HNull t -> t | t -> t) in
@@ -2434,7 +2500,7 @@ and eval_expr ctx e =
 			hold ctx a;
 			let b = eval e2 in
 			free ctx a;
-			binop r a b;
+			arithbinop r a b;
 			r
 		| OpAssign ->
 			let value() = eval_to ctx e2 (real_type ctx e1) in
@@ -2552,7 +2618,7 @@ and eval_expr ctx e =
 					hold ctx r;
 					let b = if bop = OpAdd && is_string (rtype ctx r) then to_string ctx (eval_expr ctx e2) e2.epos else eval_to ctx e2 (rtype ctx r) in
 					free ctx r;
-					binop r r b;
+					arithbinop r r b;
 					r))
 		| OpInterval | OpArrow | OpIn | OpNullCoal ->
 			die "" __LOC__)
@@ -2965,6 +3031,7 @@ and eval_expr ctx e =
 					op ctx (OCall2 (rb, alloc_fun_path ctx (["hl"],"BaseType") "check",r,rtrap));
 					let jnext = jump ctx (fun n -> OJFalse (rb,n)) in
 					op ctx (OMov (rv, unsafe_cast_to ~debugchk:false ctx rtrap (to_type ctx v.v_type) ec.epos));
+					add_assign ctx v;
 					jnext
 				in
 				let r = eval_expr ctx ec in
@@ -3230,7 +3297,7 @@ and make_fun ?gen_content ctx name fidx f cthis cparent =
 	let args = List.map (fun (v,o) ->
 		let t = to_type ctx v.v_type in
 		let r = alloc_var ctx (if o = None then v else { v with v_type = if not (is_nullable t) then TAbstract(ctx.ref_abstract,[v.v_type]) else v.v_type }) true in
-		add_assign ctx v; (* record var name *)
+		add_assign ~force:true ctx v; (* record var name *)
 		rtype ctx r
 	) f.tf_args in
 
@@ -3612,7 +3679,7 @@ let generate_static_init ctx types main =
 
 				free ctx rc;
 
-			| TEnumDecl e when not e.e_extern ->
+			| TEnumDecl e when not (has_enum_flag e EnExtern) ->
 
 				let et = enum_class ctx e in
 				let t = enum_type ctx e in
@@ -3978,7 +4045,7 @@ let write_code ch code debug =
 				end
 			end
 		in
-		Array.iter (fun (f,p) ->
+		Array.iter (fun (f,p,_) ->
 			if f <> !curfile then begin
 				flush_repeat(p);
 				curfile := f;
@@ -4033,7 +4100,7 @@ let write_code ch code debug =
 
 (* --------------------------------------------------------------------------------------------------------------------- *)
 
-let create_context com is_macro dump =
+let create_context com dump =
 	let get_type name =
 		try
 			List.find (fun t -> (t_infos t).mt_path = (["hl"],name)) com.types
@@ -4054,8 +4121,8 @@ let create_context com is_macro dump =
 	in
 	let ctx = {
 		com = com;
-		is_macro = is_macro;
 		optimize = not (Common.raw_defined com "hl_no_opt");
+		w_null_compare = Common.raw_defined com "hl_w_null_compare";
 		dump_out = if dump then Some (IO.output_channel (open_out_bin "dump/hlopt.txt")) else None;
 		m = method_context 0 HVoid null_capture false;
 		cints = new_lookup();
@@ -4115,7 +4182,7 @@ let add_types ctx types =
 				| _ ->
 					false
 			in
-			if not ctx.is_macro then List.iter (fun f -> if has_class_field_flag f CfOverride then ignore(loop c.cl_super f)) c.cl_ordered_fields;
+			List.iter (fun f -> if has_class_field_flag f CfOverride then ignore(loop c.cl_super f)) c.cl_ordered_fields;
 			List.iter (fun (m,args,p) ->
 				if m = Meta.HlNative then
 					let lib, prefix = (match args with
@@ -4185,7 +4252,7 @@ let generate com =
 		close_out ch;
 	end else
 
-	let ctx = create_context com false dump in
+	let ctx = create_context com dump in
 	add_types ctx com.types;
 	let code = build_code ctx com.types com.main.main_expr in
 	Array.sort (fun (lib1,_,_,_) (lib2,_,_,_) -> lib1 - lib2) code.natives;
@@ -4208,7 +4275,7 @@ let generate com =
 	end;*)
 	if hl_check then begin
 		check ctx;
-		Hlinterp.check code false;
+		Hlinterp.check com.error code;
 	end;
 	let t = Timer.timer ["generate";"hl";"write"] in
 

+ 3 - 3
src/generators/genjs.ml

@@ -1642,7 +1642,7 @@ let generate_type ctx = function
 			(match c.cl_path with
 			| ([],_) -> ()
 			| _ -> generate_package_create ctx c.cl_path)
-	| TEnumDecl e when e.e_extern ->
+	| TEnumDecl e when has_enum_flag e EnExtern ->
 		if Meta.has Meta.JsRequire e.e_meta && is_directly_used ctx.com e.e_meta then
 			generate_require ctx e.e_path e.e_meta
 	| TEnumDecl e -> generate_enum ctx e
@@ -1694,7 +1694,7 @@ let alloc_ctx com es_version =
 
 	ctx.type_accessor <- (fun t ->
 		match t with
-		| TEnumDecl ({ e_extern = true } as e) when not (Meta.has Meta.JsRequire e.e_meta) ->
+		| TEnumDecl e when (has_enum_flag e EnExtern) && not (Meta.has Meta.JsRequire e.e_meta) ->
 			dot_path e.e_path
 		| TClassDecl c ->
 			let p = get_generated_class_path c in
@@ -1880,7 +1880,7 @@ let generate com =
 		else vars in
 	let vars = if (enums_as_objects && (has_feature ctx "has_enum" || has_feature ctx "Type.resolveEnum")) then "$hxEnums = $hxEnums || {}" :: vars else vars in
 	let vars,has_dollar_underscore =
-		if List.exists (function TEnumDecl { e_extern = false } -> true | _ -> false) com.types then
+		if List.exists (function TEnumDecl e when not (has_enum_flag e EnExtern) -> true | _ -> false) com.types then
 			"$_" :: vars,ref true
 		else
 			vars,ref false

+ 11 - 8
src/generators/genjvm.ml

@@ -1103,13 +1103,21 @@ class texpr_to_jvm
 	method binop_compare op e1 e2 =
 		let sig1 = jsignature_of_type gctx e1.etype in
 		let sig2 = jsignature_of_type gctx e2.etype in
+		let is_eq_op = match op with
+			| CmpEq
+			| CmpGe
+			| CmpLe ->
+				true
+			| _ ->
+				false
+		in
 		match (Texpr.skip e1),(Texpr.skip e2) with
 		| {eexpr = TConst TNull},_ when not (is_unboxed sig2) ->
 			self#texpr rvalue_any e2;
-			CmpSpecial ((if op = CmpEq then jm#get_code#if_nonnull else jm#get_code#if_null) sig2)
+			CmpSpecial ((if is_eq_op then jm#get_code#if_nonnull else jm#get_code#if_null) sig2)
 		| _,{eexpr = TConst TNull} when not (is_unboxed sig1) ->
 			self#texpr rvalue_any e1;
-			CmpSpecial ((if op = CmpEq then jm#get_code#if_nonnull else jm#get_code#if_null) sig1)
+			CmpSpecial ((if is_eq_op then jm#get_code#if_nonnull else jm#get_code#if_null) sig1)
 		| {eexpr = TConst (TInt i32);etype = t2},e1 when Int32.to_int i32 = 0 && sig2 = TInt ->
 			let op = match op with
 				| CmpGt -> CmpGe
@@ -2763,11 +2771,6 @@ let generate_enum_equals gctx (jc_ctor : JvmClass.builder) =
 		else
 			compare_standard jsig
 	in
-	load();
-	jm_equals#invokevirtual java_enum_path "ordinal" (method_sig [] (Some TInt));
-	jm_equals#load_this;
-	jm_equals#invokevirtual java_enum_path "ordinal" (method_sig [] (Some TInt));
-	compare TInt;
 	let compare_field n jsig =
 		load();
 		jm_equals#getfield jc_ctor#get_this_path n jsig;
@@ -2889,7 +2892,7 @@ let generate_enum gctx en =
 let generate_module_type ctx mt =
 	match mt with
 		| TClassDecl c when not (has_class_flag c CExtern) -> generate_class ctx c
-		| TEnumDecl en when not en.e_extern -> generate_enum ctx en
+		| TEnumDecl en when not (has_enum_flag en EnExtern) -> generate_enum ctx en
 		| _ -> ()
 
 let generate_anons gctx =

+ 14 - 6
src/generators/genlua.ml

@@ -1550,7 +1550,7 @@ let check_multireturn ctx c =
 
 let check_field_name c f =
     match f.cf_name with
-    | "prototype" | "__proto__" | "constructor" ->
+    | "prototype" | "__proto__" | "constructor" | "__mt__" ->
         raise_typing_error ("The field name '" ^ f.cf_name ^ "'  is not allowed in Lua") (match f.cf_expr with None -> c.cl_pos | Some e -> e.epos);
     | _ -> ()
 
@@ -1660,8 +1660,10 @@ let generate_class ctx c =
                     | TBlock el ->
                         let bend = open_block ctx in
                         newline ctx;
-                        if not (has_prototype ctx c) then println ctx "local self = _hx_new()" else
-                            println ctx "local self = _hx_new(%s.prototype)" p;
+                        if not (has_prototype ctx c) then
+                            println ctx "local self = _hx_new()"
+                        else
+                            println ctx "local self = _hx_nsh(%s.__mt__)" p;
                         println ctx "%s.super(%s)" p (String.concat "," ("self" :: (List.map lua_arg_name f.tf_args)));
                         if p = "String" then println ctx "self = string";
                         spr ctx "return self";
@@ -1734,6 +1736,9 @@ let generate_class ctx c =
              if has_property_reflection && Codegen.has_properties csup then
                  println ctx "setmetatable(%s.prototype.__properties__,{__index=%s.prototype.__properties__})" p psup;
         );
+
+        (* Create a metatable specific for this class *)
+        println ctx "%s.__mt__ = _hx_mmt(%s.prototype)" p p;
     end
 
 let generate_enum ctx e =
@@ -1854,7 +1859,7 @@ let generate_type ctx = function
             generate_class ctx c;
         check_multireturn ctx c;
     | TEnumDecl e ->
-        if not e.e_extern then generate_enum ctx e
+        if not (has_enum_flag e EnExtern) then generate_enum ctx e
         else ();
     | TTypeDecl _ | TAbstractDecl _ -> ()
 
@@ -1869,7 +1874,7 @@ let generate_type_forward ctx = function
             end
         else if Meta.has Meta.LuaRequire c.cl_meta && is_directly_used ctx.com c.cl_meta then
             generate_require ctx c.cl_path c.cl_meta
-    | TEnumDecl e when e.e_extern ->
+    | TEnumDecl e when has_enum_flag e EnExtern ->
         if Meta.has Meta.LuaRequire e.e_meta && is_directly_used ctx.com e.e_meta then
             generate_require ctx e.e_path e.e_meta;
     | TEnumDecl e ->
@@ -1925,7 +1930,7 @@ let alloc_ctx com =
         match t with
         | TClassDecl c when (has_class_flag c CExtern) &&  not (Meta.has Meta.LuaRequire c.cl_meta)
             -> dot_path p
-        | TEnumDecl { e_extern = true }
+        | TEnumDecl e when has_enum_flag e EnExtern
             -> s_path ctx p
         | _ -> s_path ctx p);
     ctx
@@ -2023,6 +2028,9 @@ let generate com =
     (* base lua metatables for prototypes, inheritance, etc. *)
     print_file (Common.find_file com "lua/_lua/_hx_anon.lua");
 
+    (* Helpers for creating metatables from prototypes *)
+    print_file (Common.find_file com "lua/_lua/_hx_objects.lua");
+
     (* base runtime class stubs for haxe value types (Int, Float, etc) *)
     print_file (Common.find_file com "lua/_lua/_hx_classes.lua");
 

+ 3 - 3
src/generators/genneko.ml

@@ -563,7 +563,7 @@ let gen_type ctx t acc =
 		else
 			gen_class ctx c :: acc
 	| TEnumDecl e ->
-		if e.e_extern then
+		if has_enum_flag e EnExtern then
 			acc
 		else
 			gen_enum ctx e :: acc
@@ -622,7 +622,7 @@ let gen_boot ctx =
 
 let gen_name ctx acc t =
 	match t with
-	| TEnumDecl e when e.e_extern ->
+	| TEnumDecl e when has_enum_flag e EnExtern ->
 		acc
 	| TEnumDecl e ->
 		let p = pos ctx e.e_pos in
@@ -686,7 +686,7 @@ let generate_libs_init = function
 			(EVars [
 				"@s",Some (call p (loadp "sys_string" 0) []);
 			],p);
-			(EIf (op ">=" (builtin p "version") (int p 240),
+			(EIf (op ">=" (call p (builtin p "version") []) (int p 240),
 				(op "=" es (op "+" es (ESwitch (call p (loadp "sys_cpu_arch" 0) [],[
 					(str p "arm64", str p "Arm64");
 					(str p "arm", str p "Arm");

+ 1 - 1
src/generators/genphp7.ml

@@ -1020,7 +1020,7 @@ class class_wrapper (cls) =
 *)
 class enum_wrapper (enm) =
 	object (self)
-		inherit type_wrapper enm.e_path enm.e_meta (not enm.e_extern)
+		inherit type_wrapper enm.e_path enm.e_meta (not (has_enum_flag enm EnExtern))
 		(**
 			Indicates if class initialization method should be executed upon class loaded
 		*)

+ 2 - 2
src/generators/genpy.ml

@@ -2229,7 +2229,7 @@ module Generator = struct
 
 	let gen_type ctx mt = match mt with
 		| TClassDecl c -> gen_class ctx c
-		| TEnumDecl en when not en.e_extern -> gen_enum ctx en
+		| TEnumDecl en when not (has_enum_flag en EnExtern) -> gen_enum ctx en
 		| TAbstractDecl {a_path = [],"UInt"} -> ()
 		| TAbstractDecl {a_path = [],"Enum"} -> ()
 		| TAbstractDecl {a_path = [],"EnumValue"} when not (has_feature ctx "has_enum") -> ()
@@ -2339,7 +2339,7 @@ module Generator = struct
 		List.iter (fun mt ->
 			match mt with
 			| TClassDecl c when (has_class_flag c CExtern) -> import c.cl_path c.cl_meta
-			| TEnumDecl e when e.e_extern -> import e.e_path e.e_meta
+			| TEnumDecl e when has_enum_flag e EnExtern -> import e.e_path e.e_meta
 			| _ -> ()
 		) ctx.com.types
 

+ 2 - 2
src/generators/genswf.ml

@@ -153,7 +153,7 @@ let build_dependencies t =
 			List.iter add_inherit tp.ttp_class.cl_implements
 		) c.cl_params;
 		List.iter add_inherit c.cl_implements;
-	| TEnumDecl e when not e.e_extern ->
+	| TEnumDecl e when not (has_enum_flag e EnExtern) ->
 		PMap.iter (fun _ f -> add_type f.ef_type) e.e_constrs;
 	| _ -> ());
 	h := PMap.remove (([],"Int"),DKType) (!h);
@@ -524,7 +524,7 @@ let generate swf_header com =
 					if e.f9_cid <> None then List.iter (fun t ->
 						let extern = (match t with
 							| TClassDecl c -> (has_class_flag c CExtern)
-							| TEnumDecl e -> e.e_extern
+							| TEnumDecl e -> (has_enum_flag e EnExtern)
 							| TAbstractDecl a -> false
 							| TTypeDecl t -> false
 						) in

+ 3 - 3
src/generators/genswf9.ml

@@ -255,7 +255,7 @@ let rec type_id ctx t =
 		type_path ctx ([],"Function")
 	| TType ({ t_path = ([],"UInt") as path },_) ->
 		type_path ctx path
-	| TEnum ({ e_path = ["flash"],"XmlType"; e_extern = true },_) ->
+	| TEnum ({ e_path = ["flash"],"XmlType" } as e,_) when has_enum_flag e EnExtern ->
 		HMPath ([],"String")
 	| TEnum (e,_) ->
 		type_path ctx e.e_path
@@ -284,7 +284,7 @@ let classify ctx t =
 		KDynamic
 	| TAbstract ({ a_path = ["flash"],"AnyType" },_) ->
 		KDynamic
-	| TEnum ({ e_path = ["flash"],"XmlType"; e_extern = true },_) ->
+	| TEnum ({ e_path = ["flash"],"XmlType" } as e,_) when has_enum_flag e EnExtern ->
 		KType (HMPath ([],"String"))
 	| TEnum (e,_) ->
 		KType (type_id ctx t)
@@ -2800,7 +2800,7 @@ let rec generate_type ctx t =
 				hlf_metas = extract_meta c.cl_meta;
 			})
 	| TEnumDecl e ->
-		if e.e_extern then
+		if has_enum_flag e EnExtern then
 			None
 		else
 			let meta = Texpr.build_metadata ctx.com.basic t in

+ 8 - 4
src/generators/hl2c.ml

@@ -744,7 +744,7 @@ let generate_function ctx f =
 			match rtype a, rtype b with
 			| (HUI8 | HUI16 | HI32 | HF32 | HF64 | HBool | HI64), (HUI8 | HUI16 | HI32 | HF32 | HF64 | HBool | HI64) ->
 				phys_compare()
-			| HArray,HArray ->
+			| HBytes, HBytes | HArray,HArray ->
 				phys_compare()
 			| HType, HType ->
 				sexpr "if( hl_same_type(%s,%s) %s 0 ) {} else goto %s" (reg a) (reg b) (s_comp op) (label d)
@@ -846,7 +846,7 @@ let generate_function ctx f =
 			sexpr "%s = %s >> %s" (reg r) (reg a) (reg b)
 		| OUShr (r,a,b) ->
 			(match rtype r with
-			| HI64 -> sexpr "%s = ((uint64_t)%s) >> %s" (reg r) (reg a) (reg b)
+			| HI64 -> sexpr "%s = ((uint64)%s) >> %s" (reg r) (reg a) (reg b)
 			| _ -> sexpr "%s = ((unsigned)%s) >> %s" (reg r) (reg a) (reg b)
 			);
 		| OAnd (r,a,b) ->
@@ -1169,7 +1169,7 @@ let make_types_idents htypes =
 	in
 	let hashes = Hashtbl.create 0 in
 	let make_sign d =
-		let dig = Digest.to_hex (Digest.bytes (Marshal.to_bytes d [Marshal.Compat_32])) in
+		let dig = Digest.to_hex (Digest.bytes (Marshal.to_bytes d [Marshal.Closures])) in
 		let h = String.sub dig 0 7 in
 		let h = if Hashtbl.mem hashes h then dig else h in
 		Hashtbl.add hashes h ();
@@ -1710,6 +1710,7 @@ let write_c com file (code:code) gnames =
 	line "";
 	line "static void dump_types( void (*fdump)( void *, int) ) {";
 	block ctx;
+	line "#ifdef HL_DUMP_TYPES";
 	sexpr "hl_type *t";
 	sexpr "int ntypes = %d" (Array.length all_types);
 	sexpr "fdump(&ntypes,4)";
@@ -1728,6 +1729,9 @@ let write_c com file (code:code) gnames =
 			sexpr "t = (hl_type*)&%s.fun->closure_type; fdump(&t, sizeof(void*))" (type_name ctx t);
 		| _ -> ()
 	) all_types;
+	line "#else";
+	sexpr "printf(\"dump_types not available, please compile with HL_DUMP_TYPES defined\\n\")";
+	line "#endif";
 	unblock ctx;
 	line "}";
 
@@ -1792,7 +1796,7 @@ let write_c com file (code:code) gnames =
 			let file_pos f =
 				match f.fe_decl with
 				| Some f when Array.length f.debug > 0 ->
-					let fid, p = f.debug.(Array.length f.debug - 1) in
+					let fid, p, _ = f.debug.(Array.length f.debug - 1) in
 					(code.strings.(fid), p)
 				| _ ->
 					("",0)

+ 12 - 6
src/generators/hlcode.ml

@@ -45,7 +45,7 @@ type ttype =
 	| HDynObj
 	| HAbstract of string * string index
 	| HEnum of enum_proto
-	| HNull of ttype
+	| HNull of ttype (* for not nullable type only *)
 	| HMethod of ttype list * ttype
 	| HStruct of class_proto
 	| HPacked of ttype
@@ -210,7 +210,7 @@ type fundecl = {
 	ftype : ttype;
 	regs : ttype array;
 	code : opcode array;
-	debug : (int * int) array;
+	debug : (int * int * Globals.pos) array;
 	assigns : (string index * int) array;
 }
 
@@ -277,6 +277,12 @@ let is_number = function
 	| HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 -> true
 	| _ -> false
 
+let is_nullt = function
+	| HNull (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64) -> true
+	| HNull HBool -> true
+	| HNull _ -> Globals.die "" __LOC__
+	| _ -> false
+
 (*
 	does the runtime value carry its type
 *)
@@ -611,7 +617,7 @@ let dump pr code =
 		with _ ->
 			Printf.sprintf "f@%X" fid
 	in
-	let debug_infos (fid,line) =
+	let debug_infos (fid,line,_) =
 		(try code.debugfiles.(fid) with _ -> "???") ^ ":" ^ string_of_int line
 	in
 	pr ("hl v" ^ string_of_int code.version);
@@ -645,17 +651,17 @@ let dump pr code =
 	pr (string_of_int (Array.length code.functions) ^ " functions");
 	Array.iter (fun f ->
 		pr (Printf.sprintf "	fun@%d(%Xh) %s" f.findex f.findex (tstr f.ftype));
-		let fid, _ = f.debug.(0) in
+		let fid, _, _ = f.debug.(0) in
 		let cur_fid = ref fid in
 		pr (Printf.sprintf "	; %s (%s)" (debug_infos f.debug.(0)) (fundecl_name f));
 		Array.iteri (fun i r ->
 			pr ("		r" ^ string_of_int i ^ " " ^ tstr r);
 		) f.regs;
 		Array.iteri (fun i o ->
-			let fid, line = f.debug.(i) in
+			let fid, line, _ = f.debug.(i) in
 			if fid <> !cur_fid then begin
 				cur_fid := fid;
-				pr (Printf.sprintf "	; %s" (debug_infos (fid,line)));
+				pr (Printf.sprintf "	; %s" (debug_infos f.debug.(i)));
 			end;
 			pr (Printf.sprintf "		.%-5d @%X %s" line i (ostr fstr o))
 		) f.code;

+ 10 - 24
src/generators/hlinterp.ml

@@ -113,7 +113,6 @@ type context = {
 	mutable fcall : vfunction -> value list -> value;
 	mutable code : code;
 	mutable on_error : value -> (fundecl * int ref) list -> unit;
-	mutable resolve_macro_api : string -> (value list -> value) option;
 	checked : bool;
 	cached_protos : (int, vproto * ttype array * (int * (value -> value)) list) Hashtbl.t;
 	cached_strings : (int, string) Hashtbl.t;
@@ -667,7 +666,7 @@ let rec dyn_set_field ctx obj field v vt =
 
 let make_stack ctx (f,pos) =
 	let pos = !pos - 1 in
-	try let fid, line = f.debug.(pos) in ctx.code.debugfiles.(fid), line with _ -> "???", 0
+	try let fid, line, _ = f.debug.(pos) in ctx.code.debugfiles.(fid), line with _ -> "???", 0
 
 let stack_frame ctx (f,pos) =
 	let file, line = make_stack ctx (f,pos) in
@@ -2094,10 +2093,6 @@ let load_native ctx lib name t =
 			| _ -> Globals.die "" __LOC__)
 		| _ ->
 			unresolved())
-	| "macro" ->
-		(match ctx.resolve_macro_api name with
-		| None -> unresolved()
-		| Some f -> f)
 	| _ ->
 		unresolved()
 	) in
@@ -2130,7 +2125,6 @@ let create checked =
 		checked = checked;
 		fcall = (fun _ _ -> Globals.die "" __LOC__);
 		on_error = (fun _ _ -> Globals.die "" __LOC__);
-		resolve_macro_api = (fun _ -> None);
 	} in
 	ctx.on_error <- (fun msg stack -> failwith (vstr ctx msg HDyn ^ "\n" ^ String.concat "\n" (List.map (stack_frame ctx) stack)));
 	ctx.fcall <- call_fun ctx;
@@ -2139,9 +2133,6 @@ let create checked =
 let set_error_handler ctx e =
 	ctx.on_error <- e
 
-let set_macro_api ctx f =
-	ctx.resolve_macro_api <- f
-
 let add_code ctx code =
 	(* expand global table *)
 	let globals = Array.map default code.globals in
@@ -2192,26 +2183,21 @@ let add_code ctx code =
 
 (* ------------------------------- CHECK ---------------------------------------------- *)
 
-let check code macros =
+let check comerror code =
 	let ftypes = Array.make (Array.length code.natives + Array.length code.functions) HVoid in
 	let is_native_fun = Hashtbl.create 0 in
 
 	let check_fun f =
 		let pos = ref 0 in
 		let error msg =
-			let dfile, dline = f.debug.(!pos) in
-			let file = code.debugfiles.(dfile) in
+			let _, _, dpos = f.debug.(!pos) in
 			let msg = Printf.sprintf "Check failure at fun@%d @%X - %s" f.findex (!pos) msg in
-			if macros then begin
-				let low = dline land 0xFFFFF in
-				let pos = {
-					Globals.pfile = file;
-					Globals.pmin = low;
-					Globals.pmax = low + (dline lsr 20);
-				} in
-				Error.abort msg pos
-			end else
-				failwith (Printf.sprintf "\n%s:%d: %s" file dline msg)
+			comerror msg dpos;
+			()
+		in
+		let error_fail msg =
+			error msg;
+			failwith msg
 		in
 		let targs, tret = (match f.ftype with HFun (args,ret) -> args, ret | _ -> Globals.die "" __LOC__) in
 		let rtype i = try f.regs.(i) with _ -> HObj { null_proto with pname = "OUT_OF_BOUNDS:" ^ string_of_int i } in
@@ -2265,7 +2251,7 @@ let check code macros =
 			if not (is_dynamic (rtype r)) then error (reg_inf r ^ " should be castable to dynamic")
 		in
 		let get_field r p fid =
-			try snd (resolve_field p fid) with Not_found -> error (reg_inf r ^ " does not have field " ^ string_of_int fid)
+			try snd (resolve_field p fid) with Not_found -> error_fail (reg_inf r ^ " does not have field " ^ string_of_int fid)
 		in
 		let tfield o fid proto =
 			if fid < 0 then error (reg_inf o ^ " does not have " ^ (if proto then "proto " else "") ^ "field " ^ string_of_int fid);

+ 31 - 7
src/generators/hlopt.ml

@@ -47,6 +47,7 @@ type block = {
 	mutable bneed : ISet.t;
 	mutable bneed_all : ISet.t option;
 	mutable bwrite : (int, int) PMap.t;
+	mutable btrap : int list;
 }
 
 type control =
@@ -54,6 +55,7 @@ type control =
 	| CJCond of int
 	| CJAlways of int
 	| CTry of int
+	| CCatch
 	| CSwitch of int array
 	| CRet
 	| CThrow
@@ -75,6 +77,8 @@ let control = function
 		CSwitch cases
 	| OTrap (_,d) ->
 		CTry d
+	| OEndTrap _ ->
+		CCatch
 	| _ ->
 		CNo
 
@@ -460,7 +464,7 @@ let code_graph (f:fundecl) =
 		| CJAlways d | CJCond d -> Hashtbl.replace all_blocks (i + 1 + d) true
 		| _ -> ()
 	done;
-	let rec make_block pos =
+	let rec make_block trapl pos =
 		try
 			Hashtbl.find blocks_pos pos
 		with Not_found ->
@@ -474,11 +478,12 @@ let code_graph (f:fundecl) =
 				bneed = ISet.empty;
 				bwrite = PMap.empty;
 				bneed_all = None;
+				btrap = trapl;
 			} in
 			Hashtbl.add blocks_pos pos b;
 			let rec loop i =
-				let goto d =
-					let b2 = make_block (i + 1 + d) in
+				let goto ?(tl=b.btrap) d =
+					let b2 = make_block tl (i + 1 + d) in
 					b2.bprev <- b :: b2.bprev;
 					b2
 				in
@@ -488,7 +493,8 @@ let code_graph (f:fundecl) =
 				end else match control (op i) with
 				| CNo ->
 					loop (i + 1)
-				| CRet | CThrow ->
+				| CRet ->
+					assert(b.btrap = []);
 					b.bend <- i
 				| CJAlways d ->
 					b.bend <- i;
@@ -496,9 +502,27 @@ let code_graph (f:fundecl) =
 				| CSwitch pl ->
 					b.bend <- i;
 					b.bnext <- goto 0 :: Array.to_list (Array.map goto pl)
-				| CJCond d | CTry d ->
+				| CJCond d ->
 					b.bend <- i;
 					b.bnext <- [goto 0; goto d];
+				| CTry d ->
+					b.bend <- i;
+					b.bnext <- [goto ~tl:((i+1+d)::b.btrap) 0; goto d];
+				| CThrow ->
+					b.bend <- i;
+					match b.btrap with
+						| [] -> ()
+						| [p] -> b.bnext <- [goto ~tl:[] (p-1-i)];
+						| p :: pl -> b.bnext <- [goto ~tl:pl (p-1-i)];
+					;
+				| CCatch ->
+					let p, pl = match b.btrap with
+						| [] -> assert false;
+						| [p] -> p, []
+						| p :: pl -> p, pl
+					in
+					b.bend <- i;
+					b.bnext <- [goto ~tl:pl 0; goto ~tl:pl (p-1-i)];
 				| CLabel ->
 					b.bloop <- true;
 					loop (i + 1)
@@ -506,7 +530,7 @@ let code_graph (f:fundecl) =
 			loop pos;
 			b
 	in
-	blocks_pos, make_block 0
+	blocks_pos, make_block [] 0
 
 type rctx = {
 	r_root : block;
@@ -660,7 +684,7 @@ let remap_fun ctx f dump get_str old_code =
 		let jumps = ref [] in
 		let out_pos = ref 0 in
 		let out_code = Array.make (Array.length f.code - ctx.r_nop_count) (ONop "") in
-		let new_debug = Array.make (Array.length f.code - ctx.r_nop_count) (0,0) in
+		let new_debug = Array.make (Array.length f.code - ctx.r_nop_count) (0,0,Globals.null_pos) in
 		Array.iteri (fun i op ->
 			Array.unsafe_set new_pos i !out_pos;
 			match op with

+ 4 - 1
src/macro/eval/evalContext.ml

@@ -44,6 +44,7 @@ type scope = {
 type env_kind =
 	| EKLocalFunction of int
 	| EKMethod of int * int
+	| EKMacro of int * int
 	| EKEntrypoint
 
 (* Compile-time information for environments. This information is static for all
@@ -332,6 +333,8 @@ let kind_name eval kind =
 	let rec loop kind env = match kind with
 		| EKMethod(i1,i2) ->
 			Printf.sprintf "%s.%s" (rev_hash i1) (rev_hash i2)
+		| EKMacro(i1,i2) ->
+			Printf.sprintf "Macro call: %s.%s" (rev_hash i1) (rev_hash i2)
 		| EKLocalFunction i ->
 			begin match env with
 			| None -> Printf.sprintf "localFunction%i" i
@@ -467,7 +470,7 @@ let push_environment ctx info =
 		env_locals = locals;
 		env_captures = captures;
 		env_extra_locals = IntMap.empty;
-		env_parent = eval.env;
+		env_parent = if info.kind = EKEntrypoint then None else eval.env;
 		env_eval = eval;
 		env_stack_depth = stack_depth;
 	} in

+ 1 - 0
src/macro/eval/evalDebugMisc.ml

@@ -146,6 +146,7 @@ let resolve_ident ctx env s =
 					| Some env -> loop env
 				end
 			| EKMethod _ -> env
+			| EKMacro _ -> env
 			| EKEntrypoint ->
 				(* This can happen due to threads. Have to check what we can do here... *)
 				raise Not_found

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

@@ -171,7 +171,7 @@ let output_call_stack ctx eval p =
 		let line1,col1,line2,col2 = Lexer.get_pos_coords p in
 		let path = Path.get_real_path p.pfile in
 		let artificial,name = match kind with
-			| EKMethod _ | EKLocalFunction _ -> false,kind_name eval kind
+			| EKMethod _ | EKLocalFunction _ | EKMacro _ -> false,kind_name eval kind
 			| EKEntrypoint -> true,p.pfile
 		in
 		let source = if Sys.file_exists path then JString path else JNull in
@@ -473,7 +473,7 @@ module ValueCompletion = struct
 	exception JsonException of Json.t
 
 	let get_completion ctx text column env =
-		let p = { pmin = 0; pmax = 0; pfile = "" } in
+		let p = file_pos "" in
 		let save =
 			let old = !Parser.display_mode,DisplayPosition.display_position#get in
 			(fun () ->

+ 15 - 8
src/macro/eval/evalExceptions.ml

@@ -122,6 +122,17 @@ let catch_exceptions ctx ?(final=(fun() -> ())) f p =
 		eval.caught_exception <- vnull;
 		Option.may (build_exception_stack ctx) env;
 		eval.env <- env;
+
+		(* Careful: We have to get the message before resetting the context because toString() might access it. *)
+		let get_stack ctx =
+			let stack = match eval_stack with
+				| [] -> []
+				| l when p' = null_pos -> l (* If the exception position is null_pos, we're "probably" in a built-in function. *)
+				| _ :: l -> l (* Otherwise, ignore topmost frame position. *)
+			in
+			get_exc_error_stack ctx stack
+		in
+
 		if is v key_haxe_macro_Error then begin
 			let v1 = field v key_exception_message in
 			let v2 = field v key_pos in
@@ -139,7 +150,9 @@ let catch_exceptions ctx ?(final=(fun() -> ())) f p =
 							end else
 								Error.raise_typing_error (Printf.sprintf "Unexpected value where haxe.macro.Error was expected: %s" (s_value 0 v).sstring) null_pos
 						) (EvalArray.to_list sub)
-				| _ -> []
+				| _ ->
+					let stack = get_stack ctx in
+					List.map (fun p -> (Error.Custom "Called from here", p)) (List.rev stack)
 			in
 			reset_ctx();
 			final();
@@ -168,13 +181,7 @@ let catch_exceptions ctx ?(final=(fun() -> ())) f p =
 				| v ->
 					Error.raise_typing_error (Printf.sprintf "Invalid exception value where string was expected: %s" (s_value 0 v).sstring) null_pos
 		end else begin
-			(* Careful: We have to get the message before resetting the context because toString() might access it. *)
-			let stack = match eval_stack with
-				| [] -> []
-				| l when p' = null_pos -> l (* If the exception position is null_pos, we're "probably" in a built-in function. *)
-				| _ :: l -> l (* Otherwise, ignore topmost frame position. *)
-			in
-			let stack = get_exc_error_stack ctx stack in
+			let stack = get_stack ctx in
 			reset_ctx();
 			final();
 			let p = if p' = null_pos then p else p' in

+ 1 - 1
src/macro/eval/evalJit.ml

@@ -655,7 +655,7 @@ and jit_expr jit return e =
 				wrap()
 			| TUnop((Increment | Decrement),_,e1) | TBinop((OpAssign | OpAssignOp _),e1,_) ->
 				begin match (Texpr.skip e1).eexpr with
-				| TLocal {v_kind = VGenerated | VInlined | VInlinedConstructorVariable | VExtractorVariable} ->
+				| TLocal {v_kind = VGenerated | VInlined | VInlinedConstructorVariable _ | VExtractorVariable} ->
 					f
 				| _ ->
 					wrap()

+ 1 - 1
src/macro/eval/evalMain.ml

@@ -179,7 +179,7 @@ let call_path ctx path f vl api =
 			let vtype = get_static_prototype_as_value ctx (path_hash path) api.pos in
 			let vfield = field vtype (hash f) in
 			let p = api.pos in
-			let info = create_env_info true p.pfile (ctx.file_keys#get p.pfile) EKEntrypoint (Hashtbl.create 0) 0 0 in
+			let info = create_env_info true p.pfile (ctx.file_keys#get p.pfile) (EKMacro (path_hash path, hash f)) (Hashtbl.create 0) 0 0 in
 			let env = push_environment ctx info in
 			env.env_leave_pmin <- p.pmin;
 			env.env_leave_pmax <- p.pmax;

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

@@ -160,11 +160,11 @@ let init_fields init_fields builtins =
 		"strerror",vfun1 (fun code -> encode_string (mbedtls_strerror (decode_int code)));
 	] [];
 	init_fields builtins (["mbedtls"],"PkContext") [] [
-		"parse_key",vifun2 (fun this key password ->
-			vint (mbedtls_pk_parse_key (as_pk_context this) (decode_bytes key) (match password with VNull -> None | _ -> Some (decode_string password)));
+		"parse_key",vifun3 (fun this key password rng ->
+			vint (mbedtls_pk_parse_key (as_pk_context this) (decode_bytes key) (match password with VNull -> None | _ -> Some (decode_string password)) (as_ctr_drbg rng));
 		);
-		"parse_keyfile",vifun2 (fun this path password ->
-			vint (mbedtls_pk_parse_keyfile (as_pk_context this) (decode_string path) (match password with VNull -> None | _ -> Some (decode_string password)));
+		"parse_keyfile",vifun3 (fun this path password rng ->
+			vint (mbedtls_pk_parse_keyfile (as_pk_context this) (decode_string path) (match password with VNull -> None | _ -> Some (decode_string password)) (as_ctr_drbg rng));
 		);
 		"parse_public_key",vifun1 (fun this key ->
 			vint (mbedtls_pk_parse_public_key (as_pk_context this) (decode_bytes key));

+ 2 - 0
src/macro/eval/evalStackTrace.ml

@@ -19,6 +19,8 @@ let make_stack envs =
 		| EKMethod(st,sf) ->
 			let local_function = encode_enum_value key_haxe_StackItem 3 [|create_unknown (rev_hash st); create_unknown (rev_hash sf)|] None in
 			DynArray.add l (file_pos local_function);
+		| EKMacro(st,sf) ->
+			()
 		| EKEntrypoint ->
 			()
 	) envs;

+ 12 - 6
src/macro/macroApi.ml

@@ -26,6 +26,7 @@ type 'value compiler_api = {
 	init_macros_done : unit -> bool;
 	get_type : string -> Type.t option;
 	get_module : string -> Type.t list;
+	include_module : string -> unit;
 	after_init_macros : (unit -> unit) -> unit;
 	after_typing : (module_type list -> unit) -> unit;
 	on_generate : (Type.t list -> unit) -> bool -> unit;
@@ -56,7 +57,7 @@ type 'value compiler_api = {
 	add_global_metadata : string -> string -> (bool * bool * bool) -> pos -> unit;
 	register_define : string -> Define.user_define -> unit;
 	register_metadata : string -> Meta.user_meta -> unit;
-	add_module_check_policy : string list -> int list -> bool -> int -> unit;
+	add_module_check_policy : string list -> int list -> bool -> unit;
 	decode_expr : 'value -> Ast.expr;
 	encode_expr : Ast.expr -> 'value;
 	encode_ctype : Ast.type_hint -> 'value;
@@ -1057,8 +1058,8 @@ and encode_type_params tl =
 
 and encode_tenum e =
 	encode_mtype (TEnumDecl e) [
-		"isExtern", vbool e.e_extern;
-		"exclude", vfun0 (fun() -> e.e_extern <- true; vnull);
+		"isExtern", vbool (has_enum_flag e EnExtern);
+		"exclude", vfun0 (fun() -> add_enum_flag e EnExcluded; vnull);
 		"constructs", encode_string_map encode_efield e.e_constrs;
 		"names", encode_array (List.map encode_string e.e_names);
 	]
@@ -1156,7 +1157,7 @@ and encode_tclass c =
 	encode_mtype (TClassDecl c) [
 		"kind", encode_class_kind c.cl_kind;
 		"isExtern", vbool (has_class_flag c CExtern);
-		"exclude", vfun0 (fun() -> add_class_flag c CExtern; c.cl_init <- None; vnull);
+		"exclude", vfun0 (fun() -> add_class_flag c CExcluded; c.cl_init <- None; vnull);
 		"isInterface", vbool (has_class_flag c CInterface);
 		"isFinal", vbool (has_class_flag c CFinal);
 		"isAbstract", vbool (has_class_flag c CAbstract);
@@ -1319,6 +1320,7 @@ and encode_tvar v =
 		"capture", vbool (has_var_flag v VCaptured);
 		"extra", vopt f_extra v.v_extra;
 		"meta", encode_meta v.v_meta (fun m -> v.v_meta <- m);
+		"isStatic", vbool (has_var_flag v VStatic);
 		"$", encode_unsafe (Obj.repr v);
 	]
 
@@ -1877,6 +1879,10 @@ let macro_api ccom get_api =
 		"get_module", vfun1 (fun s ->
 			encode_array (List.map encode_type ((get_api()).get_module (decode_string s)))
 		);
+		"include_module", vfun1 (fun s ->
+			(get_api()).include_module (decode_string s);
+			vnull
+		);
 		"on_after_init_macros", vfun1 (fun f ->
 			let f = prepare_callback f 1 in
 			(get_api()).after_init_macros (fun tctx -> ignore(f []));
@@ -2292,10 +2298,10 @@ let macro_api ccom get_api =
 			vnull
 		);
 		(* Compilation server *)
-		"server_add_module_check_policy", vfun4 (fun filter policy recursive context_options ->
+		"server_add_module_check_policy", vfun3 (fun filter policy recursive ->
 			let filter = List.map decode_string (decode_array filter) in
 			let policy = List.map decode_int (decode_array policy) in
-			(get_api()).add_module_check_policy filter policy (decode_bool recursive) (decode_int context_options);
+			(get_api()).add_module_check_policy filter policy (decode_bool recursive);
 			vnull
 		);
 		"server_invalidate_files", vfun1 (fun a ->

+ 1 - 1
src/optimization/analyzer.ml

@@ -664,7 +664,7 @@ module LocalDce = struct
 			has_var_flag v VAnalyzed
 		in
 		let keep v =
-			is_used v || ((match v.v_kind with VUser _ | VInlined -> true | _ -> false) && not ctx.config.local_dce) || ExtType.has_reference_semantics v.v_type || has_var_flag v VCaptured || Meta.has Meta.This v.v_meta
+			is_used v || ((match v.v_kind with VUser _ | VInlined | VInlinedConstructorVariable _ -> true | _ -> false) && not ctx.config.local_dce) || ExtType.has_reference_semantics v.v_type || has_var_flag v VCaptured || Meta.has Meta.This v.v_meta
 		in
 		let rec use v =
 			if not (is_used v) then begin

+ 4 - 3
src/optimization/analyzerTexpr.ml

@@ -790,7 +790,7 @@ module Fusion = struct
 			let num_uses = state#get_reads v in
 			let num_writes = state#get_writes v in
 			let can_be_used_as_value = can_be_used_as_value com e in
-			let is_compiler_generated = match v.v_kind with VUser _ | VInlined -> false | _ -> true in
+			let is_compiler_generated = match v.v_kind with VUser _ | VInlined | VInlinedConstructorVariable _ -> false | _ -> true in
 			let has_type_params = match v.v_extra with Some ve when ve.v_params <> [] -> true | _ -> false in
 			let rec is_impure_extern e = match e.eexpr with
 				| TField(ef,(FStatic(cl,cf) | FInstance(cl,_,cf))) when has_class_flag cl CExtern ->
@@ -1250,8 +1250,9 @@ module Purity = struct
 				begin try
 					apply_to_class com c
 				with Purity_conflict(impure,p) ->
-					com.error "Impure field overrides/implements field which was explicitly marked as @:pure" impure.pn_field.cf_pos;
-					Error.raise_typing_error ~depth:1 (Error.compl_msg "Pure field is here") p;
+					Error.raise_typing_error_ext (Error.make_error (Custom "Impure field overrides/implements field which was explicitly marked as @:pure") ~sub:[
+						Error.make_error ~depth:1 (Custom (Error.compl_msg "Pure field is here")) p
+					] impure.pn_field.cf_pos)
 				end
 			| _ -> ()
 		) com.types;

+ 1 - 1
src/optimization/dce.ml

@@ -885,7 +885,7 @@ let sweep dce com =
 					if dce.debug then print_endline ("[DCE] Removed class " ^ (s_type_path c.cl_path));
 					loop acc l)
 			end
- 		| (TEnumDecl en) as mt :: l when Meta.has Meta.Used en.e_meta || en.e_extern || keep_whole_enum dce en ->
+ 		| (TEnumDecl en) as mt :: l when Meta.has Meta.Used en.e_meta || (has_enum_flag en EnExtern) || keep_whole_enum dce en ->
 			loop (mt :: acc) l
 		| TEnumDecl e :: l ->
 			if dce.debug then print_endline ("[DCE] Removed enum " ^ (s_type_path e.e_path));

+ 2 - 1
src/optimization/inline.ml

@@ -96,7 +96,7 @@ let api_inline2 com c field params p =
 let api_inline ctx c field params p =
 	let mk_typeexpr path =
 		let m = (try ctx.com.module_lut#find path with Not_found -> die "" __LOC__) in
-		add_dependency ctx.m.curmod m;
+		add_dependency ctx.m.curmod m MDepFromTyping;
 		Option.get (ExtList.List.find_map (function
 			| TClassDecl cl when cl.cl_path = path -> Some (Texpr.Builder.make_static_this cl p)
 			| _ -> None
@@ -685,6 +685,7 @@ let rec type_inline ctx cf f ethis params tret config p ?(self_calling_closure=f
 				raise_typing_error "Could not inline `this` outside of an instance context" po
 			)
 		| TVar (v,eo) ->
+			if has_var_flag v VStatic then raise_typing_error "Inline functions cannot have static locals" v.v_pos;
 			{ e with eexpr = TVar ((state#declare v).i_subst,opt (map false false) eo)}
 		| TReturn eo when not state#in_local_fun ->
 			if not term then begin

+ 21 - 8
src/optimization/inlineConstructors.ml

@@ -131,9 +131,9 @@ let inline_constructors ctx original_e =
 			| IOKCtor(ioc) ->
 				List.iter (fun v -> if v.v_id < 0 then cancel_v v p) io.io_dependent_vars;
 				if ioc.ioc_forced then begin
-					(* TODO construct error with sub *)
-					display_error ctx.com "Forced inline constructor could not be inlined" io.io_pos;
-					display_error ~depth:1 ctx.com (compl_msg "Cancellation happened here") p;
+					display_error_ext ctx.com (make_error (Custom "Forced inline constructor could not be inlined") ~sub:([
+						(make_error ~depth:1 (Custom (compl_msg "Cancellation happened here")) p)
+					]) io.io_pos);
 				end
 			| _ -> ()
 		end
@@ -731,22 +731,35 @@ let inline_constructors ctx original_e =
 		let cf = ctx.f.curfield in
 		if !included_untyped && not (Meta.has Meta.HasUntyped cf.cf_meta) then cf.cf_meta <- (Meta.HasUntyped,[],e.epos) :: cf.cf_meta;
 		let e = make_expr_for_rev_list el e.etype e.epos in
-		let rec get_pretty_name iv = match iv.iv_kind with
+		let rec get_pretty_name iv : string list = match iv.iv_kind with
 			| IVKField(io,fname,None) ->
 				begin try
 					let is_user_variable iv = match iv.iv_var.v_kind with VUser _ | VInlined -> true | _ -> false in
 					let iv = List.find is_user_variable io.io_aliases in
-					(get_pretty_name iv) ^ "_" ^ fname;
+					fname :: (get_pretty_name iv);
 				with Not_found ->
-					(get_pretty_name (List.hd io.io_aliases)) ^ "_" ^ fname;
+					fname :: (get_pretty_name (List.hd io.io_aliases));
 				end
-			| _ -> iv.iv_var.v_name
+			| _ -> [iv.iv_var.v_name]
+		in
+		let is_user_kind iv = match iv.iv_var.v_kind with VUser _ -> true | _ -> false in
+		let rec was_user iv = match iv.iv_kind with
+			| IVKField(io,_,_) ->
+				begin try
+					let iv = List.find is_user_kind io.io_aliases in
+					(was_user iv);
+				with Not_found ->
+					(was_user (List.hd io.io_aliases)) ;
+				end
+			| _ -> is_user_kind iv
 		in
 		IntMap.iter (fun _ iv ->
 			let v = iv.iv_var in
 			if v.v_id < 0 then begin
 				v.v_id <- -v.v_id;
-				v.v_name <- get_pretty_name iv
+				let vnames = List.rev (get_pretty_name iv) in
+				v.v_name <- String.concat "_" vnames;
+				if (was_user iv) then v.v_kind <- VInlinedConstructorVariable vnames;
 			end
 		) !vars;
 		e

+ 5 - 0
src/syntax/lexer.ml

@@ -360,6 +360,9 @@ let integer_digits = [%sedlex.regexp? (digit, Star sep_digit)]
 let hex_digit = [%sedlex.regexp? '0'..'9'|'a'..'f'|'A'..'F']
 let sep_hex_digit = [%sedlex.regexp? Opt '_', hex_digit]
 let hex_digits = [%sedlex.regexp? (hex_digit, Star sep_hex_digit)]
+let bin_digit = [%sedlex.regexp? '0'|'1']
+let sep_bin_digit = [%sedlex.regexp? Opt '_', bin_digit]
+let bin_digits = [%sedlex.regexp? (bin_digit, Star sep_bin_digit)]
 let integer = [%sedlex.regexp? ('1'..'9', Star sep_digit) | '0']
 
 let integer_suffix = [%sedlex.regexp? Opt '_', ('i'|'u'), Plus integer]
@@ -386,6 +389,8 @@ let rec token lexbuf =
 	| '\n' | '\r' -> newline lexbuf; token lexbuf
 	| "0x", Plus hex_digits, Opt integer_suffix ->
 		mk lexbuf (split_int_suffix (lexeme lexbuf))
+	| "0b", Plus bin_digits, Opt integer_suffix ->
+		mk lexbuf (split_int_suffix (lexeme lexbuf))
 	| integer, Opt integer_suffix ->
 		mk lexbuf (split_int_suffix (lexeme lexbuf))
 	| integer, float_suffix ->

+ 10 - 12
src/typing/callUnification.ml

@@ -14,7 +14,6 @@ let unify_call_args ctx el args r callp inline force_inline in_overload =
 		let msg = ("For " ^ (if opt then "optional " else "") ^ "function argument '" ^ name ^ "'") in
 		let e = match e.err_message with
 			| Unify l -> { e with err_message = Unify (l @ [(Unify_custom msg)])}
-			| Custom parent -> { e with err_message = Custom (parent ^ "\n" ^ msg)}
 			| _ -> { e with err_sub = (make_error (Custom (compl_msg msg)) e.err_pos) :: e.err_sub }
 		in
 		raise_error { e with err_message = (Call_error (Could_not_unify e.err_message)) }
@@ -415,9 +414,8 @@ let unify_field_call ctx fa el_typed el p inline =
 							p
 						) :: acc
 					) [] failures in
-
-					display_error_ext ctx.com (make_error ~sub (Custom "Could not find a suitable overload, reasons follow") p);
-					raise_typing_error_ext (make_error ~depth:1 (Custom "End of overload failure reasons") p)
+					let sub = (make_error ~depth:1 (Custom "End of overload failure reasons") p) :: sub in
+					raise_typing_error_ext (make_error ~sub (Custom "Could not find a suitable overload, reasons follow") p)
 				| Some err ->
 					raise_typing_error_ext err
 			end
@@ -429,12 +427,11 @@ let unify_field_call ctx fa el_typed el p inline =
 				maybe_check_access fcc.fc_field;
 				commit_delayed_display fcc
 			| fcc :: l ->
-				(* TODO construct error with sub *)
-				display_error ctx.com "Ambiguous overload, candidates follow" p;
 				let st = s_type (print_context()) in
-				List.iter (fun fcc ->
-					display_error ~depth:1 ctx.com (compl_msg (st fcc.fc_type)) fcc.fc_field.cf_name_pos;
-				) (fcc :: l);
+				let sub = List.map (fun fcc ->
+					make_error ~depth:1 (Custom (compl_msg (st fcc.fc_type))) fcc.fc_field.cf_name_pos
+				) (fcc :: l) in
+				display_error_ext ctx.com (make_error (Custom "Ambiguous overload, candidates follow") ~sub:(List.rev sub) p);
 				commit_delayed_display fcc
 		end else begin match List.rev candidates with
 			| [] -> fail()
@@ -513,9 +510,10 @@ object(self)
 			let ep = err.err_pos in
 			(* display additional info in the case the error is not part of our original call *)
 			if ep.pfile <> p.pfile || ep.pmax < p.pmin || ep.pmin > p.pmax then begin
-				old (if (ep = null_pos) then { err with err_pos = p } else err);
-				(* TODO add as sub for above error *)
-				if ep <> null_pos then old (make_error ~depth:(err.err_depth+1) (Custom (compl_msg "Called from macro here")) p);
+				if ep = null_pos then
+					old { err with err_pos = p }
+				else
+					old { err with err_sub = (make_error ~depth:(err.err_depth+1) (Custom (compl_msg "Called from macro here")) p) :: err.err_sub }
 			end else
 				old err;
 		);

+ 4 - 3
src/typing/fields.ml

@@ -221,8 +221,9 @@ let field_access ctx mode f fh e pfield =
 			if bypass_accessor then (
 				(match e.eexpr with TLocal _ when Common.defined ctx.com Define.Haxe3Compat -> warning ctx WTemp "Field set has changed here in Haxe 4: call setter explicitly to keep Haxe 3.x behaviour" pfield | _ -> ());
 				if not (is_physical_field f) then begin
-					display_error ctx.com "This field cannot be accessed because it is not a real variable" pfield;
-					display_error ctx.com "Add @:isVar here to enable it" f.cf_pos;
+					display_error_ext ctx.com (make_error (Custom "This field cannot be accessed because it is not a real variable") ~sub:[
+						make_error ~depth:1 (Custom "Add @:isVar here to enable it") f.cf_pos
+					] pfield);
 				end;
 				normal false
 			)
@@ -487,7 +488,7 @@ let type_field cfg ctx e i p mode (with_type : WithType.t) =
 			with Not_found ->
 				match loop ctx.g.global_using with
 				| AKUsingField { se_access = { fa_host = FHStatic c } } as acc ->
-					add_dependency ctx.m.curmod c.cl_module;
+					add_dependency ctx.m.curmod c.cl_module MDepFromTyping;
 					acc
 				| _ -> die "" __LOC__
 		) t e in

+ 15 - 24
src/typing/generic.ml

@@ -87,7 +87,7 @@ let rec generic_substitute_type' gctx allow_expr t =
 		(* maybe loop, or generate cascading generics *)
 		let info = gctx.ctx.g.get_build_info gctx.ctx (TClassDecl c2) gctx.p in
 		let t = info.build_apply (List.map (generic_substitute_type' gctx true) tl2) in
-		(match follow t,gctx.mg with TInst(c,_), Some m -> add_dependency m c.cl_module | _ -> ());
+		(match follow t,gctx.mg with TInst(c,_), Some m -> add_dependency m c.cl_module MDepFromTyping | _ -> ());
 		t
 	| _ ->
 		try
@@ -188,8 +188,8 @@ let static_method_container gctx c cf p =
 		let cg = mk_class mg (pack,name) c.cl_pos c.cl_name_pos in
 		mg.m_types <- [TClassDecl cg];
 		ctx.com.module_lut#add mg.m_path mg;
-		add_dependency mg m;
-		add_dependency ctx.m.curmod mg;
+		add_dependency mg m MDepFromTyping;
+		add_dependency ctx.m.curmod mg MDepFromTyping;
 		cg
 
 let set_type_parameter_dependencies mg tl =
@@ -220,7 +220,7 @@ let set_type_parameter_dependencies mg tl =
 			loop ret
 		end
 	and add_dep m tl =
-		add_dependency mg m;
+		add_dependency mg m MDepFromTyping;
 		List.iter loop tl
 	in
 	List.iter loop tl
@@ -312,7 +312,7 @@ let build_generic_class ctx c p tl =
 			| Pure
 			| Struct | StructInit
 			| Using
-			| AutoBuild ->
+			| AutoBuild | Unreflective ->
 				true
 			| _ ->
 				false
@@ -320,8 +320,8 @@ let build_generic_class ctx c p tl =
 		cg.cl_meta <- (Meta.NoDoc,[],null_pos) :: cg.cl_meta;
 		mg.m_types <- [TClassDecl cg];
 		ctx.com.module_lut#add mg.m_path mg;
-		add_dependency mg m;
-		add_dependency ctx.m.curmod mg;
+		add_dependency mg m MDepFromTyping;
+		add_dependency ctx.m.curmod mg MDepFromTyping;
 		set_type_parameter_dependencies mg tl;
 		let build_field cf_old =
 			let params = List.map (fun ttp ->
@@ -355,9 +355,9 @@ let build_generic_class ctx c p tl =
 							| None ->
 								begin match cf_old.cf_kind with
 									| Method _ when not (has_class_flag c CInterface) && not (has_class_flag c CExtern) && not (has_class_field_flag cf_old CfAbstract) ->
-										(* TODO use sub error *)
-										display_error ctx.com (Printf.sprintf "Field %s has no expression (possible typing order issue)" cf_new.cf_name) cf_new.cf_pos;
-										display_error ctx.com (Printf.sprintf "While building %s" (s_type_path cg.cl_path)) p;
+										display_error_ext ctx.com (make_error (Custom (Printf.sprintf "Field %s has no expression (possible typing order issue)" cf_new.cf_name)) ~sub:([
+											(make_error ~depth:1 (Custom (compl_msg (Printf.sprintf "While building %s" (s_type_path cg.cl_path)))) p)
+										]) cf_new.cf_pos);
 									| _ ->
 										()
 								end
@@ -452,18 +452,9 @@ let type_generic_function ctx fa fcc with_type p =
 	) monos;
 	let el = fcc.fc_args in
 	let gctx = make_generic ctx cf.cf_params monos (Meta.has (Meta.Custom ":debug.generic") cf.cf_meta) p in
+	let fc_type = build_instances ctx fcc.fc_type p in
 	let name = cf.cf_name ^ "_" ^ gctx.name in
 	let params = extract_type_parameters monos in
-	let clones = List.map (fun ttp ->
-		let name_path = if (fst ttp.ttp_class.cl_path) = [cf.cf_name] then ([name],ttp.ttp_name) else ttp.ttp_class.cl_path in
-		clone_type_parameter gctx c.cl_module name_path ttp
-	) params in
-	let param_subst = List.map2 (fun ttp ttp' ->
-		(ttp.ttp_type,ttp')
-	) params clones in
-	let param_subst = List.map (fun (t,ttp) -> t,(ttp.ttp_type,None)) param_subst in
-	let gctx = {gctx with subst = param_subst @ gctx.subst} in
-	let fc_type = build_instances ctx (generic_substitute_type gctx fcc.fc_type) p in
 	let unify_existing_field tcf pcf = try
 		unify_raise tcf fc_type p
 	with Error ({ err_message = Unify _; err_depth = depth } as err) ->
@@ -498,9 +489,9 @@ let type_generic_function ctx fa fcc with_type p =
 			ignore(follow cf.cf_type);
 			let rec check e = match e.eexpr with
 				| TNew({cl_kind = KTypeParameter _} as c,_,_) when not (TypeloadCheck.is_generic_parameter ctx c) ->
-					(* TODO use sub error *)
-					display_error ctx.com "Only generic type parameters can be constructed" e.epos;
-					display_error ctx.com "While specializing this call" p;
+					display_error_ext ctx.com (make_error (Custom "Only generic type parameters can be constructed") ~sub:([
+						(make_error ~depth:1 (Custom (compl_msg "While specializing this call")) p)
+					]) e.epos);
 				| _ ->
 					Type.iter check e
 			in
@@ -519,7 +510,7 @@ let type_generic_function ctx fa fcc with_type p =
 				| _ -> true
 			) cf.cf_meta in
 			cf2.cf_meta <- (Meta.NoCompletion,[],p) :: (Meta.NoUsing,[],p) :: (Meta.GenericInstance,[],p) :: meta;
-			cf2.cf_params <- clones
+			cf2.cf_params <- params
 		in
 		let mk_cf2 name =
 			mk_field ~static:stat name fc_type cf.cf_pos cf.cf_name_pos

+ 1 - 1
src/typing/instanceBuilder.ml

@@ -99,7 +99,7 @@ let get_build_info ctx mtype p =
 		in
 		make_build_info kind c.cl_path c.cl_params (has_class_flag c CExtern) f
 	| TEnumDecl e ->
-		make_build_info BuildNormal e.e_path e.e_params e.e_extern (fun t -> TEnum (e,t))
+		make_build_info BuildNormal e.e_path e.e_params (has_enum_flag e EnExtern) (fun t -> TEnum (e,t))
 	| TTypeDecl td ->
 		begin try
 			let msg = match Meta.get Meta.Deprecated td.t_meta with

+ 62 - 34
src/typing/macroContext.ml

@@ -41,15 +41,20 @@ module HxbWriterConfigWriterEval = HxbWriterConfig.WriterConfigWriter(EvalDataAp
 let macro_interp_cache = ref None
 
 let safe_decode com v expected t p f =
-	try
-		f ()
-	with MacroApi.Invalid_expr ->
+	let raise_decode_error s =
 		let path = [dump_path 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);
 		close_out ch;
-		raise_typing_error (Printf.sprintf "Expected %s but got %s (see %s.txt for details)" expected (Interp.value_string v) (String.concat "/" path)) p
+		raise_typing_error (Printf.sprintf "%s (see %s.txt for details)" s (String.concat "/" path)) p
+	in
+
+	try f () with
+		| EvalContext.RunTimeException (VString emsg,_,_) ->
+			raise_decode_error (Printf.sprintf "Eval runtime exception: %s" emsg.sstring)
+		| MacroApi.Invalid_expr ->
+			raise_decode_error (Printf.sprintf "Expected %s but got %s" expected (Interp.value_string v))
 
 
 let macro_timer com l =
@@ -57,17 +62,18 @@ let macro_timer com l =
 
 let typing_timer ctx need_type f =
 	let t = Timer.timer ["typing"] in
-	let old = ctx.com.error_ext in
-	let restore_report_mode = disable_report_mode ctx.com in
-	let restore_field_state = TypeloadFunction.save_field_state ctx in
-	ctx.com.error_ext <- (fun err -> raise_error { err with err_from_macro = true });
-
 	let ctx = if need_type && ctx.pass < PTypeField then begin
 		enter_field_typing_pass ctx.g ("typing_timer",[]);
 		TyperManager.clone_for_expr ctx ctx.e.curfun false
 	end else
 		ctx
 	in
+
+	let old = ctx.com.error_ext in
+	let restore_report_mode = disable_report_mode ctx.com in
+	let restore_field_state = TypeloadFunction.save_field_state ctx in
+	ctx.com.error_ext <- (fun err -> raise_error { err with err_from_macro = true });
+
 	let exit() =
 		t();
 		ctx.com.error_ext <- old;
@@ -122,6 +128,9 @@ let make_macro_com_api com mcom p =
 		get_module = (fun s ->
 			Interp.exc_string "unsupported"
 		);
+		include_module = (fun s ->
+			Interp.exc_string "unsupported"
+		);
 		after_init_macros = (fun f ->
 			com.callbacks#add_after_init_macros (fun () ->
 				let t = macro_timer com ["afterInitMacros"] in
@@ -257,7 +266,7 @@ let make_macro_com_api com mcom p =
 				com.global_metadata <- (ExtString.String.nsplit s1 ".",m,config) :: com.global_metadata;
 			) meta;
 		);
-		add_module_check_policy = (fun sl il b i ->
+		add_module_check_policy = (fun sl il b ->
 			Interp.exc_string "unsupported"
 		);
 		register_define = (fun s data -> Define.register_user_define com.user_defines s data);
@@ -395,10 +404,16 @@ let make_macro_api ctx mctx p =
 		MacroApi.get_module = (fun s ->
 			typing_timer ctx false (fun ctx ->
 				let path = parse_path s in
-				let m = List.map type_of_module_type (TypeloadModule.load_module ctx path p).m_types in
+				let m = List.map type_of_module_type (TypeloadModule.load_module ~origin:MDepFromMacro ctx path p).m_types in
 				m
 			)
 		);
+		MacroApi.include_module = (fun s ->
+			typing_timer ctx false (fun ctx ->
+				let path = parse_path s in
+				ignore(TypeloadModule.load_module ~origin:MDepFromMacroInclude ctx path p)
+			)
+		);
 		MacroApi.type_expr = (fun e ->
 			typing_timer ctx true (fun ctx -> type_expr ctx e WithType.value)
 		);
@@ -461,10 +476,11 @@ let make_macro_api ctx mctx p =
 				| _ -> false
 			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.com ctx.g ~dont_check_path:(has_native_meta) m (Path.UniqueKey.lazy_path mdep.m_extra.m_file) [tdef,pos] pos in
+				let mdep = Option.map_default (fun s -> TypeloadModule.load_module ~origin:MDepFromMacro ctx (parse_path s) pos) ctx.m.curmod mdep in
+				let mnew = TypeloadModule.type_module ctx.com ctx.g ~dont_check_path:(has_native_meta) m (ctx.com.file_keys#generate_virtual ctx.com.compilation_step) [tdef,pos] pos in
 				mnew.m_extra.m_kind <- if is_macro then MMacro else MFake;
-				add_dependency mnew mdep;
+				add_dependency mnew mdep MDepFromMacro;
+				add_dependency mdep mnew MDepFromMacroDefine;
 				ctx.com.module_nonexistent_lut#clear;
 			in
 			add false ctx;
@@ -492,20 +508,21 @@ let make_macro_api ctx mctx p =
 				let m = ctx.com.module_lut#find mpath in
 				ignore(TypeloadModule.type_types_into_module ctx.com ctx.g m types pos)
 			with Not_found ->
-				let mnew = TypeloadModule.type_module ctx.com ctx.g mpath (Path.UniqueKey.lazy_path ctx.m.curmod.m_extra.m_file) types pos in
+				let mnew = TypeloadModule.type_module ctx.com ctx.g mpath (ctx.com.file_keys#generate_virtual ctx.com.compilation_step) types pos in
 				mnew.m_extra.m_kind <- MFake;
-				add_dependency mnew ctx.m.curmod;
+				add_dependency mnew ctx.m.curmod MDepFromMacro;
+				add_dependency ctx.m.curmod mnew MDepFromMacroDefine;
 				ctx.com.module_nonexistent_lut#clear;
 			end
 		);
 		MacroApi.module_dependency = (fun mpath file ->
 			let m = typing_timer ctx false (fun ctx ->
 				let old_deps = ctx.m.curmod.m_extra.m_deps in
-				let m = TypeloadModule.load_module ctx (parse_path mpath) p in
+				let m = TypeloadModule.load_module ~origin:MDepFromMacro ctx (parse_path mpath) p in
 				ctx.m.curmod.m_extra.m_deps <- old_deps;
 				m
 			) in
-			add_dependency m (TypeloadCacheHook.create_fake_module ctx.com file);
+			add_dependency m (TypeloadCacheHook.create_fake_module ctx.com file) MDepFromMacro;
 		);
 		MacroApi.current_module = (fun() ->
 			ctx.m.curmod
@@ -526,20 +543,15 @@ let make_macro_api ctx mctx p =
 				ctx.com.global_metadata <- (ExtString.String.nsplit s1 ".",m,config) :: ctx.com.global_metadata;
 			) meta;
 		);
-		MacroApi.add_module_check_policy = (fun sl il b i ->
+		MacroApi.add_module_check_policy = (fun sl il b ->
 			let add ctx =
 				ctx.g.module_check_policies <- (List.fold_left (fun acc s -> (ExtString.String.nsplit s ".",List.map Obj.magic il,b) :: acc) ctx.g.module_check_policies sl);
 				ctx.com.module_lut#iter (fun _ m -> m.m_extra.m_check_policy <- TypeloadModule.get_policy ctx.g m.m_path);
 			in
-			let add_macro ctx = match ctx.g.macros with
+			add ctx;
+			match ctx.g.macros with
 				| None -> ()
-				| Some(_,mctx) -> add mctx;
-			in
-			let open CompilationCache in
-			match Obj.magic i with
-			| NormalContext -> add ctx
-			| MacroContext -> add_macro ctx
-			| NormalAndMacroContext -> add ctx; add_macro ctx;
+				| Some(_,mctx) -> add mctx
 		);
 		MacroApi.with_imports = (fun imports usings f ->
 			let restore_resolution = ctx.m.import_resolution#save in
@@ -582,8 +594,8 @@ let make_macro_api ctx mctx p =
 
 let init_macro_interp mctx mint =
 	let p = null_pos in
-	ignore(TypeloadModule.load_module mctx (["haxe";"macro"],"Expr") p);
-	ignore(TypeloadModule.load_module mctx (["haxe";"macro"],"Type") p);
+	ignore(TypeloadModule.load_module ~origin:MDepFromMacro mctx (["haxe";"macro"],"Expr") p);
+	ignore(TypeloadModule.load_module ~origin:MDepFromMacro mctx (["haxe";"macro"],"Type") p);
 	Interp.init mint;
 	macro_interp_cache := Some mint
 
@@ -632,11 +644,22 @@ and flush_macro_context mint mctx =
 		| _ ->
 			()
 	in
+	(* Apply native paths for externs only *)
+	let maybe_apply_native_paths t =
+		let apply_native = match t with
+			| TClassDecl { cl_kind = KAbstractImpl a } -> a.a_extern && a.a_enum
+			| TEnumDecl e -> has_enum_flag e EnExtern
+			| _ -> false
+		in
+		if apply_native then Naming.apply_native_paths t
+	in
 	let type_filters = [
 		FiltersCommon.remove_generic_base;
 		Exceptions.patch_constructors mctx;
 		(fun mt -> AddFieldInits.add_field_inits mctx.c.curclass.cl_path (RenameVars.init mctx.com) mctx.com mt);
+		Filters.update_cache_dependencies ~close_monomorphs:false mctx.com;
 		minimal_restore;
+		maybe_apply_native_paths
 	] in
 	let ready = fun t ->
 		FiltersCommon.apply_filters_once mctx expr_filters t;
@@ -696,7 +719,10 @@ let create_macro_context com =
 			[cp#clone]
 	) com.class_paths#as_list;
 	(* Eval _std must be in front so we don't look into hxnodejs or something. *)
-	com2.class_paths#add (Option.get !eval_std);
+	(* This can run before `TyperEntry.create`, so in order to display nice error when std is not found, this needs to be checked here too *)
+	(match !eval_std with
+	| Some std -> com2.class_paths#add std
+	| None -> Error.raise_std_not_found ());
 	let defines = adapt_defines_to_macro_context com2.defines; in
 	com2.defines.values <- defines.values;
 	com2.defines.defines_signature <- None;
@@ -725,7 +751,7 @@ let load_macro_module mctx com cpath display p =
 	(* Temporarily enter display mode while typing the macro. *)
 	let old = mctx.com.display in
 	if display then mctx.com.display <- com.display;
-	let mloaded = TypeloadModule.load_module mctx m p in
+	let mloaded = TypeloadModule.load_module ~origin:MDepFromMacro mctx m p in
 	mctx.m <- {
 		curmod = mloaded;
 		import_resolution = new resolution_list ["import";s_type_path cpath];
@@ -797,7 +823,7 @@ let load_macro ctx com mctx api display cpath f p =
 	let meth,mloaded = load_macro'' com mctx display cpath f p in
 	let _,_,{cl_path = cpath},_ = meth in
 	let call args =
-		add_dependency ctx.m.curmod mloaded;
+		add_dependency ctx.m.curmod mloaded MDepFromMacro;
 		do_call_macro ctx.com api cpath f args p
 	in
 	mctx, meth, call
@@ -961,7 +987,9 @@ let type_macro ctx mode cpath f (el:Ast.expr list) p =
 								| None -> die "" __LOC__
 								| Some (_,_,fields) -> fields)
 							else
-								List.map Interp.decode_field (Interp.decode_array v)
+								let ct = make_ptp_th (mk_type_path ~sub:"Field" (["haxe";"macro"], "Expr")) null_pos in
+								let t = Typeload.load_complex_type mctx false LoadNormal ct in
+								List.map (fun f -> safe_decode ctx.com f "Field" t p (fun () -> Interp.decode_field f)) (Interp.decode_array v)
 						in
 						MSuccess (EVars [mk_evar ~t:(CTAnonymous fields,p) ("fields",null_pos)],p)
 					)
@@ -994,7 +1022,7 @@ let call_macro mctx args margs call p =
 	call (List.map (fun e -> try Interp.make_const e with Exit -> raise_typing_error "Argument should be a constant" e.epos) el)
 
 let resolve_init_macro com e =
-	let p = { pfile = "--macro " ^ e; pmin = -1; pmax = -1 } in
+	let p = fake_pos ("--macro " ^ e) in
 	let e = try
 		if String.get e (String.length e - 1) = ';' then raise_typing_error "Unexpected ;" p;
 		begin match ParserEntry.parse_expr_string com.defines e p raise_typing_error false with

+ 2 - 2
src/typing/matcher/compile.ml

@@ -270,7 +270,7 @@ and compile_switch mctx subjects cases =
 	let (subject_null,subject_switch,subject_default),reset_subject =
 		let subjects = match null with
 			| [] ->
-				if is_explicit_null subject.etype then
+				if is_explicit_null_or_abstract_over_that subject.etype then
 					switch_subject,subject,subject
 				else begin match switch_cases with
 				| [] ->
@@ -291,7 +291,7 @@ and compile_switch mctx subjects cases =
 	in
 	let dt = match null with
 		| [] ->
-			if is_explicit_null subject.etype then null_guard switch_default else dt
+			if is_explicit_null_or_abstract_over_that subject.etype then null_guard switch_default else dt
 		| cases ->
 			let dt_null = compile mctx subjects (cases @ default) in
 			null_guard dt_null

+ 6 - 1
src/typing/matcher/exprToPattern.ml

@@ -365,9 +365,14 @@ let rec make pctx toplevel t e =
 			let is_matchable cf =
 				match cf.cf_kind with Method _ -> false | _ -> true
 			in
+			(* TODO: This needs a better check, but it's not obvious how to approach this. See #11433 *)
+			let is_probably_pos cf = match cf.cf_name with
+				| "pos" | "posPath" | "namePos" -> true
+				| _ -> false
+			in
 			let patterns,fields = List.fold_left (fun (patterns,fields) (cf,t) ->
 				try
-					if pctx.in_reification && cf.cf_name = "pos" then raise Not_found;
+					if pctx.in_reification && is_probably_pos cf then raise Not_found;
 					let e1 = Expr.field_assoc cf.cf_name fl in
 					make pctx false t e1 :: patterns,cf.cf_name :: fields
 				with Not_found ->

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff